mirror of
https://github.com/henrydcase/pqc.git
synced 2024-11-22 15:39:07 +00:00
Add ephemeral versions of ThreeBears
This commit is contained in:
parent
f971718ef7
commit
13c0317e25
14
crypto_kem/babybear-ephem/META.yml
Normal file
14
crypto_kem/babybear-ephem/META.yml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
name: BabyBearEphem
|
||||||
|
type: kem
|
||||||
|
claimed-nist-level: 1
|
||||||
|
claimed-security: IND-CPA
|
||||||
|
length-public-key: 804
|
||||||
|
length-ciphertext: 917
|
||||||
|
length-secret-key: 40
|
||||||
|
length-shared-secret: 32
|
||||||
|
nistkat-sha256: 1caf1dc65c7b2923c936ed464574694a8983ed5508dadfc554fd98e1095652e9
|
||||||
|
principal-submitters:
|
||||||
|
- Mike Hamburg
|
||||||
|
implementations:
|
||||||
|
- name: clean
|
||||||
|
version: https://sourceforge.net/p/threebears/code/ci/f4ce0ebfc84a5e01a75bfc8297b6d175e993cfa4/
|
24
crypto_kem/babybear-ephem/clean/LICENSE
Normal file
24
crypto_kem/babybear-ephem/clean/LICENSE
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
Copyright (c) 2016-2019 Rambus, Inc.
|
||||||
|
and licensed under the following MIT license.
|
||||||
|
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2016-2019 Rambus Inc.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
21
crypto_kem/babybear-ephem/clean/Makefile
Normal file
21
crypto_kem/babybear-ephem/clean/Makefile
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# This Makefile can be used with GNU Make or BSD Make
|
||||||
|
|
||||||
|
LIB=libbabybear-ephem_clean.a
|
||||||
|
|
||||||
|
HEADERS = api.h melas_fec.h params.h ring.h threebears.h
|
||||||
|
OBJECTS = kem.o melas_fec.o ring.o threebears.o
|
||||||
|
|
||||||
|
|
||||||
|
CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS)
|
||||||
|
|
||||||
|
all: $(LIB)
|
||||||
|
|
||||||
|
%.o: %.c $(HEADERS)
|
||||||
|
$(CC) $(CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
$(LIB): $(OBJECTS)
|
||||||
|
$(AR) -r $@ $(OBJECTS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) $(OBJECTS)
|
||||||
|
$(RM) $(LIB)
|
19
crypto_kem/babybear-ephem/clean/Makefile.Microsoft_nmake
Normal file
19
crypto_kem/babybear-ephem/clean/Makefile.Microsoft_nmake
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# This Makefile can be used with Microsoft Visual Studio's nmake using the command:
|
||||||
|
# nmake /f Makefile.Microsoft_nmake
|
||||||
|
|
||||||
|
LIBRARY=libbabybear-ephem_clean.lib
|
||||||
|
OBJECTS = kem.obj melas_fec.obj ring.obj threebears.obj
|
||||||
|
|
||||||
|
CFLAGS=/nologo /I ..\..\..\common /W4 /WX
|
||||||
|
|
||||||
|
all: $(LIBRARY)
|
||||||
|
|
||||||
|
# Make sure objects are recompiled if headers change.
|
||||||
|
$(OBJECTS): *.h
|
||||||
|
|
||||||
|
$(LIBRARY): $(OBJECTS)
|
||||||
|
LIB.EXE /NOLOGO /WX /OUT:$@ $**
|
||||||
|
|
||||||
|
clean:
|
||||||
|
-DEL $(OBJECTS)
|
||||||
|
-DEL $(LIBRARY)
|
18
crypto_kem/babybear-ephem/clean/api.h
Normal file
18
crypto_kem/babybear-ephem/clean/api.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#ifndef PQCLEAN_BABYBEAREPHEM_CLEAN_API_H
|
||||||
|
#define PQCLEAN_BABYBEAREPHEM_CLEAN_API_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define PQCLEAN_BABYBEAREPHEM_CLEAN_CRYPTO_SECRETKEYBYTES 40
|
||||||
|
#define PQCLEAN_BABYBEAREPHEM_CLEAN_CRYPTO_PUBLICKEYBYTES 804
|
||||||
|
#define PQCLEAN_BABYBEAREPHEM_CLEAN_CRYPTO_BYTES 32
|
||||||
|
#define PQCLEAN_BABYBEAREPHEM_CLEAN_CRYPTO_CIPHERTEXTBYTES 917
|
||||||
|
#define PQCLEAN_BABYBEAREPHEM_CLEAN_CRYPTO_ALGNAME "BabyBearEphem"
|
||||||
|
|
||||||
|
int PQCLEAN_BABYBEAREPHEM_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk);
|
||||||
|
int PQCLEAN_BABYBEAREPHEM_CLEAN_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk);
|
||||||
|
int PQCLEAN_BABYBEAREPHEM_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk);
|
||||||
|
|
||||||
|
#endif
|
22
crypto_kem/babybear-ephem/clean/kem.c
Normal file
22
crypto_kem/babybear-ephem/clean/kem.c
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#include "api.h"
|
||||||
|
#include "params.h"
|
||||||
|
#include "randombytes.h"
|
||||||
|
#include "threebears.h"
|
||||||
|
|
||||||
|
int PQCLEAN_BABYBEAREPHEM_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk) {
|
||||||
|
randombytes(sk, PRIVATE_KEY_BYTES);
|
||||||
|
PQCLEAN_BABYBEAREPHEM_CLEAN_get_pubkey(pk, sk);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PQCLEAN_BABYBEAREPHEM_CLEAN_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk) {
|
||||||
|
uint8_t seed[ENC_SEED_BYTES + IV_BYTES];
|
||||||
|
randombytes(seed, sizeof(seed));
|
||||||
|
encapsulate(ss, ct, pk, seed);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PQCLEAN_BABYBEAREPHEM_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk) {
|
||||||
|
PQCLEAN_BABYBEAREPHEM_CLEAN_decapsulate(ss, ct, sk);
|
||||||
|
return 0;
|
||||||
|
}
|
87
crypto_kem/babybear-ephem/clean/melas_fec.c
Normal file
87
crypto_kem/babybear-ephem/clean/melas_fec.c
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
/* Melas forward error correction, reference code (as implemented in the paper) */
|
||||||
|
#include "melas_fec.h"
|
||||||
|
|
||||||
|
/* Return s/2^n mod R */
|
||||||
|
static fec_gf_t step(size_t n, fec_gf_t R, fec_gf_t s) {
|
||||||
|
for (; n; n--) {
|
||||||
|
s = (s ^ ((s & 1) * R)) >> 1;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compute syndrome(data), where data has length len */
|
||||||
|
#define syndrome18(data,len) s18update(0,data,len)
|
||||||
|
static fec_gf_t s18update(fec_gf_t r, const uint8_t *data, size_t len) {
|
||||||
|
for (size_t i = 0; i < len; i++) {
|
||||||
|
r = step(8, 0x46231, r ^ data[i]);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Append 3 bytes of FEC(data) to data, so that the FEC becomes 0 */
|
||||||
|
void PQCLEAN_BABYBEAREPHEM_CLEAN_melas_fec_set(
|
||||||
|
uint8_t out[MELAS_FEC_BYTES],
|
||||||
|
const uint8_t *data,
|
||||||
|
size_t len
|
||||||
|
) {
|
||||||
|
fec_gf_t fec = syndrome18(data, len);
|
||||||
|
for (size_t i = 0; i < MELAS_FEC_BYTES; i++, fec >>= 8) {
|
||||||
|
out[i] = (uint8_t)fec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return a*b mod Q */
|
||||||
|
static fec_gf_t mul(fec_gf_t a, fec_gf_t b) {
|
||||||
|
fec_gf_t r = 0;
|
||||||
|
for (size_t i = 0; i < 9; i++) {
|
||||||
|
r ^= ((b >> (8 - i)) & 1) * a;
|
||||||
|
a = step(1, Q, a);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reverse an 18-bit number x */
|
||||||
|
static fec_gf_t reverse18(fec_gf_t x) {
|
||||||
|
fec_gf_t ret = 0;
|
||||||
|
for (size_t i = 0; i < 18; i++) {
|
||||||
|
ret ^= ((x >> i) & 1) << (17 - i);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Correct data to have the given FEC */
|
||||||
|
void PQCLEAN_BABYBEAREPHEM_CLEAN_melas_fec_correct (
|
||||||
|
uint8_t *data,
|
||||||
|
size_t len,
|
||||||
|
const uint8_t fec[MELAS_FEC_BYTES]
|
||||||
|
) {
|
||||||
|
|
||||||
|
fec_gf_t a = s18update(syndrome18(data, len), fec, MELAS_FEC_BYTES);
|
||||||
|
fec_gf_t c, r, htr;
|
||||||
|
size_t i;
|
||||||
|
const uint8_t table[9] = {36, 10, 43, 215, 52, 11, 116, 244, 0};
|
||||||
|
fec_gf_t e0, e1;
|
||||||
|
|
||||||
|
/* Form a quadratic equation from the syndrome */
|
||||||
|
c = mul(step(9, Q, a), step(9, Q, reverse18(a)));
|
||||||
|
for (i = 0, r = 0x100; i < 510; i++) {
|
||||||
|
r = mul(r, c);
|
||||||
|
}
|
||||||
|
r = step(17, Q, r);
|
||||||
|
a = step(511 - (len + MELAS_FEC_BYTES) * 8, Q, a);
|
||||||
|
|
||||||
|
/* Solve using the half trace */
|
||||||
|
for (i = 0, htr = 0; i < 9; i++) {
|
||||||
|
htr ^= ((r >> i) & 1) * table[i];
|
||||||
|
}
|
||||||
|
e0 = mul(a, htr);
|
||||||
|
e1 = e0 ^ a;
|
||||||
|
|
||||||
|
/* Correct the errors using the locators */
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
data[i] ^= (uint8_t)(e0 & (((e0 & (e0 - 1)) - 1) >> 9));
|
||||||
|
data[i] ^= (uint8_t)(e1 & (((e1 & (e1 - 1)) - 1) >> 9));
|
||||||
|
e0 = step(8, Q, e0);
|
||||||
|
e1 = step(8, Q, e1);
|
||||||
|
}
|
||||||
|
}
|
26
crypto_kem/babybear-ephem/clean/melas_fec.h
Normal file
26
crypto_kem/babybear-ephem/clean/melas_fec.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#ifndef __THREEBEARS_MELAS_FEC_H__
|
||||||
|
#define __THREEBEARS_MELAS_FEC_H__
|
||||||
|
|
||||||
|
#include "api.h"
|
||||||
|
|
||||||
|
#define MELAS_FEC_BYTES 3
|
||||||
|
#define MELAS_FEC_BITS 18
|
||||||
|
|
||||||
|
typedef uint32_t fec_gf_t;
|
||||||
|
static const fec_gf_t Q = 0x211;
|
||||||
|
|
||||||
|
/* Append 3 bytes of FEC(data) to data, so that the FEC becomes 0 */
|
||||||
|
void PQCLEAN_BABYBEAREPHEM_CLEAN_melas_fec_set(
|
||||||
|
uint8_t out[MELAS_FEC_BYTES],
|
||||||
|
const uint8_t *data,
|
||||||
|
size_t len
|
||||||
|
);
|
||||||
|
|
||||||
|
/* Append 3 bytes of FEC(data) to data, so that the FEC becomes 0 */
|
||||||
|
void PQCLEAN_BABYBEAREPHEM_CLEAN_melas_fec_correct(
|
||||||
|
uint8_t *data,
|
||||||
|
size_t len,
|
||||||
|
const uint8_t fec[MELAS_FEC_BYTES]
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif
|
29
crypto_kem/babybear-ephem/clean/params.h
Normal file
29
crypto_kem/babybear-ephem/clean/params.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#ifndef __THREEBEARS_PARAMS_H__
|
||||||
|
#define __THREEBEARS_PARAMS_H__
|
||||||
|
|
||||||
|
#define VERSION 1
|
||||||
|
#define MATRIX_SEED_BYTES 24
|
||||||
|
#define ENC_SEED_BYTES 32
|
||||||
|
#define IV_BYTES 0
|
||||||
|
#define LGX 10
|
||||||
|
#define DIGITS 312
|
||||||
|
#define DIM 2
|
||||||
|
#define VAR_TIMES_128 128
|
||||||
|
#define LPR_BITS 4
|
||||||
|
#define FEC_BITS 18
|
||||||
|
#define CCA 0
|
||||||
|
#define SHARED_SECRET_BYTES 32
|
||||||
|
#define PRIVATE_KEY_BYTES 40
|
||||||
|
#define PRF_KEY_BYTES PRIVATE_KEY_BYTES
|
||||||
|
|
||||||
|
#define BEAR_NAME "BabyBearEphem"
|
||||||
|
#define encapsulate PQCLEAN_BABYBEAREPHEM_CLEAN_encapsulate
|
||||||
|
#define decapsulate PQCLEAN_BABYBEAREPHEM_CLEAN_decapsulate
|
||||||
|
#define get_pubkey PQCLEAN_BABYBEAREPHEM_CLEAN_get_pubkey
|
||||||
|
|
||||||
|
#define GF_BYTES ((LGX*DIGITS+7)/8)
|
||||||
|
#define PUBLIC_KEY_BYTES (MATRIX_SEED_BYTES + DIM*GF_BYTES)
|
||||||
|
#define CAPSULE_BYTES \
|
||||||
|
(DIM*GF_BYTES + IV_BYTES + ((ENC_SEED_BYTES*8+FEC_BITS)*LPR_BITS+7)/8)
|
||||||
|
|
||||||
|
#endif
|
107
crypto_kem/babybear-ephem/clean/ring.c
Normal file
107
crypto_kem/babybear-ephem/clean/ring.c
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
/** Ring arithmetic implementation */
|
||||||
|
#include "ring.h"
|
||||||
|
|
||||||
|
/** Return the i'th limb of the modulus */
|
||||||
|
limb_t PQCLEAN_BABYBEAREPHEM_CLEAN_modulus(size_t i) {
|
||||||
|
return (i == DIGITS / 2) ? LMASK - 1 : LMASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Multiply and accumulate c += a*b */
|
||||||
|
void PQCLEAN_BABYBEAREPHEM_CLEAN_mac(gf_t c, const gf_t a, const gf_t b) {
|
||||||
|
/* Reference non-Karatsuba MAC */
|
||||||
|
dslimb_t accum[2 * DIGITS] = {0};
|
||||||
|
dslimb_t chain;
|
||||||
|
size_t i, j;
|
||||||
|
|
||||||
|
/* Initialize accumulator = unclarify(c) */
|
||||||
|
for (i = 0; i < DIGITS; i++) {
|
||||||
|
accum[i + DIGITS / 2] = c[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Multiply */
|
||||||
|
for (i = 0; i < DIGITS; i++) {
|
||||||
|
for (j = 0; j < DIGITS; j++) {
|
||||||
|
accum[i + j] += (dslimb_t)a[i] * b[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clarify and reduce */
|
||||||
|
for (i = 0; i < DIGITS / 2; i++) {
|
||||||
|
accum[i + DIGITS / 2] -= accum[i];
|
||||||
|
accum[i + DIGITS] += accum[i];
|
||||||
|
accum[i + DIGITS / 2] += accum[i + 3 * DIGITS / 2];
|
||||||
|
accum[i + DIGITS] += accum[i + 3 * DIGITS / 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Carry propagate */
|
||||||
|
chain = accum[3 * DIGITS / 2 - 1];
|
||||||
|
accum[3 * DIGITS / 2 - 1] = chain & LMASK;
|
||||||
|
chain >>= LGX;
|
||||||
|
accum[DIGITS] += chain;
|
||||||
|
for (i = DIGITS / 2; i < 3 * DIGITS / 2; i++) {
|
||||||
|
chain += accum[i];
|
||||||
|
c[i - DIGITS / 2] = chain & LMASK;
|
||||||
|
chain >>= LGX;
|
||||||
|
}
|
||||||
|
c[0] = (limb_t) (c[0] + chain);
|
||||||
|
c[DIGITS / 2] = (limb_t) (c[DIGITS / 2] + chain);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Reduce a gf_t to canonical form, i.e. strictly less than N. */
|
||||||
|
void PQCLEAN_BABYBEAREPHEM_CLEAN_canon(gf_t c) {
|
||||||
|
const limb_t DELTA = (limb_t)1 << (LGX - 1);
|
||||||
|
slimb_t hi;
|
||||||
|
dslimb_t scarry;
|
||||||
|
dlimb_t carry;
|
||||||
|
|
||||||
|
/* Reduce to 0..2p */
|
||||||
|
hi = (slimb_t) (c[DIGITS - 1] - DELTA);
|
||||||
|
c[DIGITS - 1] = (limb_t) ((hi & LMASK) + DELTA);
|
||||||
|
c[DIGITS / 2] = (limb_t) (c[DIGITS / 2] + (hi >> LGX));
|
||||||
|
|
||||||
|
/* Strong reduce. First subtract modulus */
|
||||||
|
scarry = hi >> LGX;
|
||||||
|
for (size_t i = 0; i < DIGITS; i++) {
|
||||||
|
scarry = scarry + (slimb_t)c[i] - PQCLEAN_BABYBEAREPHEM_CLEAN_modulus(i);
|
||||||
|
c[i] = scarry & LMASK;
|
||||||
|
scarry >>= LGX;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add it back */
|
||||||
|
carry = 0;
|
||||||
|
for (size_t i = 0; i < DIGITS; i++) {
|
||||||
|
carry = carry + c[i] + ((dlimb_t)scarry & PQCLEAN_BABYBEAREPHEM_CLEAN_modulus(i));
|
||||||
|
c[i] = carry & LMASK;
|
||||||
|
carry >>= LGX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Serialize a gf_t to bytes */
|
||||||
|
void PQCLEAN_BABYBEAREPHEM_CLEAN_contract(uint8_t ch[GF_BYTES], gf_t a) {
|
||||||
|
size_t pos;
|
||||||
|
|
||||||
|
PQCLEAN_BABYBEAREPHEM_CLEAN_canon(a);
|
||||||
|
for (size_t i = 0; i < GF_BYTES; i++) {
|
||||||
|
pos = (i * 8) / LGX;
|
||||||
|
ch[i] = (uint8_t)(a[pos] >> ((i * 8) % LGX));
|
||||||
|
if (i < GF_BYTES - 1) {
|
||||||
|
ch[i] |= (uint8_t)(a[pos + 1] << (LGX - ((i * 8) % LGX)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Deserialize a gf_t from bytes */
|
||||||
|
void PQCLEAN_BABYBEAREPHEM_CLEAN_expand(gf_t ll, const uint8_t ch[GF_BYTES]) {
|
||||||
|
limb_t tmp, buffer = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0, j = 0, bbits = 0; i < GF_BYTES; i++) {
|
||||||
|
tmp = ch[i];
|
||||||
|
buffer |= (limb_t)(tmp << bbits);
|
||||||
|
bbits += 8;
|
||||||
|
if (bbits >= LGX) {
|
||||||
|
ll[j++] = buffer & LMASK;
|
||||||
|
buffer = (limb_t)(tmp >> (LGX - (bbits - 8)));
|
||||||
|
bbits = bbits - LGX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
29
crypto_kem/babybear-ephem/clean/ring.h
Normal file
29
crypto_kem/babybear-ephem/clean/ring.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#ifndef __THREEBEARS_RING_H__
|
||||||
|
#define __THREEBEARS_RING_H__
|
||||||
|
|
||||||
|
#include "api.h"
|
||||||
|
#include "params.h"
|
||||||
|
|
||||||
|
typedef uint16_t limb_t;
|
||||||
|
typedef int16_t slimb_t;
|
||||||
|
typedef uint32_t dlimb_t;
|
||||||
|
typedef int32_t dslimb_t;
|
||||||
|
#define LMASK (((limb_t)1<<LGX)-1)
|
||||||
|
typedef limb_t gf_t[DIGITS];
|
||||||
|
|
||||||
|
/* Serialize a gf_t */
|
||||||
|
void PQCLEAN_BABYBEAREPHEM_CLEAN_contract(uint8_t ch[GF_BYTES], gf_t a);
|
||||||
|
|
||||||
|
/* Deserialize a gf_t */
|
||||||
|
void PQCLEAN_BABYBEAREPHEM_CLEAN_expand(gf_t ll, const uint8_t ch[GF_BYTES]);
|
||||||
|
|
||||||
|
/* Multiply and accumulate c = c + a*b */
|
||||||
|
void PQCLEAN_BABYBEAREPHEM_CLEAN_mac(gf_t c, const gf_t a, const gf_t b);
|
||||||
|
|
||||||
|
/* Reduce ring element to canonical form */
|
||||||
|
void PQCLEAN_BABYBEAREPHEM_CLEAN_canon(gf_t c);
|
||||||
|
|
||||||
|
/** Return the i'th limb of the modulus */
|
||||||
|
limb_t PQCLEAN_BABYBEAREPHEM_CLEAN_modulus(size_t i);
|
||||||
|
|
||||||
|
#endif
|
210
crypto_kem/babybear-ephem/clean/threebears.c
Normal file
210
crypto_kem/babybear-ephem/clean/threebears.c
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
/** ThreeBears reference implementation */
|
||||||
|
#include "api.h"
|
||||||
|
#include "melas_fec.h"
|
||||||
|
#include "params.h"
|
||||||
|
#include "ring.h"
|
||||||
|
#include "sp800-185.h"
|
||||||
|
#include "threebears.h"
|
||||||
|
|
||||||
|
#define FEC_BYTES ((FEC_BITS+7)/8)
|
||||||
|
#define ENC_BITS (ENC_SEED_BYTES*8 + FEC_BITS)
|
||||||
|
|
||||||
|
enum { HASH_PURPOSE_UNIFORM = 0, HASH_PURPOSE_KEYGEN = 1, HASH_PURPOSE_ENCAPS = 2, HASH_PURPOSE_PRF = 3 };
|
||||||
|
|
||||||
|
/** Initialize the hash function with a given purpose */
|
||||||
|
static void threebears_hash_init(
|
||||||
|
shake256incctx *ctx,
|
||||||
|
uint8_t purpose
|
||||||
|
) {
|
||||||
|
const unsigned char S[] = "ThreeBears";
|
||||||
|
const uint8_t pblock[15] = {
|
||||||
|
VERSION, PRIVATE_KEY_BYTES, MATRIX_SEED_BYTES, ENC_SEED_BYTES,
|
||||||
|
IV_BYTES, SHARED_SECRET_BYTES, LGX, DIGITS & 0xFF, DIGITS >> 8, DIM,
|
||||||
|
VAR_TIMES_128 - 1, LPR_BITS, FEC_BITS, CCA, 0 /* padding */
|
||||||
|
};
|
||||||
|
|
||||||
|
cshake256_inc_init(ctx, NULL, 0, (const uint8_t *)S, sizeof(S) - 1);
|
||||||
|
cshake256_inc_absorb(ctx, (const uint8_t *)pblock, sizeof(pblock));
|
||||||
|
cshake256_inc_absorb(ctx, &purpose, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sample n gf_t's uniformly from a seed */
|
||||||
|
static void uniform(gf_t matrix, const uint8_t *seed, uint8_t iv) {
|
||||||
|
uint8_t c[GF_BYTES];
|
||||||
|
shake256incctx ctx;
|
||||||
|
|
||||||
|
threebears_hash_init(&ctx, HASH_PURPOSE_UNIFORM);
|
||||||
|
cshake256_inc_absorb(&ctx, seed, MATRIX_SEED_BYTES);
|
||||||
|
cshake256_inc_absorb(&ctx, &iv, 1);
|
||||||
|
cshake256_inc_finalize(&ctx);
|
||||||
|
cshake256_inc_squeeze(c, sizeof(c), &ctx);
|
||||||
|
PQCLEAN_BABYBEAREPHEM_CLEAN_expand(matrix, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The ThreeBears error distribution */
|
||||||
|
static slimb_t psi(uint8_t ci) {
|
||||||
|
int sample = 0, var = VAR_TIMES_128;
|
||||||
|
|
||||||
|
for (; var > 64; var -= 64, ci = (uint8_t)(ci << 2)) {
|
||||||
|
sample += ((ci + 64) >> 8) + ((ci - 64) >> 8);
|
||||||
|
}
|
||||||
|
return (slimb_t)(sample + ((ci + var) >> 8) + ((ci - var) >> 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sample a vector of n noise elements */
|
||||||
|
static void noise(gf_t x, const shake256incctx *ctx, uint8_t iv) {
|
||||||
|
uint8_t c[DIGITS];
|
||||||
|
shake256incctx ctx2;
|
||||||
|
|
||||||
|
memcpy(&ctx2, ctx, sizeof(ctx2));
|
||||||
|
cshake256_inc_absorb(&ctx2, &iv, 1);
|
||||||
|
cshake256_inc_finalize(&ctx2);
|
||||||
|
cshake256_inc_squeeze(c, DIGITS, &ctx2);
|
||||||
|
for (size_t i = 0; i < DIGITS; i++) {
|
||||||
|
x[i] = (limb_t)(psi(c[i]) + PQCLEAN_BABYBEAREPHEM_CLEAN_modulus(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Expand public key from private key */
|
||||||
|
void PQCLEAN_BABYBEAREPHEM_CLEAN_get_pubkey(uint8_t *pk, const uint8_t *sk) {
|
||||||
|
shake256incctx ctx;
|
||||||
|
shake256incctx ctx2;
|
||||||
|
gf_t sk_expanded[DIM], b, c;
|
||||||
|
|
||||||
|
threebears_hash_init(&ctx, HASH_PURPOSE_KEYGEN);
|
||||||
|
cshake256_inc_absorb(&ctx, sk, PRIVATE_KEY_BYTES);
|
||||||
|
|
||||||
|
memcpy(&ctx2, &ctx, sizeof(ctx2));
|
||||||
|
cshake256_inc_finalize(&ctx2);
|
||||||
|
cshake256_inc_squeeze(pk, MATRIX_SEED_BYTES, &ctx2);
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < DIM; i++) {
|
||||||
|
noise(sk_expanded[i], &ctx, i);
|
||||||
|
}
|
||||||
|
for (uint8_t i = 0; i < DIM; i++) {
|
||||||
|
noise(c, &ctx, (uint8_t)(i + DIM));
|
||||||
|
for (uint8_t j = 0; j < DIM; j++) {
|
||||||
|
uniform(b, pk, (uint8_t) (i + DIM * j));
|
||||||
|
PQCLEAN_BABYBEAREPHEM_CLEAN_mac(c, b, sk_expanded[j]);
|
||||||
|
}
|
||||||
|
PQCLEAN_BABYBEAREPHEM_CLEAN_contract(&pk[MATRIX_SEED_BYTES + i * GF_BYTES], c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Encapsulate a shared secret and return it */
|
||||||
|
void PQCLEAN_BABYBEAREPHEM_CLEAN_encapsulate(
|
||||||
|
uint8_t *shared_secret,
|
||||||
|
uint8_t *capsule,
|
||||||
|
const uint8_t *pk,
|
||||||
|
const uint8_t *seed
|
||||||
|
) {
|
||||||
|
uint8_t *lpr_data = &capsule[GF_BYTES * DIM];
|
||||||
|
shake256incctx ctx;
|
||||||
|
gf_t sk_expanded[DIM], b, c;
|
||||||
|
uint8_t tbi[ENC_SEED_BYTES + FEC_BYTES];
|
||||||
|
dlimb_t rlimb0, rlimb1;
|
||||||
|
limb_t h;
|
||||||
|
uint8_t *iv = &lpr_data[(ENC_BITS * LPR_BITS + 7) / 8];
|
||||||
|
|
||||||
|
memcpy(iv, &seed[ENC_SEED_BYTES], IV_BYTES);
|
||||||
|
|
||||||
|
threebears_hash_init(&ctx, HASH_PURPOSE_ENCAPS);
|
||||||
|
cshake256_inc_absorb(&ctx, pk, MATRIX_SEED_BYTES);
|
||||||
|
cshake256_inc_absorb(&ctx, seed, ENC_SEED_BYTES + IV_BYTES);
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < DIM; i++) {
|
||||||
|
noise(sk_expanded[i], &ctx, i);
|
||||||
|
}
|
||||||
|
for (uint8_t i = 0; i < DIM; i++) {
|
||||||
|
noise(c, &ctx, (uint8_t)(i + DIM));
|
||||||
|
for (uint8_t j = 0; j < DIM; j++) {
|
||||||
|
uniform(b, pk, (uint8_t)(j + DIM * i));
|
||||||
|
PQCLEAN_BABYBEAREPHEM_CLEAN_mac(c, b, sk_expanded[j]);
|
||||||
|
}
|
||||||
|
PQCLEAN_BABYBEAREPHEM_CLEAN_contract(&capsule[i * GF_BYTES], c);
|
||||||
|
}
|
||||||
|
noise(c, &ctx, (uint8_t)(2 * DIM));
|
||||||
|
|
||||||
|
/* Calculate approximate shared secret */
|
||||||
|
for (uint8_t i = 0; i < DIM; i++) {
|
||||||
|
PQCLEAN_BABYBEAREPHEM_CLEAN_expand(b, &pk[MATRIX_SEED_BYTES + i * GF_BYTES]);
|
||||||
|
PQCLEAN_BABYBEAREPHEM_CLEAN_mac(c, b, sk_expanded[i]);
|
||||||
|
}
|
||||||
|
PQCLEAN_BABYBEAREPHEM_CLEAN_canon(c);
|
||||||
|
|
||||||
|
|
||||||
|
cshake256_inc_finalize(&ctx);
|
||||||
|
cshake256_inc_squeeze(tbi, ENC_SEED_BYTES, &ctx);
|
||||||
|
threebears_hash_init(&ctx, HASH_PURPOSE_ENCAPS);
|
||||||
|
cshake256_inc_absorb(&ctx, pk, MATRIX_SEED_BYTES);
|
||||||
|
cshake256_inc_absorb(&ctx, tbi, ENC_SEED_BYTES);
|
||||||
|
cshake256_inc_absorb(&ctx, iv, IV_BYTES);
|
||||||
|
|
||||||
|
PQCLEAN_BABYBEAREPHEM_CLEAN_melas_fec_set(&tbi[ENC_SEED_BYTES], tbi, ENC_SEED_BYTES);
|
||||||
|
|
||||||
|
/* Export with rounding */
|
||||||
|
for (size_t i = 0; i < ENC_BITS; i += 2) {
|
||||||
|
h = (limb_t)(tbi[i / 8] >> (i % 8));
|
||||||
|
rlimb0 = (dlimb_t)((c[i / 2] >> (LGX - LPR_BITS)) + (h << 3));
|
||||||
|
rlimb1 = (dlimb_t)((c[DIGITS - i / 2 - 1] >> (LGX - LPR_BITS)) + ((h >> 1) << 3));
|
||||||
|
lpr_data[i / 2] = (uint8_t)((rlimb0 & 0xF) | rlimb1 << 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
cshake256_inc_finalize(&ctx);
|
||||||
|
cshake256_inc_squeeze(shared_secret, SHARED_SECRET_BYTES, &ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Decapsulate a shared secret and return it */
|
||||||
|
void PQCLEAN_BABYBEAREPHEM_CLEAN_decapsulate(
|
||||||
|
uint8_t shared_secret[SHARED_SECRET_BYTES],
|
||||||
|
const uint8_t capsule[CAPSULE_BYTES],
|
||||||
|
const uint8_t sk[PRIVATE_KEY_BYTES]
|
||||||
|
) {
|
||||||
|
const uint8_t *lpr_data = &capsule[GF_BYTES * DIM];
|
||||||
|
shake256incctx ctx;
|
||||||
|
gf_t ska, b, c = {0};
|
||||||
|
uint8_t seed[ENC_SEED_BYTES + FEC_BYTES + IV_BYTES];
|
||||||
|
limb_t rounding, out;
|
||||||
|
size_t j;
|
||||||
|
limb_t our_rlimb, their_rlimb, delta;
|
||||||
|
uint8_t matrix_seed[MATRIX_SEED_BYTES];
|
||||||
|
|
||||||
|
/* Calculate approximate shared secret */
|
||||||
|
threebears_hash_init(&ctx, HASH_PURPOSE_KEYGEN);
|
||||||
|
cshake256_inc_absorb(&ctx, sk, PRIVATE_KEY_BYTES);
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < DIM; i++) {
|
||||||
|
PQCLEAN_BABYBEAREPHEM_CLEAN_expand(b, &capsule[i * GF_BYTES]);
|
||||||
|
noise(ska, &ctx, i);
|
||||||
|
PQCLEAN_BABYBEAREPHEM_CLEAN_mac(c, ska, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Recover seed from LPR data */
|
||||||
|
PQCLEAN_BABYBEAREPHEM_CLEAN_canon(c);
|
||||||
|
rounding = 1 << (LPR_BITS - 1);
|
||||||
|
out = 0;
|
||||||
|
for (int32_t i = ENC_BITS - 1; i >= 0; i--) {
|
||||||
|
j = (size_t) ((i & 1) ? DIGITS - i / 2 - 1 : i / 2);
|
||||||
|
our_rlimb = (limb_t)(c[j] >> (LGX - LPR_BITS - 1));
|
||||||
|
their_rlimb = (limb_t)(lpr_data[i * LPR_BITS / 8] >> ((i * LPR_BITS) % 8));
|
||||||
|
delta = (limb_t)(their_rlimb * 2 - our_rlimb + rounding);
|
||||||
|
out |= (limb_t)(((delta >> LPR_BITS) & 1) << (i % 8));
|
||||||
|
if (i % 8 == 0) {
|
||||||
|
seed[i / 8] = (uint8_t)out;
|
||||||
|
out = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PQCLEAN_BABYBEAREPHEM_CLEAN_melas_fec_correct(seed, ENC_SEED_BYTES, &seed[ENC_SEED_BYTES]);
|
||||||
|
|
||||||
|
/* Recalculate matrix seed */
|
||||||
|
cshake256_inc_finalize(&ctx);
|
||||||
|
cshake256_inc_squeeze(matrix_seed, MATRIX_SEED_BYTES, &ctx);
|
||||||
|
|
||||||
|
/* Re-run the key derivation from encaps */
|
||||||
|
threebears_hash_init(&ctx, HASH_PURPOSE_ENCAPS);
|
||||||
|
cshake256_inc_absorb(&ctx, matrix_seed, MATRIX_SEED_BYTES);
|
||||||
|
cshake256_inc_absorb(&ctx, seed, ENC_SEED_BYTES);
|
||||||
|
cshake256_inc_absorb(&ctx, &lpr_data[(ENC_BITS * LPR_BITS + 7) / 8], IV_BYTES);
|
||||||
|
cshake256_inc_finalize(&ctx);
|
||||||
|
cshake256_inc_squeeze(shared_secret, SHARED_SECRET_BYTES, &ctx);
|
||||||
|
}
|
60
crypto_kem/babybear-ephem/clean/threebears.h
Normal file
60
crypto_kem/babybear-ephem/clean/threebears.h
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
#ifndef __THREE_BEARS_BABYBEAREPHEM_H__
|
||||||
|
#define __THREE_BEARS_BABYBEAREPHEM_H__
|
||||||
|
|
||||||
|
#include <stddef.h> /* for size_t */
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define BABYBEAREPHEM_KEYGEN_SEED_BYTES 40
|
||||||
|
#define BABYBEAREPHEM_PRIVATE_KEY_BYTES BABYBEAREPHEM_KEYGEN_SEED_BYTES
|
||||||
|
#define BABYBEAREPHEM_SHARED_SECRET_BYTES 32
|
||||||
|
#define BABYBEAREPHEM_ENC_SEED_AND_IV_BYTES 32
|
||||||
|
#define BABYBEAREPHEM_PUBLIC_KEY_BYTES 804
|
||||||
|
#define BABYBEAREPHEM_CAPSULE_BYTES 917
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expand a secret seed to a public/private keypair.
|
||||||
|
*
|
||||||
|
* @param[out] pk The public key.
|
||||||
|
* @param[in] sk The private key, which must be uniformly random.
|
||||||
|
*/
|
||||||
|
void PQCLEAN_BABYBEAREPHEM_CLEAN_get_pubkey (
|
||||||
|
uint8_t pk[BABYBEAREPHEM_PUBLIC_KEY_BYTES],
|
||||||
|
const uint8_t sk[BABYBEAREPHEM_PRIVATE_KEY_BYTES]
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a shared secret using a random seed and another party's public key.
|
||||||
|
*
|
||||||
|
* Input and output parameters may not alias.
|
||||||
|
*
|
||||||
|
* @param[out] shared_secret The shared secret key.
|
||||||
|
* @param[out] capsule A ciphertext to send to the other party.
|
||||||
|
* @param[in] pk The other party's public key.
|
||||||
|
* @param[in] seed A random seed.
|
||||||
|
*/
|
||||||
|
void PQCLEAN_BABYBEAREPHEM_CLEAN_encapsulate (
|
||||||
|
uint8_t shared_secret[BABYBEAREPHEM_SHARED_SECRET_BYTES],
|
||||||
|
uint8_t capsule[BABYBEAREPHEM_CAPSULE_BYTES],
|
||||||
|
const uint8_t pk[BABYBEAREPHEM_PUBLIC_KEY_BYTES],
|
||||||
|
const uint8_t seed[BABYBEAREPHEM_ENC_SEED_AND_IV_BYTES]
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract the shared secret from a capsule using the private key.
|
||||||
|
* Has a negligible but nonzero probability of failure.
|
||||||
|
*
|
||||||
|
* Input and output parameters may not alias.
|
||||||
|
*
|
||||||
|
* @param[out] shared_secret The shared secret.
|
||||||
|
* @param[in] capsule The capsule produced by encapsulate_cca2.
|
||||||
|
* @param[in] sk The private key.
|
||||||
|
* @return -1 on failure, 0 on success.
|
||||||
|
* @warning The value of shared_secret must not be used on failure
|
||||||
|
*/
|
||||||
|
void PQCLEAN_BABYBEAREPHEM_CLEAN_decapsulate (
|
||||||
|
uint8_t shared_secret[BABYBEAREPHEM_SHARED_SECRET_BYTES],
|
||||||
|
const uint8_t capsule[BABYBEAREPHEM_CAPSULE_BYTES],
|
||||||
|
const uint8_t sk[BABYBEAREPHEM_PRIVATE_KEY_BYTES]
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif
|
@ -55,6 +55,4 @@ void PQCLEAN_BABYBEAR_CLEAN_decapsulate (
|
|||||||
const uint8_t sk[BABYBEAR_PRIVATE_KEY_BYTES]
|
const uint8_t sk[BABYBEAR_PRIVATE_KEY_BYTES]
|
||||||
);
|
);
|
||||||
|
|
||||||
void PQCLEAN_BABYBEAR_CLEAN_secure_bzero (void *s, size_t size);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
14
crypto_kem/mamabear-ephem/META.yml
Normal file
14
crypto_kem/mamabear-ephem/META.yml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
name: MamaBearEphem
|
||||||
|
type: kem
|
||||||
|
claimed-nist-level: 3
|
||||||
|
claimed-security: IND-CPA
|
||||||
|
length-public-key: 1194
|
||||||
|
length-ciphertext: 1307
|
||||||
|
length-secret-key: 40
|
||||||
|
length-shared-secret: 32
|
||||||
|
nistkat-sha256: ef94f0f6471a1276efd9e019195489661c2356027fc2e8163e3718a1df027123
|
||||||
|
principal-submitters:
|
||||||
|
- Mike Hamburg
|
||||||
|
implementations:
|
||||||
|
- name: clean
|
||||||
|
version: https://sourceforge.net/p/threebears/code/ci/f4ce0ebfc84a5e01a75bfc8297b6d175e993cfa4/
|
24
crypto_kem/mamabear-ephem/clean/LICENSE
Normal file
24
crypto_kem/mamabear-ephem/clean/LICENSE
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
Copyright (c) 2016-2019 Rambus, Inc.
|
||||||
|
and licensed under the following MIT license.
|
||||||
|
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2016-2019 Rambus Inc.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
21
crypto_kem/mamabear-ephem/clean/Makefile
Normal file
21
crypto_kem/mamabear-ephem/clean/Makefile
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# This Makefile can be used with GNU Make or BSD Make
|
||||||
|
|
||||||
|
LIB=libmamabear-ephem_clean.a
|
||||||
|
|
||||||
|
HEADERS = api.h melas_fec.h params.h ring.h threebears.h
|
||||||
|
OBJECTS = kem.o melas_fec.o ring.o threebears.o
|
||||||
|
|
||||||
|
|
||||||
|
CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS)
|
||||||
|
|
||||||
|
all: $(LIB)
|
||||||
|
|
||||||
|
%.o: %.c $(HEADERS)
|
||||||
|
$(CC) $(CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
$(LIB): $(OBJECTS)
|
||||||
|
$(AR) -r $@ $(OBJECTS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) $(OBJECTS)
|
||||||
|
$(RM) $(LIB)
|
19
crypto_kem/mamabear-ephem/clean/Makefile.Microsoft_nmake
Normal file
19
crypto_kem/mamabear-ephem/clean/Makefile.Microsoft_nmake
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# This Makefile can be used with Microsoft Visual Studio's nmake using the command:
|
||||||
|
# nmake /f Makefile.Microsoft_nmake
|
||||||
|
|
||||||
|
LIBRARY=libmamabear-ephem_clean.lib
|
||||||
|
OBJECTS = kem.obj melas_fec.obj ring.obj threebears.obj
|
||||||
|
|
||||||
|
CFLAGS=/nologo /I ..\..\..\common /W4 /WX
|
||||||
|
|
||||||
|
all: $(LIBRARY)
|
||||||
|
|
||||||
|
# Make sure objects are recompiled if headers change.
|
||||||
|
$(OBJECTS): *.h
|
||||||
|
|
||||||
|
$(LIBRARY): $(OBJECTS)
|
||||||
|
LIB.EXE /NOLOGO /WX /OUT:$@ $**
|
||||||
|
|
||||||
|
clean:
|
||||||
|
-DEL $(OBJECTS)
|
||||||
|
-DEL $(LIBRARY)
|
18
crypto_kem/mamabear-ephem/clean/api.h
Normal file
18
crypto_kem/mamabear-ephem/clean/api.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#ifndef PQCLEAN_MAMABEAREPHEM_CLEAN_API_H
|
||||||
|
#define PQCLEAN_MAMABEAREPHEM_CLEAN_API_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define PQCLEAN_MAMABEAREPHEM_CLEAN_CRYPTO_SECRETKEYBYTES 40
|
||||||
|
#define PQCLEAN_MAMABEAREPHEM_CLEAN_CRYPTO_PUBLICKEYBYTES 1194
|
||||||
|
#define PQCLEAN_MAMABEAREPHEM_CLEAN_CRYPTO_BYTES 32
|
||||||
|
#define PQCLEAN_MAMABEAREPHEM_CLEAN_CRYPTO_CIPHERTEXTBYTES 1307
|
||||||
|
#define PQCLEAN_MAMABEAREPHEM_CLEAN_CRYPTO_ALGNAME "MamaBearEphem"
|
||||||
|
|
||||||
|
int PQCLEAN_MAMABEAREPHEM_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk);
|
||||||
|
int PQCLEAN_MAMABEAREPHEM_CLEAN_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk);
|
||||||
|
int PQCLEAN_MAMABEAREPHEM_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk);
|
||||||
|
|
||||||
|
#endif
|
22
crypto_kem/mamabear-ephem/clean/kem.c
Normal file
22
crypto_kem/mamabear-ephem/clean/kem.c
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#include "api.h"
|
||||||
|
#include "params.h"
|
||||||
|
#include "randombytes.h"
|
||||||
|
#include "threebears.h"
|
||||||
|
|
||||||
|
int PQCLEAN_MAMABEAREPHEM_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk) {
|
||||||
|
randombytes(sk, PRIVATE_KEY_BYTES);
|
||||||
|
PQCLEAN_MAMABEAREPHEM_CLEAN_get_pubkey(pk, sk);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PQCLEAN_MAMABEAREPHEM_CLEAN_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk) {
|
||||||
|
uint8_t seed[ENC_SEED_BYTES + IV_BYTES];
|
||||||
|
randombytes(seed, sizeof(seed));
|
||||||
|
encapsulate(ss, ct, pk, seed);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PQCLEAN_MAMABEAREPHEM_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk) {
|
||||||
|
PQCLEAN_MAMABEAREPHEM_CLEAN_decapsulate(ss, ct, sk);
|
||||||
|
return 0;
|
||||||
|
}
|
87
crypto_kem/mamabear-ephem/clean/melas_fec.c
Normal file
87
crypto_kem/mamabear-ephem/clean/melas_fec.c
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
/* Melas forward error correction, reference code (as implemented in the paper) */
|
||||||
|
#include "melas_fec.h"
|
||||||
|
|
||||||
|
/* Return s/2^n mod R */
|
||||||
|
static fec_gf_t step(size_t n, fec_gf_t R, fec_gf_t s) {
|
||||||
|
for (; n; n--) {
|
||||||
|
s = (s ^ ((s & 1) * R)) >> 1;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compute syndrome(data), where data has length len */
|
||||||
|
#define syndrome18(data,len) s18update(0,data,len)
|
||||||
|
static fec_gf_t s18update(fec_gf_t r, const uint8_t *data, size_t len) {
|
||||||
|
for (size_t i = 0; i < len; i++) {
|
||||||
|
r = step(8, 0x46231, r ^ data[i]);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Append 3 bytes of FEC(data) to data, so that the FEC becomes 0 */
|
||||||
|
void PQCLEAN_MAMABEAREPHEM_CLEAN_melas_fec_set(
|
||||||
|
uint8_t out[MELAS_FEC_BYTES],
|
||||||
|
const uint8_t *data,
|
||||||
|
size_t len
|
||||||
|
) {
|
||||||
|
fec_gf_t fec = syndrome18(data, len);
|
||||||
|
for (size_t i = 0; i < MELAS_FEC_BYTES; i++, fec >>= 8) {
|
||||||
|
out[i] = (uint8_t)fec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return a*b mod Q */
|
||||||
|
static fec_gf_t mul(fec_gf_t a, fec_gf_t b) {
|
||||||
|
fec_gf_t r = 0;
|
||||||
|
for (size_t i = 0; i < 9; i++) {
|
||||||
|
r ^= ((b >> (8 - i)) & 1) * a;
|
||||||
|
a = step(1, Q, a);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reverse an 18-bit number x */
|
||||||
|
static fec_gf_t reverse18(fec_gf_t x) {
|
||||||
|
fec_gf_t ret = 0;
|
||||||
|
for (size_t i = 0; i < 18; i++) {
|
||||||
|
ret ^= ((x >> i) & 1) << (17 - i);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Correct data to have the given FEC */
|
||||||
|
void PQCLEAN_MAMABEAREPHEM_CLEAN_melas_fec_correct (
|
||||||
|
uint8_t *data,
|
||||||
|
size_t len,
|
||||||
|
const uint8_t fec[MELAS_FEC_BYTES]
|
||||||
|
) {
|
||||||
|
|
||||||
|
fec_gf_t a = s18update(syndrome18(data, len), fec, MELAS_FEC_BYTES);
|
||||||
|
fec_gf_t c, r, htr;
|
||||||
|
size_t i;
|
||||||
|
const uint8_t table[9] = {36, 10, 43, 215, 52, 11, 116, 244, 0};
|
||||||
|
fec_gf_t e0, e1;
|
||||||
|
|
||||||
|
/* Form a quadratic equation from the syndrome */
|
||||||
|
c = mul(step(9, Q, a), step(9, Q, reverse18(a)));
|
||||||
|
for (i = 0, r = 0x100; i < 510; i++) {
|
||||||
|
r = mul(r, c);
|
||||||
|
}
|
||||||
|
r = step(17, Q, r);
|
||||||
|
a = step(511 - (len + MELAS_FEC_BYTES) * 8, Q, a);
|
||||||
|
|
||||||
|
/* Solve using the half trace */
|
||||||
|
for (i = 0, htr = 0; i < 9; i++) {
|
||||||
|
htr ^= ((r >> i) & 1) * table[i];
|
||||||
|
}
|
||||||
|
e0 = mul(a, htr);
|
||||||
|
e1 = e0 ^ a;
|
||||||
|
|
||||||
|
/* Correct the errors using the locators */
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
data[i] ^= (uint8_t)(e0 & (((e0 & (e0 - 1)) - 1) >> 9));
|
||||||
|
data[i] ^= (uint8_t)(e1 & (((e1 & (e1 - 1)) - 1) >> 9));
|
||||||
|
e0 = step(8, Q, e0);
|
||||||
|
e1 = step(8, Q, e1);
|
||||||
|
}
|
||||||
|
}
|
26
crypto_kem/mamabear-ephem/clean/melas_fec.h
Normal file
26
crypto_kem/mamabear-ephem/clean/melas_fec.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#ifndef __THREEBEARS_MELAS_FEC_H__
|
||||||
|
#define __THREEBEARS_MELAS_FEC_H__
|
||||||
|
|
||||||
|
#include "api.h"
|
||||||
|
|
||||||
|
#define MELAS_FEC_BYTES 3
|
||||||
|
#define MELAS_FEC_BITS 18
|
||||||
|
|
||||||
|
typedef uint32_t fec_gf_t;
|
||||||
|
static const fec_gf_t Q = 0x211;
|
||||||
|
|
||||||
|
/* Append 3 bytes of FEC(data) to data, so that the FEC becomes 0 */
|
||||||
|
void PQCLEAN_MAMABEAREPHEM_CLEAN_melas_fec_set(
|
||||||
|
uint8_t out[MELAS_FEC_BYTES],
|
||||||
|
const uint8_t *data,
|
||||||
|
size_t len
|
||||||
|
);
|
||||||
|
|
||||||
|
/* Append 3 bytes of FEC(data) to data, so that the FEC becomes 0 */
|
||||||
|
void PQCLEAN_MAMABEAREPHEM_CLEAN_melas_fec_correct(
|
||||||
|
uint8_t *data,
|
||||||
|
size_t len,
|
||||||
|
const uint8_t fec[MELAS_FEC_BYTES]
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif
|
29
crypto_kem/mamabear-ephem/clean/params.h
Normal file
29
crypto_kem/mamabear-ephem/clean/params.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#ifndef __THREEBEARS_PARAMS_H__
|
||||||
|
#define __THREEBEARS_PARAMS_H__
|
||||||
|
|
||||||
|
#define VERSION 1
|
||||||
|
#define MATRIX_SEED_BYTES 24
|
||||||
|
#define ENC_SEED_BYTES 32
|
||||||
|
#define IV_BYTES 0
|
||||||
|
#define LGX 10
|
||||||
|
#define DIGITS 312
|
||||||
|
#define DIM 3
|
||||||
|
#define VAR_TIMES_128 112
|
||||||
|
#define LPR_BITS 4
|
||||||
|
#define FEC_BITS 18
|
||||||
|
#define CCA 0
|
||||||
|
#define SHARED_SECRET_BYTES 32
|
||||||
|
#define PRIVATE_KEY_BYTES 40
|
||||||
|
#define PRF_KEY_BYTES PRIVATE_KEY_BYTES
|
||||||
|
|
||||||
|
#define BEAR_NAME "MamaBearEphem"
|
||||||
|
#define encapsulate PQCLEAN_MAMABEAREPHEM_CLEAN_encapsulate
|
||||||
|
#define decapsulate PQCLEAN_MAMABEAREPHEM_CLEAN_decapsulate
|
||||||
|
#define get_pubkey PQCLEAN_MAMABEAREPHEM_CLEAN_get_pubkey
|
||||||
|
|
||||||
|
#define GF_BYTES ((LGX*DIGITS+7)/8)
|
||||||
|
#define PUBLIC_KEY_BYTES (MATRIX_SEED_BYTES + DIM*GF_BYTES)
|
||||||
|
#define CAPSULE_BYTES \
|
||||||
|
(DIM*GF_BYTES + IV_BYTES + ((ENC_SEED_BYTES*8+FEC_BITS)*LPR_BITS+7)/8)
|
||||||
|
|
||||||
|
#endif
|
107
crypto_kem/mamabear-ephem/clean/ring.c
Normal file
107
crypto_kem/mamabear-ephem/clean/ring.c
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
/** Ring arithmetic implementation */
|
||||||
|
#include "ring.h"
|
||||||
|
|
||||||
|
/** Return the i'th limb of the modulus */
|
||||||
|
limb_t PQCLEAN_MAMABEAREPHEM_CLEAN_modulus(size_t i) {
|
||||||
|
return (i == DIGITS / 2) ? LMASK - 1 : LMASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Multiply and accumulate c += a*b */
|
||||||
|
void PQCLEAN_MAMABEAREPHEM_CLEAN_mac(gf_t c, const gf_t a, const gf_t b) {
|
||||||
|
/* Reference non-Karatsuba MAC */
|
||||||
|
dslimb_t accum[2 * DIGITS] = {0};
|
||||||
|
dslimb_t chain;
|
||||||
|
size_t i, j;
|
||||||
|
|
||||||
|
/* Initialize accumulator = unclarify(c) */
|
||||||
|
for (i = 0; i < DIGITS; i++) {
|
||||||
|
accum[i + DIGITS / 2] = c[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Multiply */
|
||||||
|
for (i = 0; i < DIGITS; i++) {
|
||||||
|
for (j = 0; j < DIGITS; j++) {
|
||||||
|
accum[i + j] += (dslimb_t)a[i] * b[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clarify and reduce */
|
||||||
|
for (i = 0; i < DIGITS / 2; i++) {
|
||||||
|
accum[i + DIGITS / 2] -= accum[i];
|
||||||
|
accum[i + DIGITS] += accum[i];
|
||||||
|
accum[i + DIGITS / 2] += accum[i + 3 * DIGITS / 2];
|
||||||
|
accum[i + DIGITS] += accum[i + 3 * DIGITS / 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Carry propagate */
|
||||||
|
chain = accum[3 * DIGITS / 2 - 1];
|
||||||
|
accum[3 * DIGITS / 2 - 1] = chain & LMASK;
|
||||||
|
chain >>= LGX;
|
||||||
|
accum[DIGITS] += chain;
|
||||||
|
for (i = DIGITS / 2; i < 3 * DIGITS / 2; i++) {
|
||||||
|
chain += accum[i];
|
||||||
|
c[i - DIGITS / 2] = chain & LMASK;
|
||||||
|
chain >>= LGX;
|
||||||
|
}
|
||||||
|
c[0] = (limb_t) (c[0] + chain);
|
||||||
|
c[DIGITS / 2] = (limb_t) (c[DIGITS / 2] + chain);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Reduce a gf_t to canonical form, i.e. strictly less than N. */
|
||||||
|
void PQCLEAN_MAMABEAREPHEM_CLEAN_canon(gf_t c) {
|
||||||
|
const limb_t DELTA = (limb_t)1 << (LGX - 1);
|
||||||
|
slimb_t hi;
|
||||||
|
dslimb_t scarry;
|
||||||
|
dlimb_t carry;
|
||||||
|
|
||||||
|
/* Reduce to 0..2p */
|
||||||
|
hi = (slimb_t) (c[DIGITS - 1] - DELTA);
|
||||||
|
c[DIGITS - 1] = (limb_t) ((hi & LMASK) + DELTA);
|
||||||
|
c[DIGITS / 2] = (limb_t) (c[DIGITS / 2] + (hi >> LGX));
|
||||||
|
|
||||||
|
/* Strong reduce. First subtract modulus */
|
||||||
|
scarry = hi >> LGX;
|
||||||
|
for (size_t i = 0; i < DIGITS; i++) {
|
||||||
|
scarry = scarry + (slimb_t)c[i] - PQCLEAN_MAMABEAREPHEM_CLEAN_modulus(i);
|
||||||
|
c[i] = scarry & LMASK;
|
||||||
|
scarry >>= LGX;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add it back */
|
||||||
|
carry = 0;
|
||||||
|
for (size_t i = 0; i < DIGITS; i++) {
|
||||||
|
carry = carry + c[i] + ((dlimb_t)scarry & PQCLEAN_MAMABEAREPHEM_CLEAN_modulus(i));
|
||||||
|
c[i] = carry & LMASK;
|
||||||
|
carry >>= LGX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Serialize a gf_t to bytes */
|
||||||
|
void PQCLEAN_MAMABEAREPHEM_CLEAN_contract(uint8_t ch[GF_BYTES], gf_t a) {
|
||||||
|
size_t pos;
|
||||||
|
|
||||||
|
PQCLEAN_MAMABEAREPHEM_CLEAN_canon(a);
|
||||||
|
for (size_t i = 0; i < GF_BYTES; i++) {
|
||||||
|
pos = (i * 8) / LGX;
|
||||||
|
ch[i] = (uint8_t)(a[pos] >> ((i * 8) % LGX));
|
||||||
|
if (i < GF_BYTES - 1) {
|
||||||
|
ch[i] |= (uint8_t)(a[pos + 1] << (LGX - ((i * 8) % LGX)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Deserialize a gf_t from bytes */
|
||||||
|
void PQCLEAN_MAMABEAREPHEM_CLEAN_expand(gf_t ll, const uint8_t ch[GF_BYTES]) {
|
||||||
|
limb_t tmp, buffer = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0, j = 0, bbits = 0; i < GF_BYTES; i++) {
|
||||||
|
tmp = ch[i];
|
||||||
|
buffer |= (limb_t)(tmp << bbits);
|
||||||
|
bbits += 8;
|
||||||
|
if (bbits >= LGX) {
|
||||||
|
ll[j++] = buffer & LMASK;
|
||||||
|
buffer = (limb_t)(tmp >> (LGX - (bbits - 8)));
|
||||||
|
bbits = bbits - LGX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
29
crypto_kem/mamabear-ephem/clean/ring.h
Normal file
29
crypto_kem/mamabear-ephem/clean/ring.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#ifndef __THREEBEARS_RING_H__
|
||||||
|
#define __THREEBEARS_RING_H__
|
||||||
|
|
||||||
|
#include "api.h"
|
||||||
|
#include "params.h"
|
||||||
|
|
||||||
|
typedef uint16_t limb_t;
|
||||||
|
typedef int16_t slimb_t;
|
||||||
|
typedef uint32_t dlimb_t;
|
||||||
|
typedef int32_t dslimb_t;
|
||||||
|
#define LMASK (((limb_t)1<<LGX)-1)
|
||||||
|
typedef limb_t gf_t[DIGITS];
|
||||||
|
|
||||||
|
/* Serialize a gf_t */
|
||||||
|
void PQCLEAN_MAMABEAREPHEM_CLEAN_contract(uint8_t ch[GF_BYTES], gf_t a);
|
||||||
|
|
||||||
|
/* Deserialize a gf_t */
|
||||||
|
void PQCLEAN_MAMABEAREPHEM_CLEAN_expand(gf_t ll, const uint8_t ch[GF_BYTES]);
|
||||||
|
|
||||||
|
/* Multiply and accumulate c = c + a*b */
|
||||||
|
void PQCLEAN_MAMABEAREPHEM_CLEAN_mac(gf_t c, const gf_t a, const gf_t b);
|
||||||
|
|
||||||
|
/* Reduce ring element to canonical form */
|
||||||
|
void PQCLEAN_MAMABEAREPHEM_CLEAN_canon(gf_t c);
|
||||||
|
|
||||||
|
/** Return the i'th limb of the modulus */
|
||||||
|
limb_t PQCLEAN_MAMABEAREPHEM_CLEAN_modulus(size_t i);
|
||||||
|
|
||||||
|
#endif
|
210
crypto_kem/mamabear-ephem/clean/threebears.c
Normal file
210
crypto_kem/mamabear-ephem/clean/threebears.c
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
/** ThreeBears reference implementation */
|
||||||
|
#include "api.h"
|
||||||
|
#include "melas_fec.h"
|
||||||
|
#include "params.h"
|
||||||
|
#include "ring.h"
|
||||||
|
#include "sp800-185.h"
|
||||||
|
#include "threebears.h"
|
||||||
|
|
||||||
|
#define FEC_BYTES ((FEC_BITS+7)/8)
|
||||||
|
#define ENC_BITS (ENC_SEED_BYTES*8 + FEC_BITS)
|
||||||
|
|
||||||
|
enum { HASH_PURPOSE_UNIFORM = 0, HASH_PURPOSE_KEYGEN = 1, HASH_PURPOSE_ENCAPS = 2, HASH_PURPOSE_PRF = 3 };
|
||||||
|
|
||||||
|
/** Initialize the hash function with a given purpose */
|
||||||
|
static void threebears_hash_init(
|
||||||
|
shake256incctx *ctx,
|
||||||
|
uint8_t purpose
|
||||||
|
) {
|
||||||
|
const unsigned char S[] = "ThreeBears";
|
||||||
|
const uint8_t pblock[15] = {
|
||||||
|
VERSION, PRIVATE_KEY_BYTES, MATRIX_SEED_BYTES, ENC_SEED_BYTES,
|
||||||
|
IV_BYTES, SHARED_SECRET_BYTES, LGX, DIGITS & 0xFF, DIGITS >> 8, DIM,
|
||||||
|
VAR_TIMES_128 - 1, LPR_BITS, FEC_BITS, CCA, 0 /* padding */
|
||||||
|
};
|
||||||
|
|
||||||
|
cshake256_inc_init(ctx, NULL, 0, (const uint8_t *)S, sizeof(S) - 1);
|
||||||
|
cshake256_inc_absorb(ctx, (const uint8_t *)pblock, sizeof(pblock));
|
||||||
|
cshake256_inc_absorb(ctx, &purpose, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sample n gf_t's uniformly from a seed */
|
||||||
|
static void uniform(gf_t matrix, const uint8_t *seed, uint8_t iv) {
|
||||||
|
uint8_t c[GF_BYTES];
|
||||||
|
shake256incctx ctx;
|
||||||
|
|
||||||
|
threebears_hash_init(&ctx, HASH_PURPOSE_UNIFORM);
|
||||||
|
cshake256_inc_absorb(&ctx, seed, MATRIX_SEED_BYTES);
|
||||||
|
cshake256_inc_absorb(&ctx, &iv, 1);
|
||||||
|
cshake256_inc_finalize(&ctx);
|
||||||
|
cshake256_inc_squeeze(c, sizeof(c), &ctx);
|
||||||
|
PQCLEAN_MAMABEAREPHEM_CLEAN_expand(matrix, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The ThreeBears error distribution */
|
||||||
|
static slimb_t psi(uint8_t ci) {
|
||||||
|
int sample = 0, var = VAR_TIMES_128;
|
||||||
|
|
||||||
|
for (; var > 64; var -= 64, ci = (uint8_t)(ci << 2)) {
|
||||||
|
sample += ((ci + 64) >> 8) + ((ci - 64) >> 8);
|
||||||
|
}
|
||||||
|
return (slimb_t)(sample + ((ci + var) >> 8) + ((ci - var) >> 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sample a vector of n noise elements */
|
||||||
|
static void noise(gf_t x, const shake256incctx *ctx, uint8_t iv) {
|
||||||
|
uint8_t c[DIGITS];
|
||||||
|
shake256incctx ctx2;
|
||||||
|
|
||||||
|
memcpy(&ctx2, ctx, sizeof(ctx2));
|
||||||
|
cshake256_inc_absorb(&ctx2, &iv, 1);
|
||||||
|
cshake256_inc_finalize(&ctx2);
|
||||||
|
cshake256_inc_squeeze(c, DIGITS, &ctx2);
|
||||||
|
for (size_t i = 0; i < DIGITS; i++) {
|
||||||
|
x[i] = (limb_t)(psi(c[i]) + PQCLEAN_MAMABEAREPHEM_CLEAN_modulus(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Expand public key from private key */
|
||||||
|
void PQCLEAN_MAMABEAREPHEM_CLEAN_get_pubkey(uint8_t *pk, const uint8_t *sk) {
|
||||||
|
shake256incctx ctx;
|
||||||
|
shake256incctx ctx2;
|
||||||
|
gf_t sk_expanded[DIM], b, c;
|
||||||
|
|
||||||
|
threebears_hash_init(&ctx, HASH_PURPOSE_KEYGEN);
|
||||||
|
cshake256_inc_absorb(&ctx, sk, PRIVATE_KEY_BYTES);
|
||||||
|
|
||||||
|
memcpy(&ctx2, &ctx, sizeof(ctx2));
|
||||||
|
cshake256_inc_finalize(&ctx2);
|
||||||
|
cshake256_inc_squeeze(pk, MATRIX_SEED_BYTES, &ctx2);
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < DIM; i++) {
|
||||||
|
noise(sk_expanded[i], &ctx, i);
|
||||||
|
}
|
||||||
|
for (uint8_t i = 0; i < DIM; i++) {
|
||||||
|
noise(c, &ctx, (uint8_t)(i + DIM));
|
||||||
|
for (uint8_t j = 0; j < DIM; j++) {
|
||||||
|
uniform(b, pk, (uint8_t) (i + DIM * j));
|
||||||
|
PQCLEAN_MAMABEAREPHEM_CLEAN_mac(c, b, sk_expanded[j]);
|
||||||
|
}
|
||||||
|
PQCLEAN_MAMABEAREPHEM_CLEAN_contract(&pk[MATRIX_SEED_BYTES + i * GF_BYTES], c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Encapsulate a shared secret and return it */
|
||||||
|
void PQCLEAN_MAMABEAREPHEM_CLEAN_encapsulate(
|
||||||
|
uint8_t *shared_secret,
|
||||||
|
uint8_t *capsule,
|
||||||
|
const uint8_t *pk,
|
||||||
|
const uint8_t *seed
|
||||||
|
) {
|
||||||
|
uint8_t *lpr_data = &capsule[GF_BYTES * DIM];
|
||||||
|
shake256incctx ctx;
|
||||||
|
gf_t sk_expanded[DIM], b, c;
|
||||||
|
uint8_t tbi[ENC_SEED_BYTES + FEC_BYTES];
|
||||||
|
dlimb_t rlimb0, rlimb1;
|
||||||
|
limb_t h;
|
||||||
|
uint8_t *iv = &lpr_data[(ENC_BITS * LPR_BITS + 7) / 8];
|
||||||
|
|
||||||
|
memcpy(iv, &seed[ENC_SEED_BYTES], IV_BYTES);
|
||||||
|
|
||||||
|
threebears_hash_init(&ctx, HASH_PURPOSE_ENCAPS);
|
||||||
|
cshake256_inc_absorb(&ctx, pk, MATRIX_SEED_BYTES);
|
||||||
|
cshake256_inc_absorb(&ctx, seed, ENC_SEED_BYTES + IV_BYTES);
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < DIM; i++) {
|
||||||
|
noise(sk_expanded[i], &ctx, i);
|
||||||
|
}
|
||||||
|
for (uint8_t i = 0; i < DIM; i++) {
|
||||||
|
noise(c, &ctx, (uint8_t)(i + DIM));
|
||||||
|
for (uint8_t j = 0; j < DIM; j++) {
|
||||||
|
uniform(b, pk, (uint8_t)(j + DIM * i));
|
||||||
|
PQCLEAN_MAMABEAREPHEM_CLEAN_mac(c, b, sk_expanded[j]);
|
||||||
|
}
|
||||||
|
PQCLEAN_MAMABEAREPHEM_CLEAN_contract(&capsule[i * GF_BYTES], c);
|
||||||
|
}
|
||||||
|
noise(c, &ctx, (uint8_t)(2 * DIM));
|
||||||
|
|
||||||
|
/* Calculate approximate shared secret */
|
||||||
|
for (uint8_t i = 0; i < DIM; i++) {
|
||||||
|
PQCLEAN_MAMABEAREPHEM_CLEAN_expand(b, &pk[MATRIX_SEED_BYTES + i * GF_BYTES]);
|
||||||
|
PQCLEAN_MAMABEAREPHEM_CLEAN_mac(c, b, sk_expanded[i]);
|
||||||
|
}
|
||||||
|
PQCLEAN_MAMABEAREPHEM_CLEAN_canon(c);
|
||||||
|
|
||||||
|
|
||||||
|
cshake256_inc_finalize(&ctx);
|
||||||
|
cshake256_inc_squeeze(tbi, ENC_SEED_BYTES, &ctx);
|
||||||
|
threebears_hash_init(&ctx, HASH_PURPOSE_ENCAPS);
|
||||||
|
cshake256_inc_absorb(&ctx, pk, MATRIX_SEED_BYTES);
|
||||||
|
cshake256_inc_absorb(&ctx, tbi, ENC_SEED_BYTES);
|
||||||
|
cshake256_inc_absorb(&ctx, iv, IV_BYTES);
|
||||||
|
|
||||||
|
PQCLEAN_MAMABEAREPHEM_CLEAN_melas_fec_set(&tbi[ENC_SEED_BYTES], tbi, ENC_SEED_BYTES);
|
||||||
|
|
||||||
|
/* Export with rounding */
|
||||||
|
for (size_t i = 0; i < ENC_BITS; i += 2) {
|
||||||
|
h = (limb_t)(tbi[i / 8] >> (i % 8));
|
||||||
|
rlimb0 = (dlimb_t)((c[i / 2] >> (LGX - LPR_BITS)) + (h << 3));
|
||||||
|
rlimb1 = (dlimb_t)((c[DIGITS - i / 2 - 1] >> (LGX - LPR_BITS)) + ((h >> 1) << 3));
|
||||||
|
lpr_data[i / 2] = (uint8_t)((rlimb0 & 0xF) | rlimb1 << 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
cshake256_inc_finalize(&ctx);
|
||||||
|
cshake256_inc_squeeze(shared_secret, SHARED_SECRET_BYTES, &ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Decapsulate a shared secret and return it */
|
||||||
|
void PQCLEAN_MAMABEAREPHEM_CLEAN_decapsulate(
|
||||||
|
uint8_t shared_secret[SHARED_SECRET_BYTES],
|
||||||
|
const uint8_t capsule[CAPSULE_BYTES],
|
||||||
|
const uint8_t sk[PRIVATE_KEY_BYTES]
|
||||||
|
) {
|
||||||
|
const uint8_t *lpr_data = &capsule[GF_BYTES * DIM];
|
||||||
|
shake256incctx ctx;
|
||||||
|
gf_t ska, b, c = {0};
|
||||||
|
uint8_t seed[ENC_SEED_BYTES + FEC_BYTES + IV_BYTES];
|
||||||
|
limb_t rounding, out;
|
||||||
|
size_t j;
|
||||||
|
limb_t our_rlimb, their_rlimb, delta;
|
||||||
|
uint8_t matrix_seed[MATRIX_SEED_BYTES];
|
||||||
|
|
||||||
|
/* Calculate approximate shared secret */
|
||||||
|
threebears_hash_init(&ctx, HASH_PURPOSE_KEYGEN);
|
||||||
|
cshake256_inc_absorb(&ctx, sk, PRIVATE_KEY_BYTES);
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < DIM; i++) {
|
||||||
|
PQCLEAN_MAMABEAREPHEM_CLEAN_expand(b, &capsule[i * GF_BYTES]);
|
||||||
|
noise(ska, &ctx, i);
|
||||||
|
PQCLEAN_MAMABEAREPHEM_CLEAN_mac(c, ska, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Recover seed from LPR data */
|
||||||
|
PQCLEAN_MAMABEAREPHEM_CLEAN_canon(c);
|
||||||
|
rounding = 1 << (LPR_BITS - 1);
|
||||||
|
out = 0;
|
||||||
|
for (int32_t i = ENC_BITS - 1; i >= 0; i--) {
|
||||||
|
j = (size_t) ((i & 1) ? DIGITS - i / 2 - 1 : i / 2);
|
||||||
|
our_rlimb = (limb_t)(c[j] >> (LGX - LPR_BITS - 1));
|
||||||
|
their_rlimb = (limb_t)(lpr_data[i * LPR_BITS / 8] >> ((i * LPR_BITS) % 8));
|
||||||
|
delta = (limb_t)(their_rlimb * 2 - our_rlimb + rounding);
|
||||||
|
out |= (limb_t)(((delta >> LPR_BITS) & 1) << (i % 8));
|
||||||
|
if (i % 8 == 0) {
|
||||||
|
seed[i / 8] = (uint8_t)out;
|
||||||
|
out = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PQCLEAN_MAMABEAREPHEM_CLEAN_melas_fec_correct(seed, ENC_SEED_BYTES, &seed[ENC_SEED_BYTES]);
|
||||||
|
|
||||||
|
/* Recalculate matrix seed */
|
||||||
|
cshake256_inc_finalize(&ctx);
|
||||||
|
cshake256_inc_squeeze(matrix_seed, MATRIX_SEED_BYTES, &ctx);
|
||||||
|
|
||||||
|
/* Re-run the key derivation from encaps */
|
||||||
|
threebears_hash_init(&ctx, HASH_PURPOSE_ENCAPS);
|
||||||
|
cshake256_inc_absorb(&ctx, matrix_seed, MATRIX_SEED_BYTES);
|
||||||
|
cshake256_inc_absorb(&ctx, seed, ENC_SEED_BYTES);
|
||||||
|
cshake256_inc_absorb(&ctx, &lpr_data[(ENC_BITS * LPR_BITS + 7) / 8], IV_BYTES);
|
||||||
|
cshake256_inc_finalize(&ctx);
|
||||||
|
cshake256_inc_squeeze(shared_secret, SHARED_SECRET_BYTES, &ctx);
|
||||||
|
}
|
60
crypto_kem/mamabear-ephem/clean/threebears.h
Normal file
60
crypto_kem/mamabear-ephem/clean/threebears.h
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
#ifndef __THREE_BEARS_MAMABEAREPHEM_H__
|
||||||
|
#define __THREE_BEARS_MAMABEAREPHEM_H__
|
||||||
|
|
||||||
|
#include <stddef.h> /* for size_t */
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define MAMABEAREPHEM_KEYGEN_SEED_BYTES 40
|
||||||
|
#define MAMABEAREPHEM_PRIVATE_KEY_BYTES MAMABEAREPHEM_KEYGEN_SEED_BYTES
|
||||||
|
#define MAMABEAREPHEM_SHARED_SECRET_BYTES 32
|
||||||
|
#define MAMABEAREPHEM_ENC_SEED_AND_IV_BYTES 32
|
||||||
|
#define MAMABEAREPHEM_PUBLIC_KEY_BYTES 1194
|
||||||
|
#define MAMABEAREPHEM_CAPSULE_BYTES 1307
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expand a secret seed to a public/private keypair.
|
||||||
|
*
|
||||||
|
* @param[out] pk The public key.
|
||||||
|
* @param[in] sk The private key, which must be uniformly random.
|
||||||
|
*/
|
||||||
|
void PQCLEAN_MAMABEAREPHEM_CLEAN_get_pubkey (
|
||||||
|
uint8_t pk[MAMABEAREPHEM_PUBLIC_KEY_BYTES],
|
||||||
|
const uint8_t sk[MAMABEAREPHEM_PRIVATE_KEY_BYTES]
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a shared secret using a random seed and another party's public key.
|
||||||
|
*
|
||||||
|
* Input and output parameters may not alias.
|
||||||
|
*
|
||||||
|
* @param[out] shared_secret The shared secret key.
|
||||||
|
* @param[out] capsule A ciphertext to send to the other party.
|
||||||
|
* @param[in] pk The other party's public key.
|
||||||
|
* @param[in] seed A random seed.
|
||||||
|
*/
|
||||||
|
void PQCLEAN_MAMABEAREPHEM_CLEAN_encapsulate (
|
||||||
|
uint8_t shared_secret[MAMABEAREPHEM_SHARED_SECRET_BYTES],
|
||||||
|
uint8_t capsule[MAMABEAREPHEM_CAPSULE_BYTES],
|
||||||
|
const uint8_t pk[MAMABEAREPHEM_PUBLIC_KEY_BYTES],
|
||||||
|
const uint8_t seed[MAMABEAREPHEM_ENC_SEED_AND_IV_BYTES]
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract the shared secret from a capsule using the private key.
|
||||||
|
* Has a negligible but nonzero probability of failure.
|
||||||
|
*
|
||||||
|
* Input and output parameters may not alias.
|
||||||
|
*
|
||||||
|
* @param[out] shared_secret The shared secret.
|
||||||
|
* @param[in] capsule The capsule produced by encapsulate_cca2.
|
||||||
|
* @param[in] sk The private key.
|
||||||
|
* @return -1 on failure, 0 on success.
|
||||||
|
* @warning The value of shared_secret must not be used on failure
|
||||||
|
*/
|
||||||
|
void PQCLEAN_MAMABEAREPHEM_CLEAN_decapsulate (
|
||||||
|
uint8_t shared_secret[MAMABEAREPHEM_SHARED_SECRET_BYTES],
|
||||||
|
const uint8_t capsule[MAMABEAREPHEM_CAPSULE_BYTES],
|
||||||
|
const uint8_t sk[MAMABEAREPHEM_PRIVATE_KEY_BYTES]
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif
|
@ -55,6 +55,4 @@ void PQCLEAN_MAMABEAR_CLEAN_decapsulate (
|
|||||||
const uint8_t sk[MAMABEAR_PRIVATE_KEY_BYTES]
|
const uint8_t sk[MAMABEAR_PRIVATE_KEY_BYTES]
|
||||||
);
|
);
|
||||||
|
|
||||||
void PQCLEAN_MAMABEAR_CLEAN_secure_bzero (void *s, size_t size);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
14
crypto_kem/papabear-ephem/META.yml
Normal file
14
crypto_kem/papabear-ephem/META.yml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
name: PapaBearEphem
|
||||||
|
type: kem
|
||||||
|
claimed-nist-level: 5
|
||||||
|
claimed-security: IND-CPA
|
||||||
|
length-public-key: 1584
|
||||||
|
length-ciphertext: 1697
|
||||||
|
length-secret-key: 40
|
||||||
|
length-shared-secret: 32
|
||||||
|
nistkat-sha256: afe40a1172ab5f4f87135297e0a7c67047d21c87f33ab518864c030820c3674d
|
||||||
|
principal-submitters:
|
||||||
|
- Mike Hamburg
|
||||||
|
implementations:
|
||||||
|
- name: clean
|
||||||
|
version: https://sourceforge.net/p/threebears/code/ci/f4ce0ebfc84a5e01a75bfc8297b6d175e993cfa4/
|
24
crypto_kem/papabear-ephem/clean/LICENSE
Normal file
24
crypto_kem/papabear-ephem/clean/LICENSE
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
Copyright (c) 2016-2019 Rambus, Inc.
|
||||||
|
and licensed under the following MIT license.
|
||||||
|
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2016-2019 Rambus Inc.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
21
crypto_kem/papabear-ephem/clean/Makefile
Normal file
21
crypto_kem/papabear-ephem/clean/Makefile
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# This Makefile can be used with GNU Make or BSD Make
|
||||||
|
|
||||||
|
LIB=libpapabear-ephem_clean.a
|
||||||
|
|
||||||
|
HEADERS = api.h melas_fec.h params.h ring.h threebears.h
|
||||||
|
OBJECTS = kem.o melas_fec.o ring.o threebears.o
|
||||||
|
|
||||||
|
|
||||||
|
CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS)
|
||||||
|
|
||||||
|
all: $(LIB)
|
||||||
|
|
||||||
|
%.o: %.c $(HEADERS)
|
||||||
|
$(CC) $(CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
$(LIB): $(OBJECTS)
|
||||||
|
$(AR) -r $@ $(OBJECTS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) $(OBJECTS)
|
||||||
|
$(RM) $(LIB)
|
19
crypto_kem/papabear-ephem/clean/Makefile.Microsoft_nmake
Normal file
19
crypto_kem/papabear-ephem/clean/Makefile.Microsoft_nmake
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# This Makefile can be used with Microsoft Visual Studio's nmake using the command:
|
||||||
|
# nmake /f Makefile.Microsoft_nmake
|
||||||
|
|
||||||
|
LIBRARY=libpapabear-ephem_clean.lib
|
||||||
|
OBJECTS = kem.obj melas_fec.obj ring.obj threebears.obj
|
||||||
|
|
||||||
|
CFLAGS=/nologo /I ..\..\..\common /W4 /WX
|
||||||
|
|
||||||
|
all: $(LIBRARY)
|
||||||
|
|
||||||
|
# Make sure objects are recompiled if headers change.
|
||||||
|
$(OBJECTS): *.h
|
||||||
|
|
||||||
|
$(LIBRARY): $(OBJECTS)
|
||||||
|
LIB.EXE /NOLOGO /WX /OUT:$@ $**
|
||||||
|
|
||||||
|
clean:
|
||||||
|
-DEL $(OBJECTS)
|
||||||
|
-DEL $(LIBRARY)
|
18
crypto_kem/papabear-ephem/clean/api.h
Normal file
18
crypto_kem/papabear-ephem/clean/api.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#ifndef PQCLEAN_PAPABEAREPHEM_CLEAN_API_H
|
||||||
|
#define PQCLEAN_PAPABEAREPHEM_CLEAN_API_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define PQCLEAN_PAPABEAREPHEM_CLEAN_CRYPTO_SECRETKEYBYTES 40
|
||||||
|
#define PQCLEAN_PAPABEAREPHEM_CLEAN_CRYPTO_PUBLICKEYBYTES 1584
|
||||||
|
#define PQCLEAN_PAPABEAREPHEM_CLEAN_CRYPTO_BYTES 32
|
||||||
|
#define PQCLEAN_PAPABEAREPHEM_CLEAN_CRYPTO_CIPHERTEXTBYTES 1697
|
||||||
|
#define PQCLEAN_PAPABEAREPHEM_CLEAN_CRYPTO_ALGNAME "PapaBearEphem"
|
||||||
|
|
||||||
|
int PQCLEAN_PAPABEAREPHEM_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk);
|
||||||
|
int PQCLEAN_PAPABEAREPHEM_CLEAN_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk);
|
||||||
|
int PQCLEAN_PAPABEAREPHEM_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk);
|
||||||
|
|
||||||
|
#endif
|
22
crypto_kem/papabear-ephem/clean/kem.c
Normal file
22
crypto_kem/papabear-ephem/clean/kem.c
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#include "api.h"
|
||||||
|
#include "params.h"
|
||||||
|
#include "randombytes.h"
|
||||||
|
#include "threebears.h"
|
||||||
|
|
||||||
|
int PQCLEAN_PAPABEAREPHEM_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk) {
|
||||||
|
randombytes(sk, PRIVATE_KEY_BYTES);
|
||||||
|
PQCLEAN_PAPABEAREPHEM_CLEAN_get_pubkey(pk, sk);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PQCLEAN_PAPABEAREPHEM_CLEAN_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk) {
|
||||||
|
uint8_t seed[ENC_SEED_BYTES + IV_BYTES];
|
||||||
|
randombytes(seed, sizeof(seed));
|
||||||
|
encapsulate(ss, ct, pk, seed);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PQCLEAN_PAPABEAREPHEM_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk) {
|
||||||
|
PQCLEAN_PAPABEAREPHEM_CLEAN_decapsulate(ss, ct, sk);
|
||||||
|
return 0;
|
||||||
|
}
|
87
crypto_kem/papabear-ephem/clean/melas_fec.c
Normal file
87
crypto_kem/papabear-ephem/clean/melas_fec.c
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
/* Melas forward error correction, reference code (as implemented in the paper) */
|
||||||
|
#include "melas_fec.h"
|
||||||
|
|
||||||
|
/* Return s/2^n mod R */
|
||||||
|
static fec_gf_t step(size_t n, fec_gf_t R, fec_gf_t s) {
|
||||||
|
for (; n; n--) {
|
||||||
|
s = (s ^ ((s & 1) * R)) >> 1;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compute syndrome(data), where data has length len */
|
||||||
|
#define syndrome18(data,len) s18update(0,data,len)
|
||||||
|
static fec_gf_t s18update(fec_gf_t r, const uint8_t *data, size_t len) {
|
||||||
|
for (size_t i = 0; i < len; i++) {
|
||||||
|
r = step(8, 0x46231, r ^ data[i]);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Append 3 bytes of FEC(data) to data, so that the FEC becomes 0 */
|
||||||
|
void PQCLEAN_PAPABEAREPHEM_CLEAN_melas_fec_set(
|
||||||
|
uint8_t out[MELAS_FEC_BYTES],
|
||||||
|
const uint8_t *data,
|
||||||
|
size_t len
|
||||||
|
) {
|
||||||
|
fec_gf_t fec = syndrome18(data, len);
|
||||||
|
for (size_t i = 0; i < MELAS_FEC_BYTES; i++, fec >>= 8) {
|
||||||
|
out[i] = (uint8_t)fec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return a*b mod Q */
|
||||||
|
static fec_gf_t mul(fec_gf_t a, fec_gf_t b) {
|
||||||
|
fec_gf_t r = 0;
|
||||||
|
for (size_t i = 0; i < 9; i++) {
|
||||||
|
r ^= ((b >> (8 - i)) & 1) * a;
|
||||||
|
a = step(1, Q, a);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reverse an 18-bit number x */
|
||||||
|
static fec_gf_t reverse18(fec_gf_t x) {
|
||||||
|
fec_gf_t ret = 0;
|
||||||
|
for (size_t i = 0; i < 18; i++) {
|
||||||
|
ret ^= ((x >> i) & 1) << (17 - i);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Correct data to have the given FEC */
|
||||||
|
void PQCLEAN_PAPABEAREPHEM_CLEAN_melas_fec_correct (
|
||||||
|
uint8_t *data,
|
||||||
|
size_t len,
|
||||||
|
const uint8_t fec[MELAS_FEC_BYTES]
|
||||||
|
) {
|
||||||
|
|
||||||
|
fec_gf_t a = s18update(syndrome18(data, len), fec, MELAS_FEC_BYTES);
|
||||||
|
fec_gf_t c, r, htr;
|
||||||
|
size_t i;
|
||||||
|
const uint8_t table[9] = {36, 10, 43, 215, 52, 11, 116, 244, 0};
|
||||||
|
fec_gf_t e0, e1;
|
||||||
|
|
||||||
|
/* Form a quadratic equation from the syndrome */
|
||||||
|
c = mul(step(9, Q, a), step(9, Q, reverse18(a)));
|
||||||
|
for (i = 0, r = 0x100; i < 510; i++) {
|
||||||
|
r = mul(r, c);
|
||||||
|
}
|
||||||
|
r = step(17, Q, r);
|
||||||
|
a = step(511 - (len + MELAS_FEC_BYTES) * 8, Q, a);
|
||||||
|
|
||||||
|
/* Solve using the half trace */
|
||||||
|
for (i = 0, htr = 0; i < 9; i++) {
|
||||||
|
htr ^= ((r >> i) & 1) * table[i];
|
||||||
|
}
|
||||||
|
e0 = mul(a, htr);
|
||||||
|
e1 = e0 ^ a;
|
||||||
|
|
||||||
|
/* Correct the errors using the locators */
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
data[i] ^= (uint8_t)(e0 & (((e0 & (e0 - 1)) - 1) >> 9));
|
||||||
|
data[i] ^= (uint8_t)(e1 & (((e1 & (e1 - 1)) - 1) >> 9));
|
||||||
|
e0 = step(8, Q, e0);
|
||||||
|
e1 = step(8, Q, e1);
|
||||||
|
}
|
||||||
|
}
|
26
crypto_kem/papabear-ephem/clean/melas_fec.h
Normal file
26
crypto_kem/papabear-ephem/clean/melas_fec.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#ifndef __THREEBEARS_MELAS_FEC_H__
|
||||||
|
#define __THREEBEARS_MELAS_FEC_H__
|
||||||
|
|
||||||
|
#include "api.h"
|
||||||
|
|
||||||
|
#define MELAS_FEC_BYTES 3
|
||||||
|
#define MELAS_FEC_BITS 18
|
||||||
|
|
||||||
|
typedef uint32_t fec_gf_t;
|
||||||
|
static const fec_gf_t Q = 0x211;
|
||||||
|
|
||||||
|
/* Append 3 bytes of FEC(data) to data, so that the FEC becomes 0 */
|
||||||
|
void PQCLEAN_PAPABEAREPHEM_CLEAN_melas_fec_set(
|
||||||
|
uint8_t out[MELAS_FEC_BYTES],
|
||||||
|
const uint8_t *data,
|
||||||
|
size_t len
|
||||||
|
);
|
||||||
|
|
||||||
|
/* Append 3 bytes of FEC(data) to data, so that the FEC becomes 0 */
|
||||||
|
void PQCLEAN_PAPABEAREPHEM_CLEAN_melas_fec_correct(
|
||||||
|
uint8_t *data,
|
||||||
|
size_t len,
|
||||||
|
const uint8_t fec[MELAS_FEC_BYTES]
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif
|
29
crypto_kem/papabear-ephem/clean/params.h
Normal file
29
crypto_kem/papabear-ephem/clean/params.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#ifndef __THREEBEARS_PARAMS_H__
|
||||||
|
#define __THREEBEARS_PARAMS_H__
|
||||||
|
|
||||||
|
#define VERSION 1
|
||||||
|
#define MATRIX_SEED_BYTES 24
|
||||||
|
#define ENC_SEED_BYTES 32
|
||||||
|
#define IV_BYTES 0
|
||||||
|
#define LGX 10
|
||||||
|
#define DIGITS 312
|
||||||
|
#define DIM 4
|
||||||
|
#define VAR_TIMES_128 96
|
||||||
|
#define LPR_BITS 4
|
||||||
|
#define FEC_BITS 18
|
||||||
|
#define CCA 0
|
||||||
|
#define SHARED_SECRET_BYTES 32
|
||||||
|
#define PRIVATE_KEY_BYTES 40
|
||||||
|
#define PRF_KEY_BYTES PRIVATE_KEY_BYTES
|
||||||
|
|
||||||
|
#define BEAR_NAME "PapaBearEphem"
|
||||||
|
#define encapsulate PQCLEAN_PAPABEAREPHEM_CLEAN_encapsulate
|
||||||
|
#define decapsulate PQCLEAN_PAPABEAREPHEM_CLEAN_decapsulate
|
||||||
|
#define get_pubkey PQCLEAN_PAPABEAREPHEM_CLEAN_get_pubkey
|
||||||
|
|
||||||
|
#define GF_BYTES ((LGX*DIGITS+7)/8)
|
||||||
|
#define PUBLIC_KEY_BYTES (MATRIX_SEED_BYTES + DIM*GF_BYTES)
|
||||||
|
#define CAPSULE_BYTES \
|
||||||
|
(DIM*GF_BYTES + IV_BYTES + ((ENC_SEED_BYTES*8+FEC_BITS)*LPR_BITS+7)/8)
|
||||||
|
|
||||||
|
#endif
|
107
crypto_kem/papabear-ephem/clean/ring.c
Normal file
107
crypto_kem/papabear-ephem/clean/ring.c
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
/** Ring arithmetic implementation */
|
||||||
|
#include "ring.h"
|
||||||
|
|
||||||
|
/** Return the i'th limb of the modulus */
|
||||||
|
limb_t PQCLEAN_PAPABEAREPHEM_CLEAN_modulus(size_t i) {
|
||||||
|
return (i == DIGITS / 2) ? LMASK - 1 : LMASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Multiply and accumulate c += a*b */
|
||||||
|
void PQCLEAN_PAPABEAREPHEM_CLEAN_mac(gf_t c, const gf_t a, const gf_t b) {
|
||||||
|
/* Reference non-Karatsuba MAC */
|
||||||
|
dslimb_t accum[2 * DIGITS] = {0};
|
||||||
|
dslimb_t chain;
|
||||||
|
size_t i, j;
|
||||||
|
|
||||||
|
/* Initialize accumulator = unclarify(c) */
|
||||||
|
for (i = 0; i < DIGITS; i++) {
|
||||||
|
accum[i + DIGITS / 2] = c[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Multiply */
|
||||||
|
for (i = 0; i < DIGITS; i++) {
|
||||||
|
for (j = 0; j < DIGITS; j++) {
|
||||||
|
accum[i + j] += (dslimb_t)a[i] * b[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clarify and reduce */
|
||||||
|
for (i = 0; i < DIGITS / 2; i++) {
|
||||||
|
accum[i + DIGITS / 2] -= accum[i];
|
||||||
|
accum[i + DIGITS] += accum[i];
|
||||||
|
accum[i + DIGITS / 2] += accum[i + 3 * DIGITS / 2];
|
||||||
|
accum[i + DIGITS] += accum[i + 3 * DIGITS / 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Carry propagate */
|
||||||
|
chain = accum[3 * DIGITS / 2 - 1];
|
||||||
|
accum[3 * DIGITS / 2 - 1] = chain & LMASK;
|
||||||
|
chain >>= LGX;
|
||||||
|
accum[DIGITS] += chain;
|
||||||
|
for (i = DIGITS / 2; i < 3 * DIGITS / 2; i++) {
|
||||||
|
chain += accum[i];
|
||||||
|
c[i - DIGITS / 2] = chain & LMASK;
|
||||||
|
chain >>= LGX;
|
||||||
|
}
|
||||||
|
c[0] = (limb_t) (c[0] + chain);
|
||||||
|
c[DIGITS / 2] = (limb_t) (c[DIGITS / 2] + chain);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Reduce a gf_t to canonical form, i.e. strictly less than N. */
|
||||||
|
void PQCLEAN_PAPABEAREPHEM_CLEAN_canon(gf_t c) {
|
||||||
|
const limb_t DELTA = (limb_t)1 << (LGX - 1);
|
||||||
|
slimb_t hi;
|
||||||
|
dslimb_t scarry;
|
||||||
|
dlimb_t carry;
|
||||||
|
|
||||||
|
/* Reduce to 0..2p */
|
||||||
|
hi = (slimb_t) (c[DIGITS - 1] - DELTA);
|
||||||
|
c[DIGITS - 1] = (limb_t) ((hi & LMASK) + DELTA);
|
||||||
|
c[DIGITS / 2] = (limb_t) (c[DIGITS / 2] + (hi >> LGX));
|
||||||
|
|
||||||
|
/* Strong reduce. First subtract modulus */
|
||||||
|
scarry = hi >> LGX;
|
||||||
|
for (size_t i = 0; i < DIGITS; i++) {
|
||||||
|
scarry = scarry + (slimb_t)c[i] - PQCLEAN_PAPABEAREPHEM_CLEAN_modulus(i);
|
||||||
|
c[i] = scarry & LMASK;
|
||||||
|
scarry >>= LGX;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add it back */
|
||||||
|
carry = 0;
|
||||||
|
for (size_t i = 0; i < DIGITS; i++) {
|
||||||
|
carry = carry + c[i] + ((dlimb_t)scarry & PQCLEAN_PAPABEAREPHEM_CLEAN_modulus(i));
|
||||||
|
c[i] = carry & LMASK;
|
||||||
|
carry >>= LGX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Serialize a gf_t to bytes */
|
||||||
|
void PQCLEAN_PAPABEAREPHEM_CLEAN_contract(uint8_t ch[GF_BYTES], gf_t a) {
|
||||||
|
size_t pos;
|
||||||
|
|
||||||
|
PQCLEAN_PAPABEAREPHEM_CLEAN_canon(a);
|
||||||
|
for (size_t i = 0; i < GF_BYTES; i++) {
|
||||||
|
pos = (i * 8) / LGX;
|
||||||
|
ch[i] = (uint8_t)(a[pos] >> ((i * 8) % LGX));
|
||||||
|
if (i < GF_BYTES - 1) {
|
||||||
|
ch[i] |= (uint8_t)(a[pos + 1] << (LGX - ((i * 8) % LGX)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Deserialize a gf_t from bytes */
|
||||||
|
void PQCLEAN_PAPABEAREPHEM_CLEAN_expand(gf_t ll, const uint8_t ch[GF_BYTES]) {
|
||||||
|
limb_t tmp, buffer = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0, j = 0, bbits = 0; i < GF_BYTES; i++) {
|
||||||
|
tmp = ch[i];
|
||||||
|
buffer |= (limb_t)(tmp << bbits);
|
||||||
|
bbits += 8;
|
||||||
|
if (bbits >= LGX) {
|
||||||
|
ll[j++] = buffer & LMASK;
|
||||||
|
buffer = (limb_t)(tmp >> (LGX - (bbits - 8)));
|
||||||
|
bbits = bbits - LGX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
29
crypto_kem/papabear-ephem/clean/ring.h
Normal file
29
crypto_kem/papabear-ephem/clean/ring.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#ifndef __THREEBEARS_RING_H__
|
||||||
|
#define __THREEBEARS_RING_H__
|
||||||
|
|
||||||
|
#include "api.h"
|
||||||
|
#include "params.h"
|
||||||
|
|
||||||
|
typedef uint16_t limb_t;
|
||||||
|
typedef int16_t slimb_t;
|
||||||
|
typedef uint32_t dlimb_t;
|
||||||
|
typedef int32_t dslimb_t;
|
||||||
|
#define LMASK (((limb_t)1<<LGX)-1)
|
||||||
|
typedef limb_t gf_t[DIGITS];
|
||||||
|
|
||||||
|
/* Serialize a gf_t */
|
||||||
|
void PQCLEAN_PAPABEAREPHEM_CLEAN_contract(uint8_t ch[GF_BYTES], gf_t a);
|
||||||
|
|
||||||
|
/* Deserialize a gf_t */
|
||||||
|
void PQCLEAN_PAPABEAREPHEM_CLEAN_expand(gf_t ll, const uint8_t ch[GF_BYTES]);
|
||||||
|
|
||||||
|
/* Multiply and accumulate c = c + a*b */
|
||||||
|
void PQCLEAN_PAPABEAREPHEM_CLEAN_mac(gf_t c, const gf_t a, const gf_t b);
|
||||||
|
|
||||||
|
/* Reduce ring element to canonical form */
|
||||||
|
void PQCLEAN_PAPABEAREPHEM_CLEAN_canon(gf_t c);
|
||||||
|
|
||||||
|
/** Return the i'th limb of the modulus */
|
||||||
|
limb_t PQCLEAN_PAPABEAREPHEM_CLEAN_modulus(size_t i);
|
||||||
|
|
||||||
|
#endif
|
210
crypto_kem/papabear-ephem/clean/threebears.c
Normal file
210
crypto_kem/papabear-ephem/clean/threebears.c
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
/** ThreeBears reference implementation */
|
||||||
|
#include "api.h"
|
||||||
|
#include "melas_fec.h"
|
||||||
|
#include "params.h"
|
||||||
|
#include "ring.h"
|
||||||
|
#include "sp800-185.h"
|
||||||
|
#include "threebears.h"
|
||||||
|
|
||||||
|
#define FEC_BYTES ((FEC_BITS+7)/8)
|
||||||
|
#define ENC_BITS (ENC_SEED_BYTES*8 + FEC_BITS)
|
||||||
|
|
||||||
|
enum { HASH_PURPOSE_UNIFORM = 0, HASH_PURPOSE_KEYGEN = 1, HASH_PURPOSE_ENCAPS = 2, HASH_PURPOSE_PRF = 3 };
|
||||||
|
|
||||||
|
/** Initialize the hash function with a given purpose */
|
||||||
|
static void threebears_hash_init(
|
||||||
|
shake256incctx *ctx,
|
||||||
|
uint8_t purpose
|
||||||
|
) {
|
||||||
|
const unsigned char S[] = "ThreeBears";
|
||||||
|
const uint8_t pblock[15] = {
|
||||||
|
VERSION, PRIVATE_KEY_BYTES, MATRIX_SEED_BYTES, ENC_SEED_BYTES,
|
||||||
|
IV_BYTES, SHARED_SECRET_BYTES, LGX, DIGITS & 0xFF, DIGITS >> 8, DIM,
|
||||||
|
VAR_TIMES_128 - 1, LPR_BITS, FEC_BITS, CCA, 0 /* padding */
|
||||||
|
};
|
||||||
|
|
||||||
|
cshake256_inc_init(ctx, NULL, 0, (const uint8_t *)S, sizeof(S) - 1);
|
||||||
|
cshake256_inc_absorb(ctx, (const uint8_t *)pblock, sizeof(pblock));
|
||||||
|
cshake256_inc_absorb(ctx, &purpose, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sample n gf_t's uniformly from a seed */
|
||||||
|
static void uniform(gf_t matrix, const uint8_t *seed, uint8_t iv) {
|
||||||
|
uint8_t c[GF_BYTES];
|
||||||
|
shake256incctx ctx;
|
||||||
|
|
||||||
|
threebears_hash_init(&ctx, HASH_PURPOSE_UNIFORM);
|
||||||
|
cshake256_inc_absorb(&ctx, seed, MATRIX_SEED_BYTES);
|
||||||
|
cshake256_inc_absorb(&ctx, &iv, 1);
|
||||||
|
cshake256_inc_finalize(&ctx);
|
||||||
|
cshake256_inc_squeeze(c, sizeof(c), &ctx);
|
||||||
|
PQCLEAN_PAPABEAREPHEM_CLEAN_expand(matrix, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The ThreeBears error distribution */
|
||||||
|
static slimb_t psi(uint8_t ci) {
|
||||||
|
int sample = 0, var = VAR_TIMES_128;
|
||||||
|
|
||||||
|
for (; var > 64; var -= 64, ci = (uint8_t)(ci << 2)) {
|
||||||
|
sample += ((ci + 64) >> 8) + ((ci - 64) >> 8);
|
||||||
|
}
|
||||||
|
return (slimb_t)(sample + ((ci + var) >> 8) + ((ci - var) >> 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sample a vector of n noise elements */
|
||||||
|
static void noise(gf_t x, const shake256incctx *ctx, uint8_t iv) {
|
||||||
|
uint8_t c[DIGITS];
|
||||||
|
shake256incctx ctx2;
|
||||||
|
|
||||||
|
memcpy(&ctx2, ctx, sizeof(ctx2));
|
||||||
|
cshake256_inc_absorb(&ctx2, &iv, 1);
|
||||||
|
cshake256_inc_finalize(&ctx2);
|
||||||
|
cshake256_inc_squeeze(c, DIGITS, &ctx2);
|
||||||
|
for (size_t i = 0; i < DIGITS; i++) {
|
||||||
|
x[i] = (limb_t)(psi(c[i]) + PQCLEAN_PAPABEAREPHEM_CLEAN_modulus(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Expand public key from private key */
|
||||||
|
void PQCLEAN_PAPABEAREPHEM_CLEAN_get_pubkey(uint8_t *pk, const uint8_t *sk) {
|
||||||
|
shake256incctx ctx;
|
||||||
|
shake256incctx ctx2;
|
||||||
|
gf_t sk_expanded[DIM], b, c;
|
||||||
|
|
||||||
|
threebears_hash_init(&ctx, HASH_PURPOSE_KEYGEN);
|
||||||
|
cshake256_inc_absorb(&ctx, sk, PRIVATE_KEY_BYTES);
|
||||||
|
|
||||||
|
memcpy(&ctx2, &ctx, sizeof(ctx2));
|
||||||
|
cshake256_inc_finalize(&ctx2);
|
||||||
|
cshake256_inc_squeeze(pk, MATRIX_SEED_BYTES, &ctx2);
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < DIM; i++) {
|
||||||
|
noise(sk_expanded[i], &ctx, i);
|
||||||
|
}
|
||||||
|
for (uint8_t i = 0; i < DIM; i++) {
|
||||||
|
noise(c, &ctx, (uint8_t)(i + DIM));
|
||||||
|
for (uint8_t j = 0; j < DIM; j++) {
|
||||||
|
uniform(b, pk, (uint8_t) (i + DIM * j));
|
||||||
|
PQCLEAN_PAPABEAREPHEM_CLEAN_mac(c, b, sk_expanded[j]);
|
||||||
|
}
|
||||||
|
PQCLEAN_PAPABEAREPHEM_CLEAN_contract(&pk[MATRIX_SEED_BYTES + i * GF_BYTES], c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Encapsulate a shared secret and return it */
|
||||||
|
void PQCLEAN_PAPABEAREPHEM_CLEAN_encapsulate(
|
||||||
|
uint8_t *shared_secret,
|
||||||
|
uint8_t *capsule,
|
||||||
|
const uint8_t *pk,
|
||||||
|
const uint8_t *seed
|
||||||
|
) {
|
||||||
|
uint8_t *lpr_data = &capsule[GF_BYTES * DIM];
|
||||||
|
shake256incctx ctx;
|
||||||
|
gf_t sk_expanded[DIM], b, c;
|
||||||
|
uint8_t tbi[ENC_SEED_BYTES + FEC_BYTES];
|
||||||
|
dlimb_t rlimb0, rlimb1;
|
||||||
|
limb_t h;
|
||||||
|
uint8_t *iv = &lpr_data[(ENC_BITS * LPR_BITS + 7) / 8];
|
||||||
|
|
||||||
|
memcpy(iv, &seed[ENC_SEED_BYTES], IV_BYTES);
|
||||||
|
|
||||||
|
threebears_hash_init(&ctx, HASH_PURPOSE_ENCAPS);
|
||||||
|
cshake256_inc_absorb(&ctx, pk, MATRIX_SEED_BYTES);
|
||||||
|
cshake256_inc_absorb(&ctx, seed, ENC_SEED_BYTES + IV_BYTES);
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < DIM; i++) {
|
||||||
|
noise(sk_expanded[i], &ctx, i);
|
||||||
|
}
|
||||||
|
for (uint8_t i = 0; i < DIM; i++) {
|
||||||
|
noise(c, &ctx, (uint8_t)(i + DIM));
|
||||||
|
for (uint8_t j = 0; j < DIM; j++) {
|
||||||
|
uniform(b, pk, (uint8_t)(j + DIM * i));
|
||||||
|
PQCLEAN_PAPABEAREPHEM_CLEAN_mac(c, b, sk_expanded[j]);
|
||||||
|
}
|
||||||
|
PQCLEAN_PAPABEAREPHEM_CLEAN_contract(&capsule[i * GF_BYTES], c);
|
||||||
|
}
|
||||||
|
noise(c, &ctx, (uint8_t)(2 * DIM));
|
||||||
|
|
||||||
|
/* Calculate approximate shared secret */
|
||||||
|
for (uint8_t i = 0; i < DIM; i++) {
|
||||||
|
PQCLEAN_PAPABEAREPHEM_CLEAN_expand(b, &pk[MATRIX_SEED_BYTES + i * GF_BYTES]);
|
||||||
|
PQCLEAN_PAPABEAREPHEM_CLEAN_mac(c, b, sk_expanded[i]);
|
||||||
|
}
|
||||||
|
PQCLEAN_PAPABEAREPHEM_CLEAN_canon(c);
|
||||||
|
|
||||||
|
|
||||||
|
cshake256_inc_finalize(&ctx);
|
||||||
|
cshake256_inc_squeeze(tbi, ENC_SEED_BYTES, &ctx);
|
||||||
|
threebears_hash_init(&ctx, HASH_PURPOSE_ENCAPS);
|
||||||
|
cshake256_inc_absorb(&ctx, pk, MATRIX_SEED_BYTES);
|
||||||
|
cshake256_inc_absorb(&ctx, tbi, ENC_SEED_BYTES);
|
||||||
|
cshake256_inc_absorb(&ctx, iv, IV_BYTES);
|
||||||
|
|
||||||
|
PQCLEAN_PAPABEAREPHEM_CLEAN_melas_fec_set(&tbi[ENC_SEED_BYTES], tbi, ENC_SEED_BYTES);
|
||||||
|
|
||||||
|
/* Export with rounding */
|
||||||
|
for (size_t i = 0; i < ENC_BITS; i += 2) {
|
||||||
|
h = (limb_t)(tbi[i / 8] >> (i % 8));
|
||||||
|
rlimb0 = (dlimb_t)((c[i / 2] >> (LGX - LPR_BITS)) + (h << 3));
|
||||||
|
rlimb1 = (dlimb_t)((c[DIGITS - i / 2 - 1] >> (LGX - LPR_BITS)) + ((h >> 1) << 3));
|
||||||
|
lpr_data[i / 2] = (uint8_t)((rlimb0 & 0xF) | rlimb1 << 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
cshake256_inc_finalize(&ctx);
|
||||||
|
cshake256_inc_squeeze(shared_secret, SHARED_SECRET_BYTES, &ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Decapsulate a shared secret and return it */
|
||||||
|
void PQCLEAN_PAPABEAREPHEM_CLEAN_decapsulate(
|
||||||
|
uint8_t shared_secret[SHARED_SECRET_BYTES],
|
||||||
|
const uint8_t capsule[CAPSULE_BYTES],
|
||||||
|
const uint8_t sk[PRIVATE_KEY_BYTES]
|
||||||
|
) {
|
||||||
|
const uint8_t *lpr_data = &capsule[GF_BYTES * DIM];
|
||||||
|
shake256incctx ctx;
|
||||||
|
gf_t ska, b, c = {0};
|
||||||
|
uint8_t seed[ENC_SEED_BYTES + FEC_BYTES + IV_BYTES];
|
||||||
|
limb_t rounding, out;
|
||||||
|
size_t j;
|
||||||
|
limb_t our_rlimb, their_rlimb, delta;
|
||||||
|
uint8_t matrix_seed[MATRIX_SEED_BYTES];
|
||||||
|
|
||||||
|
/* Calculate approximate shared secret */
|
||||||
|
threebears_hash_init(&ctx, HASH_PURPOSE_KEYGEN);
|
||||||
|
cshake256_inc_absorb(&ctx, sk, PRIVATE_KEY_BYTES);
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < DIM; i++) {
|
||||||
|
PQCLEAN_PAPABEAREPHEM_CLEAN_expand(b, &capsule[i * GF_BYTES]);
|
||||||
|
noise(ska, &ctx, i);
|
||||||
|
PQCLEAN_PAPABEAREPHEM_CLEAN_mac(c, ska, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Recover seed from LPR data */
|
||||||
|
PQCLEAN_PAPABEAREPHEM_CLEAN_canon(c);
|
||||||
|
rounding = 1 << (LPR_BITS - 1);
|
||||||
|
out = 0;
|
||||||
|
for (int32_t i = ENC_BITS - 1; i >= 0; i--) {
|
||||||
|
j = (size_t) ((i & 1) ? DIGITS - i / 2 - 1 : i / 2);
|
||||||
|
our_rlimb = (limb_t)(c[j] >> (LGX - LPR_BITS - 1));
|
||||||
|
their_rlimb = (limb_t)(lpr_data[i * LPR_BITS / 8] >> ((i * LPR_BITS) % 8));
|
||||||
|
delta = (limb_t)(their_rlimb * 2 - our_rlimb + rounding);
|
||||||
|
out |= (limb_t)(((delta >> LPR_BITS) & 1) << (i % 8));
|
||||||
|
if (i % 8 == 0) {
|
||||||
|
seed[i / 8] = (uint8_t)out;
|
||||||
|
out = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PQCLEAN_PAPABEAREPHEM_CLEAN_melas_fec_correct(seed, ENC_SEED_BYTES, &seed[ENC_SEED_BYTES]);
|
||||||
|
|
||||||
|
/* Recalculate matrix seed */
|
||||||
|
cshake256_inc_finalize(&ctx);
|
||||||
|
cshake256_inc_squeeze(matrix_seed, MATRIX_SEED_BYTES, &ctx);
|
||||||
|
|
||||||
|
/* Re-run the key derivation from encaps */
|
||||||
|
threebears_hash_init(&ctx, HASH_PURPOSE_ENCAPS);
|
||||||
|
cshake256_inc_absorb(&ctx, matrix_seed, MATRIX_SEED_BYTES);
|
||||||
|
cshake256_inc_absorb(&ctx, seed, ENC_SEED_BYTES);
|
||||||
|
cshake256_inc_absorb(&ctx, &lpr_data[(ENC_BITS * LPR_BITS + 7) / 8], IV_BYTES);
|
||||||
|
cshake256_inc_finalize(&ctx);
|
||||||
|
cshake256_inc_squeeze(shared_secret, SHARED_SECRET_BYTES, &ctx);
|
||||||
|
}
|
60
crypto_kem/papabear-ephem/clean/threebears.h
Normal file
60
crypto_kem/papabear-ephem/clean/threebears.h
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
#ifndef __THREE_BEARS_PAPABEAREPHEM_H__
|
||||||
|
#define __THREE_BEARS_PAPABEAREPHEM_H__
|
||||||
|
|
||||||
|
#include <stddef.h> /* for size_t */
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define PAPABEAREPHEM_KEYGEN_SEED_BYTES 40
|
||||||
|
#define PAPABEAREPHEM_PRIVATE_KEY_BYTES PAPABEAREPHEM_KEYGEN_SEED_BYTES
|
||||||
|
#define PAPABEAREPHEM_SHARED_SECRET_BYTES 32
|
||||||
|
#define PAPABEAREPHEM_ENC_SEED_AND_IV_BYTES 32
|
||||||
|
#define PAPABEAREPHEM_PUBLIC_KEY_BYTES 1584
|
||||||
|
#define PAPABEAREPHEM_CAPSULE_BYTES 1697
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expand a secret seed to a public/private keypair.
|
||||||
|
*
|
||||||
|
* @param[out] pk The public key.
|
||||||
|
* @param[in] sk The private key, which must be uniformly random.
|
||||||
|
*/
|
||||||
|
void PQCLEAN_PAPABEAREPHEM_CLEAN_get_pubkey (
|
||||||
|
uint8_t pk[PAPABEAREPHEM_PUBLIC_KEY_BYTES],
|
||||||
|
const uint8_t sk[PAPABEAREPHEM_PRIVATE_KEY_BYTES]
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a shared secret using a random seed and another party's public key.
|
||||||
|
*
|
||||||
|
* Input and output parameters may not alias.
|
||||||
|
*
|
||||||
|
* @param[out] shared_secret The shared secret key.
|
||||||
|
* @param[out] capsule A ciphertext to send to the other party.
|
||||||
|
* @param[in] pk The other party's public key.
|
||||||
|
* @param[in] seed A random seed.
|
||||||
|
*/
|
||||||
|
void PQCLEAN_PAPABEAREPHEM_CLEAN_encapsulate (
|
||||||
|
uint8_t shared_secret[PAPABEAREPHEM_SHARED_SECRET_BYTES],
|
||||||
|
uint8_t capsule[PAPABEAREPHEM_CAPSULE_BYTES],
|
||||||
|
const uint8_t pk[PAPABEAREPHEM_PUBLIC_KEY_BYTES],
|
||||||
|
const uint8_t seed[PAPABEAREPHEM_ENC_SEED_AND_IV_BYTES]
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract the shared secret from a capsule using the private key.
|
||||||
|
* Has a negligible but nonzero probability of failure.
|
||||||
|
*
|
||||||
|
* Input and output parameters may not alias.
|
||||||
|
*
|
||||||
|
* @param[out] shared_secret The shared secret.
|
||||||
|
* @param[in] capsule The capsule produced by encapsulate_cca2.
|
||||||
|
* @param[in] sk The private key.
|
||||||
|
* @return -1 on failure, 0 on success.
|
||||||
|
* @warning The value of shared_secret must not be used on failure
|
||||||
|
*/
|
||||||
|
void PQCLEAN_PAPABEAREPHEM_CLEAN_decapsulate (
|
||||||
|
uint8_t shared_secret[PAPABEAREPHEM_SHARED_SECRET_BYTES],
|
||||||
|
const uint8_t capsule[PAPABEAREPHEM_CAPSULE_BYTES],
|
||||||
|
const uint8_t sk[PAPABEAREPHEM_PRIVATE_KEY_BYTES]
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif
|
@ -55,6 +55,4 @@ void PQCLEAN_PAPABEAR_CLEAN_decapsulate (
|
|||||||
const uint8_t sk[PAPABEAR_PRIVATE_KEY_BYTES]
|
const uint8_t sk[PAPABEAR_PRIVATE_KEY_BYTES]
|
||||||
);
|
);
|
||||||
|
|
||||||
void PQCLEAN_PAPABEAR_CLEAN_secure_bzero (void *s, size_t size);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
21
test/duplicate_consistency/babybear-ephem_clean.yml
Normal file
21
test/duplicate_consistency/babybear-ephem_clean.yml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
consistency_checks:
|
||||||
|
- source:
|
||||||
|
scheme: mamabear-ephem
|
||||||
|
implementation: clean
|
||||||
|
files:
|
||||||
|
- kem.c
|
||||||
|
- melas_fec.c
|
||||||
|
- melas_fec.h
|
||||||
|
- ring.c
|
||||||
|
- ring.h
|
||||||
|
- threebears.c
|
||||||
|
- source:
|
||||||
|
scheme: papabear-ephem
|
||||||
|
implementation: clean
|
||||||
|
files:
|
||||||
|
- kem.c
|
||||||
|
- melas_fec.c
|
||||||
|
- melas_fec.h
|
||||||
|
- ring.c
|
||||||
|
- ring.h
|
||||||
|
- threebears.c
|
21
test/duplicate_consistency/mamabear-ephem_clean.yml
Normal file
21
test/duplicate_consistency/mamabear-ephem_clean.yml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
consistency_checks:
|
||||||
|
- source:
|
||||||
|
scheme: babybear-ephem
|
||||||
|
implementation: clean
|
||||||
|
files:
|
||||||
|
- kem.c
|
||||||
|
- melas_fec.c
|
||||||
|
- melas_fec.h
|
||||||
|
- ring.c
|
||||||
|
- ring.h
|
||||||
|
- threebears.c
|
||||||
|
- source:
|
||||||
|
scheme: papabear-ephem
|
||||||
|
implementation: clean
|
||||||
|
files:
|
||||||
|
- kem.c
|
||||||
|
- melas_fec.c
|
||||||
|
- melas_fec.h
|
||||||
|
- ring.c
|
||||||
|
- ring.h
|
||||||
|
- threebears.c
|
21
test/duplicate_consistency/papabear-ephem_clean.yml
Normal file
21
test/duplicate_consistency/papabear-ephem_clean.yml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
consistency_checks:
|
||||||
|
- source:
|
||||||
|
scheme: babybear-ephem
|
||||||
|
implementation: clean
|
||||||
|
files:
|
||||||
|
- kem.c
|
||||||
|
- melas_fec.c
|
||||||
|
- melas_fec.h
|
||||||
|
- ring.c
|
||||||
|
- ring.h
|
||||||
|
- threebears.c
|
||||||
|
- source:
|
||||||
|
scheme: mamabear-ephem
|
||||||
|
implementation: clean
|
||||||
|
files:
|
||||||
|
- kem.c
|
||||||
|
- melas_fec.c
|
||||||
|
- melas_fec.h
|
||||||
|
- ring.c
|
||||||
|
- ring.h
|
||||||
|
- threebears.c
|
Loading…
Reference in New Issue
Block a user