From 13c0317e25b114eaa486cccdc0c60b8200fa0fcf Mon Sep 17 00:00:00 2001 From: Leon Botros Date: Sat, 4 Jan 2020 17:49:42 +0100 Subject: [PATCH] Add ephemeral versions of ThreeBears --- crypto_kem/babybear-ephem/META.yml | 14 ++ crypto_kem/babybear-ephem/clean/LICENSE | 24 ++ crypto_kem/babybear-ephem/clean/Makefile | 21 ++ .../clean/Makefile.Microsoft_nmake | 19 ++ crypto_kem/babybear-ephem/clean/api.h | 18 ++ crypto_kem/babybear-ephem/clean/kem.c | 22 ++ crypto_kem/babybear-ephem/clean/melas_fec.c | 87 ++++++++ crypto_kem/babybear-ephem/clean/melas_fec.h | 26 +++ crypto_kem/babybear-ephem/clean/params.h | 29 +++ crypto_kem/babybear-ephem/clean/ring.c | 107 +++++++++ crypto_kem/babybear-ephem/clean/ring.h | 29 +++ crypto_kem/babybear-ephem/clean/threebears.c | 210 ++++++++++++++++++ crypto_kem/babybear-ephem/clean/threebears.h | 60 +++++ crypto_kem/babybear/clean/threebears.h | 2 - crypto_kem/mamabear-ephem/META.yml | 14 ++ crypto_kem/mamabear-ephem/clean/LICENSE | 24 ++ crypto_kem/mamabear-ephem/clean/Makefile | 21 ++ .../clean/Makefile.Microsoft_nmake | 19 ++ crypto_kem/mamabear-ephem/clean/api.h | 18 ++ crypto_kem/mamabear-ephem/clean/kem.c | 22 ++ crypto_kem/mamabear-ephem/clean/melas_fec.c | 87 ++++++++ crypto_kem/mamabear-ephem/clean/melas_fec.h | 26 +++ crypto_kem/mamabear-ephem/clean/params.h | 29 +++ crypto_kem/mamabear-ephem/clean/ring.c | 107 +++++++++ crypto_kem/mamabear-ephem/clean/ring.h | 29 +++ crypto_kem/mamabear-ephem/clean/threebears.c | 210 ++++++++++++++++++ crypto_kem/mamabear-ephem/clean/threebears.h | 60 +++++ crypto_kem/mamabear/clean/threebears.h | 2 - crypto_kem/papabear-ephem/META.yml | 14 ++ crypto_kem/papabear-ephem/clean/LICENSE | 24 ++ crypto_kem/papabear-ephem/clean/Makefile | 21 ++ .../clean/Makefile.Microsoft_nmake | 19 ++ crypto_kem/papabear-ephem/clean/api.h | 18 ++ crypto_kem/papabear-ephem/clean/kem.c | 22 ++ crypto_kem/papabear-ephem/clean/melas_fec.c | 87 ++++++++ crypto_kem/papabear-ephem/clean/melas_fec.h | 26 +++ crypto_kem/papabear-ephem/clean/params.h | 29 +++ crypto_kem/papabear-ephem/clean/ring.c | 107 +++++++++ crypto_kem/papabear-ephem/clean/ring.h | 29 +++ crypto_kem/papabear-ephem/clean/threebears.c | 210 ++++++++++++++++++ crypto_kem/papabear-ephem/clean/threebears.h | 60 +++++ crypto_kem/papabear/clean/threebears.h | 2 - .../babybear-ephem_clean.yml | 21 ++ .../mamabear-ephem_clean.yml | 21 ++ .../papabear-ephem_clean.yml | 21 ++ 45 files changed, 2061 insertions(+), 6 deletions(-) create mode 100644 crypto_kem/babybear-ephem/META.yml create mode 100644 crypto_kem/babybear-ephem/clean/LICENSE create mode 100644 crypto_kem/babybear-ephem/clean/Makefile create mode 100644 crypto_kem/babybear-ephem/clean/Makefile.Microsoft_nmake create mode 100644 crypto_kem/babybear-ephem/clean/api.h create mode 100644 crypto_kem/babybear-ephem/clean/kem.c create mode 100644 crypto_kem/babybear-ephem/clean/melas_fec.c create mode 100644 crypto_kem/babybear-ephem/clean/melas_fec.h create mode 100644 crypto_kem/babybear-ephem/clean/params.h create mode 100644 crypto_kem/babybear-ephem/clean/ring.c create mode 100644 crypto_kem/babybear-ephem/clean/ring.h create mode 100644 crypto_kem/babybear-ephem/clean/threebears.c create mode 100644 crypto_kem/babybear-ephem/clean/threebears.h create mode 100644 crypto_kem/mamabear-ephem/META.yml create mode 100644 crypto_kem/mamabear-ephem/clean/LICENSE create mode 100644 crypto_kem/mamabear-ephem/clean/Makefile create mode 100644 crypto_kem/mamabear-ephem/clean/Makefile.Microsoft_nmake create mode 100644 crypto_kem/mamabear-ephem/clean/api.h create mode 100644 crypto_kem/mamabear-ephem/clean/kem.c create mode 100644 crypto_kem/mamabear-ephem/clean/melas_fec.c create mode 100644 crypto_kem/mamabear-ephem/clean/melas_fec.h create mode 100644 crypto_kem/mamabear-ephem/clean/params.h create mode 100644 crypto_kem/mamabear-ephem/clean/ring.c create mode 100644 crypto_kem/mamabear-ephem/clean/ring.h create mode 100644 crypto_kem/mamabear-ephem/clean/threebears.c create mode 100644 crypto_kem/mamabear-ephem/clean/threebears.h create mode 100644 crypto_kem/papabear-ephem/META.yml create mode 100644 crypto_kem/papabear-ephem/clean/LICENSE create mode 100644 crypto_kem/papabear-ephem/clean/Makefile create mode 100644 crypto_kem/papabear-ephem/clean/Makefile.Microsoft_nmake create mode 100644 crypto_kem/papabear-ephem/clean/api.h create mode 100644 crypto_kem/papabear-ephem/clean/kem.c create mode 100644 crypto_kem/papabear-ephem/clean/melas_fec.c create mode 100644 crypto_kem/papabear-ephem/clean/melas_fec.h create mode 100644 crypto_kem/papabear-ephem/clean/params.h create mode 100644 crypto_kem/papabear-ephem/clean/ring.c create mode 100644 crypto_kem/papabear-ephem/clean/ring.h create mode 100644 crypto_kem/papabear-ephem/clean/threebears.c create mode 100644 crypto_kem/papabear-ephem/clean/threebears.h create mode 100644 test/duplicate_consistency/babybear-ephem_clean.yml create mode 100644 test/duplicate_consistency/mamabear-ephem_clean.yml create mode 100644 test/duplicate_consistency/papabear-ephem_clean.yml diff --git a/crypto_kem/babybear-ephem/META.yml b/crypto_kem/babybear-ephem/META.yml new file mode 100644 index 00000000..260fb2e9 --- /dev/null +++ b/crypto_kem/babybear-ephem/META.yml @@ -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/ diff --git a/crypto_kem/babybear-ephem/clean/LICENSE b/crypto_kem/babybear-ephem/clean/LICENSE new file mode 100644 index 00000000..5fb15a7c --- /dev/null +++ b/crypto_kem/babybear-ephem/clean/LICENSE @@ -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. diff --git a/crypto_kem/babybear-ephem/clean/Makefile b/crypto_kem/babybear-ephem/clean/Makefile new file mode 100644 index 00000000..3a2c62ec --- /dev/null +++ b/crypto_kem/babybear-ephem/clean/Makefile @@ -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) diff --git a/crypto_kem/babybear-ephem/clean/Makefile.Microsoft_nmake b/crypto_kem/babybear-ephem/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..0e5c1bda --- /dev/null +++ b/crypto_kem/babybear-ephem/clean/Makefile.Microsoft_nmake @@ -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) diff --git a/crypto_kem/babybear-ephem/clean/api.h b/crypto_kem/babybear-ephem/clean/api.h new file mode 100644 index 00000000..6fee4132 --- /dev/null +++ b/crypto_kem/babybear-ephem/clean/api.h @@ -0,0 +1,18 @@ +#ifndef PQCLEAN_BABYBEAREPHEM_CLEAN_API_H +#define PQCLEAN_BABYBEAREPHEM_CLEAN_API_H + +#include +#include +#include + +#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 diff --git a/crypto_kem/babybear-ephem/clean/kem.c b/crypto_kem/babybear-ephem/clean/kem.c new file mode 100644 index 00000000..b3ca3a75 --- /dev/null +++ b/crypto_kem/babybear-ephem/clean/kem.c @@ -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; +} diff --git a/crypto_kem/babybear-ephem/clean/melas_fec.c b/crypto_kem/babybear-ephem/clean/melas_fec.c new file mode 100644 index 00000000..d4bd9376 --- /dev/null +++ b/crypto_kem/babybear-ephem/clean/melas_fec.c @@ -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); + } +} diff --git a/crypto_kem/babybear-ephem/clean/melas_fec.h b/crypto_kem/babybear-ephem/clean/melas_fec.h new file mode 100644 index 00000000..fd2ed191 --- /dev/null +++ b/crypto_kem/babybear-ephem/clean/melas_fec.h @@ -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 diff --git a/crypto_kem/babybear-ephem/clean/params.h b/crypto_kem/babybear-ephem/clean/params.h new file mode 100644 index 00000000..4dc8e874 --- /dev/null +++ b/crypto_kem/babybear-ephem/clean/params.h @@ -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 diff --git a/crypto_kem/babybear-ephem/clean/ring.c b/crypto_kem/babybear-ephem/clean/ring.c new file mode 100644 index 00000000..4c751556 --- /dev/null +++ b/crypto_kem/babybear-ephem/clean/ring.c @@ -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; + } + } +} diff --git a/crypto_kem/babybear-ephem/clean/ring.h b/crypto_kem/babybear-ephem/clean/ring.h new file mode 100644 index 00000000..346e0c9e --- /dev/null +++ b/crypto_kem/babybear-ephem/clean/ring.h @@ -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<> 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); +} diff --git a/crypto_kem/babybear-ephem/clean/threebears.h b/crypto_kem/babybear-ephem/clean/threebears.h new file mode 100644 index 00000000..af0d70ca --- /dev/null +++ b/crypto_kem/babybear-ephem/clean/threebears.h @@ -0,0 +1,60 @@ +#ifndef __THREE_BEARS_BABYBEAREPHEM_H__ +#define __THREE_BEARS_BABYBEAREPHEM_H__ + +#include /* for size_t */ +#include + +#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 diff --git a/crypto_kem/babybear/clean/threebears.h b/crypto_kem/babybear/clean/threebears.h index 1f345b28..8157ec94 100644 --- a/crypto_kem/babybear/clean/threebears.h +++ b/crypto_kem/babybear/clean/threebears.h @@ -55,6 +55,4 @@ void PQCLEAN_BABYBEAR_CLEAN_decapsulate ( const uint8_t sk[BABYBEAR_PRIVATE_KEY_BYTES] ); -void PQCLEAN_BABYBEAR_CLEAN_secure_bzero (void *s, size_t size); - #endif diff --git a/crypto_kem/mamabear-ephem/META.yml b/crypto_kem/mamabear-ephem/META.yml new file mode 100644 index 00000000..ba148182 --- /dev/null +++ b/crypto_kem/mamabear-ephem/META.yml @@ -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/ diff --git a/crypto_kem/mamabear-ephem/clean/LICENSE b/crypto_kem/mamabear-ephem/clean/LICENSE new file mode 100644 index 00000000..5fb15a7c --- /dev/null +++ b/crypto_kem/mamabear-ephem/clean/LICENSE @@ -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. diff --git a/crypto_kem/mamabear-ephem/clean/Makefile b/crypto_kem/mamabear-ephem/clean/Makefile new file mode 100644 index 00000000..cfec1779 --- /dev/null +++ b/crypto_kem/mamabear-ephem/clean/Makefile @@ -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) diff --git a/crypto_kem/mamabear-ephem/clean/Makefile.Microsoft_nmake b/crypto_kem/mamabear-ephem/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..078a722d --- /dev/null +++ b/crypto_kem/mamabear-ephem/clean/Makefile.Microsoft_nmake @@ -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) diff --git a/crypto_kem/mamabear-ephem/clean/api.h b/crypto_kem/mamabear-ephem/clean/api.h new file mode 100644 index 00000000..fbc93805 --- /dev/null +++ b/crypto_kem/mamabear-ephem/clean/api.h @@ -0,0 +1,18 @@ +#ifndef PQCLEAN_MAMABEAREPHEM_CLEAN_API_H +#define PQCLEAN_MAMABEAREPHEM_CLEAN_API_H + +#include +#include +#include + +#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 diff --git a/crypto_kem/mamabear-ephem/clean/kem.c b/crypto_kem/mamabear-ephem/clean/kem.c new file mode 100644 index 00000000..e70f0456 --- /dev/null +++ b/crypto_kem/mamabear-ephem/clean/kem.c @@ -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; +} diff --git a/crypto_kem/mamabear-ephem/clean/melas_fec.c b/crypto_kem/mamabear-ephem/clean/melas_fec.c new file mode 100644 index 00000000..7c11b822 --- /dev/null +++ b/crypto_kem/mamabear-ephem/clean/melas_fec.c @@ -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); + } +} diff --git a/crypto_kem/mamabear-ephem/clean/melas_fec.h b/crypto_kem/mamabear-ephem/clean/melas_fec.h new file mode 100644 index 00000000..9dd15313 --- /dev/null +++ b/crypto_kem/mamabear-ephem/clean/melas_fec.h @@ -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 diff --git a/crypto_kem/mamabear-ephem/clean/params.h b/crypto_kem/mamabear-ephem/clean/params.h new file mode 100644 index 00000000..a0eb5351 --- /dev/null +++ b/crypto_kem/mamabear-ephem/clean/params.h @@ -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 diff --git a/crypto_kem/mamabear-ephem/clean/ring.c b/crypto_kem/mamabear-ephem/clean/ring.c new file mode 100644 index 00000000..4b4251db --- /dev/null +++ b/crypto_kem/mamabear-ephem/clean/ring.c @@ -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; + } + } +} diff --git a/crypto_kem/mamabear-ephem/clean/ring.h b/crypto_kem/mamabear-ephem/clean/ring.h new file mode 100644 index 00000000..8036f3b9 --- /dev/null +++ b/crypto_kem/mamabear-ephem/clean/ring.h @@ -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<> 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); +} diff --git a/crypto_kem/mamabear-ephem/clean/threebears.h b/crypto_kem/mamabear-ephem/clean/threebears.h new file mode 100644 index 00000000..87db61c3 --- /dev/null +++ b/crypto_kem/mamabear-ephem/clean/threebears.h @@ -0,0 +1,60 @@ +#ifndef __THREE_BEARS_MAMABEAREPHEM_H__ +#define __THREE_BEARS_MAMABEAREPHEM_H__ + +#include /* for size_t */ +#include + +#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 diff --git a/crypto_kem/mamabear/clean/threebears.h b/crypto_kem/mamabear/clean/threebears.h index 00e173fa..578bcb63 100644 --- a/crypto_kem/mamabear/clean/threebears.h +++ b/crypto_kem/mamabear/clean/threebears.h @@ -55,6 +55,4 @@ void PQCLEAN_MAMABEAR_CLEAN_decapsulate ( const uint8_t sk[MAMABEAR_PRIVATE_KEY_BYTES] ); -void PQCLEAN_MAMABEAR_CLEAN_secure_bzero (void *s, size_t size); - #endif diff --git a/crypto_kem/papabear-ephem/META.yml b/crypto_kem/papabear-ephem/META.yml new file mode 100644 index 00000000..04027005 --- /dev/null +++ b/crypto_kem/papabear-ephem/META.yml @@ -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/ diff --git a/crypto_kem/papabear-ephem/clean/LICENSE b/crypto_kem/papabear-ephem/clean/LICENSE new file mode 100644 index 00000000..5fb15a7c --- /dev/null +++ b/crypto_kem/papabear-ephem/clean/LICENSE @@ -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. diff --git a/crypto_kem/papabear-ephem/clean/Makefile b/crypto_kem/papabear-ephem/clean/Makefile new file mode 100644 index 00000000..84363791 --- /dev/null +++ b/crypto_kem/papabear-ephem/clean/Makefile @@ -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) diff --git a/crypto_kem/papabear-ephem/clean/Makefile.Microsoft_nmake b/crypto_kem/papabear-ephem/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..4b6c7ef0 --- /dev/null +++ b/crypto_kem/papabear-ephem/clean/Makefile.Microsoft_nmake @@ -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) diff --git a/crypto_kem/papabear-ephem/clean/api.h b/crypto_kem/papabear-ephem/clean/api.h new file mode 100644 index 00000000..07c9f8fd --- /dev/null +++ b/crypto_kem/papabear-ephem/clean/api.h @@ -0,0 +1,18 @@ +#ifndef PQCLEAN_PAPABEAREPHEM_CLEAN_API_H +#define PQCLEAN_PAPABEAREPHEM_CLEAN_API_H + +#include +#include +#include + +#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 diff --git a/crypto_kem/papabear-ephem/clean/kem.c b/crypto_kem/papabear-ephem/clean/kem.c new file mode 100644 index 00000000..f817daa8 --- /dev/null +++ b/crypto_kem/papabear-ephem/clean/kem.c @@ -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; +} diff --git a/crypto_kem/papabear-ephem/clean/melas_fec.c b/crypto_kem/papabear-ephem/clean/melas_fec.c new file mode 100644 index 00000000..39867f58 --- /dev/null +++ b/crypto_kem/papabear-ephem/clean/melas_fec.c @@ -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); + } +} diff --git a/crypto_kem/papabear-ephem/clean/melas_fec.h b/crypto_kem/papabear-ephem/clean/melas_fec.h new file mode 100644 index 00000000..f71f9e14 --- /dev/null +++ b/crypto_kem/papabear-ephem/clean/melas_fec.h @@ -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 diff --git a/crypto_kem/papabear-ephem/clean/params.h b/crypto_kem/papabear-ephem/clean/params.h new file mode 100644 index 00000000..781f0d4c --- /dev/null +++ b/crypto_kem/papabear-ephem/clean/params.h @@ -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 diff --git a/crypto_kem/papabear-ephem/clean/ring.c b/crypto_kem/papabear-ephem/clean/ring.c new file mode 100644 index 00000000..6414ea4c --- /dev/null +++ b/crypto_kem/papabear-ephem/clean/ring.c @@ -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; + } + } +} diff --git a/crypto_kem/papabear-ephem/clean/ring.h b/crypto_kem/papabear-ephem/clean/ring.h new file mode 100644 index 00000000..28c40ca7 --- /dev/null +++ b/crypto_kem/papabear-ephem/clean/ring.h @@ -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<> 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); +} diff --git a/crypto_kem/papabear-ephem/clean/threebears.h b/crypto_kem/papabear-ephem/clean/threebears.h new file mode 100644 index 00000000..9b48e0ca --- /dev/null +++ b/crypto_kem/papabear-ephem/clean/threebears.h @@ -0,0 +1,60 @@ +#ifndef __THREE_BEARS_PAPABEAREPHEM_H__ +#define __THREE_BEARS_PAPABEAREPHEM_H__ + +#include /* for size_t */ +#include + +#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 diff --git a/crypto_kem/papabear/clean/threebears.h b/crypto_kem/papabear/clean/threebears.h index ac21c0a2..558cd557 100644 --- a/crypto_kem/papabear/clean/threebears.h +++ b/crypto_kem/papabear/clean/threebears.h @@ -55,6 +55,4 @@ void PQCLEAN_PAPABEAR_CLEAN_decapsulate ( const uint8_t sk[PAPABEAR_PRIVATE_KEY_BYTES] ); -void PQCLEAN_PAPABEAR_CLEAN_secure_bzero (void *s, size_t size); - #endif diff --git a/test/duplicate_consistency/babybear-ephem_clean.yml b/test/duplicate_consistency/babybear-ephem_clean.yml new file mode 100644 index 00000000..aa916ee4 --- /dev/null +++ b/test/duplicate_consistency/babybear-ephem_clean.yml @@ -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 diff --git a/test/duplicate_consistency/mamabear-ephem_clean.yml b/test/duplicate_consistency/mamabear-ephem_clean.yml new file mode 100644 index 00000000..5c02ca4a --- /dev/null +++ b/test/duplicate_consistency/mamabear-ephem_clean.yml @@ -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 diff --git a/test/duplicate_consistency/papabear-ephem_clean.yml b/test/duplicate_consistency/papabear-ephem_clean.yml new file mode 100644 index 00000000..f8c9b2da --- /dev/null +++ b/test/duplicate_consistency/papabear-ephem_clean.yml @@ -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