diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f7ab30e0..eaa4b9e5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -31,7 +31,7 @@ See the section [API](#API) below. length-ciphertext: # KEM only length-shared-secret: # KEM only length-signature: # Signature only - nistkat-sha256: sha256sum of 1st NIST KAT test case # KEM only + nistkat-sha256: sha256sum of 1st NIST KAT test case # KEM and signature testvectors-sha256: sha256sum of output of testvectors # Signature only principal-submitter: Eve auxiliary-submitters: diff --git a/README.md b/README.md index cde8730d..3f9af715 100644 --- a/README.md +++ b/README.md @@ -128,7 +128,7 @@ Regarding #2, adding the files to your project's build system, each implementati The following projects consume implementations from PQClean and provide their own wrappers around the implementations. Their integration strategies may serve as examples for your own projects. -- **[pqcrypto crate](https://github.com/pqrust/pqcrypto)**: Rust integration that automatically generates wrappers from PQClean source code. +- **[pqcrypto crate](https://github.com/rustpq/pqcrypto)**: Rust integration that automatically generates wrappers from PQClean source code. - **[mupq](https://github.com/mupq/)**: Runs the implementations from PQClean as reference implementations to compare with microcontroller-optimized code. - **[Open Quantum Safe](https://github.com/open-quantum-safe/)**: The Open Quantum Safe project integrates implementations from PQClean into their [liboqs](https://github.com/open-quantum-safe/liboqs) C library, which then exposes them via [C++](https://github.com/open-quantum-safe/liboqs-cpp), [C# / .NET](https://github.com/open-quantum-safe/liboqs-dotnet), and [Python](https://github.com/open-quantum-safe/liboqs-python) wrappers, as well as to forks of [OpenSSL](https://github.com/open-quantum-safe/openssl) and [OpenSSH](https://github.com/open-quantum-safe/openssh-portable). diff --git a/common/fips202.c b/common/fips202.c index ceeb6a5c..0fb29fab 100644 --- a/common/fips202.c +++ b/common/fips202.c @@ -520,36 +520,36 @@ static void keccak_inc_squeeze(uint8_t *h, size_t outlen, } } -void shake128_inc_init(uint64_t *s_inc) { - keccak_inc_init(s_inc); +void shake128_inc_init(shake128incctx *state) { + keccak_inc_init(state->ctx); } -void shake128_inc_absorb(uint64_t *s_inc, const uint8_t *input, size_t inlen) { - keccak_inc_absorb(s_inc, SHAKE128_RATE, input, inlen); +void shake128_inc_absorb(shake128incctx *state, const uint8_t *input, size_t inlen) { + keccak_inc_absorb(state->ctx, SHAKE128_RATE, input, inlen); } -void shake128_inc_finalize(uint64_t *s_inc) { - keccak_inc_finalize(s_inc, SHAKE128_RATE, 0x1F); +void shake128_inc_finalize(shake128incctx *state) { + keccak_inc_finalize(state->ctx, SHAKE128_RATE, 0x1F); } -void shake128_inc_squeeze(uint8_t *output, size_t outlen, uint64_t *s_inc) { - keccak_inc_squeeze(output, outlen, s_inc, SHAKE128_RATE); +void shake128_inc_squeeze(uint8_t *output, size_t outlen, shake128incctx *state) { + keccak_inc_squeeze(output, outlen, state->ctx, SHAKE128_RATE); } -void shake256_inc_init(uint64_t *s_inc) { - keccak_inc_init(s_inc); +void shake256_inc_init(shake256incctx *state) { + keccak_inc_init(state->ctx); } -void shake256_inc_absorb(uint64_t *s_inc, const uint8_t *input, size_t inlen) { - keccak_inc_absorb(s_inc, SHAKE256_RATE, input, inlen); +void shake256_inc_absorb(shake256incctx *state, const uint8_t *input, size_t inlen) { + keccak_inc_absorb(state->ctx, SHAKE256_RATE, input, inlen); } -void shake256_inc_finalize(uint64_t *s_inc) { - keccak_inc_finalize(s_inc, SHAKE256_RATE, 0x1F); +void shake256_inc_finalize(shake256incctx *state) { + keccak_inc_finalize(state->ctx, SHAKE256_RATE, 0x1F); } -void shake256_inc_squeeze(uint8_t *output, size_t outlen, uint64_t *s_inc) { - keccak_inc_squeeze(output, outlen, s_inc, SHAKE256_RATE); +void shake256_inc_squeeze(uint8_t *output, size_t outlen, shake256incctx *state) { + keccak_inc_squeeze(output, outlen, state->ctx, SHAKE256_RATE); } @@ -564,8 +564,8 @@ void shake256_inc_squeeze(uint8_t *output, size_t outlen, uint64_t *s_inc) { * into s * - size_t inlen: length of input in bytes **************************************************/ -void shake128_absorb(uint64_t *s, const uint8_t *input, size_t inlen) { - keccak_absorb(s, SHAKE128_RATE, input, inlen, 0x1F); +void shake128_absorb(shake128ctx *state, const uint8_t *input, size_t inlen) { + keccak_absorb(state->ctx, SHAKE128_RATE, input, inlen, 0x1F); } /************************************************* @@ -578,10 +578,10 @@ void shake128_absorb(uint64_t *s, const uint8_t *input, size_t inlen) { * Arguments: - uint8_t *output: pointer to output blocks * - size_t nblocks: number of blocks to be squeezed * (written to output) - * - uint64_t *s: pointer to input/output Keccak state + * - shake128ctx *state: pointer to input/output Keccak state **************************************************/ -void shake128_squeezeblocks(uint8_t *output, size_t nblocks, uint64_t *s) { - keccak_squeezeblocks(output, nblocks, s, SHAKE128_RATE); +void shake128_squeezeblocks(uint8_t *output, size_t nblocks, shake128ctx *state) { + keccak_squeezeblocks(output, nblocks, state->ctx, SHAKE128_RATE); } /************************************************* @@ -590,13 +590,13 @@ void shake128_squeezeblocks(uint8_t *output, size_t nblocks, uint64_t *s) { * Description: Absorb step of the SHAKE256 XOF. * non-incremental, starts by zeroeing the state. * - * Arguments: - uint64_t *s: pointer to (uninitialized) output Keccak state + * Arguments: - shake256ctx *state: pointer to (uninitialized) output Keccak state * - const uint8_t *input: pointer to input to be absorbed * into s * - size_t inlen: length of input in bytes **************************************************/ -void shake256_absorb(uint64_t *s, const uint8_t *input, size_t inlen) { - keccak_absorb(s, SHAKE256_RATE, input, inlen, 0x1F); +void shake256_absorb(shake256ctx *state, const uint8_t *input, size_t inlen) { + keccak_absorb(state->ctx, SHAKE256_RATE, input, inlen, 0x1F); } /************************************************* @@ -609,10 +609,10 @@ void shake256_absorb(uint64_t *s, const uint8_t *input, size_t inlen) { * Arguments: - uint8_t *output: pointer to output blocks * - size_t nblocks: number of blocks to be squeezed * (written to output) - * - uint64_t *s: pointer to input/output Keccak state + * - shake256ctx *state: pointer to input/output Keccak state **************************************************/ -void shake256_squeezeblocks(uint8_t *output, size_t nblocks, uint64_t *s) { - keccak_squeezeblocks(output, nblocks, s, SHAKE256_RATE); +void shake256_squeezeblocks(uint8_t *output, size_t nblocks, shake256ctx *state) { + keccak_squeezeblocks(output, nblocks, state->ctx, SHAKE256_RATE); } /************************************************* @@ -629,16 +629,16 @@ void shake128(uint8_t *output, size_t outlen, const uint8_t *input, size_t inlen) { size_t nblocks = outlen / SHAKE128_RATE; uint8_t t[SHAKE128_RATE]; - uint64_t s[25]; + shake128ctx s; - shake128_absorb(s, input, inlen); - shake128_squeezeblocks(output, nblocks, s); + shake128_absorb(&s, input, inlen); + shake128_squeezeblocks(output, nblocks, &s); output += nblocks * SHAKE128_RATE; outlen -= nblocks * SHAKE128_RATE; if (outlen) { - shake128_squeezeblocks(t, 1, s); + shake128_squeezeblocks(t, 1, &s); for (size_t i = 0; i < outlen; ++i) { output[i] = t[i]; } @@ -659,35 +659,35 @@ void shake256(uint8_t *output, size_t outlen, const uint8_t *input, size_t inlen) { size_t nblocks = outlen / SHAKE256_RATE; uint8_t t[SHAKE256_RATE]; - uint64_t s[25]; + shake256ctx s; - shake256_absorb(s, input, inlen); - shake256_squeezeblocks(output, nblocks, s); + shake256_absorb(&s, input, inlen); + shake256_squeezeblocks(output, nblocks, &s); output += nblocks * SHAKE256_RATE; outlen -= nblocks * SHAKE256_RATE; if (outlen) { - shake256_squeezeblocks(t, 1, s); + shake256_squeezeblocks(t, 1, &s); for (size_t i = 0; i < outlen; ++i) { output[i] = t[i]; } } } -void sha3_256_inc_init(uint64_t *s_inc) { - keccak_inc_init(s_inc); +void sha3_256_inc_init(sha3_256incctx *state) { + keccak_inc_init(state->ctx); } -void sha3_256_inc_absorb(uint64_t *s_inc, const uint8_t *input, size_t inlen) { - keccak_inc_absorb(s_inc, SHA3_256_RATE, input, inlen); +void sha3_256_inc_absorb(sha3_256incctx *state, const uint8_t *input, size_t inlen) { + keccak_inc_absorb(state->ctx, SHA3_256_RATE, input, inlen); } -void sha3_256_inc_finalize(uint8_t *output, uint64_t *s_inc) { +void sha3_256_inc_finalize(uint8_t *output, sha3_256incctx *state) { uint8_t t[SHA3_256_RATE]; - keccak_inc_finalize(s_inc, SHA3_256_RATE, 0x06); + keccak_inc_finalize(state->ctx, SHA3_256_RATE, 0x06); - keccak_squeezeblocks(t, 1, s_inc, SHA3_256_RATE); + keccak_squeezeblocks(t, 1, state->ctx, SHA3_256_RATE); for (size_t i = 0; i < 32; i++) { output[i] = t[i]; @@ -718,19 +718,19 @@ void sha3_256(uint8_t *output, const uint8_t *input, size_t inlen) { } } -void sha3_512_inc_init(uint64_t *s_inc) { - keccak_inc_init(s_inc); +void sha3_512_inc_init(sha3_512incctx *state) { + keccak_inc_init(state->ctx); } -void sha3_512_inc_absorb(uint64_t *s_inc, const uint8_t *input, size_t inlen) { - keccak_inc_absorb(s_inc, SHA3_512_RATE, input, inlen); +void sha3_512_inc_absorb(sha3_512incctx *state, const uint8_t *input, size_t inlen) { + keccak_inc_absorb(state->ctx, SHA3_512_RATE, input, inlen); } -void sha3_512_inc_finalize(uint8_t *output, uint64_t *s_inc) { +void sha3_512_inc_finalize(uint8_t *output, sha3_512incctx *state) { uint8_t t[SHA3_512_RATE]; - keccak_inc_finalize(s_inc, SHA3_512_RATE, 0x06); + keccak_inc_finalize(state->ctx, SHA3_512_RATE, 0x06); - keccak_squeezeblocks(t, 1, s_inc, SHA3_512_RATE); + keccak_squeezeblocks(t, 1, state->ctx, SHA3_512_RATE); for (size_t i = 0; i < 32; i++) { output[i] = t[i]; diff --git a/common/fips202.h b/common/fips202.h index 8971cf5c..622d736a 100644 --- a/common/fips202.h +++ b/common/fips202.h @@ -9,22 +9,53 @@ #define SHA3_256_RATE 136 #define SHA3_512_RATE 72 -void shake128_absorb(uint64_t *s, const uint8_t *input, size_t inlen); -void shake128_squeezeblocks(uint8_t *output, size_t nblocks, uint64_t *s); +// Context for incremental API +typedef struct { + uint64_t ctx[26]; +} shake128incctx; -void shake128_inc_init(uint64_t *s_inc); -void shake128_inc_absorb(uint64_t *s_inc, const uint8_t *input, size_t inlen); -void shake128_inc_finalize(uint64_t *s_inc); -void shake128_inc_squeeze(uint8_t *output, size_t outlen, uint64_t *s_inc); +// Context for non-incremental API +typedef struct { + uint64_t ctx[25]; +} shake128ctx; -void shake256_absorb(uint64_t *s, const uint8_t *input, size_t inlen); -void shake256_squeezeblocks(uint8_t *output, size_t nblocks, uint64_t *s); +// Context for incremental API +typedef struct { + uint64_t ctx[26]; +} shake256incctx; -void shake256_inc_init(uint64_t *s_inc); -void shake256_inc_absorb(uint64_t *s_inc, const uint8_t *input, size_t inlen); -void shake256_inc_finalize(uint64_t *s_inc); -void shake256_inc_squeeze(uint8_t *output, size_t outlen, uint64_t *s_inc); +// Context for non-incremental API +typedef struct { + uint64_t ctx[25]; +} shake256ctx; + +// Context for incremental API +typedef struct { + uint64_t ctx[26]; +} sha3_256incctx; + +// Context for incremental API +typedef struct { + uint64_t ctx[26]; +} sha3_512incctx; + +void shake128_absorb(shake128ctx *state, const uint8_t *input, size_t inlen); + +void shake128_squeezeblocks(uint8_t *output, size_t nblocks, shake128ctx *state); + +void shake128_inc_init(shake128incctx *state); +void shake128_inc_absorb(shake128incctx *state, const uint8_t *input, size_t inlen); +void shake128_inc_finalize(shake128incctx *state); +void shake128_inc_squeeze(uint8_t *output, size_t outlen, shake128incctx *state); + +void shake256_absorb(shake256ctx *state, const uint8_t *input, size_t inlen); +void shake256_squeezeblocks(uint8_t *output, size_t nblocks, shake256ctx *state); + +void shake256_inc_init(shake256incctx *state); +void shake256_inc_absorb(shake256incctx *state, const uint8_t *input, size_t inlen); +void shake256_inc_finalize(shake256incctx *state); +void shake256_inc_squeeze(uint8_t *output, size_t outlen, shake256incctx *state); void shake128(uint8_t *output, size_t outlen, const uint8_t *input, size_t inlen); @@ -32,15 +63,15 @@ void shake128(uint8_t *output, size_t outlen, void shake256(uint8_t *output, size_t outlen, const uint8_t *input, size_t inlen); -void sha3_256_inc_init(uint64_t *s_inc); -void sha3_256_inc_absorb(uint64_t *s_inc, const uint8_t *input, size_t inlen); -void sha3_256_inc_finalize(uint8_t *output, uint64_t *s_inc); +void sha3_256_inc_init(sha3_256incctx *state); +void sha3_256_inc_absorb(sha3_256incctx *state, const uint8_t *input, size_t inlen); +void sha3_256_inc_finalize(uint8_t *output, sha3_256incctx *state); void sha3_256(uint8_t *output, const uint8_t *input, size_t inlen); -void sha3_512_inc_init(uint64_t *s_inc); -void sha3_512_inc_absorb(uint64_t *s_inc, const uint8_t *input, size_t inlen); -void sha3_512_inc_finalize(uint8_t *output, uint64_t *s_inc); +void sha3_512_inc_init(sha3_512incctx *state); +void sha3_512_inc_absorb(sha3_512incctx *state, const uint8_t *input, size_t inlen); +void sha3_512_inc_finalize(uint8_t *output, sha3_512incctx *state); void sha3_512(uint8_t *output, const uint8_t *input, size_t inlen); diff --git a/common/sha2.c b/common/sha2.c index 12ba35be..cc42f760 100644 --- a/common/sha2.c +++ b/common/sha2.c @@ -492,73 +492,73 @@ static const uint8_t iv_512[64] = { 0x6b, 0x5b, 0xe0, 0xcd, 0x19, 0x13, 0x7e, 0x21, 0x79 }; -void sha224_inc_init(uint8_t *state) { +void sha224_inc_init(sha224ctx *state) { for (size_t i = 0; i < 32; ++i) { - state[i] = iv_224[i]; + state->ctx[i] = iv_224[i]; } for (size_t i = 32; i < 40; ++i) { - state[i] = 0; + state->ctx[i] = 0; } } -void sha256_inc_init(uint8_t *state) { +void sha256_inc_init(sha256ctx *state) { for (size_t i = 0; i < 32; ++i) { - state[i] = iv_256[i]; + state->ctx[i] = iv_256[i]; } for (size_t i = 32; i < 40; ++i) { - state[i] = 0; + state->ctx[i] = 0; } } -void sha384_inc_init(uint8_t *state) { +void sha384_inc_init(sha384ctx *state) { for (size_t i = 0; i < 64; ++i) { - state[i] = iv_384[i]; + state->ctx[i] = iv_384[i]; } for (size_t i = 64; i < 72; ++i) { - state[i] = 0; + state->ctx[i] = 0; } } -void sha512_inc_init(uint8_t *state) { +void sha512_inc_init(sha512ctx *state) { for (size_t i = 0; i < 64; ++i) { - state[i] = iv_512[i]; + state->ctx[i] = iv_512[i]; } for (size_t i = 64; i < 72; ++i) { - state[i] = 0; + state->ctx[i] = 0; } } -void sha256_inc_blocks(uint8_t *state, const uint8_t *in, size_t inblocks) { - uint64_t bytes = load_bigendian_64(state + 32); +void sha256_inc_blocks(sha256ctx *state, const uint8_t *in, size_t inblocks) { + uint64_t bytes = load_bigendian_64(state->ctx + 32); - crypto_hashblocks_sha256(state, in, 64 * inblocks); + crypto_hashblocks_sha256(state->ctx, in, 64 * inblocks); bytes += 64 * inblocks; - store_bigendian_64(state + 32, bytes); + store_bigendian_64(state->ctx + 32, bytes); } -void sha224_inc_blocks(uint8_t *state, const uint8_t *in, size_t inblocks) { - sha256_inc_blocks(state, in, inblocks); +void sha224_inc_blocks(sha224ctx *state, const uint8_t *in, size_t inblocks) { + sha256_inc_blocks((sha256ctx*) state, in, inblocks); } -void sha512_inc_blocks(uint8_t *state, const uint8_t *in, size_t inblocks) { - uint64_t bytes = load_bigendian_64(state + 64); +void sha512_inc_blocks(sha512ctx *state, const uint8_t *in, size_t inblocks) { + uint64_t bytes = load_bigendian_64(state->ctx + 64); - crypto_hashblocks_sha256(state, in, 128 * inblocks); + crypto_hashblocks_sha256(state->ctx, in, 128 * inblocks); bytes += 128 * inblocks; - store_bigendian_64(state + 64, bytes); + store_bigendian_64(state->ctx + 64, bytes); } -void sha384_inc_blocks(uint8_t *state, const uint8_t *in, size_t inblocks) { - sha512_inc_blocks(state, in, inblocks); +void sha384_inc_blocks(sha384ctx *state, const uint8_t *in, size_t inblocks) { + sha512_inc_blocks((sha512ctx*) state, in, inblocks); } -void sha256_inc_finalize(uint8_t *out, uint8_t *state, const uint8_t *in, size_t inlen) { +void sha256_inc_finalize(uint8_t *out, sha256ctx *state, const uint8_t *in, size_t inlen) { uint8_t padded[128]; - uint64_t bytes = load_bigendian_64(state + 32) + inlen; + uint64_t bytes = load_bigendian_64(state->ctx + 32) + inlen; - crypto_hashblocks_sha256(state, in, inlen); + crypto_hashblocks_sha256(state->ctx, in, inlen); in += inlen; inlen &= 63; in -= inlen; @@ -580,7 +580,7 @@ void sha256_inc_finalize(uint8_t *out, uint8_t *state, const uint8_t *in, size_t padded[61] = (uint8_t) (bytes >> 13); padded[62] = (uint8_t) (bytes >> 5); padded[63] = (uint8_t) (bytes << 3); - crypto_hashblocks_sha256(state, padded, 64); + crypto_hashblocks_sha256(state->ctx, padded, 64); } else { for (size_t i = inlen + 1; i < 120; ++i) { padded[i] = 0; @@ -593,27 +593,27 @@ void sha256_inc_finalize(uint8_t *out, uint8_t *state, const uint8_t *in, size_t padded[125] = (uint8_t) (bytes >> 13); padded[126] = (uint8_t) (bytes >> 5); padded[127] = (uint8_t) (bytes << 3); - crypto_hashblocks_sha256(state, padded, 128); + crypto_hashblocks_sha256(state->ctx, padded, 128); } for (size_t i = 0; i < 32; ++i) { - out[i] = state[i]; + out[i] = state->ctx[i]; } } -void sha224_inc_finalize(uint8_t *out, uint8_t *state, const uint8_t *in, size_t inlen) { - sha256_inc_finalize(state, state, in, inlen); +void sha224_inc_finalize(uint8_t *out, sha224ctx *state, const uint8_t *in, size_t inlen) { + sha256_inc_finalize(state->ctx, (sha256ctx*)state, in, inlen); for (size_t i = 0; i < 28; ++i) { - out[i] = state[i]; + out[i] = state->ctx[i]; } } -void sha512_inc_finalize(uint8_t *out, uint8_t *state, const uint8_t *in, size_t inlen) { +void sha512_inc_finalize(uint8_t *out, sha512ctx *state, const uint8_t *in, size_t inlen) { uint8_t padded[256]; - uint64_t bytes = load_bigendian_64(state + 64) + inlen; + uint64_t bytes = load_bigendian_64(state->ctx + 64) + inlen; - crypto_hashblocks_sha512(state, in, inlen); + crypto_hashblocks_sha512(state->ctx, in, inlen); in += inlen; inlen &= 127; in -= inlen; @@ -636,7 +636,7 @@ void sha512_inc_finalize(uint8_t *out, uint8_t *state, const uint8_t *in, size_t padded[125] = (uint8_t) (bytes >> 13); padded[126] = (uint8_t) (bytes >> 5); padded[127] = (uint8_t) (bytes << 3); - crypto_hashblocks_sha512(state, padded, 128); + crypto_hashblocks_sha512(state->ctx, padded, 128); } else { for (size_t i = inlen + 1; i < 247; ++i) { padded[i] = 0; @@ -650,46 +650,46 @@ void sha512_inc_finalize(uint8_t *out, uint8_t *state, const uint8_t *in, size_t padded[253] = (uint8_t) (bytes >> 13); padded[254] = (uint8_t) (bytes >> 5); padded[255] = (uint8_t) (bytes << 3); - crypto_hashblocks_sha512(state, padded, 256); + crypto_hashblocks_sha512(state->ctx, padded, 256); } for (size_t i = 0; i < 64; ++i) { - out[i] = state[i]; + out[i] = state->ctx[i]; } } -void sha384_inc_finalize(uint8_t *out, uint8_t *state, const uint8_t *in, size_t inlen) { - sha512_inc_finalize(state, state, in, inlen); +void sha384_inc_finalize(uint8_t *out, sha384ctx *state, const uint8_t *in, size_t inlen) { + sha512_inc_finalize(state->ctx, (sha512ctx*)state, in, inlen); for (size_t i = 0; i < 48; ++i) { - out[i] = state[i]; + out[i] = state->ctx[i]; } } void sha224(uint8_t *out, const uint8_t *in, size_t inlen) { - uint8_t state[40]; + sha224ctx state; - sha224_inc_init(state); - sha224_inc_finalize(out, state, in, inlen); + sha224_inc_init(&state); + sha224_inc_finalize(out, &state, in, inlen); } void sha256(uint8_t *out, const uint8_t *in, size_t inlen) { - uint8_t state[40]; + sha256ctx state; - sha256_inc_init(state); - sha256_inc_finalize(out, state, in, inlen); + sha256_inc_init(&state); + sha256_inc_finalize(out, &state, in, inlen); } void sha384(uint8_t *out, const uint8_t *in, size_t inlen) { - uint8_t state[72]; + sha384ctx state; - sha384_inc_init(state); - sha384_inc_finalize(out, state, in, inlen); + sha384_inc_init(&state); + sha384_inc_finalize(out, &state, in, inlen); } void sha512(uint8_t *out, const uint8_t *in, size_t inlen) { - uint8_t state[72]; + sha512ctx state; - sha512_inc_init(state); - sha512_inc_finalize(out, state, in, inlen); + sha512_inc_init(&state); + sha512_inc_finalize(out, &state, in, inlen); } diff --git a/common/sha2.h b/common/sha2.h index ce6a8aff..618683ef 100644 --- a/common/sha2.h +++ b/common/sha2.h @@ -8,24 +8,40 @@ must be exactly 64 bytes each. Use the 'finalize' functions for any remaining bytes (possibly over 64). */ -void sha224_inc_init(uint8_t *state); -void sha224_inc_blocks(uint8_t *state, const uint8_t *in, size_t inblocks); -void sha224_inc_finalize(uint8_t *out, uint8_t *state, const uint8_t *in, size_t inlen); +typedef struct { + uint8_t ctx[40]; +} sha224ctx; + +typedef struct { + uint8_t ctx[40]; +} sha256ctx; + +typedef struct { + uint8_t ctx[72]; +} sha384ctx; + +typedef struct { + uint8_t ctx[72]; +} sha512ctx; + +void sha224_inc_init(sha224ctx *state); +void sha224_inc_blocks(sha224ctx *state, const uint8_t *in, size_t inblocks); +void sha224_inc_finalize(uint8_t *out, sha224ctx *state, const uint8_t *in, size_t inlen); void sha224(uint8_t *out, const uint8_t *in, size_t inlen); -void sha256_inc_init(uint8_t *state); -void sha256_inc_blocks(uint8_t *state, const uint8_t *in, size_t inblocks); -void sha256_inc_finalize(uint8_t *out, uint8_t *state, const uint8_t *in, size_t inlen); +void sha256_inc_init(sha256ctx *state); +void sha256_inc_blocks(sha256ctx *state, const uint8_t *in, size_t inblocks); +void sha256_inc_finalize(uint8_t *out, sha256ctx *state, const uint8_t *in, size_t inlen); void sha256(uint8_t *out, const uint8_t *in, size_t inlen); -void sha384_inc_init(uint8_t *state); -void sha384_inc_blocks(uint8_t *state, const uint8_t *in, size_t inblocks); -void sha384_inc_finalize(uint8_t *out, uint8_t *state, const uint8_t *in, size_t inlen); +void sha384_inc_init(sha384ctx *state); +void sha384_inc_blocks(sha384ctx *state, const uint8_t *in, size_t inblocks); +void sha384_inc_finalize(uint8_t *out, sha384ctx *state, const uint8_t *in, size_t inlen); void sha384(uint8_t *out, const uint8_t *in, size_t inlen); -void sha512_inc_init(uint8_t *state); -void sha512_inc_blocks(uint8_t *state, const uint8_t *in, size_t inblocks); -void sha512_inc_finalize(uint8_t *out, uint8_t *state, const uint8_t *in, size_t inlen); +void sha512_inc_init(sha512ctx *state); +void sha512_inc_blocks(sha512ctx *state, const uint8_t *in, size_t inblocks); +void sha512_inc_finalize(uint8_t *out, sha512ctx *state, const uint8_t *in, size_t inlen); void sha512(uint8_t *out, const uint8_t *in, size_t inlen); #endif diff --git a/common/sp800-185.c b/common/sp800-185.c new file mode 100644 index 00000000..b21e81fc --- /dev/null +++ b/common/sp800-185.c @@ -0,0 +1,138 @@ +#include +#include + +#include "sp800-185.h" + +static size_t left_encode(uint8_t *encbuf, size_t value) { + size_t n, i, v; + + for (v = value, n = 0; v && (n < sizeof(size_t)); n++, v >>= 8) { + ; /* empty */ + } + if (n == 0) { + n = 1; + } + for (i = 1; i <= n; i++) { + encbuf[i] = (uint8_t)(value >> (8 * (n-i))); + } + encbuf[0] = (uint8_t)n; + return n + 1; +} + +void cshake128_inc_init(shake128incctx *state, const uint8_t *name, size_t namelen, const uint8_t *cstm, size_t cstmlen) { + uint8_t encbuf[sizeof(size_t)+1]; + + shake128_inc_init(state); + + shake128_inc_absorb(state, encbuf, left_encode(encbuf, SHAKE128_RATE)); + + shake128_inc_absorb(state, encbuf, left_encode(encbuf, namelen * 8)); + shake128_inc_absorb(state, name, namelen); + + shake128_inc_absorb(state, encbuf, left_encode(encbuf, cstmlen * 8)); + shake128_inc_absorb(state, cstm, cstmlen); + + if (state->ctx[25] != 0) { + state->ctx[25] = SHAKE128_RATE - 1; + encbuf[0] = 0; + shake128_inc_absorb(state, encbuf, 1); + } +} + +void cshake128_inc_absorb(shake128incctx *state, const uint8_t *input, size_t inlen) { + shake128_inc_absorb(state, input, inlen); +} + +void cshake128_inc_finalize(shake128incctx *state) { + state->ctx[state->ctx[25] >> 3] ^= (uint64_t)0x04 << (8 * (state->ctx[25] & 0x07)); + state->ctx[(SHAKE128_RATE - 1) >> 3] ^= (uint64_t)128 << (8 * ((SHAKE128_RATE - 1) & 0x07)); + state->ctx[25] = 0; +} + +void cshake128_inc_squeeze(uint8_t *output, size_t outlen, shake128incctx *state) { + shake128_inc_squeeze(output, outlen, state); +} + +void cshake256_inc_init(shake256incctx *state, const uint8_t *name, size_t namelen, const uint8_t *cstm, size_t cstmlen) { + uint8_t encbuf[sizeof(size_t)+1]; + + shake256_inc_init(state); + + shake256_inc_absorb(state, encbuf, left_encode(encbuf, SHAKE256_RATE)); + + shake256_inc_absorb(state, encbuf, left_encode(encbuf, namelen * 8)); + shake256_inc_absorb(state, name, namelen); + + shake256_inc_absorb(state, encbuf, left_encode(encbuf, cstmlen * 8)); + shake256_inc_absorb(state, cstm, cstmlen); + + if (state->ctx[25] != 0) { + state->ctx[25] = SHAKE256_RATE - 1; + encbuf[0] = 0; + shake256_inc_absorb(state, encbuf, 1); + } +} + +void cshake256_inc_absorb(shake256incctx *state, const uint8_t *input, size_t inlen) { + shake256_inc_absorb(state, input, inlen); +} + +void cshake256_inc_finalize(shake256incctx *state) { + state->ctx[state->ctx[25] >> 3] ^= (uint64_t)0x04 << (8 * (state->ctx[25] & 0x07)); + state->ctx[(SHAKE256_RATE - 1) >> 3] ^= (uint64_t)128 << (8 * ((SHAKE256_RATE - 1) & 0x07)); + state->ctx[25] = 0; +} + +void cshake256_inc_squeeze(uint8_t *output, size_t outlen, shake256incctx *state) { + shake256_inc_squeeze(output, outlen, state); +} + +/************************************************* + * Name: cshake128 + * + * Description: cSHAKE128 XOF with non-incremental API + * + * Arguments: - uint8_t *output: pointer to output + * - size_t outlen: requested output length in bytes + * - const uint8_t *name: pointer to function-name string + * - size_t namelen: length of function-name string in bytes + * - const uint8_t *cstm: pointer to non-empty customization string + * - size_t cstmlen: length of customization string in bytes + * - const uint8_t *input: pointer to input + * - size_t inlen: length of input in bytes + **************************************************/ +void cshake128(uint8_t *output, size_t outlen, + const uint8_t *name, size_t namelen, + const uint8_t *cstm, size_t cstmlen, + const uint8_t *input, size_t inlen) { + shake128incctx state; + cshake128_inc_init(&state, name, namelen, cstm, cstmlen); + cshake128_inc_absorb(&state, input, inlen); + cshake128_inc_finalize(&state); + cshake128_inc_squeeze(output, outlen, &state); +} + +/************************************************* + * Name: cshake256 + * + * Description: cSHAKE256 XOF with non-incremental API + * + * Arguments: - uint8_t *output: pointer to output + * - size_t outlen: requested output length in bytes + * - const uint8_t *name: pointer to function-name string + * - size_t namelen: length of function-name string in bytes + * - const uint8_t *cstm: pointer to non-empty customization string + * - size_t cstmlen: length of customization string in bytes + * - const uint8_t *input: pointer to input + * - size_t inlen: length of input in bytes + **************************************************/ +void cshake256(uint8_t *output, size_t outlen, + const uint8_t *name, size_t namelen, + const uint8_t *cstm, size_t cstmlen, + const uint8_t *input, size_t inlen) { + shake256incctx state; + cshake256_inc_init(&state, name, namelen, cstm, cstmlen); + cshake256_inc_absorb(&state, input, inlen); + cshake256_inc_finalize(&state); + cshake256_inc_squeeze(output, outlen, &state); +} diff --git a/common/sp800-185.h b/common/sp800-185.h new file mode 100644 index 00000000..06781523 --- /dev/null +++ b/common/sp800-185.h @@ -0,0 +1,23 @@ +#ifndef SP800_185_H +#define SP800_185_H + +#include +#include + +#include "fips202.h" + +void cshake128_inc_init(shake128incctx *state, const uint8_t *name, size_t namelen, const uint8_t *cstm, size_t cstmlen); +void cshake128_inc_absorb(shake128incctx *state, const uint8_t *input, size_t inlen); +void cshake128_inc_finalize(shake128incctx *state); +void cshake128_inc_squeeze(uint8_t *output, size_t outlen, shake128incctx *state); + +void cshake128(uint8_t *output, size_t outlen, const uint8_t *name, size_t namelen, const uint8_t *cstm, size_t cstmlen, const uint8_t *input, size_t inlen); + +void cshake256_inc_init(shake256incctx *state, const uint8_t *name, size_t namelen, const uint8_t *cstm, size_t cstmlen); +void cshake256_inc_absorb(shake256incctx *state, const uint8_t *input, size_t inlen); +void cshake256_inc_finalize(shake256incctx *state); +void cshake256_inc_squeeze(uint8_t *output, size_t outlen, shake256incctx *state); + +void cshake256(uint8_t *output, size_t outlen, const uint8_t *name, size_t namelen, const uint8_t* cstm, size_t cstmlen, const uint8_t *input, size_t inlen); + +#endif diff --git a/crypto_kem/frodokem1344aes/META.yml b/crypto_kem/frodokem1344aes/META.yml index 98528881..4e9c1801 100644 --- a/crypto_kem/frodokem1344aes/META.yml +++ b/crypto_kem/frodokem1344aes/META.yml @@ -23,3 +23,5 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/Microsoft/PQCrypto-LWEKE/commit/d5bbd0417ba111b08a959c0042a1dcc65fb14a89 +- name: opt + version: https://github.com/Microsoft/PQCrypto-LWEKE/commit/d5bbd0417ba111b08a959c0042a1dcc65fb14a89 diff --git a/crypto_kem/frodokem1344aes/clean/Makefile b/crypto_kem/frodokem1344aes/clean/Makefile index ba564d21..546e887d 100644 --- a/crypto_kem/frodokem1344aes/clean/Makefile +++ b/crypto_kem/frodokem1344aes/clean/Makefile @@ -4,7 +4,7 @@ LIB=libfrodokem1344aes_clean.a HEADERS=api.h params.h common.h OBJECTS=kem.o matrix_aes.o noise.o util.o -CFLAGS=-O3 -Wall -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_kem/frodokem1344aes/opt/LICENSE b/crypto_kem/frodokem1344aes/opt/LICENSE new file mode 100644 index 00000000..5cf7c8db --- /dev/null +++ b/crypto_kem/frodokem1344aes/opt/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) Microsoft Corporation. All rights reserved. + +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/frodokem1344aes/opt/Makefile b/crypto_kem/frodokem1344aes/opt/Makefile new file mode 100644 index 00000000..f15cc3e3 --- /dev/null +++ b/crypto_kem/frodokem1344aes/opt/Makefile @@ -0,0 +1,19 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libfrodokem1344aes_opt.a +HEADERS=api.h params.h common.h +OBJECTS=kem.o matrix_aes.o noise.o util.o + +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -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/frodokem1344aes/opt/Makefile.Microsoft_nmake b/crypto_kem/frodokem1344aes/opt/Makefile.Microsoft_nmake new file mode 100644 index 00000000..809ae4da --- /dev/null +++ b/crypto_kem/frodokem1344aes/opt/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=libfrodokem1344aes_opt.lib +OBJECTS=kem.obj matrix_aes.obj noise.obj util.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/frodokem1344aes/opt/api.h b/crypto_kem/frodokem1344aes/opt/api.h new file mode 100644 index 00000000..d164186c --- /dev/null +++ b/crypto_kem/frodokem1344aes/opt/api.h @@ -0,0 +1,20 @@ +#ifndef PQCLEAN_FRODOKEM1344AES_OPT_API_H +#define PQCLEAN_FRODOKEM1344AES_OPT_API_H + +#include +#include + +#define PQCLEAN_FRODOKEM1344AES_OPT_CRYPTO_SECRETKEYBYTES 43088 // sizeof(s) + CRYPTO_PUBLICKEYBYTES + 2*PARAMS_N*PARAMS_NBAR + BYTES_PKHASH +#define PQCLEAN_FRODOKEM1344AES_OPT_CRYPTO_PUBLICKEYBYTES 21520 // sizeof(seed_A) + (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 +#define PQCLEAN_FRODOKEM1344AES_OPT_CRYPTO_BYTES 32 +#define PQCLEAN_FRODOKEM1344AES_OPT_CRYPTO_CIPHERTEXTBYTES 21632 // (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 + (PARAMS_LOGQ*PARAMS_NBAR*PARAMS_NBAR)/8 + +#define PQCLEAN_FRODOKEM1344AES_OPT_CRYPTO_ALGNAME "FrodoKEM-1344-AES" + +int PQCLEAN_FRODOKEM1344AES_OPT_crypto_kem_keypair(uint8_t *pk, uint8_t *sk); + +int PQCLEAN_FRODOKEM1344AES_OPT_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk); + +int PQCLEAN_FRODOKEM1344AES_OPT_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk); + +#endif diff --git a/crypto_kem/frodokem1344aes/opt/common.h b/crypto_kem/frodokem1344aes/opt/common.h new file mode 100644 index 00000000..1ea3ac89 --- /dev/null +++ b/crypto_kem/frodokem1344aes/opt/common.h @@ -0,0 +1,19 @@ +#ifndef COMMON_H +#define COMMON_H + +int PQCLEAN_FRODOKEM1344AES_OPT_mul_add_as_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A); +int PQCLEAN_FRODOKEM1344AES_OPT_mul_add_sa_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A); +void PQCLEAN_FRODOKEM1344AES_OPT_sample_n(uint16_t *s, size_t n); +void PQCLEAN_FRODOKEM1344AES_OPT_mul_bs(uint16_t *out, const uint16_t *b, const uint16_t *s); +void PQCLEAN_FRODOKEM1344AES_OPT_mul_add_sb_plus_e(uint16_t *out, const uint16_t *b, const uint16_t *s, const uint16_t *e); +void PQCLEAN_FRODOKEM1344AES_OPT_add(uint16_t *out, const uint16_t *a, const uint16_t *b); +void PQCLEAN_FRODOKEM1344AES_OPT_sub(uint16_t *out, const uint16_t *a, const uint16_t *b); +void PQCLEAN_FRODOKEM1344AES_OPT_key_encode(uint16_t *out, const uint16_t *in); +void PQCLEAN_FRODOKEM1344AES_OPT_key_decode(uint16_t *out, const uint16_t *in); +void PQCLEAN_FRODOKEM1344AES_OPT_pack(uint8_t *out, size_t outlen, const uint16_t *in, size_t inlen, uint8_t lsb); +void PQCLEAN_FRODOKEM1344AES_OPT_unpack(uint16_t *out, size_t outlen, const uint8_t *in, size_t inlen, uint8_t lsb); +void PQCLEAN_FRODOKEM1344AES_OPT_clear_bytes(uint8_t *mem, size_t n); +uint16_t PQCLEAN_FRODOKEM1344AES_OPT_LE_TO_UINT16(uint16_t n); +uint16_t PQCLEAN_FRODOKEM1344AES_OPT_UINT16_TO_LE(uint16_t n); + +#endif diff --git a/crypto_kem/frodokem1344aes/opt/kem.c b/crypto_kem/frodokem1344aes/opt/kem.c new file mode 100644 index 00000000..d989588a --- /dev/null +++ b/crypto_kem/frodokem1344aes/opt/kem.c @@ -0,0 +1,238 @@ +/******************************************************************************************** +* FrodoKEM: Learning with Errors Key Encapsulation +* +* Abstract: Key Encapsulation Mechanism (KEM) based on Frodo +*********************************************************************************************/ + +#include +#include + +#include "fips202.h" +#include "randombytes.h" + +#include "api.h" +#include "common.h" +#include "params.h" + +int PQCLEAN_FRODOKEM1344AES_OPT_crypto_kem_keypair(uint8_t *pk, uint8_t *sk) { + // FrodoKEM's key generation + // Outputs: public key pk ( BYTES_SEED_A + (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 bytes) + // secret key sk (CRYPTO_BYTES + BYTES_SEED_A + (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 + 2*PARAMS_N*PARAMS_NBAR + BYTES_PKHASH bytes) + uint8_t *pk_seedA = &pk[0]; + uint8_t *pk_b = &pk[BYTES_SEED_A]; + uint8_t *sk_s = &sk[0]; + uint8_t *sk_pk = &sk[CRYPTO_BYTES]; + uint8_t *sk_S = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES]; + uint8_t *sk_pkh = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES + 2 * PARAMS_N * PARAMS_NBAR]; + uint16_t B[PARAMS_N * PARAMS_NBAR] = {0}; + uint16_t S[2 * PARAMS_N * PARAMS_NBAR] = {0}; // contains secret data + uint16_t *E = &S[PARAMS_N * PARAMS_NBAR]; // contains secret data + uint8_t randomness[2 * CRYPTO_BYTES + BYTES_SEED_A]; // contains secret data via randomness_s and randomness_seedSE + uint8_t *randomness_s = &randomness[0]; // contains secret data + uint8_t *randomness_seedSE = &randomness[CRYPTO_BYTES]; // contains secret data + uint8_t *randomness_z = &randomness[2 * CRYPTO_BYTES]; + uint8_t shake_input_seedSE[1 + CRYPTO_BYTES]; // contains secret data + + // Generate the secret value s, the seed for S and E, and the seed for the seed for A. Add seed_A to the public key + randombytes(randomness, CRYPTO_BYTES + CRYPTO_BYTES + BYTES_SEED_A); + shake(pk_seedA, BYTES_SEED_A, randomness_z, BYTES_SEED_A); + + // Generate S and E, and compute B = A*S + E. Generate A on-the-fly + shake_input_seedSE[0] = 0x5F; + memcpy(&shake_input_seedSE[1], randomness_seedSE, CRYPTO_BYTES); + shake((uint8_t *)S, 2 * PARAMS_N * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSE, 1 + CRYPTO_BYTES); + for (size_t i = 0; i < 2 * PARAMS_N * PARAMS_NBAR; i++) { + S[i] = PQCLEAN_FRODOKEM1344AES_OPT_LE_TO_UINT16(S[i]); + } + PQCLEAN_FRODOKEM1344AES_OPT_sample_n(S, PARAMS_N * PARAMS_NBAR); + PQCLEAN_FRODOKEM1344AES_OPT_sample_n(E, PARAMS_N * PARAMS_NBAR); + PQCLEAN_FRODOKEM1344AES_OPT_mul_add_as_plus_e(B, S, E, pk); + + // Encode the second part of the public key + PQCLEAN_FRODOKEM1344AES_OPT_pack(pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, B, PARAMS_N * PARAMS_NBAR, PARAMS_LOGQ); + + // Add s, pk and S to the secret key + memcpy(sk_s, randomness_s, CRYPTO_BYTES); + memcpy(sk_pk, pk, CRYPTO_PUBLICKEYBYTES); + for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) { + S[i] = PQCLEAN_FRODOKEM1344AES_OPT_UINT16_TO_LE(S[i]); + } + memcpy(sk_S, S, 2 * PARAMS_N * PARAMS_NBAR); + + // Add H(pk) to the secret key + shake(sk_pkh, BYTES_PKHASH, pk, CRYPTO_PUBLICKEYBYTES); + + // Cleanup: + PQCLEAN_FRODOKEM1344AES_OPT_clear_bytes((uint8_t *)S, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM1344AES_OPT_clear_bytes((uint8_t *)E, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM1344AES_OPT_clear_bytes(randomness, 2 * CRYPTO_BYTES); + PQCLEAN_FRODOKEM1344AES_OPT_clear_bytes(shake_input_seedSE, 1 + CRYPTO_BYTES); + return 0; +} + + +int PQCLEAN_FRODOKEM1344AES_OPT_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk) { + // FrodoKEM's key encapsulation + const uint8_t *pk_seedA = &pk[0]; + const uint8_t *pk_b = &pk[BYTES_SEED_A]; + uint8_t *ct_c1 = &ct[0]; + uint8_t *ct_c2 = &ct[(PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8]; + uint16_t B[PARAMS_N * PARAMS_NBAR] = {0}; + uint16_t V[PARAMS_NBAR * PARAMS_NBAR] = {0}; // contains secret data + uint16_t C[PARAMS_NBAR * PARAMS_NBAR] = {0}; + uint16_t Bp[PARAMS_N * PARAMS_NBAR] = {0}; + uint16_t Sp[(2 * PARAMS_N + PARAMS_NBAR)*PARAMS_NBAR] = {0}; // contains secret data + uint16_t *Ep = &Sp[PARAMS_N * PARAMS_NBAR]; // contains secret data + uint16_t *Epp = &Sp[2 * PARAMS_N * PARAMS_NBAR]; // contains secret data + uint8_t G2in[BYTES_PKHASH + BYTES_MU]; // contains secret data via mu + uint8_t *pkh = &G2in[0]; + uint8_t *mu = &G2in[BYTES_PKHASH]; // contains secret data + uint8_t G2out[2 * CRYPTO_BYTES]; // contains secret data + uint8_t *seedSE = &G2out[0]; // contains secret data + uint8_t *k = &G2out[CRYPTO_BYTES]; // contains secret data + uint8_t Fin[CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES]; // contains secret data via Fin_k + uint8_t *Fin_ct = &Fin[0]; + uint8_t *Fin_k = &Fin[CRYPTO_CIPHERTEXTBYTES]; // contains secret data + uint8_t shake_input_seedSE[1 + CRYPTO_BYTES]; // contains secret data + + // pkh <- G_1(pk), generate random mu, compute (seedSE || k) = G_2(pkh || mu) + shake(pkh, BYTES_PKHASH, pk, CRYPTO_PUBLICKEYBYTES); + randombytes(mu, BYTES_MU); + shake(G2out, CRYPTO_BYTES + CRYPTO_BYTES, G2in, BYTES_PKHASH + BYTES_MU); + + // Generate Sp and Ep, and compute Bp = Sp*A + Ep. Generate A on-the-fly + shake_input_seedSE[0] = 0x96; + memcpy(&shake_input_seedSE[1], seedSE, CRYPTO_BYTES); + shake((uint8_t *)Sp, (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSE, 1 + CRYPTO_BYTES); + for (size_t i = 0; i < (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR; i++) { + Sp[i] = PQCLEAN_FRODOKEM1344AES_OPT_LE_TO_UINT16(Sp[i]); + } + PQCLEAN_FRODOKEM1344AES_OPT_sample_n(Sp, PARAMS_N * PARAMS_NBAR); + PQCLEAN_FRODOKEM1344AES_OPT_sample_n(Ep, PARAMS_N * PARAMS_NBAR); + PQCLEAN_FRODOKEM1344AES_OPT_mul_add_sa_plus_e(Bp, Sp, Ep, pk_seedA); + PQCLEAN_FRODOKEM1344AES_OPT_pack(ct_c1, (PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8, Bp, PARAMS_N * PARAMS_NBAR, PARAMS_LOGQ); + + // Generate Epp, and compute V = Sp*B + Epp + PQCLEAN_FRODOKEM1344AES_OPT_sample_n(Epp, PARAMS_NBAR * PARAMS_NBAR); + PQCLEAN_FRODOKEM1344AES_OPT_unpack(B, PARAMS_N * PARAMS_NBAR, pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, PARAMS_LOGQ); + PQCLEAN_FRODOKEM1344AES_OPT_mul_add_sb_plus_e(V, B, Sp, Epp); + + // Encode mu, and compute C = V + enc(mu) (mod q) + PQCLEAN_FRODOKEM1344AES_OPT_key_encode(C, (uint16_t *)mu); + PQCLEAN_FRODOKEM1344AES_OPT_add(C, V, C); + PQCLEAN_FRODOKEM1344AES_OPT_pack(ct_c2, (PARAMS_LOGQ * PARAMS_NBAR * PARAMS_NBAR) / 8, C, PARAMS_NBAR * PARAMS_NBAR, PARAMS_LOGQ); + + // Compute ss = F(ct||KK) + memcpy(Fin_ct, ct, CRYPTO_CIPHERTEXTBYTES); + memcpy(Fin_k, k, CRYPTO_BYTES); + shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES); + + // Cleanup: + PQCLEAN_FRODOKEM1344AES_OPT_clear_bytes((uint8_t *)V, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM1344AES_OPT_clear_bytes((uint8_t *)Sp, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM1344AES_OPT_clear_bytes((uint8_t *)Ep, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM1344AES_OPT_clear_bytes((uint8_t *)Epp, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM1344AES_OPT_clear_bytes(mu, BYTES_MU); + PQCLEAN_FRODOKEM1344AES_OPT_clear_bytes(G2out, 2 * CRYPTO_BYTES); + PQCLEAN_FRODOKEM1344AES_OPT_clear_bytes(Fin_k, CRYPTO_BYTES); + PQCLEAN_FRODOKEM1344AES_OPT_clear_bytes(shake_input_seedSE, 1 + CRYPTO_BYTES); + return 0; +} + + +int PQCLEAN_FRODOKEM1344AES_OPT_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk) { + // FrodoKEM's key decapsulation + uint16_t B[PARAMS_N * PARAMS_NBAR] = {0}; + uint16_t Bp[PARAMS_N * PARAMS_NBAR] = {0}; + uint16_t W[PARAMS_NBAR * PARAMS_NBAR] = {0}; // contains secret data + uint16_t C[PARAMS_NBAR * PARAMS_NBAR] = {0}; + uint16_t CC[PARAMS_NBAR * PARAMS_NBAR] = {0}; + uint16_t BBp[PARAMS_N * PARAMS_NBAR] = {0}; + uint16_t Sp[(2 * PARAMS_N + PARAMS_NBAR)*PARAMS_NBAR] = {0}; // contains secret data + uint16_t *Ep = &Sp[PARAMS_N * PARAMS_NBAR]; // contains secret data + uint16_t *Epp = &Sp[2 * PARAMS_N * PARAMS_NBAR]; // contains secret data + const uint8_t *ct_c1 = &ct[0]; + const uint8_t *ct_c2 = &ct[(PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8]; + const uint8_t *sk_s = &sk[0]; + const uint8_t *sk_pk = &sk[CRYPTO_BYTES]; + const uint16_t *sk_S = (uint16_t *) &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES]; + uint16_t S[PARAMS_N * PARAMS_NBAR]; // contains secret data + const uint8_t *sk_pkh = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES + 2 * PARAMS_N * PARAMS_NBAR]; + const uint8_t *pk_seedA = &sk_pk[0]; + const uint8_t *pk_b = &sk_pk[BYTES_SEED_A]; + uint8_t G2in[BYTES_PKHASH + BYTES_MU]; // contains secret data via muprime + uint8_t *pkh = &G2in[0]; + uint8_t *muprime = &G2in[BYTES_PKHASH]; // contains secret data + uint8_t G2out[2 * CRYPTO_BYTES]; // contains secret data + uint8_t *seedSEprime = &G2out[0]; // contains secret data + uint8_t *kprime = &G2out[CRYPTO_BYTES]; // contains secret data + uint8_t Fin[CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES]; // contains secret data via Fin_k + uint8_t *Fin_ct = &Fin[0]; + uint8_t *Fin_k = &Fin[CRYPTO_CIPHERTEXTBYTES]; // contains secret data + uint8_t shake_input_seedSEprime[1 + CRYPTO_BYTES]; // contains secret data + + for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) { + S[i] = PQCLEAN_FRODOKEM1344AES_OPT_LE_TO_UINT16(sk_S[i]); + } + + // Compute W = C - Bp*S (mod q), and decode the randomness mu + PQCLEAN_FRODOKEM1344AES_OPT_unpack(Bp, PARAMS_N * PARAMS_NBAR, ct_c1, (PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8, PARAMS_LOGQ); + PQCLEAN_FRODOKEM1344AES_OPT_unpack(C, PARAMS_NBAR * PARAMS_NBAR, ct_c2, (PARAMS_LOGQ * PARAMS_NBAR * PARAMS_NBAR) / 8, PARAMS_LOGQ); + PQCLEAN_FRODOKEM1344AES_OPT_mul_bs(W, Bp, S); + PQCLEAN_FRODOKEM1344AES_OPT_sub(W, C, W); + PQCLEAN_FRODOKEM1344AES_OPT_key_decode((uint16_t *)muprime, W); + + // Generate (seedSE' || k') = G_2(pkh || mu') + memcpy(pkh, sk_pkh, BYTES_PKHASH); + shake(G2out, CRYPTO_BYTES + CRYPTO_BYTES, G2in, BYTES_PKHASH + BYTES_MU); + + // Generate Sp and Ep, and compute BBp = Sp*A + Ep. Generate A on-the-fly + shake_input_seedSEprime[0] = 0x96; + memcpy(&shake_input_seedSEprime[1], seedSEprime, CRYPTO_BYTES); + shake((uint8_t *)Sp, (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSEprime, 1 + CRYPTO_BYTES); + for (size_t i = 0; i < (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR; i++) { + Sp[i] = PQCLEAN_FRODOKEM1344AES_OPT_LE_TO_UINT16(Sp[i]); + } + PQCLEAN_FRODOKEM1344AES_OPT_sample_n(Sp, PARAMS_N * PARAMS_NBAR); + PQCLEAN_FRODOKEM1344AES_OPT_sample_n(Ep, PARAMS_N * PARAMS_NBAR); + PQCLEAN_FRODOKEM1344AES_OPT_mul_add_sa_plus_e(BBp, Sp, Ep, pk_seedA); + + // Generate Epp, and compute W = Sp*B + Epp + PQCLEAN_FRODOKEM1344AES_OPT_sample_n(Epp, PARAMS_NBAR * PARAMS_NBAR); + PQCLEAN_FRODOKEM1344AES_OPT_unpack(B, PARAMS_N * PARAMS_NBAR, pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, PARAMS_LOGQ); + PQCLEAN_FRODOKEM1344AES_OPT_mul_add_sb_plus_e(W, B, Sp, Epp); + + // Encode mu, and compute CC = W + enc(mu') (mod q) + PQCLEAN_FRODOKEM1344AES_OPT_key_encode(CC, (uint16_t *)muprime); + PQCLEAN_FRODOKEM1344AES_OPT_add(CC, W, CC); + + // Prepare input to F + memcpy(Fin_ct, ct, CRYPTO_CIPHERTEXTBYTES); + + // Reducing BBp modulo q + for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) { + BBp[i] = BBp[i] & ((1 << PARAMS_LOGQ) - 1); + } + + // Is (Bp == BBp & C == CC) = true + if (memcmp(Bp, BBp, 2 * PARAMS_N * PARAMS_NBAR) == 0 && memcmp(C, CC, 2 * PARAMS_NBAR * PARAMS_NBAR) == 0) { + // Load k' to do ss = F(ct || k') + memcpy(Fin_k, kprime, CRYPTO_BYTES); + } else { + // Load s to do ss = F(ct || s) + memcpy(Fin_k, sk_s, CRYPTO_BYTES); + } + shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES); + + // Cleanup: + PQCLEAN_FRODOKEM1344AES_OPT_clear_bytes((uint8_t *)W, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM1344AES_OPT_clear_bytes((uint8_t *)Sp, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM1344AES_OPT_clear_bytes((uint8_t *)S, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM1344AES_OPT_clear_bytes((uint8_t *)Ep, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM1344AES_OPT_clear_bytes((uint8_t *)Epp, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM1344AES_OPT_clear_bytes(muprime, BYTES_MU); + PQCLEAN_FRODOKEM1344AES_OPT_clear_bytes(G2out, 2 * CRYPTO_BYTES); + PQCLEAN_FRODOKEM1344AES_OPT_clear_bytes(Fin_k, CRYPTO_BYTES); + PQCLEAN_FRODOKEM1344AES_OPT_clear_bytes(shake_input_seedSEprime, 1 + CRYPTO_BYTES); + return 0; +} diff --git a/crypto_kem/frodokem1344aes/opt/matrix_aes.c b/crypto_kem/frodokem1344aes/opt/matrix_aes.c new file mode 100644 index 00000000..9d29da6c --- /dev/null +++ b/crypto_kem/frodokem1344aes/opt/matrix_aes.c @@ -0,0 +1,125 @@ +/******************************************************************************************** +* FrodoKEM: Learning with Errors Key Encapsulation +* +* Abstract: matrix arithmetic functions used by the KEM +*********************************************************************************************/ + +#include +#include + +#include "aes.h" + +#include "api.h" +#include "common.h" +#include "params.h" + +int PQCLEAN_FRODOKEM1344AES_OPT_mul_add_as_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A) { + // Generate-and-multiply: generate matrix A (N x N) row-wise, multiply by s on the right. + // Inputs: s, e (N x N_BAR) + // Output: out = A*s + e (N x N_BAR) + int k; + uint16_t i, j; + int16_t a_row[4 * PARAMS_N]; + + for (i = 0; i < (PARAMS_N * PARAMS_NBAR); i += 2) { + *((uint32_t *)&out[i]) = *((uint32_t *)&e[i]); + } + + int16_t a_row_temp[4 * PARAMS_N] = {0}; // Take four lines of A at once + aes128ctx ctx128; + + aes128_keyexp(&ctx128, seed_A); + + for (j = 0; j < PARAMS_N; j += PARAMS_STRIPE_STEP) { + a_row_temp[j + 1 + 0 * PARAMS_N] = PQCLEAN_FRODOKEM1344AES_OPT_UINT16_TO_LE(j); // Loading values in the little-endian order + a_row_temp[j + 1 + 1 * PARAMS_N] = PQCLEAN_FRODOKEM1344AES_OPT_UINT16_TO_LE(j); + a_row_temp[j + 1 + 2 * PARAMS_N] = PQCLEAN_FRODOKEM1344AES_OPT_UINT16_TO_LE(j); + a_row_temp[j + 1 + 3 * PARAMS_N] = PQCLEAN_FRODOKEM1344AES_OPT_UINT16_TO_LE(j); + } + + for (i = 0; i < PARAMS_N; i += 4) { + for (j = 0; j < PARAMS_N; j += PARAMS_STRIPE_STEP) { // Go through A, four rows at a time + a_row_temp[j + 0 * PARAMS_N] = PQCLEAN_FRODOKEM1344AES_OPT_UINT16_TO_LE(i + 0); // Loading values in the little-endian order + a_row_temp[j + 1 * PARAMS_N] = PQCLEAN_FRODOKEM1344AES_OPT_UINT16_TO_LE(i + 1); + a_row_temp[j + 2 * PARAMS_N] = PQCLEAN_FRODOKEM1344AES_OPT_UINT16_TO_LE(i + 2); + a_row_temp[j + 3 * PARAMS_N] = PQCLEAN_FRODOKEM1344AES_OPT_UINT16_TO_LE(i + 3); + } + aes128_ecb((uint8_t *)a_row, (uint8_t *)a_row_temp, 4 * PARAMS_N * sizeof(int16_t) / AES_BLOCKBYTES, &ctx128); + for (k = 0; k < 4 * PARAMS_N; k++) { + a_row[k] = PQCLEAN_FRODOKEM1344AES_OPT_LE_TO_UINT16(a_row[k]); + } + for (k = 0; k < PARAMS_NBAR; k++) { + uint16_t sum[4] = {0}; + for (j = 0; j < PARAMS_N; j++) { // Matrix-vector multiplication + uint16_t sp = s[k * PARAMS_N + j]; + sum[0] += a_row[0 * PARAMS_N + j] * sp; // Go through four lines with same s + sum[1] += a_row[1 * PARAMS_N + j] * sp; + sum[2] += a_row[2 * PARAMS_N + j] * sp; + sum[3] += a_row[3 * PARAMS_N + j] * sp; + } + out[(i + 0)*PARAMS_NBAR + k] += sum[0]; + out[(i + 2)*PARAMS_NBAR + k] += sum[2]; + out[(i + 1)*PARAMS_NBAR + k] += sum[1]; + out[(i + 3)*PARAMS_NBAR + k] += sum[3]; + } + } + return 1; +} + + + + +int PQCLEAN_FRODOKEM1344AES_OPT_mul_add_sa_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A) { + // Generate-and-multiply: generate matrix A (N x N) column-wise, multiply by s' on the left. + // Inputs: s', e' (N_BAR x N) + // Output: out = s'*A + e' (N_BAR x N) + int j; + uint16_t i, kk; + for (i = 0; i < (PARAMS_N * PARAMS_NBAR); i += 2) { + *((uint32_t *)&out[i]) = *((uint32_t *)&e[i]); + } + + int k; + uint16_t a_cols[PARAMS_N * PARAMS_STRIPE_STEP] = {0}; + uint16_t a_cols_t[PARAMS_N * PARAMS_STRIPE_STEP]; + uint16_t a_cols_temp[PARAMS_N * PARAMS_STRIPE_STEP] = {0}; + aes128ctx ctx128; + + aes128_keyexp(&ctx128, seed_A); + + for (i = 0, j = 0; i < PARAMS_N; i++, j += PARAMS_STRIPE_STEP) { + a_cols_temp[j] = PQCLEAN_FRODOKEM1344AES_OPT_UINT16_TO_LE(i); // Loading values in the little-endian order + } + + for (kk = 0; kk < PARAMS_N; kk += PARAMS_STRIPE_STEP) { // Go through A's columns, 8 (== PARAMS_STRIPE_STEP) columns at a time. + for (i = 0; i < (PARAMS_N * PARAMS_STRIPE_STEP); i += PARAMS_STRIPE_STEP) { + a_cols_temp[i + 1] = PQCLEAN_FRODOKEM1344AES_OPT_UINT16_TO_LE(kk); // Loading values in the little-endian order + } + + aes128_ecb((uint8_t *)a_cols, (uint8_t *)a_cols_temp, PARAMS_N * PARAMS_STRIPE_STEP * sizeof(int16_t) / AES_BLOCKBYTES, &ctx128); + + for (i = 0; i < PARAMS_N; i++) { // Transpose a_cols to have access to it in the column-major order. + for (k = 0; k < PARAMS_STRIPE_STEP; k++) { + a_cols_t[k * PARAMS_N + i] = PQCLEAN_FRODOKEM1344AES_OPT_LE_TO_UINT16(a_cols[i * PARAMS_STRIPE_STEP + k]); + } + } + + for (i = 0; i < PARAMS_NBAR; i++) { + for (k = 0; k < PARAMS_STRIPE_STEP; k += PARAMS_PARALLEL) { + uint16_t sum[PARAMS_PARALLEL] = {0}; + for (j = 0; j < PARAMS_N; j++) { // Matrix-vector multiplication + uint16_t sp = s[i * PARAMS_N + j]; + sum[0] += sp * a_cols_t[(k + 0) * PARAMS_N + j]; + sum[1] += sp * a_cols_t[(k + 1) * PARAMS_N + j]; + sum[2] += sp * a_cols_t[(k + 2) * PARAMS_N + j]; + sum[3] += sp * a_cols_t[(k + 3) * PARAMS_N + j]; + } + out[i * PARAMS_N + kk + k + 0] += sum[0]; + out[i * PARAMS_N + kk + k + 2] += sum[2]; + out[i * PARAMS_N + kk + k + 1] += sum[1]; + out[i * PARAMS_N + kk + k + 3] += sum[3]; + } + } + } + return 1; +} diff --git a/crypto_kem/frodokem1344aes/opt/noise.c b/crypto_kem/frodokem1344aes/opt/noise.c new file mode 100644 index 00000000..1e8b66c6 --- /dev/null +++ b/crypto_kem/frodokem1344aes/opt/noise.c @@ -0,0 +1,35 @@ +/******************************************************************************************** +* FrodoKEM: Learning with Errors Key Encapsulation +* +* Abstract: noise sampling functions +*********************************************************************************************/ + +#include + +#include "api.h" +#include "common.h" +#include "params.h" + +static uint16_t CDF_TABLE[CDF_TABLE_LEN] = CDF_TABLE_DATA; + +void PQCLEAN_FRODOKEM1344AES_OPT_sample_n(uint16_t *s, size_t n) { + // Fills vector s with n samples from the noise distribution which requires 16 bits to sample. + // The distribution is specified by its CDF. + // Input: pseudo-random values (2*n bytes) passed in s. The input is overwritten by the output. + size_t i; + unsigned int j; + + for (i = 0; i < n; ++i) { + uint16_t sample = 0; + uint16_t prnd = s[i] >> 1; // Drop the least significant bit + uint16_t sign = s[i] & 0x1; // Pick the least significant bit + + // No need to compare with the last value. + for (j = 0; j < (unsigned int)(CDF_TABLE_LEN - 1); j++) { + // Constant time comparison: 1 if CDF_TABLE[j] < s, 0 otherwise. Uses the fact that CDF_TABLE[j] and s fit in 15 bits. + sample += (uint16_t)(CDF_TABLE[j] - prnd) >> 15; + } + // Assuming that sign is either 0 or 1, flips sample iff sign = 1 + s[i] = ((-sign) ^ sample) + sign; + } +} diff --git a/crypto_kem/frodokem1344aes/opt/params.h b/crypto_kem/frodokem1344aes/opt/params.h new file mode 100644 index 00000000..08e6d4bb --- /dev/null +++ b/crypto_kem/frodokem1344aes/opt/params.h @@ -0,0 +1,27 @@ +#ifndef PARAMS_H +#define PARAMS_H + +#define CRYPTO_SECRETKEYBYTES PQCLEAN_FRODOKEM1344AES_OPT_CRYPTO_SECRETKEYBYTES +#define CRYPTO_PUBLICKEYBYTES PQCLEAN_FRODOKEM1344AES_OPT_CRYPTO_PUBLICKEYBYTES +#define CRYPTO_BYTES PQCLEAN_FRODOKEM1344AES_OPT_CRYPTO_BYTES +#define CRYPTO_CIPHERTEXTBYTES PQCLEAN_FRODOKEM1344AES_OPT_CRYPTO_CIPHERTEXTBYTES + +#define PARAMS_N 1344 +#define PARAMS_NBAR 8 +#define PARAMS_LOGQ 16 +#define PARAMS_Q (1 << PARAMS_LOGQ) +#define PARAMS_EXTRACTED_BITS 4 +#define PARAMS_STRIPE_STEP 8 +#define PARAMS_PARALLEL 4 +#define BYTES_SEED_A 16 +#define BYTES_MU ((PARAMS_EXTRACTED_BITS * PARAMS_NBAR * PARAMS_NBAR) / 8) +#define BYTES_PKHASH CRYPTO_BYTES + +// Selecting SHAKE XOF function for the KEM and noise sampling +#define shake shake256 + +// CDF table +#define CDF_TABLE_DATA {9142, 23462, 30338, 32361, 32725, 32765, 32767} +#define CDF_TABLE_LEN 7 + +#endif diff --git a/crypto_kem/frodokem1344aes/opt/util.c b/crypto_kem/frodokem1344aes/opt/util.c new file mode 100644 index 00000000..33b28109 --- /dev/null +++ b/crypto_kem/frodokem1344aes/opt/util.c @@ -0,0 +1,235 @@ +/******************************************************************************************** +* FrodoKEM: Learning with Errors Key Encapsulation +* +* Abstract: additional functions for FrodoKEM +*********************************************************************************************/ + +#include +#include + +#include "api.h" +#include "common.h" +#include "params.h" + +#define min(x, y) (((x) < (y)) ? (x) : (y)) + +uint16_t PQCLEAN_FRODOKEM1344AES_OPT_LE_TO_UINT16(uint16_t n) { + return (((uint8_t *) &n)[0] | (((uint8_t *) &n)[1] << 8)); +} + +uint16_t PQCLEAN_FRODOKEM1344AES_OPT_UINT16_TO_LE(uint16_t n) { + uint16_t y; + uint8_t *z = (uint8_t *) &y; + z[0] = n & 0xFF; + z[1] = (n & 0xFF00) >> 8; + return y; +} + +void PQCLEAN_FRODOKEM1344AES_OPT_mul_bs(uint16_t *out, const uint16_t *b, const uint16_t *s) { + // Multiply by s on the right + // Inputs: b (N_BAR x N), s (N x N_BAR) + // Output: out = b*s (N_BAR x N_BAR) + int i, j, k; + + for (i = 0; i < PARAMS_NBAR; i++) { + for (j = 0; j < PARAMS_NBAR; j++) { + out[i * PARAMS_NBAR + j] = 0; + for (k = 0; k < PARAMS_N; k++) { + out[i * PARAMS_NBAR + j] += b[i * PARAMS_N + k] * s[j * PARAMS_N + k]; + } + out[i * PARAMS_NBAR + j] = (uint32_t)(out[i * PARAMS_NBAR + j]) & ((1 << PARAMS_LOGQ) - 1); + } + } +} + + +void PQCLEAN_FRODOKEM1344AES_OPT_mul_add_sb_plus_e(uint16_t *out, const uint16_t *b, const uint16_t *s, const uint16_t *e) { + // Multiply by s on the left + // Inputs: b (N x N_BAR), s (N_BAR x N), e (N_BAR x N_BAR) + // Output: out = s*b + e (N_BAR x N_BAR) + int i, j, k; + + for (k = 0; k < PARAMS_NBAR; k++) { + for (i = 0; i < PARAMS_NBAR; i++) { + out[k * PARAMS_NBAR + i] = e[k * PARAMS_NBAR + i]; + for (j = 0; j < PARAMS_N; j++) { + out[k * PARAMS_NBAR + i] += s[k * PARAMS_N + j] * b[j * PARAMS_NBAR + i]; + } + out[k * PARAMS_NBAR + i] = (uint32_t)(out[k * PARAMS_NBAR + i]) & ((1 << PARAMS_LOGQ) - 1); + } + } +} + + +void PQCLEAN_FRODOKEM1344AES_OPT_add(uint16_t *out, const uint16_t *a, const uint16_t *b) { + // Add a and b + // Inputs: a, b (N_BAR x N_BAR) + // Output: c = a + b + + for (size_t i = 0; i < (PARAMS_NBAR * PARAMS_NBAR); i++) { + out[i] = (a[i] + b[i]) & ((1 << PARAMS_LOGQ) - 1); + } +} + + +void PQCLEAN_FRODOKEM1344AES_OPT_sub(uint16_t *out, const uint16_t *a, const uint16_t *b) { + // Subtract a and b + // Inputs: a, b (N_BAR x N_BAR) + // Output: c = a - b + + for (size_t i = 0; i < (PARAMS_NBAR * PARAMS_NBAR); i++) { + out[i] = (a[i] - b[i]) & ((1 << PARAMS_LOGQ) - 1); + } +} + + +void PQCLEAN_FRODOKEM1344AES_OPT_key_encode(uint16_t *out, const uint16_t *in) { + // Encoding + unsigned int i, j, npieces_word = 8; + unsigned int nwords = (PARAMS_NBAR * PARAMS_NBAR) / 8; + uint64_t temp, mask = ((uint64_t)1 << PARAMS_EXTRACTED_BITS) - 1; + uint16_t *pos = out; + + for (i = 0; i < nwords; i++) { + temp = 0; + for (j = 0; j < PARAMS_EXTRACTED_BITS; j++) { + temp |= ((uint64_t)((uint8_t *)in)[i * PARAMS_EXTRACTED_BITS + j]) << (8 * j); + } + for (j = 0; j < npieces_word; j++) { + *pos = (uint16_t)((temp & mask) << (PARAMS_LOGQ - PARAMS_EXTRACTED_BITS)); + temp >>= PARAMS_EXTRACTED_BITS; + pos++; + } + } +} + + +void PQCLEAN_FRODOKEM1344AES_OPT_key_decode(uint16_t *out, const uint16_t *in) { + // Decoding + unsigned int i, j, index = 0, npieces_word = 8; + unsigned int nwords = (PARAMS_NBAR * PARAMS_NBAR) / 8; + uint16_t temp, maskex = ((uint16_t)1 << PARAMS_EXTRACTED_BITS) - 1, maskq = ((uint16_t)1 << PARAMS_LOGQ) - 1; + uint8_t *pos = (uint8_t *)out; + uint64_t templong; + + for (i = 0; i < nwords; i++) { + templong = 0; + for (j = 0; j < npieces_word; j++) { // temp = floor(in*2^{-11}+0.5) + temp = ((in[index] & maskq) + (1 << (PARAMS_LOGQ - PARAMS_EXTRACTED_BITS - 1))) >> (PARAMS_LOGQ - PARAMS_EXTRACTED_BITS); + templong |= ((uint64_t)(temp & maskex)) << (PARAMS_EXTRACTED_BITS * j); + index++; + } + for (j = 0; j < PARAMS_EXTRACTED_BITS; j++) { + pos[i * PARAMS_EXTRACTED_BITS + j] = (templong >> (8 * j)) & 0xFF; + } + } +} + + +void PQCLEAN_FRODOKEM1344AES_OPT_pack(uint8_t *out, size_t outlen, const uint16_t *in, size_t inlen, uint8_t lsb) { + // Pack the input uint16 vector into a char output vector, copying lsb bits from each input element. + // If inlen * lsb / 8 > outlen, only outlen * 8 bits are copied. + memset(out, 0, outlen); + + size_t i = 0; // whole bytes already filled in + size_t j = 0; // whole uint16_t already copied + uint16_t w = 0; // the leftover, not yet copied + uint8_t bits = 0; // the number of lsb in w + + while (i < outlen && (j < inlen || ((j == inlen) && (bits > 0)))) { + /* + in: | | |********|********| + ^ + j + w : | ****| + ^ + bits + out:|**|**|**|**|**|**|**|**|* | + ^^ + ib + */ + uint8_t b = 0; // bits in out[i] already filled in + while (b < 8) { + int nbits = min(8 - b, bits); + uint16_t mask = (1 << nbits) - 1; + uint8_t t = (uint8_t) ((w >> (bits - nbits)) & mask); // the bits to copy from w to out + out[i] = out[i] + (t << (8 - b - nbits)); + b += (uint8_t) nbits; + bits -= (uint8_t) nbits; + w &= ~(mask << bits); // not strictly necessary; mostly for debugging + + if (bits == 0) { + if (j < inlen) { + w = in[j]; + bits = lsb; + j++; + } else { + break; // the input vector is exhausted + } + } + } + if (b == 8) { // out[i] is filled in + i++; + } + } +} + + +void PQCLEAN_FRODOKEM1344AES_OPT_unpack(uint16_t *out, size_t outlen, const uint8_t *in, size_t inlen, uint8_t lsb) { + // Unpack the input char vector into a uint16_t output vector, copying lsb bits + // for each output element from input. outlen must be at least ceil(inlen * 8 / lsb). + memset(out, 0, outlen * sizeof(uint16_t)); + + size_t i = 0; // whole uint16_t already filled in + size_t j = 0; // whole bytes already copied + uint8_t w = 0; // the leftover, not yet copied + uint8_t bits = 0; // the number of lsb bits of w + + while (i < outlen && (j < inlen || ((j == inlen) && (bits > 0)))) { + /* + in: | | | | | | |**|**|... + ^ + j + w : | *| + ^ + bits + out:| *****| *****| *** | |... + ^ ^ + i b + */ + uint8_t b = 0; // bits in out[i] already filled in + while (b < lsb) { + int nbits = min(lsb - b, bits); + uint16_t mask = (1 << nbits) - 1; + uint8_t t = (w >> (bits - nbits)) & mask; // the bits to copy from w to out + out[i] = out[i] + (t << (lsb - b - nbits)); + b += (uint8_t) nbits; + bits -= (uint8_t) nbits; + w &= ~(mask << bits); // not strictly necessary; mostly for debugging + + if (bits == 0) { + if (j < inlen) { + w = in[j]; + bits = 8; + j++; + } else { + break; // the input vector is exhausted + } + } + } + if (b == lsb) { // out[i] is filled in + i++; + } + } +} + + +void PQCLEAN_FRODOKEM1344AES_OPT_clear_bytes(uint8_t *mem, size_t n) { + // Clear 8-bit bytes from memory. "n" indicates the number of bytes to be zeroed. + // This function uses the volatile type qualifier to inform the compiler not to optimize out the memory clearing. + volatile uint8_t *v = mem; + + for (size_t i = 0; i < n; i++) { + v[i] = 0; + } +} diff --git a/crypto_kem/frodokem1344shake/META.yml b/crypto_kem/frodokem1344shake/META.yml index 534d3f43..43a699eb 100644 --- a/crypto_kem/frodokem1344shake/META.yml +++ b/crypto_kem/frodokem1344shake/META.yml @@ -23,3 +23,5 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/Microsoft/PQCrypto-LWEKE/commit/d5bbd0417ba111b08a959c0042a1dcc65fb14a89 +- name: opt + version: https://github.com/Microsoft/PQCrypto-LWEKE/commit/d5bbd0417ba111b08a959c0042a1dcc65fb14a89 diff --git a/crypto_kem/frodokem1344shake/clean/Makefile b/crypto_kem/frodokem1344shake/clean/Makefile index 39df6863..0f21a201 100644 --- a/crypto_kem/frodokem1344shake/clean/Makefile +++ b/crypto_kem/frodokem1344shake/clean/Makefile @@ -4,7 +4,7 @@ LIB=libfrodokem1344shake_clean.a HEADERS=api.h params.h common.h OBJECTS=kem.o matrix_shake.o noise.o util.o -CFLAGS=-O3 -Wall -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_kem/frodokem1344shake/opt/LICENSE b/crypto_kem/frodokem1344shake/opt/LICENSE new file mode 100644 index 00000000..5cf7c8db --- /dev/null +++ b/crypto_kem/frodokem1344shake/opt/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) Microsoft Corporation. All rights reserved. + +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/frodokem1344shake/opt/Makefile b/crypto_kem/frodokem1344shake/opt/Makefile new file mode 100644 index 00000000..f8c5fd4a --- /dev/null +++ b/crypto_kem/frodokem1344shake/opt/Makefile @@ -0,0 +1,19 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libfrodokem1344shake_opt.a +HEADERS=api.h params.h common.h +OBJECTS=kem.o matrix_shake.o noise.o util.o + +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -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/frodokem1344shake/opt/Makefile.Microsoft_nmake b/crypto_kem/frodokem1344shake/opt/Makefile.Microsoft_nmake new file mode 100644 index 00000000..0142c1e1 --- /dev/null +++ b/crypto_kem/frodokem1344shake/opt/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=libfrodokem1344shake_opt.lib +OBJECTS=kem.obj matrix_shake.obj noise.obj util.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/frodokem1344shake/opt/api.h b/crypto_kem/frodokem1344shake/opt/api.h new file mode 100644 index 00000000..76255168 --- /dev/null +++ b/crypto_kem/frodokem1344shake/opt/api.h @@ -0,0 +1,20 @@ +#ifndef PQCLEAN_FRODOKEM1344SHAKE_OPT_API_H +#define PQCLEAN_FRODOKEM1344SHAKE_OPT_API_H + +#include +#include + +#define PQCLEAN_FRODOKEM1344SHAKE_OPT_CRYPTO_SECRETKEYBYTES 43088 // sizeof(s) + CRYPTO_PUBLICKEYBYTES + 2*PARAMS_N*PARAMS_NBAR + BYTES_PKHASH +#define PQCLEAN_FRODOKEM1344SHAKE_OPT_CRYPTO_PUBLICKEYBYTES 21520 // sizeof(seed_A) + (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 +#define PQCLEAN_FRODOKEM1344SHAKE_OPT_CRYPTO_BYTES 32 +#define PQCLEAN_FRODOKEM1344SHAKE_OPT_CRYPTO_CIPHERTEXTBYTES 21632 // (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 + (PARAMS_LOGQ*PARAMS_NBAR*PARAMS_NBAR)/8 + +#define PQCLEAN_FRODOKEM1344SHAKE_OPT_CRYPTO_ALGNAME "FrodoKEM-1344-SHAKE" + +int PQCLEAN_FRODOKEM1344SHAKE_OPT_crypto_kem_keypair(uint8_t *pk, uint8_t *sk); + +int PQCLEAN_FRODOKEM1344SHAKE_OPT_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk); + +int PQCLEAN_FRODOKEM1344SHAKE_OPT_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk); + +#endif diff --git a/crypto_kem/frodokem1344shake/opt/common.h b/crypto_kem/frodokem1344shake/opt/common.h new file mode 100644 index 00000000..32af833b --- /dev/null +++ b/crypto_kem/frodokem1344shake/opt/common.h @@ -0,0 +1,19 @@ +#ifndef COMMON_H +#define COMMON_H + +int PQCLEAN_FRODOKEM1344SHAKE_OPT_mul_add_as_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A); +int PQCLEAN_FRODOKEM1344SHAKE_OPT_mul_add_sa_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A); +void PQCLEAN_FRODOKEM1344SHAKE_OPT_sample_n(uint16_t *s, size_t n); +void PQCLEAN_FRODOKEM1344SHAKE_OPT_mul_bs(uint16_t *out, const uint16_t *b, const uint16_t *s); +void PQCLEAN_FRODOKEM1344SHAKE_OPT_mul_add_sb_plus_e(uint16_t *out, const uint16_t *b, const uint16_t *s, const uint16_t *e); +void PQCLEAN_FRODOKEM1344SHAKE_OPT_add(uint16_t *out, const uint16_t *a, const uint16_t *b); +void PQCLEAN_FRODOKEM1344SHAKE_OPT_sub(uint16_t *out, const uint16_t *a, const uint16_t *b); +void PQCLEAN_FRODOKEM1344SHAKE_OPT_key_encode(uint16_t *out, const uint16_t *in); +void PQCLEAN_FRODOKEM1344SHAKE_OPT_key_decode(uint16_t *out, const uint16_t *in); +void PQCLEAN_FRODOKEM1344SHAKE_OPT_pack(uint8_t *out, size_t outlen, const uint16_t *in, size_t inlen, uint8_t lsb); +void PQCLEAN_FRODOKEM1344SHAKE_OPT_unpack(uint16_t *out, size_t outlen, const uint8_t *in, size_t inlen, uint8_t lsb); +void PQCLEAN_FRODOKEM1344SHAKE_OPT_clear_bytes(uint8_t *mem, size_t n); +uint16_t PQCLEAN_FRODOKEM1344SHAKE_OPT_LE_TO_UINT16(uint16_t n); +uint16_t PQCLEAN_FRODOKEM1344SHAKE_OPT_UINT16_TO_LE(uint16_t n); + +#endif diff --git a/crypto_kem/frodokem1344shake/opt/kem.c b/crypto_kem/frodokem1344shake/opt/kem.c new file mode 100644 index 00000000..45a940ae --- /dev/null +++ b/crypto_kem/frodokem1344shake/opt/kem.c @@ -0,0 +1,238 @@ +/******************************************************************************************** +* FrodoKEM: Learning with Errors Key Encapsulation +* +* Abstract: Key Encapsulation Mechanism (KEM) based on Frodo +*********************************************************************************************/ + +#include +#include + +#include "fips202.h" +#include "randombytes.h" + +#include "api.h" +#include "common.h" +#include "params.h" + +int PQCLEAN_FRODOKEM1344SHAKE_OPT_crypto_kem_keypair(uint8_t *pk, uint8_t *sk) { + // FrodoKEM's key generation + // Outputs: public key pk ( BYTES_SEED_A + (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 bytes) + // secret key sk (CRYPTO_BYTES + BYTES_SEED_A + (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 + 2*PARAMS_N*PARAMS_NBAR + BYTES_PKHASH bytes) + uint8_t *pk_seedA = &pk[0]; + uint8_t *pk_b = &pk[BYTES_SEED_A]; + uint8_t *sk_s = &sk[0]; + uint8_t *sk_pk = &sk[CRYPTO_BYTES]; + uint8_t *sk_S = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES]; + uint8_t *sk_pkh = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES + 2 * PARAMS_N * PARAMS_NBAR]; + uint16_t B[PARAMS_N * PARAMS_NBAR] = {0}; + uint16_t S[2 * PARAMS_N * PARAMS_NBAR] = {0}; // contains secret data + uint16_t *E = &S[PARAMS_N * PARAMS_NBAR]; // contains secret data + uint8_t randomness[2 * CRYPTO_BYTES + BYTES_SEED_A]; // contains secret data via randomness_s and randomness_seedSE + uint8_t *randomness_s = &randomness[0]; // contains secret data + uint8_t *randomness_seedSE = &randomness[CRYPTO_BYTES]; // contains secret data + uint8_t *randomness_z = &randomness[2 * CRYPTO_BYTES]; + uint8_t shake_input_seedSE[1 + CRYPTO_BYTES]; // contains secret data + + // Generate the secret value s, the seed for S and E, and the seed for the seed for A. Add seed_A to the public key + randombytes(randomness, CRYPTO_BYTES + CRYPTO_BYTES + BYTES_SEED_A); + shake(pk_seedA, BYTES_SEED_A, randomness_z, BYTES_SEED_A); + + // Generate S and E, and compute B = A*S + E. Generate A on-the-fly + shake_input_seedSE[0] = 0x5F; + memcpy(&shake_input_seedSE[1], randomness_seedSE, CRYPTO_BYTES); + shake((uint8_t *)S, 2 * PARAMS_N * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSE, 1 + CRYPTO_BYTES); + for (size_t i = 0; i < 2 * PARAMS_N * PARAMS_NBAR; i++) { + S[i] = PQCLEAN_FRODOKEM1344SHAKE_OPT_LE_TO_UINT16(S[i]); + } + PQCLEAN_FRODOKEM1344SHAKE_OPT_sample_n(S, PARAMS_N * PARAMS_NBAR); + PQCLEAN_FRODOKEM1344SHAKE_OPT_sample_n(E, PARAMS_N * PARAMS_NBAR); + PQCLEAN_FRODOKEM1344SHAKE_OPT_mul_add_as_plus_e(B, S, E, pk); + + // Encode the second part of the public key + PQCLEAN_FRODOKEM1344SHAKE_OPT_pack(pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, B, PARAMS_N * PARAMS_NBAR, PARAMS_LOGQ); + + // Add s, pk and S to the secret key + memcpy(sk_s, randomness_s, CRYPTO_BYTES); + memcpy(sk_pk, pk, CRYPTO_PUBLICKEYBYTES); + for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) { + S[i] = PQCLEAN_FRODOKEM1344SHAKE_OPT_UINT16_TO_LE(S[i]); + } + memcpy(sk_S, S, 2 * PARAMS_N * PARAMS_NBAR); + + // Add H(pk) to the secret key + shake(sk_pkh, BYTES_PKHASH, pk, CRYPTO_PUBLICKEYBYTES); + + // Cleanup: + PQCLEAN_FRODOKEM1344SHAKE_OPT_clear_bytes((uint8_t *)S, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM1344SHAKE_OPT_clear_bytes((uint8_t *)E, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM1344SHAKE_OPT_clear_bytes(randomness, 2 * CRYPTO_BYTES); + PQCLEAN_FRODOKEM1344SHAKE_OPT_clear_bytes(shake_input_seedSE, 1 + CRYPTO_BYTES); + return 0; +} + + +int PQCLEAN_FRODOKEM1344SHAKE_OPT_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk) { + // FrodoKEM's key encapsulation + const uint8_t *pk_seedA = &pk[0]; + const uint8_t *pk_b = &pk[BYTES_SEED_A]; + uint8_t *ct_c1 = &ct[0]; + uint8_t *ct_c2 = &ct[(PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8]; + uint16_t B[PARAMS_N * PARAMS_NBAR] = {0}; + uint16_t V[PARAMS_NBAR * PARAMS_NBAR] = {0}; // contains secret data + uint16_t C[PARAMS_NBAR * PARAMS_NBAR] = {0}; + uint16_t Bp[PARAMS_N * PARAMS_NBAR] = {0}; + uint16_t Sp[(2 * PARAMS_N + PARAMS_NBAR)*PARAMS_NBAR] = {0}; // contains secret data + uint16_t *Ep = &Sp[PARAMS_N * PARAMS_NBAR]; // contains secret data + uint16_t *Epp = &Sp[2 * PARAMS_N * PARAMS_NBAR]; // contains secret data + uint8_t G2in[BYTES_PKHASH + BYTES_MU]; // contains secret data via mu + uint8_t *pkh = &G2in[0]; + uint8_t *mu = &G2in[BYTES_PKHASH]; // contains secret data + uint8_t G2out[2 * CRYPTO_BYTES]; // contains secret data + uint8_t *seedSE = &G2out[0]; // contains secret data + uint8_t *k = &G2out[CRYPTO_BYTES]; // contains secret data + uint8_t Fin[CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES]; // contains secret data via Fin_k + uint8_t *Fin_ct = &Fin[0]; + uint8_t *Fin_k = &Fin[CRYPTO_CIPHERTEXTBYTES]; // contains secret data + uint8_t shake_input_seedSE[1 + CRYPTO_BYTES]; // contains secret data + + // pkh <- G_1(pk), generate random mu, compute (seedSE || k) = G_2(pkh || mu) + shake(pkh, BYTES_PKHASH, pk, CRYPTO_PUBLICKEYBYTES); + randombytes(mu, BYTES_MU); + shake(G2out, CRYPTO_BYTES + CRYPTO_BYTES, G2in, BYTES_PKHASH + BYTES_MU); + + // Generate Sp and Ep, and compute Bp = Sp*A + Ep. Generate A on-the-fly + shake_input_seedSE[0] = 0x96; + memcpy(&shake_input_seedSE[1], seedSE, CRYPTO_BYTES); + shake((uint8_t *)Sp, (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSE, 1 + CRYPTO_BYTES); + for (size_t i = 0; i < (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR; i++) { + Sp[i] = PQCLEAN_FRODOKEM1344SHAKE_OPT_LE_TO_UINT16(Sp[i]); + } + PQCLEAN_FRODOKEM1344SHAKE_OPT_sample_n(Sp, PARAMS_N * PARAMS_NBAR); + PQCLEAN_FRODOKEM1344SHAKE_OPT_sample_n(Ep, PARAMS_N * PARAMS_NBAR); + PQCLEAN_FRODOKEM1344SHAKE_OPT_mul_add_sa_plus_e(Bp, Sp, Ep, pk_seedA); + PQCLEAN_FRODOKEM1344SHAKE_OPT_pack(ct_c1, (PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8, Bp, PARAMS_N * PARAMS_NBAR, PARAMS_LOGQ); + + // Generate Epp, and compute V = Sp*B + Epp + PQCLEAN_FRODOKEM1344SHAKE_OPT_sample_n(Epp, PARAMS_NBAR * PARAMS_NBAR); + PQCLEAN_FRODOKEM1344SHAKE_OPT_unpack(B, PARAMS_N * PARAMS_NBAR, pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, PARAMS_LOGQ); + PQCLEAN_FRODOKEM1344SHAKE_OPT_mul_add_sb_plus_e(V, B, Sp, Epp); + + // Encode mu, and compute C = V + enc(mu) (mod q) + PQCLEAN_FRODOKEM1344SHAKE_OPT_key_encode(C, (uint16_t *)mu); + PQCLEAN_FRODOKEM1344SHAKE_OPT_add(C, V, C); + PQCLEAN_FRODOKEM1344SHAKE_OPT_pack(ct_c2, (PARAMS_LOGQ * PARAMS_NBAR * PARAMS_NBAR) / 8, C, PARAMS_NBAR * PARAMS_NBAR, PARAMS_LOGQ); + + // Compute ss = F(ct||KK) + memcpy(Fin_ct, ct, CRYPTO_CIPHERTEXTBYTES); + memcpy(Fin_k, k, CRYPTO_BYTES); + shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES); + + // Cleanup: + PQCLEAN_FRODOKEM1344SHAKE_OPT_clear_bytes((uint8_t *)V, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM1344SHAKE_OPT_clear_bytes((uint8_t *)Sp, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM1344SHAKE_OPT_clear_bytes((uint8_t *)Ep, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM1344SHAKE_OPT_clear_bytes((uint8_t *)Epp, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM1344SHAKE_OPT_clear_bytes(mu, BYTES_MU); + PQCLEAN_FRODOKEM1344SHAKE_OPT_clear_bytes(G2out, 2 * CRYPTO_BYTES); + PQCLEAN_FRODOKEM1344SHAKE_OPT_clear_bytes(Fin_k, CRYPTO_BYTES); + PQCLEAN_FRODOKEM1344SHAKE_OPT_clear_bytes(shake_input_seedSE, 1 + CRYPTO_BYTES); + return 0; +} + + +int PQCLEAN_FRODOKEM1344SHAKE_OPT_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk) { + // FrodoKEM's key decapsulation + uint16_t B[PARAMS_N * PARAMS_NBAR] = {0}; + uint16_t Bp[PARAMS_N * PARAMS_NBAR] = {0}; + uint16_t W[PARAMS_NBAR * PARAMS_NBAR] = {0}; // contains secret data + uint16_t C[PARAMS_NBAR * PARAMS_NBAR] = {0}; + uint16_t CC[PARAMS_NBAR * PARAMS_NBAR] = {0}; + uint16_t BBp[PARAMS_N * PARAMS_NBAR] = {0}; + uint16_t Sp[(2 * PARAMS_N + PARAMS_NBAR)*PARAMS_NBAR] = {0}; // contains secret data + uint16_t *Ep = &Sp[PARAMS_N * PARAMS_NBAR]; // contains secret data + uint16_t *Epp = &Sp[2 * PARAMS_N * PARAMS_NBAR]; // contains secret data + const uint8_t *ct_c1 = &ct[0]; + const uint8_t *ct_c2 = &ct[(PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8]; + const uint8_t *sk_s = &sk[0]; + const uint8_t *sk_pk = &sk[CRYPTO_BYTES]; + const uint16_t *sk_S = (uint16_t *) &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES]; + uint16_t S[PARAMS_N * PARAMS_NBAR]; // contains secret data + const uint8_t *sk_pkh = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES + 2 * PARAMS_N * PARAMS_NBAR]; + const uint8_t *pk_seedA = &sk_pk[0]; + const uint8_t *pk_b = &sk_pk[BYTES_SEED_A]; + uint8_t G2in[BYTES_PKHASH + BYTES_MU]; // contains secret data via muprime + uint8_t *pkh = &G2in[0]; + uint8_t *muprime = &G2in[BYTES_PKHASH]; // contains secret data + uint8_t G2out[2 * CRYPTO_BYTES]; // contains secret data + uint8_t *seedSEprime = &G2out[0]; // contains secret data + uint8_t *kprime = &G2out[CRYPTO_BYTES]; // contains secret data + uint8_t Fin[CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES]; // contains secret data via Fin_k + uint8_t *Fin_ct = &Fin[0]; + uint8_t *Fin_k = &Fin[CRYPTO_CIPHERTEXTBYTES]; // contains secret data + uint8_t shake_input_seedSEprime[1 + CRYPTO_BYTES]; // contains secret data + + for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) { + S[i] = PQCLEAN_FRODOKEM1344SHAKE_OPT_LE_TO_UINT16(sk_S[i]); + } + + // Compute W = C - Bp*S (mod q), and decode the randomness mu + PQCLEAN_FRODOKEM1344SHAKE_OPT_unpack(Bp, PARAMS_N * PARAMS_NBAR, ct_c1, (PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8, PARAMS_LOGQ); + PQCLEAN_FRODOKEM1344SHAKE_OPT_unpack(C, PARAMS_NBAR * PARAMS_NBAR, ct_c2, (PARAMS_LOGQ * PARAMS_NBAR * PARAMS_NBAR) / 8, PARAMS_LOGQ); + PQCLEAN_FRODOKEM1344SHAKE_OPT_mul_bs(W, Bp, S); + PQCLEAN_FRODOKEM1344SHAKE_OPT_sub(W, C, W); + PQCLEAN_FRODOKEM1344SHAKE_OPT_key_decode((uint16_t *)muprime, W); + + // Generate (seedSE' || k') = G_2(pkh || mu') + memcpy(pkh, sk_pkh, BYTES_PKHASH); + shake(G2out, CRYPTO_BYTES + CRYPTO_BYTES, G2in, BYTES_PKHASH + BYTES_MU); + + // Generate Sp and Ep, and compute BBp = Sp*A + Ep. Generate A on-the-fly + shake_input_seedSEprime[0] = 0x96; + memcpy(&shake_input_seedSEprime[1], seedSEprime, CRYPTO_BYTES); + shake((uint8_t *)Sp, (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSEprime, 1 + CRYPTO_BYTES); + for (size_t i = 0; i < (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR; i++) { + Sp[i] = PQCLEAN_FRODOKEM1344SHAKE_OPT_LE_TO_UINT16(Sp[i]); + } + PQCLEAN_FRODOKEM1344SHAKE_OPT_sample_n(Sp, PARAMS_N * PARAMS_NBAR); + PQCLEAN_FRODOKEM1344SHAKE_OPT_sample_n(Ep, PARAMS_N * PARAMS_NBAR); + PQCLEAN_FRODOKEM1344SHAKE_OPT_mul_add_sa_plus_e(BBp, Sp, Ep, pk_seedA); + + // Generate Epp, and compute W = Sp*B + Epp + PQCLEAN_FRODOKEM1344SHAKE_OPT_sample_n(Epp, PARAMS_NBAR * PARAMS_NBAR); + PQCLEAN_FRODOKEM1344SHAKE_OPT_unpack(B, PARAMS_N * PARAMS_NBAR, pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, PARAMS_LOGQ); + PQCLEAN_FRODOKEM1344SHAKE_OPT_mul_add_sb_plus_e(W, B, Sp, Epp); + + // Encode mu, and compute CC = W + enc(mu') (mod q) + PQCLEAN_FRODOKEM1344SHAKE_OPT_key_encode(CC, (uint16_t *)muprime); + PQCLEAN_FRODOKEM1344SHAKE_OPT_add(CC, W, CC); + + // Prepare input to F + memcpy(Fin_ct, ct, CRYPTO_CIPHERTEXTBYTES); + + // Reducing BBp modulo q + for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) { + BBp[i] = BBp[i] & ((1 << PARAMS_LOGQ) - 1); + } + + // Is (Bp == BBp & C == CC) = true + if (memcmp(Bp, BBp, 2 * PARAMS_N * PARAMS_NBAR) == 0 && memcmp(C, CC, 2 * PARAMS_NBAR * PARAMS_NBAR) == 0) { + // Load k' to do ss = F(ct || k') + memcpy(Fin_k, kprime, CRYPTO_BYTES); + } else { + // Load s to do ss = F(ct || s) + memcpy(Fin_k, sk_s, CRYPTO_BYTES); + } + shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES); + + // Cleanup: + PQCLEAN_FRODOKEM1344SHAKE_OPT_clear_bytes((uint8_t *)W, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM1344SHAKE_OPT_clear_bytes((uint8_t *)Sp, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM1344SHAKE_OPT_clear_bytes((uint8_t *)S, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM1344SHAKE_OPT_clear_bytes((uint8_t *)Ep, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM1344SHAKE_OPT_clear_bytes((uint8_t *)Epp, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM1344SHAKE_OPT_clear_bytes(muprime, BYTES_MU); + PQCLEAN_FRODOKEM1344SHAKE_OPT_clear_bytes(G2out, 2 * CRYPTO_BYTES); + PQCLEAN_FRODOKEM1344SHAKE_OPT_clear_bytes(Fin_k, CRYPTO_BYTES); + PQCLEAN_FRODOKEM1344SHAKE_OPT_clear_bytes(shake_input_seedSEprime, 1 + CRYPTO_BYTES); + return 0; +} diff --git a/crypto_kem/frodokem1344shake/opt/matrix_shake.c b/crypto_kem/frodokem1344shake/opt/matrix_shake.c new file mode 100644 index 00000000..7fab5e5f --- /dev/null +++ b/crypto_kem/frodokem1344shake/opt/matrix_shake.c @@ -0,0 +1,108 @@ +/******************************************************************************************** +* FrodoKEM: Learning with Errors Key Encapsulation +* +* Abstract: matrix arithmetic functions used by the KEM +*********************************************************************************************/ + +#include +#include + +#include "fips202.h" + +#include "api.h" +#include "common.h" +#include "params.h" + +int PQCLEAN_FRODOKEM1344SHAKE_OPT_mul_add_as_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A) { + // Generate-and-multiply: generate matrix A (N x N) row-wise, multiply by s on the right. + // Inputs: s, e (N x N_BAR) + // Output: out = A*s + e (N x N_BAR) + int j, k; + uint16_t i; + int16_t a_row[4 * PARAMS_N]; + + for (i = 0; i < (PARAMS_N * PARAMS_NBAR); i += 2) { + *((uint32_t *)&out[i]) = *((uint32_t *)&e[i]); + } + + uint8_t seed_A_separated[2 + BYTES_SEED_A]; + uint16_t *seed_A_origin = (uint16_t *)&seed_A_separated; + memcpy(&seed_A_separated[2], seed_A, BYTES_SEED_A); + for (i = 0; i < PARAMS_N; i += 4) { + seed_A_origin[0] = PQCLEAN_FRODOKEM1344SHAKE_OPT_UINT16_TO_LE(i + 0); + shake128((unsigned char *)(a_row + 0 * PARAMS_N), (unsigned long long)(2 * PARAMS_N), seed_A_separated, 2 + BYTES_SEED_A); + seed_A_origin[0] = PQCLEAN_FRODOKEM1344SHAKE_OPT_UINT16_TO_LE(i + 1); + shake128((unsigned char *)(a_row + 1 * PARAMS_N), (unsigned long long)(2 * PARAMS_N), seed_A_separated, 2 + BYTES_SEED_A); + seed_A_origin[0] = PQCLEAN_FRODOKEM1344SHAKE_OPT_UINT16_TO_LE(i + 2); + shake128((unsigned char *)(a_row + 2 * PARAMS_N), (unsigned long long)(2 * PARAMS_N), seed_A_separated, 2 + BYTES_SEED_A); + seed_A_origin[0] = PQCLEAN_FRODOKEM1344SHAKE_OPT_UINT16_TO_LE(i + 3); + shake128((unsigned char *)(a_row + 3 * PARAMS_N), (unsigned long long)(2 * PARAMS_N), seed_A_separated, 2 + BYTES_SEED_A); + for (k = 0; k < 4 * PARAMS_N; k++) { + a_row[k] = PQCLEAN_FRODOKEM1344SHAKE_OPT_LE_TO_UINT16(a_row[k]); + } + for (k = 0; k < PARAMS_NBAR; k++) { + uint16_t sum[4] = {0}; + for (j = 0; j < PARAMS_N; j++) { // Matrix-vector multiplication + uint16_t sp = s[k * PARAMS_N + j]; + sum[0] += a_row[0 * PARAMS_N + j] * sp; // Go through four lines with same s + sum[1] += a_row[1 * PARAMS_N + j] * sp; + sum[2] += a_row[2 * PARAMS_N + j] * sp; + sum[3] += a_row[3 * PARAMS_N + j] * sp; + } + out[(i + 0)*PARAMS_NBAR + k] += sum[0]; + out[(i + 2)*PARAMS_NBAR + k] += sum[2]; + out[(i + 1)*PARAMS_NBAR + k] += sum[1]; + out[(i + 3)*PARAMS_NBAR + k] += sum[3]; + } + } + return 1; +} + + + + +int PQCLEAN_FRODOKEM1344SHAKE_OPT_mul_add_sa_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A) { + // Generate-and-multiply: generate matrix A (N x N) column-wise, multiply by s' on the left. + // Inputs: s', e' (N_BAR x N) + // Output: out = s'*A + e' (N_BAR x N) + int i, j; + uint16_t kk; + for (i = 0; i < (PARAMS_N * PARAMS_NBAR); i += 2) { + *((uint32_t *)&out[i]) = *((uint32_t *)&e[i]); + } + + int t = 0; + uint16_t a_cols[4 * PARAMS_N]; + + int k; + uint8_t seed_A_separated[2 + BYTES_SEED_A]; + uint16_t *seed_A_origin = (uint16_t *)&seed_A_separated; + memcpy(&seed_A_separated[2], seed_A, BYTES_SEED_A); + for (kk = 0; kk < PARAMS_N; kk += 4) { + seed_A_origin[0] = PQCLEAN_FRODOKEM1344SHAKE_OPT_UINT16_TO_LE(kk + 0); + shake128((unsigned char *)(a_cols + 0 * PARAMS_N), (unsigned long long)(2 * PARAMS_N), seed_A_separated, 2 + BYTES_SEED_A); + seed_A_origin[0] = PQCLEAN_FRODOKEM1344SHAKE_OPT_UINT16_TO_LE(kk + 1); + shake128((unsigned char *)(a_cols + 1 * PARAMS_N), (unsigned long long)(2 * PARAMS_N), seed_A_separated, 2 + BYTES_SEED_A); + seed_A_origin[0] = PQCLEAN_FRODOKEM1344SHAKE_OPT_UINT16_TO_LE(kk + 2); + shake128((unsigned char *)(a_cols + 2 * PARAMS_N), (unsigned long long)(2 * PARAMS_N), seed_A_separated, 2 + BYTES_SEED_A); + seed_A_origin[0] = PQCLEAN_FRODOKEM1344SHAKE_OPT_UINT16_TO_LE(kk + 3); + shake128((unsigned char *)(a_cols + 3 * PARAMS_N), (unsigned long long)(2 * PARAMS_N), seed_A_separated, 2 + BYTES_SEED_A); + for (i = 0; i < 4 * PARAMS_N; i++) { + a_cols[i] = PQCLEAN_FRODOKEM1344SHAKE_OPT_LE_TO_UINT16(a_cols[i]); + } + + for (i = 0; i < PARAMS_NBAR; i++) { + uint16_t sum[PARAMS_N] = {0}; + for (j = 0; j < 4; j++) { + uint16_t sp = s[i * PARAMS_N + kk + j]; + for (k = 0; k < PARAMS_N; k++) { // Matrix-vector multiplication + sum[k] += sp * a_cols[(t + j) * PARAMS_N + k]; + } + } + for (k = 0; k < PARAMS_N; k++) { + out[i * PARAMS_N + k] += sum[k]; + } + } + } + return 1; +} diff --git a/crypto_kem/frodokem1344shake/opt/noise.c b/crypto_kem/frodokem1344shake/opt/noise.c new file mode 100644 index 00000000..b64fe022 --- /dev/null +++ b/crypto_kem/frodokem1344shake/opt/noise.c @@ -0,0 +1,35 @@ +/******************************************************************************************** +* FrodoKEM: Learning with Errors Key Encapsulation +* +* Abstract: noise sampling functions +*********************************************************************************************/ + +#include + +#include "api.h" +#include "common.h" +#include "params.h" + +static uint16_t CDF_TABLE[CDF_TABLE_LEN] = CDF_TABLE_DATA; + +void PQCLEAN_FRODOKEM1344SHAKE_OPT_sample_n(uint16_t *s, size_t n) { + // Fills vector s with n samples from the noise distribution which requires 16 bits to sample. + // The distribution is specified by its CDF. + // Input: pseudo-random values (2*n bytes) passed in s. The input is overwritten by the output. + size_t i; + unsigned int j; + + for (i = 0; i < n; ++i) { + uint16_t sample = 0; + uint16_t prnd = s[i] >> 1; // Drop the least significant bit + uint16_t sign = s[i] & 0x1; // Pick the least significant bit + + // No need to compare with the last value. + for (j = 0; j < (unsigned int)(CDF_TABLE_LEN - 1); j++) { + // Constant time comparison: 1 if CDF_TABLE[j] < s, 0 otherwise. Uses the fact that CDF_TABLE[j] and s fit in 15 bits. + sample += (uint16_t)(CDF_TABLE[j] - prnd) >> 15; + } + // Assuming that sign is either 0 or 1, flips sample iff sign = 1 + s[i] = ((-sign) ^ sample) + sign; + } +} diff --git a/crypto_kem/frodokem1344shake/opt/params.h b/crypto_kem/frodokem1344shake/opt/params.h new file mode 100644 index 00000000..c7d91d49 --- /dev/null +++ b/crypto_kem/frodokem1344shake/opt/params.h @@ -0,0 +1,27 @@ +#ifndef PARAMS_H +#define PARAMS_H + +#define CRYPTO_SECRETKEYBYTES PQCLEAN_FRODOKEM1344SHAKE_OPT_CRYPTO_SECRETKEYBYTES +#define CRYPTO_PUBLICKEYBYTES PQCLEAN_FRODOKEM1344SHAKE_OPT_CRYPTO_PUBLICKEYBYTES +#define CRYPTO_BYTES PQCLEAN_FRODOKEM1344SHAKE_OPT_CRYPTO_BYTES +#define CRYPTO_CIPHERTEXTBYTES PQCLEAN_FRODOKEM1344SHAKE_OPT_CRYPTO_CIPHERTEXTBYTES + +#define PARAMS_N 1344 +#define PARAMS_NBAR 8 +#define PARAMS_LOGQ 16 +#define PARAMS_Q (1 << PARAMS_LOGQ) +#define PARAMS_EXTRACTED_BITS 4 +#define PARAMS_STRIPE_STEP 8 +#define PARAMS_PARALLEL 4 +#define BYTES_SEED_A 16 +#define BYTES_MU ((PARAMS_EXTRACTED_BITS * PARAMS_NBAR * PARAMS_NBAR) / 8) +#define BYTES_PKHASH CRYPTO_BYTES + +// Selecting SHAKE XOF function for the KEM and noise sampling +#define shake shake256 + +// CDF table +#define CDF_TABLE_DATA {9142, 23462, 30338, 32361, 32725, 32765, 32767} +#define CDF_TABLE_LEN 7 + +#endif diff --git a/crypto_kem/frodokem1344shake/opt/util.c b/crypto_kem/frodokem1344shake/opt/util.c new file mode 100644 index 00000000..22606c95 --- /dev/null +++ b/crypto_kem/frodokem1344shake/opt/util.c @@ -0,0 +1,235 @@ +/******************************************************************************************** +* FrodoKEM: Learning with Errors Key Encapsulation +* +* Abstract: additional functions for FrodoKEM +*********************************************************************************************/ + +#include +#include + +#include "api.h" +#include "common.h" +#include "params.h" + +#define min(x, y) (((x) < (y)) ? (x) : (y)) + +uint16_t PQCLEAN_FRODOKEM1344SHAKE_OPT_LE_TO_UINT16(uint16_t n) { + return (((uint8_t *) &n)[0] | (((uint8_t *) &n)[1] << 8)); +} + +uint16_t PQCLEAN_FRODOKEM1344SHAKE_OPT_UINT16_TO_LE(uint16_t n) { + uint16_t y; + uint8_t *z = (uint8_t *) &y; + z[0] = n & 0xFF; + z[1] = (n & 0xFF00) >> 8; + return y; +} + +void PQCLEAN_FRODOKEM1344SHAKE_OPT_mul_bs(uint16_t *out, const uint16_t *b, const uint16_t *s) { + // Multiply by s on the right + // Inputs: b (N_BAR x N), s (N x N_BAR) + // Output: out = b*s (N_BAR x N_BAR) + int i, j, k; + + for (i = 0; i < PARAMS_NBAR; i++) { + for (j = 0; j < PARAMS_NBAR; j++) { + out[i * PARAMS_NBAR + j] = 0; + for (k = 0; k < PARAMS_N; k++) { + out[i * PARAMS_NBAR + j] += b[i * PARAMS_N + k] * s[j * PARAMS_N + k]; + } + out[i * PARAMS_NBAR + j] = (uint32_t)(out[i * PARAMS_NBAR + j]) & ((1 << PARAMS_LOGQ) - 1); + } + } +} + + +void PQCLEAN_FRODOKEM1344SHAKE_OPT_mul_add_sb_plus_e(uint16_t *out, const uint16_t *b, const uint16_t *s, const uint16_t *e) { + // Multiply by s on the left + // Inputs: b (N x N_BAR), s (N_BAR x N), e (N_BAR x N_BAR) + // Output: out = s*b + e (N_BAR x N_BAR) + int i, j, k; + + for (k = 0; k < PARAMS_NBAR; k++) { + for (i = 0; i < PARAMS_NBAR; i++) { + out[k * PARAMS_NBAR + i] = e[k * PARAMS_NBAR + i]; + for (j = 0; j < PARAMS_N; j++) { + out[k * PARAMS_NBAR + i] += s[k * PARAMS_N + j] * b[j * PARAMS_NBAR + i]; + } + out[k * PARAMS_NBAR + i] = (uint32_t)(out[k * PARAMS_NBAR + i]) & ((1 << PARAMS_LOGQ) - 1); + } + } +} + + +void PQCLEAN_FRODOKEM1344SHAKE_OPT_add(uint16_t *out, const uint16_t *a, const uint16_t *b) { + // Add a and b + // Inputs: a, b (N_BAR x N_BAR) + // Output: c = a + b + + for (size_t i = 0; i < (PARAMS_NBAR * PARAMS_NBAR); i++) { + out[i] = (a[i] + b[i]) & ((1 << PARAMS_LOGQ) - 1); + } +} + + +void PQCLEAN_FRODOKEM1344SHAKE_OPT_sub(uint16_t *out, const uint16_t *a, const uint16_t *b) { + // Subtract a and b + // Inputs: a, b (N_BAR x N_BAR) + // Output: c = a - b + + for (size_t i = 0; i < (PARAMS_NBAR * PARAMS_NBAR); i++) { + out[i] = (a[i] - b[i]) & ((1 << PARAMS_LOGQ) - 1); + } +} + + +void PQCLEAN_FRODOKEM1344SHAKE_OPT_key_encode(uint16_t *out, const uint16_t *in) { + // Encoding + unsigned int i, j, npieces_word = 8; + unsigned int nwords = (PARAMS_NBAR * PARAMS_NBAR) / 8; + uint64_t temp, mask = ((uint64_t)1 << PARAMS_EXTRACTED_BITS) - 1; + uint16_t *pos = out; + + for (i = 0; i < nwords; i++) { + temp = 0; + for (j = 0; j < PARAMS_EXTRACTED_BITS; j++) { + temp |= ((uint64_t)((uint8_t *)in)[i * PARAMS_EXTRACTED_BITS + j]) << (8 * j); + } + for (j = 0; j < npieces_word; j++) { + *pos = (uint16_t)((temp & mask) << (PARAMS_LOGQ - PARAMS_EXTRACTED_BITS)); + temp >>= PARAMS_EXTRACTED_BITS; + pos++; + } + } +} + + +void PQCLEAN_FRODOKEM1344SHAKE_OPT_key_decode(uint16_t *out, const uint16_t *in) { + // Decoding + unsigned int i, j, index = 0, npieces_word = 8; + unsigned int nwords = (PARAMS_NBAR * PARAMS_NBAR) / 8; + uint16_t temp, maskex = ((uint16_t)1 << PARAMS_EXTRACTED_BITS) - 1, maskq = ((uint16_t)1 << PARAMS_LOGQ) - 1; + uint8_t *pos = (uint8_t *)out; + uint64_t templong; + + for (i = 0; i < nwords; i++) { + templong = 0; + for (j = 0; j < npieces_word; j++) { // temp = floor(in*2^{-11}+0.5) + temp = ((in[index] & maskq) + (1 << (PARAMS_LOGQ - PARAMS_EXTRACTED_BITS - 1))) >> (PARAMS_LOGQ - PARAMS_EXTRACTED_BITS); + templong |= ((uint64_t)(temp & maskex)) << (PARAMS_EXTRACTED_BITS * j); + index++; + } + for (j = 0; j < PARAMS_EXTRACTED_BITS; j++) { + pos[i * PARAMS_EXTRACTED_BITS + j] = (templong >> (8 * j)) & 0xFF; + } + } +} + + +void PQCLEAN_FRODOKEM1344SHAKE_OPT_pack(uint8_t *out, size_t outlen, const uint16_t *in, size_t inlen, uint8_t lsb) { + // Pack the input uint16 vector into a char output vector, copying lsb bits from each input element. + // If inlen * lsb / 8 > outlen, only outlen * 8 bits are copied. + memset(out, 0, outlen); + + size_t i = 0; // whole bytes already filled in + size_t j = 0; // whole uint16_t already copied + uint16_t w = 0; // the leftover, not yet copied + uint8_t bits = 0; // the number of lsb in w + + while (i < outlen && (j < inlen || ((j == inlen) && (bits > 0)))) { + /* + in: | | |********|********| + ^ + j + w : | ****| + ^ + bits + out:|**|**|**|**|**|**|**|**|* | + ^^ + ib + */ + uint8_t b = 0; // bits in out[i] already filled in + while (b < 8) { + int nbits = min(8 - b, bits); + uint16_t mask = (1 << nbits) - 1; + uint8_t t = (uint8_t) ((w >> (bits - nbits)) & mask); // the bits to copy from w to out + out[i] = out[i] + (t << (8 - b - nbits)); + b += (uint8_t) nbits; + bits -= (uint8_t) nbits; + w &= ~(mask << bits); // not strictly necessary; mostly for debugging + + if (bits == 0) { + if (j < inlen) { + w = in[j]; + bits = lsb; + j++; + } else { + break; // the input vector is exhausted + } + } + } + if (b == 8) { // out[i] is filled in + i++; + } + } +} + + +void PQCLEAN_FRODOKEM1344SHAKE_OPT_unpack(uint16_t *out, size_t outlen, const uint8_t *in, size_t inlen, uint8_t lsb) { + // Unpack the input char vector into a uint16_t output vector, copying lsb bits + // for each output element from input. outlen must be at least ceil(inlen * 8 / lsb). + memset(out, 0, outlen * sizeof(uint16_t)); + + size_t i = 0; // whole uint16_t already filled in + size_t j = 0; // whole bytes already copied + uint8_t w = 0; // the leftover, not yet copied + uint8_t bits = 0; // the number of lsb bits of w + + while (i < outlen && (j < inlen || ((j == inlen) && (bits > 0)))) { + /* + in: | | | | | | |**|**|... + ^ + j + w : | *| + ^ + bits + out:| *****| *****| *** | |... + ^ ^ + i b + */ + uint8_t b = 0; // bits in out[i] already filled in + while (b < lsb) { + int nbits = min(lsb - b, bits); + uint16_t mask = (1 << nbits) - 1; + uint8_t t = (w >> (bits - nbits)) & mask; // the bits to copy from w to out + out[i] = out[i] + (t << (lsb - b - nbits)); + b += (uint8_t) nbits; + bits -= (uint8_t) nbits; + w &= ~(mask << bits); // not strictly necessary; mostly for debugging + + if (bits == 0) { + if (j < inlen) { + w = in[j]; + bits = 8; + j++; + } else { + break; // the input vector is exhausted + } + } + } + if (b == lsb) { // out[i] is filled in + i++; + } + } +} + + +void PQCLEAN_FRODOKEM1344SHAKE_OPT_clear_bytes(uint8_t *mem, size_t n) { + // Clear 8-bit bytes from memory. "n" indicates the number of bytes to be zeroed. + // This function uses the volatile type qualifier to inform the compiler not to optimize out the memory clearing. + volatile uint8_t *v = mem; + + for (size_t i = 0; i < n; i++) { + v[i] = 0; + } +} diff --git a/crypto_kem/frodokem640aes/META.yml b/crypto_kem/frodokem640aes/META.yml index a4932688..1e462e5d 100644 --- a/crypto_kem/frodokem640aes/META.yml +++ b/crypto_kem/frodokem640aes/META.yml @@ -23,3 +23,5 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/Microsoft/PQCrypto-LWEKE/commit/d5bbd0417ba111b08a959c0042a1dcc65fb14a89 +- name: opt + version: https://github.com/Microsoft/PQCrypto-LWEKE/commit/d5bbd0417ba111b08a959c0042a1dcc65fb14a89 diff --git a/crypto_kem/frodokem640aes/clean/Makefile b/crypto_kem/frodokem640aes/clean/Makefile index 81e5d62d..efddb726 100644 --- a/crypto_kem/frodokem640aes/clean/Makefile +++ b/crypto_kem/frodokem640aes/clean/Makefile @@ -4,7 +4,7 @@ LIB=libfrodokem640aes_clean.a HEADERS=api.h params.h common.h OBJECTS=kem.o matrix_aes.o noise.o util.o -CFLAGS=-O3 -Wall -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_kem/frodokem640aes/opt/LICENSE b/crypto_kem/frodokem640aes/opt/LICENSE new file mode 100644 index 00000000..5cf7c8db --- /dev/null +++ b/crypto_kem/frodokem640aes/opt/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) Microsoft Corporation. All rights reserved. + +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/frodokem640aes/opt/Makefile b/crypto_kem/frodokem640aes/opt/Makefile new file mode 100644 index 00000000..1dfc87fc --- /dev/null +++ b/crypto_kem/frodokem640aes/opt/Makefile @@ -0,0 +1,19 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libfrodokem640aes_opt.a +HEADERS=api.h params.h common.h +OBJECTS=kem.o matrix_aes.o noise.o util.o + +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -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/frodokem640aes/opt/Makefile.Microsoft_nmake b/crypto_kem/frodokem640aes/opt/Makefile.Microsoft_nmake new file mode 100644 index 00000000..ce195a97 --- /dev/null +++ b/crypto_kem/frodokem640aes/opt/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=libfrodokem640aes_opt.lib +OBJECTS=kem.obj matrix_aes.obj noise.obj util.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/frodokem640aes/opt/api.h b/crypto_kem/frodokem640aes/opt/api.h new file mode 100644 index 00000000..896e73c2 --- /dev/null +++ b/crypto_kem/frodokem640aes/opt/api.h @@ -0,0 +1,20 @@ +#ifndef PQCLEAN_FRODOKEM640AES_OPT_API_H +#define PQCLEAN_FRODOKEM640AES_OPT_API_H + +#include +#include + +#define PQCLEAN_FRODOKEM640AES_OPT_CRYPTO_SECRETKEYBYTES 19888 // sizeof(s) + CRYPTO_PUBLICKEYBYTES + 2*PARAMS_N*PARAMS_NBAR + BYTES_PKHASH +#define PQCLEAN_FRODOKEM640AES_OPT_CRYPTO_PUBLICKEYBYTES 9616 // sizeof(seed_A) + (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 +#define PQCLEAN_FRODOKEM640AES_OPT_CRYPTO_BYTES 16 +#define PQCLEAN_FRODOKEM640AES_OPT_CRYPTO_CIPHERTEXTBYTES 9720 // (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 + (PARAMS_LOGQ*PARAMS_NBAR*PARAMS_NBAR)/8 + +#define PQCLEAN_FRODOKEM640AES_OPT_CRYPTO_ALGNAME "FrodoKEM-640-AES" + +int PQCLEAN_FRODOKEM640AES_OPT_crypto_kem_keypair(uint8_t *pk, uint8_t *sk); + +int PQCLEAN_FRODOKEM640AES_OPT_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk); + +int PQCLEAN_FRODOKEM640AES_OPT_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk); + +#endif diff --git a/crypto_kem/frodokem640aes/opt/common.h b/crypto_kem/frodokem640aes/opt/common.h new file mode 100644 index 00000000..ea2f4d6d --- /dev/null +++ b/crypto_kem/frodokem640aes/opt/common.h @@ -0,0 +1,19 @@ +#ifndef COMMON_H +#define COMMON_H + +int PQCLEAN_FRODOKEM640AES_OPT_mul_add_as_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A); +int PQCLEAN_FRODOKEM640AES_OPT_mul_add_sa_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A); +void PQCLEAN_FRODOKEM640AES_OPT_sample_n(uint16_t *s, size_t n); +void PQCLEAN_FRODOKEM640AES_OPT_mul_bs(uint16_t *out, const uint16_t *b, const uint16_t *s); +void PQCLEAN_FRODOKEM640AES_OPT_mul_add_sb_plus_e(uint16_t *out, const uint16_t *b, const uint16_t *s, const uint16_t *e); +void PQCLEAN_FRODOKEM640AES_OPT_add(uint16_t *out, const uint16_t *a, const uint16_t *b); +void PQCLEAN_FRODOKEM640AES_OPT_sub(uint16_t *out, const uint16_t *a, const uint16_t *b); +void PQCLEAN_FRODOKEM640AES_OPT_key_encode(uint16_t *out, const uint16_t *in); +void PQCLEAN_FRODOKEM640AES_OPT_key_decode(uint16_t *out, const uint16_t *in); +void PQCLEAN_FRODOKEM640AES_OPT_pack(uint8_t *out, size_t outlen, const uint16_t *in, size_t inlen, uint8_t lsb); +void PQCLEAN_FRODOKEM640AES_OPT_unpack(uint16_t *out, size_t outlen, const uint8_t *in, size_t inlen, uint8_t lsb); +void PQCLEAN_FRODOKEM640AES_OPT_clear_bytes(uint8_t *mem, size_t n); +uint16_t PQCLEAN_FRODOKEM640AES_OPT_LE_TO_UINT16(uint16_t n); +uint16_t PQCLEAN_FRODOKEM640AES_OPT_UINT16_TO_LE(uint16_t n); + +#endif diff --git a/crypto_kem/frodokem640aes/opt/kem.c b/crypto_kem/frodokem640aes/opt/kem.c new file mode 100644 index 00000000..386553a1 --- /dev/null +++ b/crypto_kem/frodokem640aes/opt/kem.c @@ -0,0 +1,238 @@ +/******************************************************************************************** +* FrodoKEM: Learning with Errors Key Encapsulation +* +* Abstract: Key Encapsulation Mechanism (KEM) based on Frodo +*********************************************************************************************/ + +#include +#include + +#include "fips202.h" +#include "randombytes.h" + +#include "api.h" +#include "common.h" +#include "params.h" + +int PQCLEAN_FRODOKEM640AES_OPT_crypto_kem_keypair(uint8_t *pk, uint8_t *sk) { + // FrodoKEM's key generation + // Outputs: public key pk ( BYTES_SEED_A + (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 bytes) + // secret key sk (CRYPTO_BYTES + BYTES_SEED_A + (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 + 2*PARAMS_N*PARAMS_NBAR + BYTES_PKHASH bytes) + uint8_t *pk_seedA = &pk[0]; + uint8_t *pk_b = &pk[BYTES_SEED_A]; + uint8_t *sk_s = &sk[0]; + uint8_t *sk_pk = &sk[CRYPTO_BYTES]; + uint8_t *sk_S = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES]; + uint8_t *sk_pkh = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES + 2 * PARAMS_N * PARAMS_NBAR]; + uint16_t B[PARAMS_N * PARAMS_NBAR] = {0}; + uint16_t S[2 * PARAMS_N * PARAMS_NBAR] = {0}; // contains secret data + uint16_t *E = &S[PARAMS_N * PARAMS_NBAR]; // contains secret data + uint8_t randomness[2 * CRYPTO_BYTES + BYTES_SEED_A]; // contains secret data via randomness_s and randomness_seedSE + uint8_t *randomness_s = &randomness[0]; // contains secret data + uint8_t *randomness_seedSE = &randomness[CRYPTO_BYTES]; // contains secret data + uint8_t *randomness_z = &randomness[2 * CRYPTO_BYTES]; + uint8_t shake_input_seedSE[1 + CRYPTO_BYTES]; // contains secret data + + // Generate the secret value s, the seed for S and E, and the seed for the seed for A. Add seed_A to the public key + randombytes(randomness, CRYPTO_BYTES + CRYPTO_BYTES + BYTES_SEED_A); + shake(pk_seedA, BYTES_SEED_A, randomness_z, BYTES_SEED_A); + + // Generate S and E, and compute B = A*S + E. Generate A on-the-fly + shake_input_seedSE[0] = 0x5F; + memcpy(&shake_input_seedSE[1], randomness_seedSE, CRYPTO_BYTES); + shake((uint8_t *)S, 2 * PARAMS_N * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSE, 1 + CRYPTO_BYTES); + for (size_t i = 0; i < 2 * PARAMS_N * PARAMS_NBAR; i++) { + S[i] = PQCLEAN_FRODOKEM640AES_OPT_LE_TO_UINT16(S[i]); + } + PQCLEAN_FRODOKEM640AES_OPT_sample_n(S, PARAMS_N * PARAMS_NBAR); + PQCLEAN_FRODOKEM640AES_OPT_sample_n(E, PARAMS_N * PARAMS_NBAR); + PQCLEAN_FRODOKEM640AES_OPT_mul_add_as_plus_e(B, S, E, pk); + + // Encode the second part of the public key + PQCLEAN_FRODOKEM640AES_OPT_pack(pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, B, PARAMS_N * PARAMS_NBAR, PARAMS_LOGQ); + + // Add s, pk and S to the secret key + memcpy(sk_s, randomness_s, CRYPTO_BYTES); + memcpy(sk_pk, pk, CRYPTO_PUBLICKEYBYTES); + for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) { + S[i] = PQCLEAN_FRODOKEM640AES_OPT_UINT16_TO_LE(S[i]); + } + memcpy(sk_S, S, 2 * PARAMS_N * PARAMS_NBAR); + + // Add H(pk) to the secret key + shake(sk_pkh, BYTES_PKHASH, pk, CRYPTO_PUBLICKEYBYTES); + + // Cleanup: + PQCLEAN_FRODOKEM640AES_OPT_clear_bytes((uint8_t *)S, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM640AES_OPT_clear_bytes((uint8_t *)E, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM640AES_OPT_clear_bytes(randomness, 2 * CRYPTO_BYTES); + PQCLEAN_FRODOKEM640AES_OPT_clear_bytes(shake_input_seedSE, 1 + CRYPTO_BYTES); + return 0; +} + + +int PQCLEAN_FRODOKEM640AES_OPT_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk) { + // FrodoKEM's key encapsulation + const uint8_t *pk_seedA = &pk[0]; + const uint8_t *pk_b = &pk[BYTES_SEED_A]; + uint8_t *ct_c1 = &ct[0]; + uint8_t *ct_c2 = &ct[(PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8]; + uint16_t B[PARAMS_N * PARAMS_NBAR] = {0}; + uint16_t V[PARAMS_NBAR * PARAMS_NBAR] = {0}; // contains secret data + uint16_t C[PARAMS_NBAR * PARAMS_NBAR] = {0}; + uint16_t Bp[PARAMS_N * PARAMS_NBAR] = {0}; + uint16_t Sp[(2 * PARAMS_N + PARAMS_NBAR)*PARAMS_NBAR] = {0}; // contains secret data + uint16_t *Ep = &Sp[PARAMS_N * PARAMS_NBAR]; // contains secret data + uint16_t *Epp = &Sp[2 * PARAMS_N * PARAMS_NBAR]; // contains secret data + uint8_t G2in[BYTES_PKHASH + BYTES_MU]; // contains secret data via mu + uint8_t *pkh = &G2in[0]; + uint8_t *mu = &G2in[BYTES_PKHASH]; // contains secret data + uint8_t G2out[2 * CRYPTO_BYTES]; // contains secret data + uint8_t *seedSE = &G2out[0]; // contains secret data + uint8_t *k = &G2out[CRYPTO_BYTES]; // contains secret data + uint8_t Fin[CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES]; // contains secret data via Fin_k + uint8_t *Fin_ct = &Fin[0]; + uint8_t *Fin_k = &Fin[CRYPTO_CIPHERTEXTBYTES]; // contains secret data + uint8_t shake_input_seedSE[1 + CRYPTO_BYTES]; // contains secret data + + // pkh <- G_1(pk), generate random mu, compute (seedSE || k) = G_2(pkh || mu) + shake(pkh, BYTES_PKHASH, pk, CRYPTO_PUBLICKEYBYTES); + randombytes(mu, BYTES_MU); + shake(G2out, CRYPTO_BYTES + CRYPTO_BYTES, G2in, BYTES_PKHASH + BYTES_MU); + + // Generate Sp and Ep, and compute Bp = Sp*A + Ep. Generate A on-the-fly + shake_input_seedSE[0] = 0x96; + memcpy(&shake_input_seedSE[1], seedSE, CRYPTO_BYTES); + shake((uint8_t *)Sp, (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSE, 1 + CRYPTO_BYTES); + for (size_t i = 0; i < (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR; i++) { + Sp[i] = PQCLEAN_FRODOKEM640AES_OPT_LE_TO_UINT16(Sp[i]); + } + PQCLEAN_FRODOKEM640AES_OPT_sample_n(Sp, PARAMS_N * PARAMS_NBAR); + PQCLEAN_FRODOKEM640AES_OPT_sample_n(Ep, PARAMS_N * PARAMS_NBAR); + PQCLEAN_FRODOKEM640AES_OPT_mul_add_sa_plus_e(Bp, Sp, Ep, pk_seedA); + PQCLEAN_FRODOKEM640AES_OPT_pack(ct_c1, (PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8, Bp, PARAMS_N * PARAMS_NBAR, PARAMS_LOGQ); + + // Generate Epp, and compute V = Sp*B + Epp + PQCLEAN_FRODOKEM640AES_OPT_sample_n(Epp, PARAMS_NBAR * PARAMS_NBAR); + PQCLEAN_FRODOKEM640AES_OPT_unpack(B, PARAMS_N * PARAMS_NBAR, pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, PARAMS_LOGQ); + PQCLEAN_FRODOKEM640AES_OPT_mul_add_sb_plus_e(V, B, Sp, Epp); + + // Encode mu, and compute C = V + enc(mu) (mod q) + PQCLEAN_FRODOKEM640AES_OPT_key_encode(C, (uint16_t *)mu); + PQCLEAN_FRODOKEM640AES_OPT_add(C, V, C); + PQCLEAN_FRODOKEM640AES_OPT_pack(ct_c2, (PARAMS_LOGQ * PARAMS_NBAR * PARAMS_NBAR) / 8, C, PARAMS_NBAR * PARAMS_NBAR, PARAMS_LOGQ); + + // Compute ss = F(ct||KK) + memcpy(Fin_ct, ct, CRYPTO_CIPHERTEXTBYTES); + memcpy(Fin_k, k, CRYPTO_BYTES); + shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES); + + // Cleanup: + PQCLEAN_FRODOKEM640AES_OPT_clear_bytes((uint8_t *)V, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM640AES_OPT_clear_bytes((uint8_t *)Sp, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM640AES_OPT_clear_bytes((uint8_t *)Ep, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM640AES_OPT_clear_bytes((uint8_t *)Epp, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM640AES_OPT_clear_bytes(mu, BYTES_MU); + PQCLEAN_FRODOKEM640AES_OPT_clear_bytes(G2out, 2 * CRYPTO_BYTES); + PQCLEAN_FRODOKEM640AES_OPT_clear_bytes(Fin_k, CRYPTO_BYTES); + PQCLEAN_FRODOKEM640AES_OPT_clear_bytes(shake_input_seedSE, 1 + CRYPTO_BYTES); + return 0; +} + + +int PQCLEAN_FRODOKEM640AES_OPT_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk) { + // FrodoKEM's key decapsulation + uint16_t B[PARAMS_N * PARAMS_NBAR] = {0}; + uint16_t Bp[PARAMS_N * PARAMS_NBAR] = {0}; + uint16_t W[PARAMS_NBAR * PARAMS_NBAR] = {0}; // contains secret data + uint16_t C[PARAMS_NBAR * PARAMS_NBAR] = {0}; + uint16_t CC[PARAMS_NBAR * PARAMS_NBAR] = {0}; + uint16_t BBp[PARAMS_N * PARAMS_NBAR] = {0}; + uint16_t Sp[(2 * PARAMS_N + PARAMS_NBAR)*PARAMS_NBAR] = {0}; // contains secret data + uint16_t *Ep = &Sp[PARAMS_N * PARAMS_NBAR]; // contains secret data + uint16_t *Epp = &Sp[2 * PARAMS_N * PARAMS_NBAR]; // contains secret data + const uint8_t *ct_c1 = &ct[0]; + const uint8_t *ct_c2 = &ct[(PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8]; + const uint8_t *sk_s = &sk[0]; + const uint8_t *sk_pk = &sk[CRYPTO_BYTES]; + const uint16_t *sk_S = (uint16_t *) &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES]; + uint16_t S[PARAMS_N * PARAMS_NBAR]; // contains secret data + const uint8_t *sk_pkh = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES + 2 * PARAMS_N * PARAMS_NBAR]; + const uint8_t *pk_seedA = &sk_pk[0]; + const uint8_t *pk_b = &sk_pk[BYTES_SEED_A]; + uint8_t G2in[BYTES_PKHASH + BYTES_MU]; // contains secret data via muprime + uint8_t *pkh = &G2in[0]; + uint8_t *muprime = &G2in[BYTES_PKHASH]; // contains secret data + uint8_t G2out[2 * CRYPTO_BYTES]; // contains secret data + uint8_t *seedSEprime = &G2out[0]; // contains secret data + uint8_t *kprime = &G2out[CRYPTO_BYTES]; // contains secret data + uint8_t Fin[CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES]; // contains secret data via Fin_k + uint8_t *Fin_ct = &Fin[0]; + uint8_t *Fin_k = &Fin[CRYPTO_CIPHERTEXTBYTES]; // contains secret data + uint8_t shake_input_seedSEprime[1 + CRYPTO_BYTES]; // contains secret data + + for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) { + S[i] = PQCLEAN_FRODOKEM640AES_OPT_LE_TO_UINT16(sk_S[i]); + } + + // Compute W = C - Bp*S (mod q), and decode the randomness mu + PQCLEAN_FRODOKEM640AES_OPT_unpack(Bp, PARAMS_N * PARAMS_NBAR, ct_c1, (PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8, PARAMS_LOGQ); + PQCLEAN_FRODOKEM640AES_OPT_unpack(C, PARAMS_NBAR * PARAMS_NBAR, ct_c2, (PARAMS_LOGQ * PARAMS_NBAR * PARAMS_NBAR) / 8, PARAMS_LOGQ); + PQCLEAN_FRODOKEM640AES_OPT_mul_bs(W, Bp, S); + PQCLEAN_FRODOKEM640AES_OPT_sub(W, C, W); + PQCLEAN_FRODOKEM640AES_OPT_key_decode((uint16_t *)muprime, W); + + // Generate (seedSE' || k') = G_2(pkh || mu') + memcpy(pkh, sk_pkh, BYTES_PKHASH); + shake(G2out, CRYPTO_BYTES + CRYPTO_BYTES, G2in, BYTES_PKHASH + BYTES_MU); + + // Generate Sp and Ep, and compute BBp = Sp*A + Ep. Generate A on-the-fly + shake_input_seedSEprime[0] = 0x96; + memcpy(&shake_input_seedSEprime[1], seedSEprime, CRYPTO_BYTES); + shake((uint8_t *)Sp, (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSEprime, 1 + CRYPTO_BYTES); + for (size_t i = 0; i < (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR; i++) { + Sp[i] = PQCLEAN_FRODOKEM640AES_OPT_LE_TO_UINT16(Sp[i]); + } + PQCLEAN_FRODOKEM640AES_OPT_sample_n(Sp, PARAMS_N * PARAMS_NBAR); + PQCLEAN_FRODOKEM640AES_OPT_sample_n(Ep, PARAMS_N * PARAMS_NBAR); + PQCLEAN_FRODOKEM640AES_OPT_mul_add_sa_plus_e(BBp, Sp, Ep, pk_seedA); + + // Generate Epp, and compute W = Sp*B + Epp + PQCLEAN_FRODOKEM640AES_OPT_sample_n(Epp, PARAMS_NBAR * PARAMS_NBAR); + PQCLEAN_FRODOKEM640AES_OPT_unpack(B, PARAMS_N * PARAMS_NBAR, pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, PARAMS_LOGQ); + PQCLEAN_FRODOKEM640AES_OPT_mul_add_sb_plus_e(W, B, Sp, Epp); + + // Encode mu, and compute CC = W + enc(mu') (mod q) + PQCLEAN_FRODOKEM640AES_OPT_key_encode(CC, (uint16_t *)muprime); + PQCLEAN_FRODOKEM640AES_OPT_add(CC, W, CC); + + // Prepare input to F + memcpy(Fin_ct, ct, CRYPTO_CIPHERTEXTBYTES); + + // Reducing BBp modulo q + for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) { + BBp[i] = BBp[i] & ((1 << PARAMS_LOGQ) - 1); + } + + // Is (Bp == BBp & C == CC) = true + if (memcmp(Bp, BBp, 2 * PARAMS_N * PARAMS_NBAR) == 0 && memcmp(C, CC, 2 * PARAMS_NBAR * PARAMS_NBAR) == 0) { + // Load k' to do ss = F(ct || k') + memcpy(Fin_k, kprime, CRYPTO_BYTES); + } else { + // Load s to do ss = F(ct || s) + memcpy(Fin_k, sk_s, CRYPTO_BYTES); + } + shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES); + + // Cleanup: + PQCLEAN_FRODOKEM640AES_OPT_clear_bytes((uint8_t *)W, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM640AES_OPT_clear_bytes((uint8_t *)Sp, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM640AES_OPT_clear_bytes((uint8_t *)S, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM640AES_OPT_clear_bytes((uint8_t *)Ep, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM640AES_OPT_clear_bytes((uint8_t *)Epp, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM640AES_OPT_clear_bytes(muprime, BYTES_MU); + PQCLEAN_FRODOKEM640AES_OPT_clear_bytes(G2out, 2 * CRYPTO_BYTES); + PQCLEAN_FRODOKEM640AES_OPT_clear_bytes(Fin_k, CRYPTO_BYTES); + PQCLEAN_FRODOKEM640AES_OPT_clear_bytes(shake_input_seedSEprime, 1 + CRYPTO_BYTES); + return 0; +} diff --git a/crypto_kem/frodokem640aes/opt/matrix_aes.c b/crypto_kem/frodokem640aes/opt/matrix_aes.c new file mode 100644 index 00000000..24372876 --- /dev/null +++ b/crypto_kem/frodokem640aes/opt/matrix_aes.c @@ -0,0 +1,125 @@ +/******************************************************************************************** +* FrodoKEM: Learning with Errors Key Encapsulation +* +* Abstract: matrix arithmetic functions used by the KEM +*********************************************************************************************/ + +#include +#include + +#include "aes.h" + +#include "api.h" +#include "common.h" +#include "params.h" + +int PQCLEAN_FRODOKEM640AES_OPT_mul_add_as_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A) { + // Generate-and-multiply: generate matrix A (N x N) row-wise, multiply by s on the right. + // Inputs: s, e (N x N_BAR) + // Output: out = A*s + e (N x N_BAR) + int k; + uint16_t i, j; + int16_t a_row[4 * PARAMS_N]; + + for (i = 0; i < (PARAMS_N * PARAMS_NBAR); i += 2) { + *((uint32_t *)&out[i]) = *((uint32_t *)&e[i]); + } + + int16_t a_row_temp[4 * PARAMS_N] = {0}; // Take four lines of A at once + aes128ctx ctx128; + + aes128_keyexp(&ctx128, seed_A); + + for (j = 0; j < PARAMS_N; j += PARAMS_STRIPE_STEP) { + a_row_temp[j + 1 + 0 * PARAMS_N] = PQCLEAN_FRODOKEM640AES_OPT_UINT16_TO_LE(j); // Loading values in the little-endian order + a_row_temp[j + 1 + 1 * PARAMS_N] = PQCLEAN_FRODOKEM640AES_OPT_UINT16_TO_LE(j); + a_row_temp[j + 1 + 2 * PARAMS_N] = PQCLEAN_FRODOKEM640AES_OPT_UINT16_TO_LE(j); + a_row_temp[j + 1 + 3 * PARAMS_N] = PQCLEAN_FRODOKEM640AES_OPT_UINT16_TO_LE(j); + } + + for (i = 0; i < PARAMS_N; i += 4) { + for (j = 0; j < PARAMS_N; j += PARAMS_STRIPE_STEP) { // Go through A, four rows at a time + a_row_temp[j + 0 * PARAMS_N] = PQCLEAN_FRODOKEM640AES_OPT_UINT16_TO_LE(i + 0); // Loading values in the little-endian order + a_row_temp[j + 1 * PARAMS_N] = PQCLEAN_FRODOKEM640AES_OPT_UINT16_TO_LE(i + 1); + a_row_temp[j + 2 * PARAMS_N] = PQCLEAN_FRODOKEM640AES_OPT_UINT16_TO_LE(i + 2); + a_row_temp[j + 3 * PARAMS_N] = PQCLEAN_FRODOKEM640AES_OPT_UINT16_TO_LE(i + 3); + } + aes128_ecb((uint8_t *)a_row, (uint8_t *)a_row_temp, 4 * PARAMS_N * sizeof(int16_t) / AES_BLOCKBYTES, &ctx128); + for (k = 0; k < 4 * PARAMS_N; k++) { + a_row[k] = PQCLEAN_FRODOKEM640AES_OPT_LE_TO_UINT16(a_row[k]); + } + for (k = 0; k < PARAMS_NBAR; k++) { + uint16_t sum[4] = {0}; + for (j = 0; j < PARAMS_N; j++) { // Matrix-vector multiplication + uint16_t sp = s[k * PARAMS_N + j]; + sum[0] += a_row[0 * PARAMS_N + j] * sp; // Go through four lines with same s + sum[1] += a_row[1 * PARAMS_N + j] * sp; + sum[2] += a_row[2 * PARAMS_N + j] * sp; + sum[3] += a_row[3 * PARAMS_N + j] * sp; + } + out[(i + 0)*PARAMS_NBAR + k] += sum[0]; + out[(i + 2)*PARAMS_NBAR + k] += sum[2]; + out[(i + 1)*PARAMS_NBAR + k] += sum[1]; + out[(i + 3)*PARAMS_NBAR + k] += sum[3]; + } + } + return 1; +} + + + + +int PQCLEAN_FRODOKEM640AES_OPT_mul_add_sa_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A) { + // Generate-and-multiply: generate matrix A (N x N) column-wise, multiply by s' on the left. + // Inputs: s', e' (N_BAR x N) + // Output: out = s'*A + e' (N_BAR x N) + int j; + uint16_t i, kk; + for (i = 0; i < (PARAMS_N * PARAMS_NBAR); i += 2) { + *((uint32_t *)&out[i]) = *((uint32_t *)&e[i]); + } + + int k; + uint16_t a_cols[PARAMS_N * PARAMS_STRIPE_STEP] = {0}; + uint16_t a_cols_t[PARAMS_N * PARAMS_STRIPE_STEP]; + uint16_t a_cols_temp[PARAMS_N * PARAMS_STRIPE_STEP] = {0}; + aes128ctx ctx128; + + aes128_keyexp(&ctx128, seed_A); + + for (i = 0, j = 0; i < PARAMS_N; i++, j += PARAMS_STRIPE_STEP) { + a_cols_temp[j] = PQCLEAN_FRODOKEM640AES_OPT_UINT16_TO_LE(i); // Loading values in the little-endian order + } + + for (kk = 0; kk < PARAMS_N; kk += PARAMS_STRIPE_STEP) { // Go through A's columns, 8 (== PARAMS_STRIPE_STEP) columns at a time. + for (i = 0; i < (PARAMS_N * PARAMS_STRIPE_STEP); i += PARAMS_STRIPE_STEP) { + a_cols_temp[i + 1] = PQCLEAN_FRODOKEM640AES_OPT_UINT16_TO_LE(kk); // Loading values in the little-endian order + } + + aes128_ecb((uint8_t *)a_cols, (uint8_t *)a_cols_temp, PARAMS_N * PARAMS_STRIPE_STEP * sizeof(int16_t) / AES_BLOCKBYTES, &ctx128); + + for (i = 0; i < PARAMS_N; i++) { // Transpose a_cols to have access to it in the column-major order. + for (k = 0; k < PARAMS_STRIPE_STEP; k++) { + a_cols_t[k * PARAMS_N + i] = PQCLEAN_FRODOKEM640AES_OPT_LE_TO_UINT16(a_cols[i * PARAMS_STRIPE_STEP + k]); + } + } + + for (i = 0; i < PARAMS_NBAR; i++) { + for (k = 0; k < PARAMS_STRIPE_STEP; k += PARAMS_PARALLEL) { + uint16_t sum[PARAMS_PARALLEL] = {0}; + for (j = 0; j < PARAMS_N; j++) { // Matrix-vector multiplication + uint16_t sp = s[i * PARAMS_N + j]; + sum[0] += sp * a_cols_t[(k + 0) * PARAMS_N + j]; + sum[1] += sp * a_cols_t[(k + 1) * PARAMS_N + j]; + sum[2] += sp * a_cols_t[(k + 2) * PARAMS_N + j]; + sum[3] += sp * a_cols_t[(k + 3) * PARAMS_N + j]; + } + out[i * PARAMS_N + kk + k + 0] += sum[0]; + out[i * PARAMS_N + kk + k + 2] += sum[2]; + out[i * PARAMS_N + kk + k + 1] += sum[1]; + out[i * PARAMS_N + kk + k + 3] += sum[3]; + } + } + } + return 1; +} diff --git a/crypto_kem/frodokem640aes/opt/noise.c b/crypto_kem/frodokem640aes/opt/noise.c new file mode 100644 index 00000000..86ecf4d2 --- /dev/null +++ b/crypto_kem/frodokem640aes/opt/noise.c @@ -0,0 +1,35 @@ +/******************************************************************************************** +* FrodoKEM: Learning with Errors Key Encapsulation +* +* Abstract: noise sampling functions +*********************************************************************************************/ + +#include + +#include "api.h" +#include "common.h" +#include "params.h" + +static uint16_t CDF_TABLE[CDF_TABLE_LEN] = CDF_TABLE_DATA; + +void PQCLEAN_FRODOKEM640AES_OPT_sample_n(uint16_t *s, size_t n) { + // Fills vector s with n samples from the noise distribution which requires 16 bits to sample. + // The distribution is specified by its CDF. + // Input: pseudo-random values (2*n bytes) passed in s. The input is overwritten by the output. + size_t i; + unsigned int j; + + for (i = 0; i < n; ++i) { + uint16_t sample = 0; + uint16_t prnd = s[i] >> 1; // Drop the least significant bit + uint16_t sign = s[i] & 0x1; // Pick the least significant bit + + // No need to compare with the last value. + for (j = 0; j < (unsigned int)(CDF_TABLE_LEN - 1); j++) { + // Constant time comparison: 1 if CDF_TABLE[j] < s, 0 otherwise. Uses the fact that CDF_TABLE[j] and s fit in 15 bits. + sample += (uint16_t)(CDF_TABLE[j] - prnd) >> 15; + } + // Assuming that sign is either 0 or 1, flips sample iff sign = 1 + s[i] = ((-sign) ^ sample) + sign; + } +} diff --git a/crypto_kem/frodokem640aes/opt/params.h b/crypto_kem/frodokem640aes/opt/params.h new file mode 100644 index 00000000..f5fbb743 --- /dev/null +++ b/crypto_kem/frodokem640aes/opt/params.h @@ -0,0 +1,27 @@ +#ifndef PARAMS_H +#define PARAMS_H + +#define CRYPTO_SECRETKEYBYTES PQCLEAN_FRODOKEM640AES_OPT_CRYPTO_SECRETKEYBYTES +#define CRYPTO_PUBLICKEYBYTES PQCLEAN_FRODOKEM640AES_OPT_CRYPTO_PUBLICKEYBYTES +#define CRYPTO_BYTES PQCLEAN_FRODOKEM640AES_OPT_CRYPTO_BYTES +#define CRYPTO_CIPHERTEXTBYTES PQCLEAN_FRODOKEM640AES_OPT_CRYPTO_CIPHERTEXTBYTES + +#define PARAMS_N 640 +#define PARAMS_NBAR 8 +#define PARAMS_LOGQ 15 +#define PARAMS_Q (1 << PARAMS_LOGQ) +#define PARAMS_EXTRACTED_BITS 2 +#define PARAMS_STRIPE_STEP 8 +#define PARAMS_PARALLEL 4 +#define BYTES_SEED_A 16 +#define BYTES_MU ((PARAMS_EXTRACTED_BITS * PARAMS_NBAR * PARAMS_NBAR) / 8) +#define BYTES_PKHASH CRYPTO_BYTES + +// Selecting SHAKE XOF function for the KEM and noise sampling +#define shake shake128 + +// CDF table +#define CDF_TABLE_DATA {4643, 13363, 20579, 25843, 29227, 31145, 32103, 32525, 32689, 32745, 32762, 32766, 32767} +#define CDF_TABLE_LEN 13 + +#endif diff --git a/crypto_kem/frodokem640aes/opt/util.c b/crypto_kem/frodokem640aes/opt/util.c new file mode 100644 index 00000000..716c36dc --- /dev/null +++ b/crypto_kem/frodokem640aes/opt/util.c @@ -0,0 +1,235 @@ +/******************************************************************************************** +* FrodoKEM: Learning with Errors Key Encapsulation +* +* Abstract: additional functions for FrodoKEM +*********************************************************************************************/ + +#include +#include + +#include "api.h" +#include "common.h" +#include "params.h" + +#define min(x, y) (((x) < (y)) ? (x) : (y)) + +uint16_t PQCLEAN_FRODOKEM640AES_OPT_LE_TO_UINT16(uint16_t n) { + return (((uint8_t *) &n)[0] | (((uint8_t *) &n)[1] << 8)); +} + +uint16_t PQCLEAN_FRODOKEM640AES_OPT_UINT16_TO_LE(uint16_t n) { + uint16_t y; + uint8_t *z = (uint8_t *) &y; + z[0] = n & 0xFF; + z[1] = (n & 0xFF00) >> 8; + return y; +} + +void PQCLEAN_FRODOKEM640AES_OPT_mul_bs(uint16_t *out, const uint16_t *b, const uint16_t *s) { + // Multiply by s on the right + // Inputs: b (N_BAR x N), s (N x N_BAR) + // Output: out = b*s (N_BAR x N_BAR) + int i, j, k; + + for (i = 0; i < PARAMS_NBAR; i++) { + for (j = 0; j < PARAMS_NBAR; j++) { + out[i * PARAMS_NBAR + j] = 0; + for (k = 0; k < PARAMS_N; k++) { + out[i * PARAMS_NBAR + j] += b[i * PARAMS_N + k] * s[j * PARAMS_N + k]; + } + out[i * PARAMS_NBAR + j] = (uint32_t)(out[i * PARAMS_NBAR + j]) & ((1 << PARAMS_LOGQ) - 1); + } + } +} + + +void PQCLEAN_FRODOKEM640AES_OPT_mul_add_sb_plus_e(uint16_t *out, const uint16_t *b, const uint16_t *s, const uint16_t *e) { + // Multiply by s on the left + // Inputs: b (N x N_BAR), s (N_BAR x N), e (N_BAR x N_BAR) + // Output: out = s*b + e (N_BAR x N_BAR) + int i, j, k; + + for (k = 0; k < PARAMS_NBAR; k++) { + for (i = 0; i < PARAMS_NBAR; i++) { + out[k * PARAMS_NBAR + i] = e[k * PARAMS_NBAR + i]; + for (j = 0; j < PARAMS_N; j++) { + out[k * PARAMS_NBAR + i] += s[k * PARAMS_N + j] * b[j * PARAMS_NBAR + i]; + } + out[k * PARAMS_NBAR + i] = (uint32_t)(out[k * PARAMS_NBAR + i]) & ((1 << PARAMS_LOGQ) - 1); + } + } +} + + +void PQCLEAN_FRODOKEM640AES_OPT_add(uint16_t *out, const uint16_t *a, const uint16_t *b) { + // Add a and b + // Inputs: a, b (N_BAR x N_BAR) + // Output: c = a + b + + for (size_t i = 0; i < (PARAMS_NBAR * PARAMS_NBAR); i++) { + out[i] = (a[i] + b[i]) & ((1 << PARAMS_LOGQ) - 1); + } +} + + +void PQCLEAN_FRODOKEM640AES_OPT_sub(uint16_t *out, const uint16_t *a, const uint16_t *b) { + // Subtract a and b + // Inputs: a, b (N_BAR x N_BAR) + // Output: c = a - b + + for (size_t i = 0; i < (PARAMS_NBAR * PARAMS_NBAR); i++) { + out[i] = (a[i] - b[i]) & ((1 << PARAMS_LOGQ) - 1); + } +} + + +void PQCLEAN_FRODOKEM640AES_OPT_key_encode(uint16_t *out, const uint16_t *in) { + // Encoding + unsigned int i, j, npieces_word = 8; + unsigned int nwords = (PARAMS_NBAR * PARAMS_NBAR) / 8; + uint64_t temp, mask = ((uint64_t)1 << PARAMS_EXTRACTED_BITS) - 1; + uint16_t *pos = out; + + for (i = 0; i < nwords; i++) { + temp = 0; + for (j = 0; j < PARAMS_EXTRACTED_BITS; j++) { + temp |= ((uint64_t)((uint8_t *)in)[i * PARAMS_EXTRACTED_BITS + j]) << (8 * j); + } + for (j = 0; j < npieces_word; j++) { + *pos = (uint16_t)((temp & mask) << (PARAMS_LOGQ - PARAMS_EXTRACTED_BITS)); + temp >>= PARAMS_EXTRACTED_BITS; + pos++; + } + } +} + + +void PQCLEAN_FRODOKEM640AES_OPT_key_decode(uint16_t *out, const uint16_t *in) { + // Decoding + unsigned int i, j, index = 0, npieces_word = 8; + unsigned int nwords = (PARAMS_NBAR * PARAMS_NBAR) / 8; + uint16_t temp, maskex = ((uint16_t)1 << PARAMS_EXTRACTED_BITS) - 1, maskq = ((uint16_t)1 << PARAMS_LOGQ) - 1; + uint8_t *pos = (uint8_t *)out; + uint64_t templong; + + for (i = 0; i < nwords; i++) { + templong = 0; + for (j = 0; j < npieces_word; j++) { // temp = floor(in*2^{-11}+0.5) + temp = ((in[index] & maskq) + (1 << (PARAMS_LOGQ - PARAMS_EXTRACTED_BITS - 1))) >> (PARAMS_LOGQ - PARAMS_EXTRACTED_BITS); + templong |= ((uint64_t)(temp & maskex)) << (PARAMS_EXTRACTED_BITS * j); + index++; + } + for (j = 0; j < PARAMS_EXTRACTED_BITS; j++) { + pos[i * PARAMS_EXTRACTED_BITS + j] = (templong >> (8 * j)) & 0xFF; + } + } +} + + +void PQCLEAN_FRODOKEM640AES_OPT_pack(uint8_t *out, size_t outlen, const uint16_t *in, size_t inlen, uint8_t lsb) { + // Pack the input uint16 vector into a char output vector, copying lsb bits from each input element. + // If inlen * lsb / 8 > outlen, only outlen * 8 bits are copied. + memset(out, 0, outlen); + + size_t i = 0; // whole bytes already filled in + size_t j = 0; // whole uint16_t already copied + uint16_t w = 0; // the leftover, not yet copied + uint8_t bits = 0; // the number of lsb in w + + while (i < outlen && (j < inlen || ((j == inlen) && (bits > 0)))) { + /* + in: | | |********|********| + ^ + j + w : | ****| + ^ + bits + out:|**|**|**|**|**|**|**|**|* | + ^^ + ib + */ + uint8_t b = 0; // bits in out[i] already filled in + while (b < 8) { + int nbits = min(8 - b, bits); + uint16_t mask = (1 << nbits) - 1; + uint8_t t = (uint8_t) ((w >> (bits - nbits)) & mask); // the bits to copy from w to out + out[i] = out[i] + (t << (8 - b - nbits)); + b += (uint8_t) nbits; + bits -= (uint8_t) nbits; + w &= ~(mask << bits); // not strictly necessary; mostly for debugging + + if (bits == 0) { + if (j < inlen) { + w = in[j]; + bits = lsb; + j++; + } else { + break; // the input vector is exhausted + } + } + } + if (b == 8) { // out[i] is filled in + i++; + } + } +} + + +void PQCLEAN_FRODOKEM640AES_OPT_unpack(uint16_t *out, size_t outlen, const uint8_t *in, size_t inlen, uint8_t lsb) { + // Unpack the input char vector into a uint16_t output vector, copying lsb bits + // for each output element from input. outlen must be at least ceil(inlen * 8 / lsb). + memset(out, 0, outlen * sizeof(uint16_t)); + + size_t i = 0; // whole uint16_t already filled in + size_t j = 0; // whole bytes already copied + uint8_t w = 0; // the leftover, not yet copied + uint8_t bits = 0; // the number of lsb bits of w + + while (i < outlen && (j < inlen || ((j == inlen) && (bits > 0)))) { + /* + in: | | | | | | |**|**|... + ^ + j + w : | *| + ^ + bits + out:| *****| *****| *** | |... + ^ ^ + i b + */ + uint8_t b = 0; // bits in out[i] already filled in + while (b < lsb) { + int nbits = min(lsb - b, bits); + uint16_t mask = (1 << nbits) - 1; + uint8_t t = (w >> (bits - nbits)) & mask; // the bits to copy from w to out + out[i] = out[i] + (t << (lsb - b - nbits)); + b += (uint8_t) nbits; + bits -= (uint8_t) nbits; + w &= ~(mask << bits); // not strictly necessary; mostly for debugging + + if (bits == 0) { + if (j < inlen) { + w = in[j]; + bits = 8; + j++; + } else { + break; // the input vector is exhausted + } + } + } + if (b == lsb) { // out[i] is filled in + i++; + } + } +} + + +void PQCLEAN_FRODOKEM640AES_OPT_clear_bytes(uint8_t *mem, size_t n) { + // Clear 8-bit bytes from memory. "n" indicates the number of bytes to be zeroed. + // This function uses the volatile type qualifier to inform the compiler not to optimize out the memory clearing. + volatile uint8_t *v = mem; + + for (size_t i = 0; i < n; i++) { + v[i] = 0; + } +} diff --git a/crypto_kem/frodokem640shake/META.yml b/crypto_kem/frodokem640shake/META.yml index 99e685c5..2a37b7f9 100644 --- a/crypto_kem/frodokem640shake/META.yml +++ b/crypto_kem/frodokem640shake/META.yml @@ -23,3 +23,5 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/Microsoft/PQCrypto-LWEKE/commit/d5bbd0417ba111b08a959c0042a1dcc65fb14a89 +- name: opt + version: https://github.com/Microsoft/PQCrypto-LWEKE/commit/d5bbd0417ba111b08a959c0042a1dcc65fb14a89 diff --git a/crypto_kem/frodokem640shake/clean/Makefile b/crypto_kem/frodokem640shake/clean/Makefile index a7949f55..af1010fb 100644 --- a/crypto_kem/frodokem640shake/clean/Makefile +++ b/crypto_kem/frodokem640shake/clean/Makefile @@ -4,7 +4,7 @@ LIB=libfrodokem640shake_clean.a HEADERS=api.h params.h common.h OBJECTS=kem.o matrix_shake.o noise.o util.o -CFLAGS=-O3 -Wall -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_kem/frodokem640shake/opt/LICENSE b/crypto_kem/frodokem640shake/opt/LICENSE new file mode 100644 index 00000000..5cf7c8db --- /dev/null +++ b/crypto_kem/frodokem640shake/opt/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) Microsoft Corporation. All rights reserved. + +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/frodokem640shake/opt/Makefile b/crypto_kem/frodokem640shake/opt/Makefile new file mode 100644 index 00000000..6059e5df --- /dev/null +++ b/crypto_kem/frodokem640shake/opt/Makefile @@ -0,0 +1,19 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libfrodokem640shake_opt.a +HEADERS=api.h params.h common.h +OBJECTS=kem.o matrix_shake.o noise.o util.o + +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -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/frodokem640shake/opt/Makefile.Microsoft_nmake b/crypto_kem/frodokem640shake/opt/Makefile.Microsoft_nmake new file mode 100644 index 00000000..3a590958 --- /dev/null +++ b/crypto_kem/frodokem640shake/opt/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=libfrodokem640shake_opt.lib +OBJECTS=kem.obj matrix_shake.obj noise.obj util.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/frodokem640shake/opt/api.h b/crypto_kem/frodokem640shake/opt/api.h new file mode 100644 index 00000000..c63d9f9d --- /dev/null +++ b/crypto_kem/frodokem640shake/opt/api.h @@ -0,0 +1,20 @@ +#ifndef PQCLEAN_FRODOKEM640SHAKE_OPT_API_H +#define PQCLEAN_FRODOKEM640SHAKE_OPT_API_H + +#include +#include + +#define PQCLEAN_FRODOKEM640SHAKE_OPT_CRYPTO_SECRETKEYBYTES 19888 // sizeof(s) + CRYPTO_PUBLICKEYBYTES + 2*PARAMS_N*PARAMS_NBAR + BYTES_PKHASH +#define PQCLEAN_FRODOKEM640SHAKE_OPT_CRYPTO_PUBLICKEYBYTES 9616 // sizeof(seed_A) + (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 +#define PQCLEAN_FRODOKEM640SHAKE_OPT_CRYPTO_BYTES 16 +#define PQCLEAN_FRODOKEM640SHAKE_OPT_CRYPTO_CIPHERTEXTBYTES 9720 // (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 + (PARAMS_LOGQ*PARAMS_NBAR*PARAMS_NBAR)/8 + +#define PQCLEAN_FRODOKEM640SHAKE_OPT_CRYPTO_ALGNAME "FrodoKEM-640-SHAKE" + +int PQCLEAN_FRODOKEM640SHAKE_OPT_crypto_kem_keypair(uint8_t *pk, uint8_t *sk); + +int PQCLEAN_FRODOKEM640SHAKE_OPT_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk); + +int PQCLEAN_FRODOKEM640SHAKE_OPT_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk); + +#endif diff --git a/crypto_kem/frodokem640shake/opt/common.h b/crypto_kem/frodokem640shake/opt/common.h new file mode 100644 index 00000000..2910c84f --- /dev/null +++ b/crypto_kem/frodokem640shake/opt/common.h @@ -0,0 +1,19 @@ +#ifndef COMMON_H +#define COMMON_H + +int PQCLEAN_FRODOKEM640SHAKE_OPT_mul_add_as_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A); +int PQCLEAN_FRODOKEM640SHAKE_OPT_mul_add_sa_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A); +void PQCLEAN_FRODOKEM640SHAKE_OPT_sample_n(uint16_t *s, size_t n); +void PQCLEAN_FRODOKEM640SHAKE_OPT_mul_bs(uint16_t *out, const uint16_t *b, const uint16_t *s); +void PQCLEAN_FRODOKEM640SHAKE_OPT_mul_add_sb_plus_e(uint16_t *out, const uint16_t *b, const uint16_t *s, const uint16_t *e); +void PQCLEAN_FRODOKEM640SHAKE_OPT_add(uint16_t *out, const uint16_t *a, const uint16_t *b); +void PQCLEAN_FRODOKEM640SHAKE_OPT_sub(uint16_t *out, const uint16_t *a, const uint16_t *b); +void PQCLEAN_FRODOKEM640SHAKE_OPT_key_encode(uint16_t *out, const uint16_t *in); +void PQCLEAN_FRODOKEM640SHAKE_OPT_key_decode(uint16_t *out, const uint16_t *in); +void PQCLEAN_FRODOKEM640SHAKE_OPT_pack(uint8_t *out, size_t outlen, const uint16_t *in, size_t inlen, uint8_t lsb); +void PQCLEAN_FRODOKEM640SHAKE_OPT_unpack(uint16_t *out, size_t outlen, const uint8_t *in, size_t inlen, uint8_t lsb); +void PQCLEAN_FRODOKEM640SHAKE_OPT_clear_bytes(uint8_t *mem, size_t n); +uint16_t PQCLEAN_FRODOKEM640SHAKE_OPT_LE_TO_UINT16(uint16_t n); +uint16_t PQCLEAN_FRODOKEM640SHAKE_OPT_UINT16_TO_LE(uint16_t n); + +#endif diff --git a/crypto_kem/frodokem640shake/opt/kem.c b/crypto_kem/frodokem640shake/opt/kem.c new file mode 100644 index 00000000..50bb88c8 --- /dev/null +++ b/crypto_kem/frodokem640shake/opt/kem.c @@ -0,0 +1,238 @@ +/******************************************************************************************** +* FrodoKEM: Learning with Errors Key Encapsulation +* +* Abstract: Key Encapsulation Mechanism (KEM) based on Frodo +*********************************************************************************************/ + +#include +#include + +#include "fips202.h" +#include "randombytes.h" + +#include "api.h" +#include "common.h" +#include "params.h" + +int PQCLEAN_FRODOKEM640SHAKE_OPT_crypto_kem_keypair(uint8_t *pk, uint8_t *sk) { + // FrodoKEM's key generation + // Outputs: public key pk ( BYTES_SEED_A + (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 bytes) + // secret key sk (CRYPTO_BYTES + BYTES_SEED_A + (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 + 2*PARAMS_N*PARAMS_NBAR + BYTES_PKHASH bytes) + uint8_t *pk_seedA = &pk[0]; + uint8_t *pk_b = &pk[BYTES_SEED_A]; + uint8_t *sk_s = &sk[0]; + uint8_t *sk_pk = &sk[CRYPTO_BYTES]; + uint8_t *sk_S = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES]; + uint8_t *sk_pkh = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES + 2 * PARAMS_N * PARAMS_NBAR]; + uint16_t B[PARAMS_N * PARAMS_NBAR] = {0}; + uint16_t S[2 * PARAMS_N * PARAMS_NBAR] = {0}; // contains secret data + uint16_t *E = &S[PARAMS_N * PARAMS_NBAR]; // contains secret data + uint8_t randomness[2 * CRYPTO_BYTES + BYTES_SEED_A]; // contains secret data via randomness_s and randomness_seedSE + uint8_t *randomness_s = &randomness[0]; // contains secret data + uint8_t *randomness_seedSE = &randomness[CRYPTO_BYTES]; // contains secret data + uint8_t *randomness_z = &randomness[2 * CRYPTO_BYTES]; + uint8_t shake_input_seedSE[1 + CRYPTO_BYTES]; // contains secret data + + // Generate the secret value s, the seed for S and E, and the seed for the seed for A. Add seed_A to the public key + randombytes(randomness, CRYPTO_BYTES + CRYPTO_BYTES + BYTES_SEED_A); + shake(pk_seedA, BYTES_SEED_A, randomness_z, BYTES_SEED_A); + + // Generate S and E, and compute B = A*S + E. Generate A on-the-fly + shake_input_seedSE[0] = 0x5F; + memcpy(&shake_input_seedSE[1], randomness_seedSE, CRYPTO_BYTES); + shake((uint8_t *)S, 2 * PARAMS_N * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSE, 1 + CRYPTO_BYTES); + for (size_t i = 0; i < 2 * PARAMS_N * PARAMS_NBAR; i++) { + S[i] = PQCLEAN_FRODOKEM640SHAKE_OPT_LE_TO_UINT16(S[i]); + } + PQCLEAN_FRODOKEM640SHAKE_OPT_sample_n(S, PARAMS_N * PARAMS_NBAR); + PQCLEAN_FRODOKEM640SHAKE_OPT_sample_n(E, PARAMS_N * PARAMS_NBAR); + PQCLEAN_FRODOKEM640SHAKE_OPT_mul_add_as_plus_e(B, S, E, pk); + + // Encode the second part of the public key + PQCLEAN_FRODOKEM640SHAKE_OPT_pack(pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, B, PARAMS_N * PARAMS_NBAR, PARAMS_LOGQ); + + // Add s, pk and S to the secret key + memcpy(sk_s, randomness_s, CRYPTO_BYTES); + memcpy(sk_pk, pk, CRYPTO_PUBLICKEYBYTES); + for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) { + S[i] = PQCLEAN_FRODOKEM640SHAKE_OPT_UINT16_TO_LE(S[i]); + } + memcpy(sk_S, S, 2 * PARAMS_N * PARAMS_NBAR); + + // Add H(pk) to the secret key + shake(sk_pkh, BYTES_PKHASH, pk, CRYPTO_PUBLICKEYBYTES); + + // Cleanup: + PQCLEAN_FRODOKEM640SHAKE_OPT_clear_bytes((uint8_t *)S, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM640SHAKE_OPT_clear_bytes((uint8_t *)E, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM640SHAKE_OPT_clear_bytes(randomness, 2 * CRYPTO_BYTES); + PQCLEAN_FRODOKEM640SHAKE_OPT_clear_bytes(shake_input_seedSE, 1 + CRYPTO_BYTES); + return 0; +} + + +int PQCLEAN_FRODOKEM640SHAKE_OPT_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk) { + // FrodoKEM's key encapsulation + const uint8_t *pk_seedA = &pk[0]; + const uint8_t *pk_b = &pk[BYTES_SEED_A]; + uint8_t *ct_c1 = &ct[0]; + uint8_t *ct_c2 = &ct[(PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8]; + uint16_t B[PARAMS_N * PARAMS_NBAR] = {0}; + uint16_t V[PARAMS_NBAR * PARAMS_NBAR] = {0}; // contains secret data + uint16_t C[PARAMS_NBAR * PARAMS_NBAR] = {0}; + uint16_t Bp[PARAMS_N * PARAMS_NBAR] = {0}; + uint16_t Sp[(2 * PARAMS_N + PARAMS_NBAR)*PARAMS_NBAR] = {0}; // contains secret data + uint16_t *Ep = &Sp[PARAMS_N * PARAMS_NBAR]; // contains secret data + uint16_t *Epp = &Sp[2 * PARAMS_N * PARAMS_NBAR]; // contains secret data + uint8_t G2in[BYTES_PKHASH + BYTES_MU]; // contains secret data via mu + uint8_t *pkh = &G2in[0]; + uint8_t *mu = &G2in[BYTES_PKHASH]; // contains secret data + uint8_t G2out[2 * CRYPTO_BYTES]; // contains secret data + uint8_t *seedSE = &G2out[0]; // contains secret data + uint8_t *k = &G2out[CRYPTO_BYTES]; // contains secret data + uint8_t Fin[CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES]; // contains secret data via Fin_k + uint8_t *Fin_ct = &Fin[0]; + uint8_t *Fin_k = &Fin[CRYPTO_CIPHERTEXTBYTES]; // contains secret data + uint8_t shake_input_seedSE[1 + CRYPTO_BYTES]; // contains secret data + + // pkh <- G_1(pk), generate random mu, compute (seedSE || k) = G_2(pkh || mu) + shake(pkh, BYTES_PKHASH, pk, CRYPTO_PUBLICKEYBYTES); + randombytes(mu, BYTES_MU); + shake(G2out, CRYPTO_BYTES + CRYPTO_BYTES, G2in, BYTES_PKHASH + BYTES_MU); + + // Generate Sp and Ep, and compute Bp = Sp*A + Ep. Generate A on-the-fly + shake_input_seedSE[0] = 0x96; + memcpy(&shake_input_seedSE[1], seedSE, CRYPTO_BYTES); + shake((uint8_t *)Sp, (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSE, 1 + CRYPTO_BYTES); + for (size_t i = 0; i < (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR; i++) { + Sp[i] = PQCLEAN_FRODOKEM640SHAKE_OPT_LE_TO_UINT16(Sp[i]); + } + PQCLEAN_FRODOKEM640SHAKE_OPT_sample_n(Sp, PARAMS_N * PARAMS_NBAR); + PQCLEAN_FRODOKEM640SHAKE_OPT_sample_n(Ep, PARAMS_N * PARAMS_NBAR); + PQCLEAN_FRODOKEM640SHAKE_OPT_mul_add_sa_plus_e(Bp, Sp, Ep, pk_seedA); + PQCLEAN_FRODOKEM640SHAKE_OPT_pack(ct_c1, (PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8, Bp, PARAMS_N * PARAMS_NBAR, PARAMS_LOGQ); + + // Generate Epp, and compute V = Sp*B + Epp + PQCLEAN_FRODOKEM640SHAKE_OPT_sample_n(Epp, PARAMS_NBAR * PARAMS_NBAR); + PQCLEAN_FRODOKEM640SHAKE_OPT_unpack(B, PARAMS_N * PARAMS_NBAR, pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, PARAMS_LOGQ); + PQCLEAN_FRODOKEM640SHAKE_OPT_mul_add_sb_plus_e(V, B, Sp, Epp); + + // Encode mu, and compute C = V + enc(mu) (mod q) + PQCLEAN_FRODOKEM640SHAKE_OPT_key_encode(C, (uint16_t *)mu); + PQCLEAN_FRODOKEM640SHAKE_OPT_add(C, V, C); + PQCLEAN_FRODOKEM640SHAKE_OPT_pack(ct_c2, (PARAMS_LOGQ * PARAMS_NBAR * PARAMS_NBAR) / 8, C, PARAMS_NBAR * PARAMS_NBAR, PARAMS_LOGQ); + + // Compute ss = F(ct||KK) + memcpy(Fin_ct, ct, CRYPTO_CIPHERTEXTBYTES); + memcpy(Fin_k, k, CRYPTO_BYTES); + shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES); + + // Cleanup: + PQCLEAN_FRODOKEM640SHAKE_OPT_clear_bytes((uint8_t *)V, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM640SHAKE_OPT_clear_bytes((uint8_t *)Sp, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM640SHAKE_OPT_clear_bytes((uint8_t *)Ep, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM640SHAKE_OPT_clear_bytes((uint8_t *)Epp, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM640SHAKE_OPT_clear_bytes(mu, BYTES_MU); + PQCLEAN_FRODOKEM640SHAKE_OPT_clear_bytes(G2out, 2 * CRYPTO_BYTES); + PQCLEAN_FRODOKEM640SHAKE_OPT_clear_bytes(Fin_k, CRYPTO_BYTES); + PQCLEAN_FRODOKEM640SHAKE_OPT_clear_bytes(shake_input_seedSE, 1 + CRYPTO_BYTES); + return 0; +} + + +int PQCLEAN_FRODOKEM640SHAKE_OPT_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk) { + // FrodoKEM's key decapsulation + uint16_t B[PARAMS_N * PARAMS_NBAR] = {0}; + uint16_t Bp[PARAMS_N * PARAMS_NBAR] = {0}; + uint16_t W[PARAMS_NBAR * PARAMS_NBAR] = {0}; // contains secret data + uint16_t C[PARAMS_NBAR * PARAMS_NBAR] = {0}; + uint16_t CC[PARAMS_NBAR * PARAMS_NBAR] = {0}; + uint16_t BBp[PARAMS_N * PARAMS_NBAR] = {0}; + uint16_t Sp[(2 * PARAMS_N + PARAMS_NBAR)*PARAMS_NBAR] = {0}; // contains secret data + uint16_t *Ep = &Sp[PARAMS_N * PARAMS_NBAR]; // contains secret data + uint16_t *Epp = &Sp[2 * PARAMS_N * PARAMS_NBAR]; // contains secret data + const uint8_t *ct_c1 = &ct[0]; + const uint8_t *ct_c2 = &ct[(PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8]; + const uint8_t *sk_s = &sk[0]; + const uint8_t *sk_pk = &sk[CRYPTO_BYTES]; + const uint16_t *sk_S = (uint16_t *) &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES]; + uint16_t S[PARAMS_N * PARAMS_NBAR]; // contains secret data + const uint8_t *sk_pkh = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES + 2 * PARAMS_N * PARAMS_NBAR]; + const uint8_t *pk_seedA = &sk_pk[0]; + const uint8_t *pk_b = &sk_pk[BYTES_SEED_A]; + uint8_t G2in[BYTES_PKHASH + BYTES_MU]; // contains secret data via muprime + uint8_t *pkh = &G2in[0]; + uint8_t *muprime = &G2in[BYTES_PKHASH]; // contains secret data + uint8_t G2out[2 * CRYPTO_BYTES]; // contains secret data + uint8_t *seedSEprime = &G2out[0]; // contains secret data + uint8_t *kprime = &G2out[CRYPTO_BYTES]; // contains secret data + uint8_t Fin[CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES]; // contains secret data via Fin_k + uint8_t *Fin_ct = &Fin[0]; + uint8_t *Fin_k = &Fin[CRYPTO_CIPHERTEXTBYTES]; // contains secret data + uint8_t shake_input_seedSEprime[1 + CRYPTO_BYTES]; // contains secret data + + for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) { + S[i] = PQCLEAN_FRODOKEM640SHAKE_OPT_LE_TO_UINT16(sk_S[i]); + } + + // Compute W = C - Bp*S (mod q), and decode the randomness mu + PQCLEAN_FRODOKEM640SHAKE_OPT_unpack(Bp, PARAMS_N * PARAMS_NBAR, ct_c1, (PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8, PARAMS_LOGQ); + PQCLEAN_FRODOKEM640SHAKE_OPT_unpack(C, PARAMS_NBAR * PARAMS_NBAR, ct_c2, (PARAMS_LOGQ * PARAMS_NBAR * PARAMS_NBAR) / 8, PARAMS_LOGQ); + PQCLEAN_FRODOKEM640SHAKE_OPT_mul_bs(W, Bp, S); + PQCLEAN_FRODOKEM640SHAKE_OPT_sub(W, C, W); + PQCLEAN_FRODOKEM640SHAKE_OPT_key_decode((uint16_t *)muprime, W); + + // Generate (seedSE' || k') = G_2(pkh || mu') + memcpy(pkh, sk_pkh, BYTES_PKHASH); + shake(G2out, CRYPTO_BYTES + CRYPTO_BYTES, G2in, BYTES_PKHASH + BYTES_MU); + + // Generate Sp and Ep, and compute BBp = Sp*A + Ep. Generate A on-the-fly + shake_input_seedSEprime[0] = 0x96; + memcpy(&shake_input_seedSEprime[1], seedSEprime, CRYPTO_BYTES); + shake((uint8_t *)Sp, (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSEprime, 1 + CRYPTO_BYTES); + for (size_t i = 0; i < (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR; i++) { + Sp[i] = PQCLEAN_FRODOKEM640SHAKE_OPT_LE_TO_UINT16(Sp[i]); + } + PQCLEAN_FRODOKEM640SHAKE_OPT_sample_n(Sp, PARAMS_N * PARAMS_NBAR); + PQCLEAN_FRODOKEM640SHAKE_OPT_sample_n(Ep, PARAMS_N * PARAMS_NBAR); + PQCLEAN_FRODOKEM640SHAKE_OPT_mul_add_sa_plus_e(BBp, Sp, Ep, pk_seedA); + + // Generate Epp, and compute W = Sp*B + Epp + PQCLEAN_FRODOKEM640SHAKE_OPT_sample_n(Epp, PARAMS_NBAR * PARAMS_NBAR); + PQCLEAN_FRODOKEM640SHAKE_OPT_unpack(B, PARAMS_N * PARAMS_NBAR, pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, PARAMS_LOGQ); + PQCLEAN_FRODOKEM640SHAKE_OPT_mul_add_sb_plus_e(W, B, Sp, Epp); + + // Encode mu, and compute CC = W + enc(mu') (mod q) + PQCLEAN_FRODOKEM640SHAKE_OPT_key_encode(CC, (uint16_t *)muprime); + PQCLEAN_FRODOKEM640SHAKE_OPT_add(CC, W, CC); + + // Prepare input to F + memcpy(Fin_ct, ct, CRYPTO_CIPHERTEXTBYTES); + + // Reducing BBp modulo q + for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) { + BBp[i] = BBp[i] & ((1 << PARAMS_LOGQ) - 1); + } + + // Is (Bp == BBp & C == CC) = true + if (memcmp(Bp, BBp, 2 * PARAMS_N * PARAMS_NBAR) == 0 && memcmp(C, CC, 2 * PARAMS_NBAR * PARAMS_NBAR) == 0) { + // Load k' to do ss = F(ct || k') + memcpy(Fin_k, kprime, CRYPTO_BYTES); + } else { + // Load s to do ss = F(ct || s) + memcpy(Fin_k, sk_s, CRYPTO_BYTES); + } + shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES); + + // Cleanup: + PQCLEAN_FRODOKEM640SHAKE_OPT_clear_bytes((uint8_t *)W, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM640SHAKE_OPT_clear_bytes((uint8_t *)Sp, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM640SHAKE_OPT_clear_bytes((uint8_t *)S, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM640SHAKE_OPT_clear_bytes((uint8_t *)Ep, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM640SHAKE_OPT_clear_bytes((uint8_t *)Epp, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM640SHAKE_OPT_clear_bytes(muprime, BYTES_MU); + PQCLEAN_FRODOKEM640SHAKE_OPT_clear_bytes(G2out, 2 * CRYPTO_BYTES); + PQCLEAN_FRODOKEM640SHAKE_OPT_clear_bytes(Fin_k, CRYPTO_BYTES); + PQCLEAN_FRODOKEM640SHAKE_OPT_clear_bytes(shake_input_seedSEprime, 1 + CRYPTO_BYTES); + return 0; +} diff --git a/crypto_kem/frodokem640shake/opt/matrix_shake.c b/crypto_kem/frodokem640shake/opt/matrix_shake.c new file mode 100644 index 00000000..3094f2a9 --- /dev/null +++ b/crypto_kem/frodokem640shake/opt/matrix_shake.c @@ -0,0 +1,108 @@ +/******************************************************************************************** +* FrodoKEM: Learning with Errors Key Encapsulation +* +* Abstract: matrix arithmetic functions used by the KEM +*********************************************************************************************/ + +#include +#include + +#include "fips202.h" + +#include "api.h" +#include "common.h" +#include "params.h" + +int PQCLEAN_FRODOKEM640SHAKE_OPT_mul_add_as_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A) { + // Generate-and-multiply: generate matrix A (N x N) row-wise, multiply by s on the right. + // Inputs: s, e (N x N_BAR) + // Output: out = A*s + e (N x N_BAR) + int j, k; + uint16_t i; + int16_t a_row[4 * PARAMS_N]; + + for (i = 0; i < (PARAMS_N * PARAMS_NBAR); i += 2) { + *((uint32_t *)&out[i]) = *((uint32_t *)&e[i]); + } + + uint8_t seed_A_separated[2 + BYTES_SEED_A]; + uint16_t *seed_A_origin = (uint16_t *)&seed_A_separated; + memcpy(&seed_A_separated[2], seed_A, BYTES_SEED_A); + for (i = 0; i < PARAMS_N; i += 4) { + seed_A_origin[0] = PQCLEAN_FRODOKEM640SHAKE_OPT_UINT16_TO_LE(i + 0); + shake128((unsigned char *)(a_row + 0 * PARAMS_N), (unsigned long long)(2 * PARAMS_N), seed_A_separated, 2 + BYTES_SEED_A); + seed_A_origin[0] = PQCLEAN_FRODOKEM640SHAKE_OPT_UINT16_TO_LE(i + 1); + shake128((unsigned char *)(a_row + 1 * PARAMS_N), (unsigned long long)(2 * PARAMS_N), seed_A_separated, 2 + BYTES_SEED_A); + seed_A_origin[0] = PQCLEAN_FRODOKEM640SHAKE_OPT_UINT16_TO_LE(i + 2); + shake128((unsigned char *)(a_row + 2 * PARAMS_N), (unsigned long long)(2 * PARAMS_N), seed_A_separated, 2 + BYTES_SEED_A); + seed_A_origin[0] = PQCLEAN_FRODOKEM640SHAKE_OPT_UINT16_TO_LE(i + 3); + shake128((unsigned char *)(a_row + 3 * PARAMS_N), (unsigned long long)(2 * PARAMS_N), seed_A_separated, 2 + BYTES_SEED_A); + for (k = 0; k < 4 * PARAMS_N; k++) { + a_row[k] = PQCLEAN_FRODOKEM640SHAKE_OPT_LE_TO_UINT16(a_row[k]); + } + for (k = 0; k < PARAMS_NBAR; k++) { + uint16_t sum[4] = {0}; + for (j = 0; j < PARAMS_N; j++) { // Matrix-vector multiplication + uint16_t sp = s[k * PARAMS_N + j]; + sum[0] += a_row[0 * PARAMS_N + j] * sp; // Go through four lines with same s + sum[1] += a_row[1 * PARAMS_N + j] * sp; + sum[2] += a_row[2 * PARAMS_N + j] * sp; + sum[3] += a_row[3 * PARAMS_N + j] * sp; + } + out[(i + 0)*PARAMS_NBAR + k] += sum[0]; + out[(i + 2)*PARAMS_NBAR + k] += sum[2]; + out[(i + 1)*PARAMS_NBAR + k] += sum[1]; + out[(i + 3)*PARAMS_NBAR + k] += sum[3]; + } + } + return 1; +} + + + + +int PQCLEAN_FRODOKEM640SHAKE_OPT_mul_add_sa_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A) { + // Generate-and-multiply: generate matrix A (N x N) column-wise, multiply by s' on the left. + // Inputs: s', e' (N_BAR x N) + // Output: out = s'*A + e' (N_BAR x N) + int i, j; + uint16_t kk; + for (i = 0; i < (PARAMS_N * PARAMS_NBAR); i += 2) { + *((uint32_t *)&out[i]) = *((uint32_t *)&e[i]); + } + + int t = 0; + uint16_t a_cols[4 * PARAMS_N]; + + int k; + uint8_t seed_A_separated[2 + BYTES_SEED_A]; + uint16_t *seed_A_origin = (uint16_t *)&seed_A_separated; + memcpy(&seed_A_separated[2], seed_A, BYTES_SEED_A); + for (kk = 0; kk < PARAMS_N; kk += 4) { + seed_A_origin[0] = PQCLEAN_FRODOKEM640SHAKE_OPT_UINT16_TO_LE(kk + 0); + shake128((unsigned char *)(a_cols + 0 * PARAMS_N), (unsigned long long)(2 * PARAMS_N), seed_A_separated, 2 + BYTES_SEED_A); + seed_A_origin[0] = PQCLEAN_FRODOKEM640SHAKE_OPT_UINT16_TO_LE(kk + 1); + shake128((unsigned char *)(a_cols + 1 * PARAMS_N), (unsigned long long)(2 * PARAMS_N), seed_A_separated, 2 + BYTES_SEED_A); + seed_A_origin[0] = PQCLEAN_FRODOKEM640SHAKE_OPT_UINT16_TO_LE(kk + 2); + shake128((unsigned char *)(a_cols + 2 * PARAMS_N), (unsigned long long)(2 * PARAMS_N), seed_A_separated, 2 + BYTES_SEED_A); + seed_A_origin[0] = PQCLEAN_FRODOKEM640SHAKE_OPT_UINT16_TO_LE(kk + 3); + shake128((unsigned char *)(a_cols + 3 * PARAMS_N), (unsigned long long)(2 * PARAMS_N), seed_A_separated, 2 + BYTES_SEED_A); + for (i = 0; i < 4 * PARAMS_N; i++) { + a_cols[i] = PQCLEAN_FRODOKEM640SHAKE_OPT_LE_TO_UINT16(a_cols[i]); + } + + for (i = 0; i < PARAMS_NBAR; i++) { + uint16_t sum[PARAMS_N] = {0}; + for (j = 0; j < 4; j++) { + uint16_t sp = s[i * PARAMS_N + kk + j]; + for (k = 0; k < PARAMS_N; k++) { // Matrix-vector multiplication + sum[k] += sp * a_cols[(t + j) * PARAMS_N + k]; + } + } + for (k = 0; k < PARAMS_N; k++) { + out[i * PARAMS_N + k] += sum[k]; + } + } + } + return 1; +} diff --git a/crypto_kem/frodokem640shake/opt/noise.c b/crypto_kem/frodokem640shake/opt/noise.c new file mode 100644 index 00000000..170a944b --- /dev/null +++ b/crypto_kem/frodokem640shake/opt/noise.c @@ -0,0 +1,35 @@ +/******************************************************************************************** +* FrodoKEM: Learning with Errors Key Encapsulation +* +* Abstract: noise sampling functions +*********************************************************************************************/ + +#include + +#include "api.h" +#include "common.h" +#include "params.h" + +static uint16_t CDF_TABLE[CDF_TABLE_LEN] = CDF_TABLE_DATA; + +void PQCLEAN_FRODOKEM640SHAKE_OPT_sample_n(uint16_t *s, size_t n) { + // Fills vector s with n samples from the noise distribution which requires 16 bits to sample. + // The distribution is specified by its CDF. + // Input: pseudo-random values (2*n bytes) passed in s. The input is overwritten by the output. + size_t i; + unsigned int j; + + for (i = 0; i < n; ++i) { + uint16_t sample = 0; + uint16_t prnd = s[i] >> 1; // Drop the least significant bit + uint16_t sign = s[i] & 0x1; // Pick the least significant bit + + // No need to compare with the last value. + for (j = 0; j < (unsigned int)(CDF_TABLE_LEN - 1); j++) { + // Constant time comparison: 1 if CDF_TABLE[j] < s, 0 otherwise. Uses the fact that CDF_TABLE[j] and s fit in 15 bits. + sample += (uint16_t)(CDF_TABLE[j] - prnd) >> 15; + } + // Assuming that sign is either 0 or 1, flips sample iff sign = 1 + s[i] = ((-sign) ^ sample) + sign; + } +} diff --git a/crypto_kem/frodokem640shake/opt/params.h b/crypto_kem/frodokem640shake/opt/params.h new file mode 100644 index 00000000..dcdad3d3 --- /dev/null +++ b/crypto_kem/frodokem640shake/opt/params.h @@ -0,0 +1,27 @@ +#ifndef PARAMS_H +#define PARAMS_H + +#define CRYPTO_SECRETKEYBYTES PQCLEAN_FRODOKEM640SHAKE_OPT_CRYPTO_SECRETKEYBYTES +#define CRYPTO_PUBLICKEYBYTES PQCLEAN_FRODOKEM640SHAKE_OPT_CRYPTO_PUBLICKEYBYTES +#define CRYPTO_BYTES PQCLEAN_FRODOKEM640SHAKE_OPT_CRYPTO_BYTES +#define CRYPTO_CIPHERTEXTBYTES PQCLEAN_FRODOKEM640SHAKE_OPT_CRYPTO_CIPHERTEXTBYTES + +#define PARAMS_N 640 +#define PARAMS_NBAR 8 +#define PARAMS_LOGQ 15 +#define PARAMS_Q (1 << PARAMS_LOGQ) +#define PARAMS_EXTRACTED_BITS 2 +#define PARAMS_STRIPE_STEP 8 +#define PARAMS_PARALLEL 4 +#define BYTES_SEED_A 16 +#define BYTES_MU ((PARAMS_EXTRACTED_BITS * PARAMS_NBAR * PARAMS_NBAR) / 8) +#define BYTES_PKHASH CRYPTO_BYTES + +// Selecting SHAKE XOF function for the KEM and noise sampling +#define shake shake128 + +// CDF table +#define CDF_TABLE_DATA {4643, 13363, 20579, 25843, 29227, 31145, 32103, 32525, 32689, 32745, 32762, 32766, 32767} +#define CDF_TABLE_LEN 13 + +#endif diff --git a/crypto_kem/frodokem640shake/opt/util.c b/crypto_kem/frodokem640shake/opt/util.c new file mode 100644 index 00000000..ab2f74c9 --- /dev/null +++ b/crypto_kem/frodokem640shake/opt/util.c @@ -0,0 +1,235 @@ +/******************************************************************************************** +* FrodoKEM: Learning with Errors Key Encapsulation +* +* Abstract: additional functions for FrodoKEM +*********************************************************************************************/ + +#include +#include + +#include "api.h" +#include "common.h" +#include "params.h" + +#define min(x, y) (((x) < (y)) ? (x) : (y)) + +uint16_t PQCLEAN_FRODOKEM640SHAKE_OPT_LE_TO_UINT16(uint16_t n) { + return (((uint8_t *) &n)[0] | (((uint8_t *) &n)[1] << 8)); +} + +uint16_t PQCLEAN_FRODOKEM640SHAKE_OPT_UINT16_TO_LE(uint16_t n) { + uint16_t y; + uint8_t *z = (uint8_t *) &y; + z[0] = n & 0xFF; + z[1] = (n & 0xFF00) >> 8; + return y; +} + +void PQCLEAN_FRODOKEM640SHAKE_OPT_mul_bs(uint16_t *out, const uint16_t *b, const uint16_t *s) { + // Multiply by s on the right + // Inputs: b (N_BAR x N), s (N x N_BAR) + // Output: out = b*s (N_BAR x N_BAR) + int i, j, k; + + for (i = 0; i < PARAMS_NBAR; i++) { + for (j = 0; j < PARAMS_NBAR; j++) { + out[i * PARAMS_NBAR + j] = 0; + for (k = 0; k < PARAMS_N; k++) { + out[i * PARAMS_NBAR + j] += b[i * PARAMS_N + k] * s[j * PARAMS_N + k]; + } + out[i * PARAMS_NBAR + j] = (uint32_t)(out[i * PARAMS_NBAR + j]) & ((1 << PARAMS_LOGQ) - 1); + } + } +} + + +void PQCLEAN_FRODOKEM640SHAKE_OPT_mul_add_sb_plus_e(uint16_t *out, const uint16_t *b, const uint16_t *s, const uint16_t *e) { + // Multiply by s on the left + // Inputs: b (N x N_BAR), s (N_BAR x N), e (N_BAR x N_BAR) + // Output: out = s*b + e (N_BAR x N_BAR) + int i, j, k; + + for (k = 0; k < PARAMS_NBAR; k++) { + for (i = 0; i < PARAMS_NBAR; i++) { + out[k * PARAMS_NBAR + i] = e[k * PARAMS_NBAR + i]; + for (j = 0; j < PARAMS_N; j++) { + out[k * PARAMS_NBAR + i] += s[k * PARAMS_N + j] * b[j * PARAMS_NBAR + i]; + } + out[k * PARAMS_NBAR + i] = (uint32_t)(out[k * PARAMS_NBAR + i]) & ((1 << PARAMS_LOGQ) - 1); + } + } +} + + +void PQCLEAN_FRODOKEM640SHAKE_OPT_add(uint16_t *out, const uint16_t *a, const uint16_t *b) { + // Add a and b + // Inputs: a, b (N_BAR x N_BAR) + // Output: c = a + b + + for (size_t i = 0; i < (PARAMS_NBAR * PARAMS_NBAR); i++) { + out[i] = (a[i] + b[i]) & ((1 << PARAMS_LOGQ) - 1); + } +} + + +void PQCLEAN_FRODOKEM640SHAKE_OPT_sub(uint16_t *out, const uint16_t *a, const uint16_t *b) { + // Subtract a and b + // Inputs: a, b (N_BAR x N_BAR) + // Output: c = a - b + + for (size_t i = 0; i < (PARAMS_NBAR * PARAMS_NBAR); i++) { + out[i] = (a[i] - b[i]) & ((1 << PARAMS_LOGQ) - 1); + } +} + + +void PQCLEAN_FRODOKEM640SHAKE_OPT_key_encode(uint16_t *out, const uint16_t *in) { + // Encoding + unsigned int i, j, npieces_word = 8; + unsigned int nwords = (PARAMS_NBAR * PARAMS_NBAR) / 8; + uint64_t temp, mask = ((uint64_t)1 << PARAMS_EXTRACTED_BITS) - 1; + uint16_t *pos = out; + + for (i = 0; i < nwords; i++) { + temp = 0; + for (j = 0; j < PARAMS_EXTRACTED_BITS; j++) { + temp |= ((uint64_t)((uint8_t *)in)[i * PARAMS_EXTRACTED_BITS + j]) << (8 * j); + } + for (j = 0; j < npieces_word; j++) { + *pos = (uint16_t)((temp & mask) << (PARAMS_LOGQ - PARAMS_EXTRACTED_BITS)); + temp >>= PARAMS_EXTRACTED_BITS; + pos++; + } + } +} + + +void PQCLEAN_FRODOKEM640SHAKE_OPT_key_decode(uint16_t *out, const uint16_t *in) { + // Decoding + unsigned int i, j, index = 0, npieces_word = 8; + unsigned int nwords = (PARAMS_NBAR * PARAMS_NBAR) / 8; + uint16_t temp, maskex = ((uint16_t)1 << PARAMS_EXTRACTED_BITS) - 1, maskq = ((uint16_t)1 << PARAMS_LOGQ) - 1; + uint8_t *pos = (uint8_t *)out; + uint64_t templong; + + for (i = 0; i < nwords; i++) { + templong = 0; + for (j = 0; j < npieces_word; j++) { // temp = floor(in*2^{-11}+0.5) + temp = ((in[index] & maskq) + (1 << (PARAMS_LOGQ - PARAMS_EXTRACTED_BITS - 1))) >> (PARAMS_LOGQ - PARAMS_EXTRACTED_BITS); + templong |= ((uint64_t)(temp & maskex)) << (PARAMS_EXTRACTED_BITS * j); + index++; + } + for (j = 0; j < PARAMS_EXTRACTED_BITS; j++) { + pos[i * PARAMS_EXTRACTED_BITS + j] = (templong >> (8 * j)) & 0xFF; + } + } +} + + +void PQCLEAN_FRODOKEM640SHAKE_OPT_pack(uint8_t *out, size_t outlen, const uint16_t *in, size_t inlen, uint8_t lsb) { + // Pack the input uint16 vector into a char output vector, copying lsb bits from each input element. + // If inlen * lsb / 8 > outlen, only outlen * 8 bits are copied. + memset(out, 0, outlen); + + size_t i = 0; // whole bytes already filled in + size_t j = 0; // whole uint16_t already copied + uint16_t w = 0; // the leftover, not yet copied + uint8_t bits = 0; // the number of lsb in w + + while (i < outlen && (j < inlen || ((j == inlen) && (bits > 0)))) { + /* + in: | | |********|********| + ^ + j + w : | ****| + ^ + bits + out:|**|**|**|**|**|**|**|**|* | + ^^ + ib + */ + uint8_t b = 0; // bits in out[i] already filled in + while (b < 8) { + int nbits = min(8 - b, bits); + uint16_t mask = (1 << nbits) - 1; + uint8_t t = (uint8_t) ((w >> (bits - nbits)) & mask); // the bits to copy from w to out + out[i] = out[i] + (t << (8 - b - nbits)); + b += (uint8_t) nbits; + bits -= (uint8_t) nbits; + w &= ~(mask << bits); // not strictly necessary; mostly for debugging + + if (bits == 0) { + if (j < inlen) { + w = in[j]; + bits = lsb; + j++; + } else { + break; // the input vector is exhausted + } + } + } + if (b == 8) { // out[i] is filled in + i++; + } + } +} + + +void PQCLEAN_FRODOKEM640SHAKE_OPT_unpack(uint16_t *out, size_t outlen, const uint8_t *in, size_t inlen, uint8_t lsb) { + // Unpack the input char vector into a uint16_t output vector, copying lsb bits + // for each output element from input. outlen must be at least ceil(inlen * 8 / lsb). + memset(out, 0, outlen * sizeof(uint16_t)); + + size_t i = 0; // whole uint16_t already filled in + size_t j = 0; // whole bytes already copied + uint8_t w = 0; // the leftover, not yet copied + uint8_t bits = 0; // the number of lsb bits of w + + while (i < outlen && (j < inlen || ((j == inlen) && (bits > 0)))) { + /* + in: | | | | | | |**|**|... + ^ + j + w : | *| + ^ + bits + out:| *****| *****| *** | |... + ^ ^ + i b + */ + uint8_t b = 0; // bits in out[i] already filled in + while (b < lsb) { + int nbits = min(lsb - b, bits); + uint16_t mask = (1 << nbits) - 1; + uint8_t t = (w >> (bits - nbits)) & mask; // the bits to copy from w to out + out[i] = out[i] + (t << (lsb - b - nbits)); + b += (uint8_t) nbits; + bits -= (uint8_t) nbits; + w &= ~(mask << bits); // not strictly necessary; mostly for debugging + + if (bits == 0) { + if (j < inlen) { + w = in[j]; + bits = 8; + j++; + } else { + break; // the input vector is exhausted + } + } + } + if (b == lsb) { // out[i] is filled in + i++; + } + } +} + + +void PQCLEAN_FRODOKEM640SHAKE_OPT_clear_bytes(uint8_t *mem, size_t n) { + // Clear 8-bit bytes from memory. "n" indicates the number of bytes to be zeroed. + // This function uses the volatile type qualifier to inform the compiler not to optimize out the memory clearing. + volatile uint8_t *v = mem; + + for (size_t i = 0; i < n; i++) { + v[i] = 0; + } +} diff --git a/crypto_kem/frodokem976aes/META.yml b/crypto_kem/frodokem976aes/META.yml index 78f277b1..2e6e2cfc 100644 --- a/crypto_kem/frodokem976aes/META.yml +++ b/crypto_kem/frodokem976aes/META.yml @@ -23,3 +23,5 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/Microsoft/PQCrypto-LWEKE/commit/d5bbd0417ba111b08a959c0042a1dcc65fb14a89 +- name: opt + version: https://github.com/Microsoft/PQCrypto-LWEKE/commit/d5bbd0417ba111b08a959c0042a1dcc65fb14a89 diff --git a/crypto_kem/frodokem976aes/clean/Makefile b/crypto_kem/frodokem976aes/clean/Makefile index 376d9655..02d18827 100644 --- a/crypto_kem/frodokem976aes/clean/Makefile +++ b/crypto_kem/frodokem976aes/clean/Makefile @@ -4,7 +4,7 @@ LIB=libfrodokem976aes_clean.a HEADERS=api.h params.h common.h OBJECTS=kem.o matrix_aes.o noise.o util.o -CFLAGS=-O3 -Wall -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_kem/frodokem976aes/opt/LICENSE b/crypto_kem/frodokem976aes/opt/LICENSE new file mode 100644 index 00000000..5cf7c8db --- /dev/null +++ b/crypto_kem/frodokem976aes/opt/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) Microsoft Corporation. All rights reserved. + +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/frodokem976aes/opt/Makefile b/crypto_kem/frodokem976aes/opt/Makefile new file mode 100644 index 00000000..f61cff68 --- /dev/null +++ b/crypto_kem/frodokem976aes/opt/Makefile @@ -0,0 +1,19 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libfrodokem976aes_opt.a +HEADERS=api.h params.h common.h +OBJECTS=kem.o matrix_aes.o noise.o util.o + +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -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/frodokem976aes/opt/Makefile.Microsoft_nmake b/crypto_kem/frodokem976aes/opt/Makefile.Microsoft_nmake new file mode 100644 index 00000000..6c65e681 --- /dev/null +++ b/crypto_kem/frodokem976aes/opt/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=libfrodokem976aes_opt.lib +OBJECTS=kem.obj matrix_aes.obj noise.obj util.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/frodokem976aes/opt/api.h b/crypto_kem/frodokem976aes/opt/api.h new file mode 100644 index 00000000..d4be07a2 --- /dev/null +++ b/crypto_kem/frodokem976aes/opt/api.h @@ -0,0 +1,20 @@ +#ifndef PQCLEAN_FRODOKEM976AES_OPT_API_H +#define PQCLEAN_FRODOKEM976AES_OPT_API_H + +#include +#include + +#define PQCLEAN_FRODOKEM976AES_OPT_CRYPTO_SECRETKEYBYTES 31296 // sizeof(s) + CRYPTO_PUBLICKEYBYTES + 2*PARAMS_N*PARAMS_NBAR + BYTES_PKHASH +#define PQCLEAN_FRODOKEM976AES_OPT_CRYPTO_PUBLICKEYBYTES 15632 // sizeof(seed_A) + (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 +#define PQCLEAN_FRODOKEM976AES_OPT_CRYPTO_BYTES 24 +#define PQCLEAN_FRODOKEM976AES_OPT_CRYPTO_CIPHERTEXTBYTES 15744 // (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 + (PARAMS_LOGQ*PARAMS_NBAR*PARAMS_NBAR)/8 + +#define PQCLEAN_FRODOKEM976AES_OPT_CRYPTO_ALGNAME "FrodoKEM-976-AES" + +int PQCLEAN_FRODOKEM976AES_OPT_crypto_kem_keypair(uint8_t *pk, uint8_t *sk); + +int PQCLEAN_FRODOKEM976AES_OPT_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk); + +int PQCLEAN_FRODOKEM976AES_OPT_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk); + +#endif diff --git a/crypto_kem/frodokem976aes/opt/common.h b/crypto_kem/frodokem976aes/opt/common.h new file mode 100644 index 00000000..141e41b0 --- /dev/null +++ b/crypto_kem/frodokem976aes/opt/common.h @@ -0,0 +1,19 @@ +#ifndef COMMON_H +#define COMMON_H + +int PQCLEAN_FRODOKEM976AES_OPT_mul_add_as_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A); +int PQCLEAN_FRODOKEM976AES_OPT_mul_add_sa_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A); +void PQCLEAN_FRODOKEM976AES_OPT_sample_n(uint16_t *s, size_t n); +void PQCLEAN_FRODOKEM976AES_OPT_mul_bs(uint16_t *out, const uint16_t *b, const uint16_t *s); +void PQCLEAN_FRODOKEM976AES_OPT_mul_add_sb_plus_e(uint16_t *out, const uint16_t *b, const uint16_t *s, const uint16_t *e); +void PQCLEAN_FRODOKEM976AES_OPT_add(uint16_t *out, const uint16_t *a, const uint16_t *b); +void PQCLEAN_FRODOKEM976AES_OPT_sub(uint16_t *out, const uint16_t *a, const uint16_t *b); +void PQCLEAN_FRODOKEM976AES_OPT_key_encode(uint16_t *out, const uint16_t *in); +void PQCLEAN_FRODOKEM976AES_OPT_key_decode(uint16_t *out, const uint16_t *in); +void PQCLEAN_FRODOKEM976AES_OPT_pack(uint8_t *out, size_t outlen, const uint16_t *in, size_t inlen, uint8_t lsb); +void PQCLEAN_FRODOKEM976AES_OPT_unpack(uint16_t *out, size_t outlen, const uint8_t *in, size_t inlen, uint8_t lsb); +void PQCLEAN_FRODOKEM976AES_OPT_clear_bytes(uint8_t *mem, size_t n); +uint16_t PQCLEAN_FRODOKEM976AES_OPT_LE_TO_UINT16(uint16_t n); +uint16_t PQCLEAN_FRODOKEM976AES_OPT_UINT16_TO_LE(uint16_t n); + +#endif diff --git a/crypto_kem/frodokem976aes/opt/kem.c b/crypto_kem/frodokem976aes/opt/kem.c new file mode 100644 index 00000000..a6ebdc0b --- /dev/null +++ b/crypto_kem/frodokem976aes/opt/kem.c @@ -0,0 +1,238 @@ +/******************************************************************************************** +* FrodoKEM: Learning with Errors Key Encapsulation +* +* Abstract: Key Encapsulation Mechanism (KEM) based on Frodo +*********************************************************************************************/ + +#include +#include + +#include "fips202.h" +#include "randombytes.h" + +#include "api.h" +#include "common.h" +#include "params.h" + +int PQCLEAN_FRODOKEM976AES_OPT_crypto_kem_keypair(uint8_t *pk, uint8_t *sk) { + // FrodoKEM's key generation + // Outputs: public key pk ( BYTES_SEED_A + (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 bytes) + // secret key sk (CRYPTO_BYTES + BYTES_SEED_A + (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 + 2*PARAMS_N*PARAMS_NBAR + BYTES_PKHASH bytes) + uint8_t *pk_seedA = &pk[0]; + uint8_t *pk_b = &pk[BYTES_SEED_A]; + uint8_t *sk_s = &sk[0]; + uint8_t *sk_pk = &sk[CRYPTO_BYTES]; + uint8_t *sk_S = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES]; + uint8_t *sk_pkh = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES + 2 * PARAMS_N * PARAMS_NBAR]; + uint16_t B[PARAMS_N * PARAMS_NBAR] = {0}; + uint16_t S[2 * PARAMS_N * PARAMS_NBAR] = {0}; // contains secret data + uint16_t *E = &S[PARAMS_N * PARAMS_NBAR]; // contains secret data + uint8_t randomness[2 * CRYPTO_BYTES + BYTES_SEED_A]; // contains secret data via randomness_s and randomness_seedSE + uint8_t *randomness_s = &randomness[0]; // contains secret data + uint8_t *randomness_seedSE = &randomness[CRYPTO_BYTES]; // contains secret data + uint8_t *randomness_z = &randomness[2 * CRYPTO_BYTES]; + uint8_t shake_input_seedSE[1 + CRYPTO_BYTES]; // contains secret data + + // Generate the secret value s, the seed for S and E, and the seed for the seed for A. Add seed_A to the public key + randombytes(randomness, CRYPTO_BYTES + CRYPTO_BYTES + BYTES_SEED_A); + shake(pk_seedA, BYTES_SEED_A, randomness_z, BYTES_SEED_A); + + // Generate S and E, and compute B = A*S + E. Generate A on-the-fly + shake_input_seedSE[0] = 0x5F; + memcpy(&shake_input_seedSE[1], randomness_seedSE, CRYPTO_BYTES); + shake((uint8_t *)S, 2 * PARAMS_N * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSE, 1 + CRYPTO_BYTES); + for (size_t i = 0; i < 2 * PARAMS_N * PARAMS_NBAR; i++) { + S[i] = PQCLEAN_FRODOKEM976AES_OPT_LE_TO_UINT16(S[i]); + } + PQCLEAN_FRODOKEM976AES_OPT_sample_n(S, PARAMS_N * PARAMS_NBAR); + PQCLEAN_FRODOKEM976AES_OPT_sample_n(E, PARAMS_N * PARAMS_NBAR); + PQCLEAN_FRODOKEM976AES_OPT_mul_add_as_plus_e(B, S, E, pk); + + // Encode the second part of the public key + PQCLEAN_FRODOKEM976AES_OPT_pack(pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, B, PARAMS_N * PARAMS_NBAR, PARAMS_LOGQ); + + // Add s, pk and S to the secret key + memcpy(sk_s, randomness_s, CRYPTO_BYTES); + memcpy(sk_pk, pk, CRYPTO_PUBLICKEYBYTES); + for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) { + S[i] = PQCLEAN_FRODOKEM976AES_OPT_UINT16_TO_LE(S[i]); + } + memcpy(sk_S, S, 2 * PARAMS_N * PARAMS_NBAR); + + // Add H(pk) to the secret key + shake(sk_pkh, BYTES_PKHASH, pk, CRYPTO_PUBLICKEYBYTES); + + // Cleanup: + PQCLEAN_FRODOKEM976AES_OPT_clear_bytes((uint8_t *)S, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM976AES_OPT_clear_bytes((uint8_t *)E, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM976AES_OPT_clear_bytes(randomness, 2 * CRYPTO_BYTES); + PQCLEAN_FRODOKEM976AES_OPT_clear_bytes(shake_input_seedSE, 1 + CRYPTO_BYTES); + return 0; +} + + +int PQCLEAN_FRODOKEM976AES_OPT_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk) { + // FrodoKEM's key encapsulation + const uint8_t *pk_seedA = &pk[0]; + const uint8_t *pk_b = &pk[BYTES_SEED_A]; + uint8_t *ct_c1 = &ct[0]; + uint8_t *ct_c2 = &ct[(PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8]; + uint16_t B[PARAMS_N * PARAMS_NBAR] = {0}; + uint16_t V[PARAMS_NBAR * PARAMS_NBAR] = {0}; // contains secret data + uint16_t C[PARAMS_NBAR * PARAMS_NBAR] = {0}; + uint16_t Bp[PARAMS_N * PARAMS_NBAR] = {0}; + uint16_t Sp[(2 * PARAMS_N + PARAMS_NBAR)*PARAMS_NBAR] = {0}; // contains secret data + uint16_t *Ep = &Sp[PARAMS_N * PARAMS_NBAR]; // contains secret data + uint16_t *Epp = &Sp[2 * PARAMS_N * PARAMS_NBAR]; // contains secret data + uint8_t G2in[BYTES_PKHASH + BYTES_MU]; // contains secret data via mu + uint8_t *pkh = &G2in[0]; + uint8_t *mu = &G2in[BYTES_PKHASH]; // contains secret data + uint8_t G2out[2 * CRYPTO_BYTES]; // contains secret data + uint8_t *seedSE = &G2out[0]; // contains secret data + uint8_t *k = &G2out[CRYPTO_BYTES]; // contains secret data + uint8_t Fin[CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES]; // contains secret data via Fin_k + uint8_t *Fin_ct = &Fin[0]; + uint8_t *Fin_k = &Fin[CRYPTO_CIPHERTEXTBYTES]; // contains secret data + uint8_t shake_input_seedSE[1 + CRYPTO_BYTES]; // contains secret data + + // pkh <- G_1(pk), generate random mu, compute (seedSE || k) = G_2(pkh || mu) + shake(pkh, BYTES_PKHASH, pk, CRYPTO_PUBLICKEYBYTES); + randombytes(mu, BYTES_MU); + shake(G2out, CRYPTO_BYTES + CRYPTO_BYTES, G2in, BYTES_PKHASH + BYTES_MU); + + // Generate Sp and Ep, and compute Bp = Sp*A + Ep. Generate A on-the-fly + shake_input_seedSE[0] = 0x96; + memcpy(&shake_input_seedSE[1], seedSE, CRYPTO_BYTES); + shake((uint8_t *)Sp, (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSE, 1 + CRYPTO_BYTES); + for (size_t i = 0; i < (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR; i++) { + Sp[i] = PQCLEAN_FRODOKEM976AES_OPT_LE_TO_UINT16(Sp[i]); + } + PQCLEAN_FRODOKEM976AES_OPT_sample_n(Sp, PARAMS_N * PARAMS_NBAR); + PQCLEAN_FRODOKEM976AES_OPT_sample_n(Ep, PARAMS_N * PARAMS_NBAR); + PQCLEAN_FRODOKEM976AES_OPT_mul_add_sa_plus_e(Bp, Sp, Ep, pk_seedA); + PQCLEAN_FRODOKEM976AES_OPT_pack(ct_c1, (PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8, Bp, PARAMS_N * PARAMS_NBAR, PARAMS_LOGQ); + + // Generate Epp, and compute V = Sp*B + Epp + PQCLEAN_FRODOKEM976AES_OPT_sample_n(Epp, PARAMS_NBAR * PARAMS_NBAR); + PQCLEAN_FRODOKEM976AES_OPT_unpack(B, PARAMS_N * PARAMS_NBAR, pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, PARAMS_LOGQ); + PQCLEAN_FRODOKEM976AES_OPT_mul_add_sb_plus_e(V, B, Sp, Epp); + + // Encode mu, and compute C = V + enc(mu) (mod q) + PQCLEAN_FRODOKEM976AES_OPT_key_encode(C, (uint16_t *)mu); + PQCLEAN_FRODOKEM976AES_OPT_add(C, V, C); + PQCLEAN_FRODOKEM976AES_OPT_pack(ct_c2, (PARAMS_LOGQ * PARAMS_NBAR * PARAMS_NBAR) / 8, C, PARAMS_NBAR * PARAMS_NBAR, PARAMS_LOGQ); + + // Compute ss = F(ct||KK) + memcpy(Fin_ct, ct, CRYPTO_CIPHERTEXTBYTES); + memcpy(Fin_k, k, CRYPTO_BYTES); + shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES); + + // Cleanup: + PQCLEAN_FRODOKEM976AES_OPT_clear_bytes((uint8_t *)V, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM976AES_OPT_clear_bytes((uint8_t *)Sp, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM976AES_OPT_clear_bytes((uint8_t *)Ep, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM976AES_OPT_clear_bytes((uint8_t *)Epp, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM976AES_OPT_clear_bytes(mu, BYTES_MU); + PQCLEAN_FRODOKEM976AES_OPT_clear_bytes(G2out, 2 * CRYPTO_BYTES); + PQCLEAN_FRODOKEM976AES_OPT_clear_bytes(Fin_k, CRYPTO_BYTES); + PQCLEAN_FRODOKEM976AES_OPT_clear_bytes(shake_input_seedSE, 1 + CRYPTO_BYTES); + return 0; +} + + +int PQCLEAN_FRODOKEM976AES_OPT_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk) { + // FrodoKEM's key decapsulation + uint16_t B[PARAMS_N * PARAMS_NBAR] = {0}; + uint16_t Bp[PARAMS_N * PARAMS_NBAR] = {0}; + uint16_t W[PARAMS_NBAR * PARAMS_NBAR] = {0}; // contains secret data + uint16_t C[PARAMS_NBAR * PARAMS_NBAR] = {0}; + uint16_t CC[PARAMS_NBAR * PARAMS_NBAR] = {0}; + uint16_t BBp[PARAMS_N * PARAMS_NBAR] = {0}; + uint16_t Sp[(2 * PARAMS_N + PARAMS_NBAR)*PARAMS_NBAR] = {0}; // contains secret data + uint16_t *Ep = &Sp[PARAMS_N * PARAMS_NBAR]; // contains secret data + uint16_t *Epp = &Sp[2 * PARAMS_N * PARAMS_NBAR]; // contains secret data + const uint8_t *ct_c1 = &ct[0]; + const uint8_t *ct_c2 = &ct[(PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8]; + const uint8_t *sk_s = &sk[0]; + const uint8_t *sk_pk = &sk[CRYPTO_BYTES]; + const uint16_t *sk_S = (uint16_t *) &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES]; + uint16_t S[PARAMS_N * PARAMS_NBAR]; // contains secret data + const uint8_t *sk_pkh = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES + 2 * PARAMS_N * PARAMS_NBAR]; + const uint8_t *pk_seedA = &sk_pk[0]; + const uint8_t *pk_b = &sk_pk[BYTES_SEED_A]; + uint8_t G2in[BYTES_PKHASH + BYTES_MU]; // contains secret data via muprime + uint8_t *pkh = &G2in[0]; + uint8_t *muprime = &G2in[BYTES_PKHASH]; // contains secret data + uint8_t G2out[2 * CRYPTO_BYTES]; // contains secret data + uint8_t *seedSEprime = &G2out[0]; // contains secret data + uint8_t *kprime = &G2out[CRYPTO_BYTES]; // contains secret data + uint8_t Fin[CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES]; // contains secret data via Fin_k + uint8_t *Fin_ct = &Fin[0]; + uint8_t *Fin_k = &Fin[CRYPTO_CIPHERTEXTBYTES]; // contains secret data + uint8_t shake_input_seedSEprime[1 + CRYPTO_BYTES]; // contains secret data + + for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) { + S[i] = PQCLEAN_FRODOKEM976AES_OPT_LE_TO_UINT16(sk_S[i]); + } + + // Compute W = C - Bp*S (mod q), and decode the randomness mu + PQCLEAN_FRODOKEM976AES_OPT_unpack(Bp, PARAMS_N * PARAMS_NBAR, ct_c1, (PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8, PARAMS_LOGQ); + PQCLEAN_FRODOKEM976AES_OPT_unpack(C, PARAMS_NBAR * PARAMS_NBAR, ct_c2, (PARAMS_LOGQ * PARAMS_NBAR * PARAMS_NBAR) / 8, PARAMS_LOGQ); + PQCLEAN_FRODOKEM976AES_OPT_mul_bs(W, Bp, S); + PQCLEAN_FRODOKEM976AES_OPT_sub(W, C, W); + PQCLEAN_FRODOKEM976AES_OPT_key_decode((uint16_t *)muprime, W); + + // Generate (seedSE' || k') = G_2(pkh || mu') + memcpy(pkh, sk_pkh, BYTES_PKHASH); + shake(G2out, CRYPTO_BYTES + CRYPTO_BYTES, G2in, BYTES_PKHASH + BYTES_MU); + + // Generate Sp and Ep, and compute BBp = Sp*A + Ep. Generate A on-the-fly + shake_input_seedSEprime[0] = 0x96; + memcpy(&shake_input_seedSEprime[1], seedSEprime, CRYPTO_BYTES); + shake((uint8_t *)Sp, (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSEprime, 1 + CRYPTO_BYTES); + for (size_t i = 0; i < (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR; i++) { + Sp[i] = PQCLEAN_FRODOKEM976AES_OPT_LE_TO_UINT16(Sp[i]); + } + PQCLEAN_FRODOKEM976AES_OPT_sample_n(Sp, PARAMS_N * PARAMS_NBAR); + PQCLEAN_FRODOKEM976AES_OPT_sample_n(Ep, PARAMS_N * PARAMS_NBAR); + PQCLEAN_FRODOKEM976AES_OPT_mul_add_sa_plus_e(BBp, Sp, Ep, pk_seedA); + + // Generate Epp, and compute W = Sp*B + Epp + PQCLEAN_FRODOKEM976AES_OPT_sample_n(Epp, PARAMS_NBAR * PARAMS_NBAR); + PQCLEAN_FRODOKEM976AES_OPT_unpack(B, PARAMS_N * PARAMS_NBAR, pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, PARAMS_LOGQ); + PQCLEAN_FRODOKEM976AES_OPT_mul_add_sb_plus_e(W, B, Sp, Epp); + + // Encode mu, and compute CC = W + enc(mu') (mod q) + PQCLEAN_FRODOKEM976AES_OPT_key_encode(CC, (uint16_t *)muprime); + PQCLEAN_FRODOKEM976AES_OPT_add(CC, W, CC); + + // Prepare input to F + memcpy(Fin_ct, ct, CRYPTO_CIPHERTEXTBYTES); + + // Reducing BBp modulo q + for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) { + BBp[i] = BBp[i] & ((1 << PARAMS_LOGQ) - 1); + } + + // Is (Bp == BBp & C == CC) = true + if (memcmp(Bp, BBp, 2 * PARAMS_N * PARAMS_NBAR) == 0 && memcmp(C, CC, 2 * PARAMS_NBAR * PARAMS_NBAR) == 0) { + // Load k' to do ss = F(ct || k') + memcpy(Fin_k, kprime, CRYPTO_BYTES); + } else { + // Load s to do ss = F(ct || s) + memcpy(Fin_k, sk_s, CRYPTO_BYTES); + } + shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES); + + // Cleanup: + PQCLEAN_FRODOKEM976AES_OPT_clear_bytes((uint8_t *)W, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM976AES_OPT_clear_bytes((uint8_t *)Sp, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM976AES_OPT_clear_bytes((uint8_t *)S, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM976AES_OPT_clear_bytes((uint8_t *)Ep, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM976AES_OPT_clear_bytes((uint8_t *)Epp, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM976AES_OPT_clear_bytes(muprime, BYTES_MU); + PQCLEAN_FRODOKEM976AES_OPT_clear_bytes(G2out, 2 * CRYPTO_BYTES); + PQCLEAN_FRODOKEM976AES_OPT_clear_bytes(Fin_k, CRYPTO_BYTES); + PQCLEAN_FRODOKEM976AES_OPT_clear_bytes(shake_input_seedSEprime, 1 + CRYPTO_BYTES); + return 0; +} diff --git a/crypto_kem/frodokem976aes/opt/matrix_aes.c b/crypto_kem/frodokem976aes/opt/matrix_aes.c new file mode 100644 index 00000000..a1332fc1 --- /dev/null +++ b/crypto_kem/frodokem976aes/opt/matrix_aes.c @@ -0,0 +1,125 @@ +/******************************************************************************************** +* FrodoKEM: Learning with Errors Key Encapsulation +* +* Abstract: matrix arithmetic functions used by the KEM +*********************************************************************************************/ + +#include +#include + +#include "aes.h" + +#include "api.h" +#include "common.h" +#include "params.h" + +int PQCLEAN_FRODOKEM976AES_OPT_mul_add_as_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A) { + // Generate-and-multiply: generate matrix A (N x N) row-wise, multiply by s on the right. + // Inputs: s, e (N x N_BAR) + // Output: out = A*s + e (N x N_BAR) + int k; + uint16_t i, j; + int16_t a_row[4 * PARAMS_N]; + + for (i = 0; i < (PARAMS_N * PARAMS_NBAR); i += 2) { + *((uint32_t *)&out[i]) = *((uint32_t *)&e[i]); + } + + int16_t a_row_temp[4 * PARAMS_N] = {0}; // Take four lines of A at once + aes128ctx ctx128; + + aes128_keyexp(&ctx128, seed_A); + + for (j = 0; j < PARAMS_N; j += PARAMS_STRIPE_STEP) { + a_row_temp[j + 1 + 0 * PARAMS_N] = PQCLEAN_FRODOKEM976AES_OPT_UINT16_TO_LE(j); // Loading values in the little-endian order + a_row_temp[j + 1 + 1 * PARAMS_N] = PQCLEAN_FRODOKEM976AES_OPT_UINT16_TO_LE(j); + a_row_temp[j + 1 + 2 * PARAMS_N] = PQCLEAN_FRODOKEM976AES_OPT_UINT16_TO_LE(j); + a_row_temp[j + 1 + 3 * PARAMS_N] = PQCLEAN_FRODOKEM976AES_OPT_UINT16_TO_LE(j); + } + + for (i = 0; i < PARAMS_N; i += 4) { + for (j = 0; j < PARAMS_N; j += PARAMS_STRIPE_STEP) { // Go through A, four rows at a time + a_row_temp[j + 0 * PARAMS_N] = PQCLEAN_FRODOKEM976AES_OPT_UINT16_TO_LE(i + 0); // Loading values in the little-endian order + a_row_temp[j + 1 * PARAMS_N] = PQCLEAN_FRODOKEM976AES_OPT_UINT16_TO_LE(i + 1); + a_row_temp[j + 2 * PARAMS_N] = PQCLEAN_FRODOKEM976AES_OPT_UINT16_TO_LE(i + 2); + a_row_temp[j + 3 * PARAMS_N] = PQCLEAN_FRODOKEM976AES_OPT_UINT16_TO_LE(i + 3); + } + aes128_ecb((uint8_t *)a_row, (uint8_t *)a_row_temp, 4 * PARAMS_N * sizeof(int16_t) / AES_BLOCKBYTES, &ctx128); + for (k = 0; k < 4 * PARAMS_N; k++) { + a_row[k] = PQCLEAN_FRODOKEM976AES_OPT_LE_TO_UINT16(a_row[k]); + } + for (k = 0; k < PARAMS_NBAR; k++) { + uint16_t sum[4] = {0}; + for (j = 0; j < PARAMS_N; j++) { // Matrix-vector multiplication + uint16_t sp = s[k * PARAMS_N + j]; + sum[0] += a_row[0 * PARAMS_N + j] * sp; // Go through four lines with same s + sum[1] += a_row[1 * PARAMS_N + j] * sp; + sum[2] += a_row[2 * PARAMS_N + j] * sp; + sum[3] += a_row[3 * PARAMS_N + j] * sp; + } + out[(i + 0)*PARAMS_NBAR + k] += sum[0]; + out[(i + 2)*PARAMS_NBAR + k] += sum[2]; + out[(i + 1)*PARAMS_NBAR + k] += sum[1]; + out[(i + 3)*PARAMS_NBAR + k] += sum[3]; + } + } + return 1; +} + + + + +int PQCLEAN_FRODOKEM976AES_OPT_mul_add_sa_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A) { + // Generate-and-multiply: generate matrix A (N x N) column-wise, multiply by s' on the left. + // Inputs: s', e' (N_BAR x N) + // Output: out = s'*A + e' (N_BAR x N) + int j; + uint16_t i, kk; + for (i = 0; i < (PARAMS_N * PARAMS_NBAR); i += 2) { + *((uint32_t *)&out[i]) = *((uint32_t *)&e[i]); + } + + int k; + uint16_t a_cols[PARAMS_N * PARAMS_STRIPE_STEP] = {0}; + uint16_t a_cols_t[PARAMS_N * PARAMS_STRIPE_STEP]; + uint16_t a_cols_temp[PARAMS_N * PARAMS_STRIPE_STEP] = {0}; + aes128ctx ctx128; + + aes128_keyexp(&ctx128, seed_A); + + for (i = 0, j = 0; i < PARAMS_N; i++, j += PARAMS_STRIPE_STEP) { + a_cols_temp[j] = PQCLEAN_FRODOKEM976AES_OPT_UINT16_TO_LE(i); // Loading values in the little-endian order + } + + for (kk = 0; kk < PARAMS_N; kk += PARAMS_STRIPE_STEP) { // Go through A's columns, 8 (== PARAMS_STRIPE_STEP) columns at a time. + for (i = 0; i < (PARAMS_N * PARAMS_STRIPE_STEP); i += PARAMS_STRIPE_STEP) { + a_cols_temp[i + 1] = PQCLEAN_FRODOKEM976AES_OPT_UINT16_TO_LE(kk); // Loading values in the little-endian order + } + + aes128_ecb((uint8_t *)a_cols, (uint8_t *)a_cols_temp, PARAMS_N * PARAMS_STRIPE_STEP * sizeof(int16_t) / AES_BLOCKBYTES, &ctx128); + + for (i = 0; i < PARAMS_N; i++) { // Transpose a_cols to have access to it in the column-major order. + for (k = 0; k < PARAMS_STRIPE_STEP; k++) { + a_cols_t[k * PARAMS_N + i] = PQCLEAN_FRODOKEM976AES_OPT_LE_TO_UINT16(a_cols[i * PARAMS_STRIPE_STEP + k]); + } + } + + for (i = 0; i < PARAMS_NBAR; i++) { + for (k = 0; k < PARAMS_STRIPE_STEP; k += PARAMS_PARALLEL) { + uint16_t sum[PARAMS_PARALLEL] = {0}; + for (j = 0; j < PARAMS_N; j++) { // Matrix-vector multiplication + uint16_t sp = s[i * PARAMS_N + j]; + sum[0] += sp * a_cols_t[(k + 0) * PARAMS_N + j]; + sum[1] += sp * a_cols_t[(k + 1) * PARAMS_N + j]; + sum[2] += sp * a_cols_t[(k + 2) * PARAMS_N + j]; + sum[3] += sp * a_cols_t[(k + 3) * PARAMS_N + j]; + } + out[i * PARAMS_N + kk + k + 0] += sum[0]; + out[i * PARAMS_N + kk + k + 2] += sum[2]; + out[i * PARAMS_N + kk + k + 1] += sum[1]; + out[i * PARAMS_N + kk + k + 3] += sum[3]; + } + } + } + return 1; +} diff --git a/crypto_kem/frodokem976aes/opt/noise.c b/crypto_kem/frodokem976aes/opt/noise.c new file mode 100644 index 00000000..aa8aa1fd --- /dev/null +++ b/crypto_kem/frodokem976aes/opt/noise.c @@ -0,0 +1,35 @@ +/******************************************************************************************** +* FrodoKEM: Learning with Errors Key Encapsulation +* +* Abstract: noise sampling functions +*********************************************************************************************/ + +#include + +#include "api.h" +#include "common.h" +#include "params.h" + +static uint16_t CDF_TABLE[CDF_TABLE_LEN] = CDF_TABLE_DATA; + +void PQCLEAN_FRODOKEM976AES_OPT_sample_n(uint16_t *s, size_t n) { + // Fills vector s with n samples from the noise distribution which requires 16 bits to sample. + // The distribution is specified by its CDF. + // Input: pseudo-random values (2*n bytes) passed in s. The input is overwritten by the output. + size_t i; + unsigned int j; + + for (i = 0; i < n; ++i) { + uint16_t sample = 0; + uint16_t prnd = s[i] >> 1; // Drop the least significant bit + uint16_t sign = s[i] & 0x1; // Pick the least significant bit + + // No need to compare with the last value. + for (j = 0; j < (unsigned int)(CDF_TABLE_LEN - 1); j++) { + // Constant time comparison: 1 if CDF_TABLE[j] < s, 0 otherwise. Uses the fact that CDF_TABLE[j] and s fit in 15 bits. + sample += (uint16_t)(CDF_TABLE[j] - prnd) >> 15; + } + // Assuming that sign is either 0 or 1, flips sample iff sign = 1 + s[i] = ((-sign) ^ sample) + sign; + } +} diff --git a/crypto_kem/frodokem976aes/opt/params.h b/crypto_kem/frodokem976aes/opt/params.h new file mode 100644 index 00000000..b746f1e7 --- /dev/null +++ b/crypto_kem/frodokem976aes/opt/params.h @@ -0,0 +1,27 @@ +#ifndef PARAMS_H +#define PARAMS_H + +#define CRYPTO_SECRETKEYBYTES PQCLEAN_FRODOKEM976AES_OPT_CRYPTO_SECRETKEYBYTES +#define CRYPTO_PUBLICKEYBYTES PQCLEAN_FRODOKEM976AES_OPT_CRYPTO_PUBLICKEYBYTES +#define CRYPTO_BYTES PQCLEAN_FRODOKEM976AES_OPT_CRYPTO_BYTES +#define CRYPTO_CIPHERTEXTBYTES PQCLEAN_FRODOKEM976AES_OPT_CRYPTO_CIPHERTEXTBYTES + +#define PARAMS_N 976 +#define PARAMS_NBAR 8 +#define PARAMS_LOGQ 16 +#define PARAMS_Q (1 << PARAMS_LOGQ) +#define PARAMS_EXTRACTED_BITS 3 +#define PARAMS_STRIPE_STEP 8 +#define PARAMS_PARALLEL 4 +#define BYTES_SEED_A 16 +#define BYTES_MU ((PARAMS_EXTRACTED_BITS * PARAMS_NBAR * PARAMS_NBAR) / 8) +#define BYTES_PKHASH CRYPTO_BYTES + +// Selecting SHAKE XOF function for the KEM and noise sampling +#define shake shake256 + +// CDF table +#define CDF_TABLE_DATA {5638, 15915, 23689, 28571, 31116, 32217, 32613, 32731, 32760, 32766, 32767} +#define CDF_TABLE_LEN 11 + +#endif diff --git a/crypto_kem/frodokem976aes/opt/util.c b/crypto_kem/frodokem976aes/opt/util.c new file mode 100644 index 00000000..0369e652 --- /dev/null +++ b/crypto_kem/frodokem976aes/opt/util.c @@ -0,0 +1,235 @@ +/******************************************************************************************** +* FrodoKEM: Learning with Errors Key Encapsulation +* +* Abstract: additional functions for FrodoKEM +*********************************************************************************************/ + +#include +#include + +#include "api.h" +#include "common.h" +#include "params.h" + +#define min(x, y) (((x) < (y)) ? (x) : (y)) + +uint16_t PQCLEAN_FRODOKEM976AES_OPT_LE_TO_UINT16(uint16_t n) { + return (((uint8_t *) &n)[0] | (((uint8_t *) &n)[1] << 8)); +} + +uint16_t PQCLEAN_FRODOKEM976AES_OPT_UINT16_TO_LE(uint16_t n) { + uint16_t y; + uint8_t *z = (uint8_t *) &y; + z[0] = n & 0xFF; + z[1] = (n & 0xFF00) >> 8; + return y; +} + +void PQCLEAN_FRODOKEM976AES_OPT_mul_bs(uint16_t *out, const uint16_t *b, const uint16_t *s) { + // Multiply by s on the right + // Inputs: b (N_BAR x N), s (N x N_BAR) + // Output: out = b*s (N_BAR x N_BAR) + int i, j, k; + + for (i = 0; i < PARAMS_NBAR; i++) { + for (j = 0; j < PARAMS_NBAR; j++) { + out[i * PARAMS_NBAR + j] = 0; + for (k = 0; k < PARAMS_N; k++) { + out[i * PARAMS_NBAR + j] += b[i * PARAMS_N + k] * s[j * PARAMS_N + k]; + } + out[i * PARAMS_NBAR + j] = (uint32_t)(out[i * PARAMS_NBAR + j]) & ((1 << PARAMS_LOGQ) - 1); + } + } +} + + +void PQCLEAN_FRODOKEM976AES_OPT_mul_add_sb_plus_e(uint16_t *out, const uint16_t *b, const uint16_t *s, const uint16_t *e) { + // Multiply by s on the left + // Inputs: b (N x N_BAR), s (N_BAR x N), e (N_BAR x N_BAR) + // Output: out = s*b + e (N_BAR x N_BAR) + int i, j, k; + + for (k = 0; k < PARAMS_NBAR; k++) { + for (i = 0; i < PARAMS_NBAR; i++) { + out[k * PARAMS_NBAR + i] = e[k * PARAMS_NBAR + i]; + for (j = 0; j < PARAMS_N; j++) { + out[k * PARAMS_NBAR + i] += s[k * PARAMS_N + j] * b[j * PARAMS_NBAR + i]; + } + out[k * PARAMS_NBAR + i] = (uint32_t)(out[k * PARAMS_NBAR + i]) & ((1 << PARAMS_LOGQ) - 1); + } + } +} + + +void PQCLEAN_FRODOKEM976AES_OPT_add(uint16_t *out, const uint16_t *a, const uint16_t *b) { + // Add a and b + // Inputs: a, b (N_BAR x N_BAR) + // Output: c = a + b + + for (size_t i = 0; i < (PARAMS_NBAR * PARAMS_NBAR); i++) { + out[i] = (a[i] + b[i]) & ((1 << PARAMS_LOGQ) - 1); + } +} + + +void PQCLEAN_FRODOKEM976AES_OPT_sub(uint16_t *out, const uint16_t *a, const uint16_t *b) { + // Subtract a and b + // Inputs: a, b (N_BAR x N_BAR) + // Output: c = a - b + + for (size_t i = 0; i < (PARAMS_NBAR * PARAMS_NBAR); i++) { + out[i] = (a[i] - b[i]) & ((1 << PARAMS_LOGQ) - 1); + } +} + + +void PQCLEAN_FRODOKEM976AES_OPT_key_encode(uint16_t *out, const uint16_t *in) { + // Encoding + unsigned int i, j, npieces_word = 8; + unsigned int nwords = (PARAMS_NBAR * PARAMS_NBAR) / 8; + uint64_t temp, mask = ((uint64_t)1 << PARAMS_EXTRACTED_BITS) - 1; + uint16_t *pos = out; + + for (i = 0; i < nwords; i++) { + temp = 0; + for (j = 0; j < PARAMS_EXTRACTED_BITS; j++) { + temp |= ((uint64_t)((uint8_t *)in)[i * PARAMS_EXTRACTED_BITS + j]) << (8 * j); + } + for (j = 0; j < npieces_word; j++) { + *pos = (uint16_t)((temp & mask) << (PARAMS_LOGQ - PARAMS_EXTRACTED_BITS)); + temp >>= PARAMS_EXTRACTED_BITS; + pos++; + } + } +} + + +void PQCLEAN_FRODOKEM976AES_OPT_key_decode(uint16_t *out, const uint16_t *in) { + // Decoding + unsigned int i, j, index = 0, npieces_word = 8; + unsigned int nwords = (PARAMS_NBAR * PARAMS_NBAR) / 8; + uint16_t temp, maskex = ((uint16_t)1 << PARAMS_EXTRACTED_BITS) - 1, maskq = ((uint16_t)1 << PARAMS_LOGQ) - 1; + uint8_t *pos = (uint8_t *)out; + uint64_t templong; + + for (i = 0; i < nwords; i++) { + templong = 0; + for (j = 0; j < npieces_word; j++) { // temp = floor(in*2^{-11}+0.5) + temp = ((in[index] & maskq) + (1 << (PARAMS_LOGQ - PARAMS_EXTRACTED_BITS - 1))) >> (PARAMS_LOGQ - PARAMS_EXTRACTED_BITS); + templong |= ((uint64_t)(temp & maskex)) << (PARAMS_EXTRACTED_BITS * j); + index++; + } + for (j = 0; j < PARAMS_EXTRACTED_BITS; j++) { + pos[i * PARAMS_EXTRACTED_BITS + j] = (templong >> (8 * j)) & 0xFF; + } + } +} + + +void PQCLEAN_FRODOKEM976AES_OPT_pack(uint8_t *out, size_t outlen, const uint16_t *in, size_t inlen, uint8_t lsb) { + // Pack the input uint16 vector into a char output vector, copying lsb bits from each input element. + // If inlen * lsb / 8 > outlen, only outlen * 8 bits are copied. + memset(out, 0, outlen); + + size_t i = 0; // whole bytes already filled in + size_t j = 0; // whole uint16_t already copied + uint16_t w = 0; // the leftover, not yet copied + uint8_t bits = 0; // the number of lsb in w + + while (i < outlen && (j < inlen || ((j == inlen) && (bits > 0)))) { + /* + in: | | |********|********| + ^ + j + w : | ****| + ^ + bits + out:|**|**|**|**|**|**|**|**|* | + ^^ + ib + */ + uint8_t b = 0; // bits in out[i] already filled in + while (b < 8) { + int nbits = min(8 - b, bits); + uint16_t mask = (1 << nbits) - 1; + uint8_t t = (uint8_t) ((w >> (bits - nbits)) & mask); // the bits to copy from w to out + out[i] = out[i] + (t << (8 - b - nbits)); + b += (uint8_t) nbits; + bits -= (uint8_t) nbits; + w &= ~(mask << bits); // not strictly necessary; mostly for debugging + + if (bits == 0) { + if (j < inlen) { + w = in[j]; + bits = lsb; + j++; + } else { + break; // the input vector is exhausted + } + } + } + if (b == 8) { // out[i] is filled in + i++; + } + } +} + + +void PQCLEAN_FRODOKEM976AES_OPT_unpack(uint16_t *out, size_t outlen, const uint8_t *in, size_t inlen, uint8_t lsb) { + // Unpack the input char vector into a uint16_t output vector, copying lsb bits + // for each output element from input. outlen must be at least ceil(inlen * 8 / lsb). + memset(out, 0, outlen * sizeof(uint16_t)); + + size_t i = 0; // whole uint16_t already filled in + size_t j = 0; // whole bytes already copied + uint8_t w = 0; // the leftover, not yet copied + uint8_t bits = 0; // the number of lsb bits of w + + while (i < outlen && (j < inlen || ((j == inlen) && (bits > 0)))) { + /* + in: | | | | | | |**|**|... + ^ + j + w : | *| + ^ + bits + out:| *****| *****| *** | |... + ^ ^ + i b + */ + uint8_t b = 0; // bits in out[i] already filled in + while (b < lsb) { + int nbits = min(lsb - b, bits); + uint16_t mask = (1 << nbits) - 1; + uint8_t t = (w >> (bits - nbits)) & mask; // the bits to copy from w to out + out[i] = out[i] + (t << (lsb - b - nbits)); + b += (uint8_t) nbits; + bits -= (uint8_t) nbits; + w &= ~(mask << bits); // not strictly necessary; mostly for debugging + + if (bits == 0) { + if (j < inlen) { + w = in[j]; + bits = 8; + j++; + } else { + break; // the input vector is exhausted + } + } + } + if (b == lsb) { // out[i] is filled in + i++; + } + } +} + + +void PQCLEAN_FRODOKEM976AES_OPT_clear_bytes(uint8_t *mem, size_t n) { + // Clear 8-bit bytes from memory. "n" indicates the number of bytes to be zeroed. + // This function uses the volatile type qualifier to inform the compiler not to optimize out the memory clearing. + volatile uint8_t *v = mem; + + for (size_t i = 0; i < n; i++) { + v[i] = 0; + } +} diff --git a/crypto_kem/frodokem976shake/META.yml b/crypto_kem/frodokem976shake/META.yml index 35c9c8a8..a519d3e2 100644 --- a/crypto_kem/frodokem976shake/META.yml +++ b/crypto_kem/frodokem976shake/META.yml @@ -23,3 +23,5 @@ auxiliary-submitters: implementations: - name: clean version: https://github.com/Microsoft/PQCrypto-LWEKE/commit/d5bbd0417ba111b08a959c0042a1dcc65fb14a89 +- name: opt + version: https://github.com/Microsoft/PQCrypto-LWEKE/commit/d5bbd0417ba111b08a959c0042a1dcc65fb14a89 diff --git a/crypto_kem/frodokem976shake/clean/Makefile b/crypto_kem/frodokem976shake/clean/Makefile index 2d0a4652..ac582018 100644 --- a/crypto_kem/frodokem976shake/clean/Makefile +++ b/crypto_kem/frodokem976shake/clean/Makefile @@ -4,7 +4,7 @@ LIB=libfrodokem976shake_clean.a HEADERS=api.h params.h common.h OBJECTS=kem.o matrix_shake.o noise.o util.o -CFLAGS=-O3 -Wall -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_kem/frodokem976shake/opt/LICENSE b/crypto_kem/frodokem976shake/opt/LICENSE new file mode 100644 index 00000000..5cf7c8db --- /dev/null +++ b/crypto_kem/frodokem976shake/opt/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) Microsoft Corporation. All rights reserved. + +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/frodokem976shake/opt/Makefile b/crypto_kem/frodokem976shake/opt/Makefile new file mode 100644 index 00000000..f1a31b0b --- /dev/null +++ b/crypto_kem/frodokem976shake/opt/Makefile @@ -0,0 +1,19 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libfrodokem976shake_opt.a +HEADERS=api.h params.h common.h +OBJECTS=kem.o matrix_shake.o noise.o util.o + +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -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/frodokem976shake/opt/Makefile.Microsoft_nmake b/crypto_kem/frodokem976shake/opt/Makefile.Microsoft_nmake new file mode 100644 index 00000000..34550918 --- /dev/null +++ b/crypto_kem/frodokem976shake/opt/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=libfrodokem976shake_opt.lib +OBJECTS=kem.obj matrix_shake.obj noise.obj util.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/frodokem976shake/opt/api.h b/crypto_kem/frodokem976shake/opt/api.h new file mode 100644 index 00000000..b6bb1a7b --- /dev/null +++ b/crypto_kem/frodokem976shake/opt/api.h @@ -0,0 +1,20 @@ +#ifndef PQCLEAN_FRODOKEM976SHAKE_OPT_API_H +#define PQCLEAN_FRODOKEM976SHAKE_OPT_API_H + +#include +#include + +#define PQCLEAN_FRODOKEM976SHAKE_OPT_CRYPTO_SECRETKEYBYTES 31296 // sizeof(s) + CRYPTO_PUBLICKEYBYTES + 2*PARAMS_N*PARAMS_NBAR + BYTES_PKHASH +#define PQCLEAN_FRODOKEM976SHAKE_OPT_CRYPTO_PUBLICKEYBYTES 15632 // sizeof(seed_A) + (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 +#define PQCLEAN_FRODOKEM976SHAKE_OPT_CRYPTO_BYTES 24 +#define PQCLEAN_FRODOKEM976SHAKE_OPT_CRYPTO_CIPHERTEXTBYTES 15744 // (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 + (PARAMS_LOGQ*PARAMS_NBAR*PARAMS_NBAR)/8 + +#define PQCLEAN_FRODOKEM976SHAKE_OPT_CRYPTO_ALGNAME "FrodoKEM-976-SHAKE" + +int PQCLEAN_FRODOKEM976SHAKE_OPT_crypto_kem_keypair(uint8_t *pk, uint8_t *sk); + +int PQCLEAN_FRODOKEM976SHAKE_OPT_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk); + +int PQCLEAN_FRODOKEM976SHAKE_OPT_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk); + +#endif diff --git a/crypto_kem/frodokem976shake/opt/common.h b/crypto_kem/frodokem976shake/opt/common.h new file mode 100644 index 00000000..b51cfdf1 --- /dev/null +++ b/crypto_kem/frodokem976shake/opt/common.h @@ -0,0 +1,19 @@ +#ifndef COMMON_H +#define COMMON_H + +int PQCLEAN_FRODOKEM976SHAKE_OPT_mul_add_as_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A); +int PQCLEAN_FRODOKEM976SHAKE_OPT_mul_add_sa_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A); +void PQCLEAN_FRODOKEM976SHAKE_OPT_sample_n(uint16_t *s, size_t n); +void PQCLEAN_FRODOKEM976SHAKE_OPT_mul_bs(uint16_t *out, const uint16_t *b, const uint16_t *s); +void PQCLEAN_FRODOKEM976SHAKE_OPT_mul_add_sb_plus_e(uint16_t *out, const uint16_t *b, const uint16_t *s, const uint16_t *e); +void PQCLEAN_FRODOKEM976SHAKE_OPT_add(uint16_t *out, const uint16_t *a, const uint16_t *b); +void PQCLEAN_FRODOKEM976SHAKE_OPT_sub(uint16_t *out, const uint16_t *a, const uint16_t *b); +void PQCLEAN_FRODOKEM976SHAKE_OPT_key_encode(uint16_t *out, const uint16_t *in); +void PQCLEAN_FRODOKEM976SHAKE_OPT_key_decode(uint16_t *out, const uint16_t *in); +void PQCLEAN_FRODOKEM976SHAKE_OPT_pack(uint8_t *out, size_t outlen, const uint16_t *in, size_t inlen, uint8_t lsb); +void PQCLEAN_FRODOKEM976SHAKE_OPT_unpack(uint16_t *out, size_t outlen, const uint8_t *in, size_t inlen, uint8_t lsb); +void PQCLEAN_FRODOKEM976SHAKE_OPT_clear_bytes(uint8_t *mem, size_t n); +uint16_t PQCLEAN_FRODOKEM976SHAKE_OPT_LE_TO_UINT16(uint16_t n); +uint16_t PQCLEAN_FRODOKEM976SHAKE_OPT_UINT16_TO_LE(uint16_t n); + +#endif diff --git a/crypto_kem/frodokem976shake/opt/kem.c b/crypto_kem/frodokem976shake/opt/kem.c new file mode 100644 index 00000000..69b94ee0 --- /dev/null +++ b/crypto_kem/frodokem976shake/opt/kem.c @@ -0,0 +1,238 @@ +/******************************************************************************************** +* FrodoKEM: Learning with Errors Key Encapsulation +* +* Abstract: Key Encapsulation Mechanism (KEM) based on Frodo +*********************************************************************************************/ + +#include +#include + +#include "fips202.h" +#include "randombytes.h" + +#include "api.h" +#include "common.h" +#include "params.h" + +int PQCLEAN_FRODOKEM976SHAKE_OPT_crypto_kem_keypair(uint8_t *pk, uint8_t *sk) { + // FrodoKEM's key generation + // Outputs: public key pk ( BYTES_SEED_A + (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 bytes) + // secret key sk (CRYPTO_BYTES + BYTES_SEED_A + (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 + 2*PARAMS_N*PARAMS_NBAR + BYTES_PKHASH bytes) + uint8_t *pk_seedA = &pk[0]; + uint8_t *pk_b = &pk[BYTES_SEED_A]; + uint8_t *sk_s = &sk[0]; + uint8_t *sk_pk = &sk[CRYPTO_BYTES]; + uint8_t *sk_S = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES]; + uint8_t *sk_pkh = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES + 2 * PARAMS_N * PARAMS_NBAR]; + uint16_t B[PARAMS_N * PARAMS_NBAR] = {0}; + uint16_t S[2 * PARAMS_N * PARAMS_NBAR] = {0}; // contains secret data + uint16_t *E = &S[PARAMS_N * PARAMS_NBAR]; // contains secret data + uint8_t randomness[2 * CRYPTO_BYTES + BYTES_SEED_A]; // contains secret data via randomness_s and randomness_seedSE + uint8_t *randomness_s = &randomness[0]; // contains secret data + uint8_t *randomness_seedSE = &randomness[CRYPTO_BYTES]; // contains secret data + uint8_t *randomness_z = &randomness[2 * CRYPTO_BYTES]; + uint8_t shake_input_seedSE[1 + CRYPTO_BYTES]; // contains secret data + + // Generate the secret value s, the seed for S and E, and the seed for the seed for A. Add seed_A to the public key + randombytes(randomness, CRYPTO_BYTES + CRYPTO_BYTES + BYTES_SEED_A); + shake(pk_seedA, BYTES_SEED_A, randomness_z, BYTES_SEED_A); + + // Generate S and E, and compute B = A*S + E. Generate A on-the-fly + shake_input_seedSE[0] = 0x5F; + memcpy(&shake_input_seedSE[1], randomness_seedSE, CRYPTO_BYTES); + shake((uint8_t *)S, 2 * PARAMS_N * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSE, 1 + CRYPTO_BYTES); + for (size_t i = 0; i < 2 * PARAMS_N * PARAMS_NBAR; i++) { + S[i] = PQCLEAN_FRODOKEM976SHAKE_OPT_LE_TO_UINT16(S[i]); + } + PQCLEAN_FRODOKEM976SHAKE_OPT_sample_n(S, PARAMS_N * PARAMS_NBAR); + PQCLEAN_FRODOKEM976SHAKE_OPT_sample_n(E, PARAMS_N * PARAMS_NBAR); + PQCLEAN_FRODOKEM976SHAKE_OPT_mul_add_as_plus_e(B, S, E, pk); + + // Encode the second part of the public key + PQCLEAN_FRODOKEM976SHAKE_OPT_pack(pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, B, PARAMS_N * PARAMS_NBAR, PARAMS_LOGQ); + + // Add s, pk and S to the secret key + memcpy(sk_s, randomness_s, CRYPTO_BYTES); + memcpy(sk_pk, pk, CRYPTO_PUBLICKEYBYTES); + for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) { + S[i] = PQCLEAN_FRODOKEM976SHAKE_OPT_UINT16_TO_LE(S[i]); + } + memcpy(sk_S, S, 2 * PARAMS_N * PARAMS_NBAR); + + // Add H(pk) to the secret key + shake(sk_pkh, BYTES_PKHASH, pk, CRYPTO_PUBLICKEYBYTES); + + // Cleanup: + PQCLEAN_FRODOKEM976SHAKE_OPT_clear_bytes((uint8_t *)S, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM976SHAKE_OPT_clear_bytes((uint8_t *)E, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM976SHAKE_OPT_clear_bytes(randomness, 2 * CRYPTO_BYTES); + PQCLEAN_FRODOKEM976SHAKE_OPT_clear_bytes(shake_input_seedSE, 1 + CRYPTO_BYTES); + return 0; +} + + +int PQCLEAN_FRODOKEM976SHAKE_OPT_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk) { + // FrodoKEM's key encapsulation + const uint8_t *pk_seedA = &pk[0]; + const uint8_t *pk_b = &pk[BYTES_SEED_A]; + uint8_t *ct_c1 = &ct[0]; + uint8_t *ct_c2 = &ct[(PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8]; + uint16_t B[PARAMS_N * PARAMS_NBAR] = {0}; + uint16_t V[PARAMS_NBAR * PARAMS_NBAR] = {0}; // contains secret data + uint16_t C[PARAMS_NBAR * PARAMS_NBAR] = {0}; + uint16_t Bp[PARAMS_N * PARAMS_NBAR] = {0}; + uint16_t Sp[(2 * PARAMS_N + PARAMS_NBAR)*PARAMS_NBAR] = {0}; // contains secret data + uint16_t *Ep = &Sp[PARAMS_N * PARAMS_NBAR]; // contains secret data + uint16_t *Epp = &Sp[2 * PARAMS_N * PARAMS_NBAR]; // contains secret data + uint8_t G2in[BYTES_PKHASH + BYTES_MU]; // contains secret data via mu + uint8_t *pkh = &G2in[0]; + uint8_t *mu = &G2in[BYTES_PKHASH]; // contains secret data + uint8_t G2out[2 * CRYPTO_BYTES]; // contains secret data + uint8_t *seedSE = &G2out[0]; // contains secret data + uint8_t *k = &G2out[CRYPTO_BYTES]; // contains secret data + uint8_t Fin[CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES]; // contains secret data via Fin_k + uint8_t *Fin_ct = &Fin[0]; + uint8_t *Fin_k = &Fin[CRYPTO_CIPHERTEXTBYTES]; // contains secret data + uint8_t shake_input_seedSE[1 + CRYPTO_BYTES]; // contains secret data + + // pkh <- G_1(pk), generate random mu, compute (seedSE || k) = G_2(pkh || mu) + shake(pkh, BYTES_PKHASH, pk, CRYPTO_PUBLICKEYBYTES); + randombytes(mu, BYTES_MU); + shake(G2out, CRYPTO_BYTES + CRYPTO_BYTES, G2in, BYTES_PKHASH + BYTES_MU); + + // Generate Sp and Ep, and compute Bp = Sp*A + Ep. Generate A on-the-fly + shake_input_seedSE[0] = 0x96; + memcpy(&shake_input_seedSE[1], seedSE, CRYPTO_BYTES); + shake((uint8_t *)Sp, (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSE, 1 + CRYPTO_BYTES); + for (size_t i = 0; i < (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR; i++) { + Sp[i] = PQCLEAN_FRODOKEM976SHAKE_OPT_LE_TO_UINT16(Sp[i]); + } + PQCLEAN_FRODOKEM976SHAKE_OPT_sample_n(Sp, PARAMS_N * PARAMS_NBAR); + PQCLEAN_FRODOKEM976SHAKE_OPT_sample_n(Ep, PARAMS_N * PARAMS_NBAR); + PQCLEAN_FRODOKEM976SHAKE_OPT_mul_add_sa_plus_e(Bp, Sp, Ep, pk_seedA); + PQCLEAN_FRODOKEM976SHAKE_OPT_pack(ct_c1, (PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8, Bp, PARAMS_N * PARAMS_NBAR, PARAMS_LOGQ); + + // Generate Epp, and compute V = Sp*B + Epp + PQCLEAN_FRODOKEM976SHAKE_OPT_sample_n(Epp, PARAMS_NBAR * PARAMS_NBAR); + PQCLEAN_FRODOKEM976SHAKE_OPT_unpack(B, PARAMS_N * PARAMS_NBAR, pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, PARAMS_LOGQ); + PQCLEAN_FRODOKEM976SHAKE_OPT_mul_add_sb_plus_e(V, B, Sp, Epp); + + // Encode mu, and compute C = V + enc(mu) (mod q) + PQCLEAN_FRODOKEM976SHAKE_OPT_key_encode(C, (uint16_t *)mu); + PQCLEAN_FRODOKEM976SHAKE_OPT_add(C, V, C); + PQCLEAN_FRODOKEM976SHAKE_OPT_pack(ct_c2, (PARAMS_LOGQ * PARAMS_NBAR * PARAMS_NBAR) / 8, C, PARAMS_NBAR * PARAMS_NBAR, PARAMS_LOGQ); + + // Compute ss = F(ct||KK) + memcpy(Fin_ct, ct, CRYPTO_CIPHERTEXTBYTES); + memcpy(Fin_k, k, CRYPTO_BYTES); + shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES); + + // Cleanup: + PQCLEAN_FRODOKEM976SHAKE_OPT_clear_bytes((uint8_t *)V, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM976SHAKE_OPT_clear_bytes((uint8_t *)Sp, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM976SHAKE_OPT_clear_bytes((uint8_t *)Ep, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM976SHAKE_OPT_clear_bytes((uint8_t *)Epp, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM976SHAKE_OPT_clear_bytes(mu, BYTES_MU); + PQCLEAN_FRODOKEM976SHAKE_OPT_clear_bytes(G2out, 2 * CRYPTO_BYTES); + PQCLEAN_FRODOKEM976SHAKE_OPT_clear_bytes(Fin_k, CRYPTO_BYTES); + PQCLEAN_FRODOKEM976SHAKE_OPT_clear_bytes(shake_input_seedSE, 1 + CRYPTO_BYTES); + return 0; +} + + +int PQCLEAN_FRODOKEM976SHAKE_OPT_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk) { + // FrodoKEM's key decapsulation + uint16_t B[PARAMS_N * PARAMS_NBAR] = {0}; + uint16_t Bp[PARAMS_N * PARAMS_NBAR] = {0}; + uint16_t W[PARAMS_NBAR * PARAMS_NBAR] = {0}; // contains secret data + uint16_t C[PARAMS_NBAR * PARAMS_NBAR] = {0}; + uint16_t CC[PARAMS_NBAR * PARAMS_NBAR] = {0}; + uint16_t BBp[PARAMS_N * PARAMS_NBAR] = {0}; + uint16_t Sp[(2 * PARAMS_N + PARAMS_NBAR)*PARAMS_NBAR] = {0}; // contains secret data + uint16_t *Ep = &Sp[PARAMS_N * PARAMS_NBAR]; // contains secret data + uint16_t *Epp = &Sp[2 * PARAMS_N * PARAMS_NBAR]; // contains secret data + const uint8_t *ct_c1 = &ct[0]; + const uint8_t *ct_c2 = &ct[(PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8]; + const uint8_t *sk_s = &sk[0]; + const uint8_t *sk_pk = &sk[CRYPTO_BYTES]; + const uint16_t *sk_S = (uint16_t *) &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES]; + uint16_t S[PARAMS_N * PARAMS_NBAR]; // contains secret data + const uint8_t *sk_pkh = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES + 2 * PARAMS_N * PARAMS_NBAR]; + const uint8_t *pk_seedA = &sk_pk[0]; + const uint8_t *pk_b = &sk_pk[BYTES_SEED_A]; + uint8_t G2in[BYTES_PKHASH + BYTES_MU]; // contains secret data via muprime + uint8_t *pkh = &G2in[0]; + uint8_t *muprime = &G2in[BYTES_PKHASH]; // contains secret data + uint8_t G2out[2 * CRYPTO_BYTES]; // contains secret data + uint8_t *seedSEprime = &G2out[0]; // contains secret data + uint8_t *kprime = &G2out[CRYPTO_BYTES]; // contains secret data + uint8_t Fin[CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES]; // contains secret data via Fin_k + uint8_t *Fin_ct = &Fin[0]; + uint8_t *Fin_k = &Fin[CRYPTO_CIPHERTEXTBYTES]; // contains secret data + uint8_t shake_input_seedSEprime[1 + CRYPTO_BYTES]; // contains secret data + + for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) { + S[i] = PQCLEAN_FRODOKEM976SHAKE_OPT_LE_TO_UINT16(sk_S[i]); + } + + // Compute W = C - Bp*S (mod q), and decode the randomness mu + PQCLEAN_FRODOKEM976SHAKE_OPT_unpack(Bp, PARAMS_N * PARAMS_NBAR, ct_c1, (PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8, PARAMS_LOGQ); + PQCLEAN_FRODOKEM976SHAKE_OPT_unpack(C, PARAMS_NBAR * PARAMS_NBAR, ct_c2, (PARAMS_LOGQ * PARAMS_NBAR * PARAMS_NBAR) / 8, PARAMS_LOGQ); + PQCLEAN_FRODOKEM976SHAKE_OPT_mul_bs(W, Bp, S); + PQCLEAN_FRODOKEM976SHAKE_OPT_sub(W, C, W); + PQCLEAN_FRODOKEM976SHAKE_OPT_key_decode((uint16_t *)muprime, W); + + // Generate (seedSE' || k') = G_2(pkh || mu') + memcpy(pkh, sk_pkh, BYTES_PKHASH); + shake(G2out, CRYPTO_BYTES + CRYPTO_BYTES, G2in, BYTES_PKHASH + BYTES_MU); + + // Generate Sp and Ep, and compute BBp = Sp*A + Ep. Generate A on-the-fly + shake_input_seedSEprime[0] = 0x96; + memcpy(&shake_input_seedSEprime[1], seedSEprime, CRYPTO_BYTES); + shake((uint8_t *)Sp, (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSEprime, 1 + CRYPTO_BYTES); + for (size_t i = 0; i < (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR; i++) { + Sp[i] = PQCLEAN_FRODOKEM976SHAKE_OPT_LE_TO_UINT16(Sp[i]); + } + PQCLEAN_FRODOKEM976SHAKE_OPT_sample_n(Sp, PARAMS_N * PARAMS_NBAR); + PQCLEAN_FRODOKEM976SHAKE_OPT_sample_n(Ep, PARAMS_N * PARAMS_NBAR); + PQCLEAN_FRODOKEM976SHAKE_OPT_mul_add_sa_plus_e(BBp, Sp, Ep, pk_seedA); + + // Generate Epp, and compute W = Sp*B + Epp + PQCLEAN_FRODOKEM976SHAKE_OPT_sample_n(Epp, PARAMS_NBAR * PARAMS_NBAR); + PQCLEAN_FRODOKEM976SHAKE_OPT_unpack(B, PARAMS_N * PARAMS_NBAR, pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, PARAMS_LOGQ); + PQCLEAN_FRODOKEM976SHAKE_OPT_mul_add_sb_plus_e(W, B, Sp, Epp); + + // Encode mu, and compute CC = W + enc(mu') (mod q) + PQCLEAN_FRODOKEM976SHAKE_OPT_key_encode(CC, (uint16_t *)muprime); + PQCLEAN_FRODOKEM976SHAKE_OPT_add(CC, W, CC); + + // Prepare input to F + memcpy(Fin_ct, ct, CRYPTO_CIPHERTEXTBYTES); + + // Reducing BBp modulo q + for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) { + BBp[i] = BBp[i] & ((1 << PARAMS_LOGQ) - 1); + } + + // Is (Bp == BBp & C == CC) = true + if (memcmp(Bp, BBp, 2 * PARAMS_N * PARAMS_NBAR) == 0 && memcmp(C, CC, 2 * PARAMS_NBAR * PARAMS_NBAR) == 0) { + // Load k' to do ss = F(ct || k') + memcpy(Fin_k, kprime, CRYPTO_BYTES); + } else { + // Load s to do ss = F(ct || s) + memcpy(Fin_k, sk_s, CRYPTO_BYTES); + } + shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES); + + // Cleanup: + PQCLEAN_FRODOKEM976SHAKE_OPT_clear_bytes((uint8_t *)W, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM976SHAKE_OPT_clear_bytes((uint8_t *)Sp, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM976SHAKE_OPT_clear_bytes((uint8_t *)S, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM976SHAKE_OPT_clear_bytes((uint8_t *)Ep, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM976SHAKE_OPT_clear_bytes((uint8_t *)Epp, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t)); + PQCLEAN_FRODOKEM976SHAKE_OPT_clear_bytes(muprime, BYTES_MU); + PQCLEAN_FRODOKEM976SHAKE_OPT_clear_bytes(G2out, 2 * CRYPTO_BYTES); + PQCLEAN_FRODOKEM976SHAKE_OPT_clear_bytes(Fin_k, CRYPTO_BYTES); + PQCLEAN_FRODOKEM976SHAKE_OPT_clear_bytes(shake_input_seedSEprime, 1 + CRYPTO_BYTES); + return 0; +} diff --git a/crypto_kem/frodokem976shake/opt/matrix_shake.c b/crypto_kem/frodokem976shake/opt/matrix_shake.c new file mode 100644 index 00000000..43cf3fd2 --- /dev/null +++ b/crypto_kem/frodokem976shake/opt/matrix_shake.c @@ -0,0 +1,108 @@ +/******************************************************************************************** +* FrodoKEM: Learning with Errors Key Encapsulation +* +* Abstract: matrix arithmetic functions used by the KEM +*********************************************************************************************/ + +#include +#include + +#include "fips202.h" + +#include "api.h" +#include "common.h" +#include "params.h" + +int PQCLEAN_FRODOKEM976SHAKE_OPT_mul_add_as_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A) { + // Generate-and-multiply: generate matrix A (N x N) row-wise, multiply by s on the right. + // Inputs: s, e (N x N_BAR) + // Output: out = A*s + e (N x N_BAR) + int j, k; + uint16_t i; + int16_t a_row[4 * PARAMS_N]; + + for (i = 0; i < (PARAMS_N * PARAMS_NBAR); i += 2) { + *((uint32_t *)&out[i]) = *((uint32_t *)&e[i]); + } + + uint8_t seed_A_separated[2 + BYTES_SEED_A]; + uint16_t *seed_A_origin = (uint16_t *)&seed_A_separated; + memcpy(&seed_A_separated[2], seed_A, BYTES_SEED_A); + for (i = 0; i < PARAMS_N; i += 4) { + seed_A_origin[0] = PQCLEAN_FRODOKEM976SHAKE_OPT_UINT16_TO_LE(i + 0); + shake128((unsigned char *)(a_row + 0 * PARAMS_N), (unsigned long long)(2 * PARAMS_N), seed_A_separated, 2 + BYTES_SEED_A); + seed_A_origin[0] = PQCLEAN_FRODOKEM976SHAKE_OPT_UINT16_TO_LE(i + 1); + shake128((unsigned char *)(a_row + 1 * PARAMS_N), (unsigned long long)(2 * PARAMS_N), seed_A_separated, 2 + BYTES_SEED_A); + seed_A_origin[0] = PQCLEAN_FRODOKEM976SHAKE_OPT_UINT16_TO_LE(i + 2); + shake128((unsigned char *)(a_row + 2 * PARAMS_N), (unsigned long long)(2 * PARAMS_N), seed_A_separated, 2 + BYTES_SEED_A); + seed_A_origin[0] = PQCLEAN_FRODOKEM976SHAKE_OPT_UINT16_TO_LE(i + 3); + shake128((unsigned char *)(a_row + 3 * PARAMS_N), (unsigned long long)(2 * PARAMS_N), seed_A_separated, 2 + BYTES_SEED_A); + for (k = 0; k < 4 * PARAMS_N; k++) { + a_row[k] = PQCLEAN_FRODOKEM976SHAKE_OPT_LE_TO_UINT16(a_row[k]); + } + for (k = 0; k < PARAMS_NBAR; k++) { + uint16_t sum[4] = {0}; + for (j = 0; j < PARAMS_N; j++) { // Matrix-vector multiplication + uint16_t sp = s[k * PARAMS_N + j]; + sum[0] += a_row[0 * PARAMS_N + j] * sp; // Go through four lines with same s + sum[1] += a_row[1 * PARAMS_N + j] * sp; + sum[2] += a_row[2 * PARAMS_N + j] * sp; + sum[3] += a_row[3 * PARAMS_N + j] * sp; + } + out[(i + 0)*PARAMS_NBAR + k] += sum[0]; + out[(i + 2)*PARAMS_NBAR + k] += sum[2]; + out[(i + 1)*PARAMS_NBAR + k] += sum[1]; + out[(i + 3)*PARAMS_NBAR + k] += sum[3]; + } + } + return 1; +} + + + + +int PQCLEAN_FRODOKEM976SHAKE_OPT_mul_add_sa_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A) { + // Generate-and-multiply: generate matrix A (N x N) column-wise, multiply by s' on the left. + // Inputs: s', e' (N_BAR x N) + // Output: out = s'*A + e' (N_BAR x N) + int i, j; + uint16_t kk; + for (i = 0; i < (PARAMS_N * PARAMS_NBAR); i += 2) { + *((uint32_t *)&out[i]) = *((uint32_t *)&e[i]); + } + + int t = 0; + uint16_t a_cols[4 * PARAMS_N]; + + int k; + uint8_t seed_A_separated[2 + BYTES_SEED_A]; + uint16_t *seed_A_origin = (uint16_t *)&seed_A_separated; + memcpy(&seed_A_separated[2], seed_A, BYTES_SEED_A); + for (kk = 0; kk < PARAMS_N; kk += 4) { + seed_A_origin[0] = PQCLEAN_FRODOKEM976SHAKE_OPT_UINT16_TO_LE(kk + 0); + shake128((unsigned char *)(a_cols + 0 * PARAMS_N), (unsigned long long)(2 * PARAMS_N), seed_A_separated, 2 + BYTES_SEED_A); + seed_A_origin[0] = PQCLEAN_FRODOKEM976SHAKE_OPT_UINT16_TO_LE(kk + 1); + shake128((unsigned char *)(a_cols + 1 * PARAMS_N), (unsigned long long)(2 * PARAMS_N), seed_A_separated, 2 + BYTES_SEED_A); + seed_A_origin[0] = PQCLEAN_FRODOKEM976SHAKE_OPT_UINT16_TO_LE(kk + 2); + shake128((unsigned char *)(a_cols + 2 * PARAMS_N), (unsigned long long)(2 * PARAMS_N), seed_A_separated, 2 + BYTES_SEED_A); + seed_A_origin[0] = PQCLEAN_FRODOKEM976SHAKE_OPT_UINT16_TO_LE(kk + 3); + shake128((unsigned char *)(a_cols + 3 * PARAMS_N), (unsigned long long)(2 * PARAMS_N), seed_A_separated, 2 + BYTES_SEED_A); + for (i = 0; i < 4 * PARAMS_N; i++) { + a_cols[i] = PQCLEAN_FRODOKEM976SHAKE_OPT_LE_TO_UINT16(a_cols[i]); + } + + for (i = 0; i < PARAMS_NBAR; i++) { + uint16_t sum[PARAMS_N] = {0}; + for (j = 0; j < 4; j++) { + uint16_t sp = s[i * PARAMS_N + kk + j]; + for (k = 0; k < PARAMS_N; k++) { // Matrix-vector multiplication + sum[k] += sp * a_cols[(t + j) * PARAMS_N + k]; + } + } + for (k = 0; k < PARAMS_N; k++) { + out[i * PARAMS_N + k] += sum[k]; + } + } + } + return 1; +} diff --git a/crypto_kem/frodokem976shake/opt/noise.c b/crypto_kem/frodokem976shake/opt/noise.c new file mode 100644 index 00000000..d75e1956 --- /dev/null +++ b/crypto_kem/frodokem976shake/opt/noise.c @@ -0,0 +1,35 @@ +/******************************************************************************************** +* FrodoKEM: Learning with Errors Key Encapsulation +* +* Abstract: noise sampling functions +*********************************************************************************************/ + +#include + +#include "api.h" +#include "common.h" +#include "params.h" + +static uint16_t CDF_TABLE[CDF_TABLE_LEN] = CDF_TABLE_DATA; + +void PQCLEAN_FRODOKEM976SHAKE_OPT_sample_n(uint16_t *s, size_t n) { + // Fills vector s with n samples from the noise distribution which requires 16 bits to sample. + // The distribution is specified by its CDF. + // Input: pseudo-random values (2*n bytes) passed in s. The input is overwritten by the output. + size_t i; + unsigned int j; + + for (i = 0; i < n; ++i) { + uint16_t sample = 0; + uint16_t prnd = s[i] >> 1; // Drop the least significant bit + uint16_t sign = s[i] & 0x1; // Pick the least significant bit + + // No need to compare with the last value. + for (j = 0; j < (unsigned int)(CDF_TABLE_LEN - 1); j++) { + // Constant time comparison: 1 if CDF_TABLE[j] < s, 0 otherwise. Uses the fact that CDF_TABLE[j] and s fit in 15 bits. + sample += (uint16_t)(CDF_TABLE[j] - prnd) >> 15; + } + // Assuming that sign is either 0 or 1, flips sample iff sign = 1 + s[i] = ((-sign) ^ sample) + sign; + } +} diff --git a/crypto_kem/frodokem976shake/opt/params.h b/crypto_kem/frodokem976shake/opt/params.h new file mode 100644 index 00000000..0bf83cfd --- /dev/null +++ b/crypto_kem/frodokem976shake/opt/params.h @@ -0,0 +1,27 @@ +#ifndef PARAMS_H +#define PARAMS_H + +#define CRYPTO_SECRETKEYBYTES PQCLEAN_FRODOKEM976SHAKE_OPT_CRYPTO_SECRETKEYBYTES +#define CRYPTO_PUBLICKEYBYTES PQCLEAN_FRODOKEM976SHAKE_OPT_CRYPTO_PUBLICKEYBYTES +#define CRYPTO_BYTES PQCLEAN_FRODOKEM976SHAKE_OPT_CRYPTO_BYTES +#define CRYPTO_CIPHERTEXTBYTES PQCLEAN_FRODOKEM976SHAKE_OPT_CRYPTO_CIPHERTEXTBYTES + +#define PARAMS_N 976 +#define PARAMS_NBAR 8 +#define PARAMS_LOGQ 16 +#define PARAMS_Q (1 << PARAMS_LOGQ) +#define PARAMS_EXTRACTED_BITS 3 +#define PARAMS_STRIPE_STEP 8 +#define PARAMS_PARALLEL 4 +#define BYTES_SEED_A 16 +#define BYTES_MU ((PARAMS_EXTRACTED_BITS * PARAMS_NBAR * PARAMS_NBAR) / 8) +#define BYTES_PKHASH CRYPTO_BYTES + +// Selecting SHAKE XOF function for the KEM and noise sampling +#define shake shake256 + +// CDF table +#define CDF_TABLE_DATA {5638, 15915, 23689, 28571, 31116, 32217, 32613, 32731, 32760, 32766, 32767} +#define CDF_TABLE_LEN 11 + +#endif diff --git a/crypto_kem/frodokem976shake/opt/util.c b/crypto_kem/frodokem976shake/opt/util.c new file mode 100644 index 00000000..47b20190 --- /dev/null +++ b/crypto_kem/frodokem976shake/opt/util.c @@ -0,0 +1,235 @@ +/******************************************************************************************** +* FrodoKEM: Learning with Errors Key Encapsulation +* +* Abstract: additional functions for FrodoKEM +*********************************************************************************************/ + +#include +#include + +#include "api.h" +#include "common.h" +#include "params.h" + +#define min(x, y) (((x) < (y)) ? (x) : (y)) + +uint16_t PQCLEAN_FRODOKEM976SHAKE_OPT_LE_TO_UINT16(uint16_t n) { + return (((uint8_t *) &n)[0] | (((uint8_t *) &n)[1] << 8)); +} + +uint16_t PQCLEAN_FRODOKEM976SHAKE_OPT_UINT16_TO_LE(uint16_t n) { + uint16_t y; + uint8_t *z = (uint8_t *) &y; + z[0] = n & 0xFF; + z[1] = (n & 0xFF00) >> 8; + return y; +} + +void PQCLEAN_FRODOKEM976SHAKE_OPT_mul_bs(uint16_t *out, const uint16_t *b, const uint16_t *s) { + // Multiply by s on the right + // Inputs: b (N_BAR x N), s (N x N_BAR) + // Output: out = b*s (N_BAR x N_BAR) + int i, j, k; + + for (i = 0; i < PARAMS_NBAR; i++) { + for (j = 0; j < PARAMS_NBAR; j++) { + out[i * PARAMS_NBAR + j] = 0; + for (k = 0; k < PARAMS_N; k++) { + out[i * PARAMS_NBAR + j] += b[i * PARAMS_N + k] * s[j * PARAMS_N + k]; + } + out[i * PARAMS_NBAR + j] = (uint32_t)(out[i * PARAMS_NBAR + j]) & ((1 << PARAMS_LOGQ) - 1); + } + } +} + + +void PQCLEAN_FRODOKEM976SHAKE_OPT_mul_add_sb_plus_e(uint16_t *out, const uint16_t *b, const uint16_t *s, const uint16_t *e) { + // Multiply by s on the left + // Inputs: b (N x N_BAR), s (N_BAR x N), e (N_BAR x N_BAR) + // Output: out = s*b + e (N_BAR x N_BAR) + int i, j, k; + + for (k = 0; k < PARAMS_NBAR; k++) { + for (i = 0; i < PARAMS_NBAR; i++) { + out[k * PARAMS_NBAR + i] = e[k * PARAMS_NBAR + i]; + for (j = 0; j < PARAMS_N; j++) { + out[k * PARAMS_NBAR + i] += s[k * PARAMS_N + j] * b[j * PARAMS_NBAR + i]; + } + out[k * PARAMS_NBAR + i] = (uint32_t)(out[k * PARAMS_NBAR + i]) & ((1 << PARAMS_LOGQ) - 1); + } + } +} + + +void PQCLEAN_FRODOKEM976SHAKE_OPT_add(uint16_t *out, const uint16_t *a, const uint16_t *b) { + // Add a and b + // Inputs: a, b (N_BAR x N_BAR) + // Output: c = a + b + + for (size_t i = 0; i < (PARAMS_NBAR * PARAMS_NBAR); i++) { + out[i] = (a[i] + b[i]) & ((1 << PARAMS_LOGQ) - 1); + } +} + + +void PQCLEAN_FRODOKEM976SHAKE_OPT_sub(uint16_t *out, const uint16_t *a, const uint16_t *b) { + // Subtract a and b + // Inputs: a, b (N_BAR x N_BAR) + // Output: c = a - b + + for (size_t i = 0; i < (PARAMS_NBAR * PARAMS_NBAR); i++) { + out[i] = (a[i] - b[i]) & ((1 << PARAMS_LOGQ) - 1); + } +} + + +void PQCLEAN_FRODOKEM976SHAKE_OPT_key_encode(uint16_t *out, const uint16_t *in) { + // Encoding + unsigned int i, j, npieces_word = 8; + unsigned int nwords = (PARAMS_NBAR * PARAMS_NBAR) / 8; + uint64_t temp, mask = ((uint64_t)1 << PARAMS_EXTRACTED_BITS) - 1; + uint16_t *pos = out; + + for (i = 0; i < nwords; i++) { + temp = 0; + for (j = 0; j < PARAMS_EXTRACTED_BITS; j++) { + temp |= ((uint64_t)((uint8_t *)in)[i * PARAMS_EXTRACTED_BITS + j]) << (8 * j); + } + for (j = 0; j < npieces_word; j++) { + *pos = (uint16_t)((temp & mask) << (PARAMS_LOGQ - PARAMS_EXTRACTED_BITS)); + temp >>= PARAMS_EXTRACTED_BITS; + pos++; + } + } +} + + +void PQCLEAN_FRODOKEM976SHAKE_OPT_key_decode(uint16_t *out, const uint16_t *in) { + // Decoding + unsigned int i, j, index = 0, npieces_word = 8; + unsigned int nwords = (PARAMS_NBAR * PARAMS_NBAR) / 8; + uint16_t temp, maskex = ((uint16_t)1 << PARAMS_EXTRACTED_BITS) - 1, maskq = ((uint16_t)1 << PARAMS_LOGQ) - 1; + uint8_t *pos = (uint8_t *)out; + uint64_t templong; + + for (i = 0; i < nwords; i++) { + templong = 0; + for (j = 0; j < npieces_word; j++) { // temp = floor(in*2^{-11}+0.5) + temp = ((in[index] & maskq) + (1 << (PARAMS_LOGQ - PARAMS_EXTRACTED_BITS - 1))) >> (PARAMS_LOGQ - PARAMS_EXTRACTED_BITS); + templong |= ((uint64_t)(temp & maskex)) << (PARAMS_EXTRACTED_BITS * j); + index++; + } + for (j = 0; j < PARAMS_EXTRACTED_BITS; j++) { + pos[i * PARAMS_EXTRACTED_BITS + j] = (templong >> (8 * j)) & 0xFF; + } + } +} + + +void PQCLEAN_FRODOKEM976SHAKE_OPT_pack(uint8_t *out, size_t outlen, const uint16_t *in, size_t inlen, uint8_t lsb) { + // Pack the input uint16 vector into a char output vector, copying lsb bits from each input element. + // If inlen * lsb / 8 > outlen, only outlen * 8 bits are copied. + memset(out, 0, outlen); + + size_t i = 0; // whole bytes already filled in + size_t j = 0; // whole uint16_t already copied + uint16_t w = 0; // the leftover, not yet copied + uint8_t bits = 0; // the number of lsb in w + + while (i < outlen && (j < inlen || ((j == inlen) && (bits > 0)))) { + /* + in: | | |********|********| + ^ + j + w : | ****| + ^ + bits + out:|**|**|**|**|**|**|**|**|* | + ^^ + ib + */ + uint8_t b = 0; // bits in out[i] already filled in + while (b < 8) { + int nbits = min(8 - b, bits); + uint16_t mask = (1 << nbits) - 1; + uint8_t t = (uint8_t) ((w >> (bits - nbits)) & mask); // the bits to copy from w to out + out[i] = out[i] + (t << (8 - b - nbits)); + b += (uint8_t) nbits; + bits -= (uint8_t) nbits; + w &= ~(mask << bits); // not strictly necessary; mostly for debugging + + if (bits == 0) { + if (j < inlen) { + w = in[j]; + bits = lsb; + j++; + } else { + break; // the input vector is exhausted + } + } + } + if (b == 8) { // out[i] is filled in + i++; + } + } +} + + +void PQCLEAN_FRODOKEM976SHAKE_OPT_unpack(uint16_t *out, size_t outlen, const uint8_t *in, size_t inlen, uint8_t lsb) { + // Unpack the input char vector into a uint16_t output vector, copying lsb bits + // for each output element from input. outlen must be at least ceil(inlen * 8 / lsb). + memset(out, 0, outlen * sizeof(uint16_t)); + + size_t i = 0; // whole uint16_t already filled in + size_t j = 0; // whole bytes already copied + uint8_t w = 0; // the leftover, not yet copied + uint8_t bits = 0; // the number of lsb bits of w + + while (i < outlen && (j < inlen || ((j == inlen) && (bits > 0)))) { + /* + in: | | | | | | |**|**|... + ^ + j + w : | *| + ^ + bits + out:| *****| *****| *** | |... + ^ ^ + i b + */ + uint8_t b = 0; // bits in out[i] already filled in + while (b < lsb) { + int nbits = min(lsb - b, bits); + uint16_t mask = (1 << nbits) - 1; + uint8_t t = (w >> (bits - nbits)) & mask; // the bits to copy from w to out + out[i] = out[i] + (t << (lsb - b - nbits)); + b += (uint8_t) nbits; + bits -= (uint8_t) nbits; + w &= ~(mask << bits); // not strictly necessary; mostly for debugging + + if (bits == 0) { + if (j < inlen) { + w = in[j]; + bits = 8; + j++; + } else { + break; // the input vector is exhausted + } + } + } + if (b == lsb) { // out[i] is filled in + i++; + } + } +} + + +void PQCLEAN_FRODOKEM976SHAKE_OPT_clear_bytes(uint8_t *mem, size_t n) { + // Clear 8-bit bytes from memory. "n" indicates the number of bytes to be zeroed. + // This function uses the volatile type qualifier to inform the compiler not to optimize out the memory clearing. + volatile uint8_t *v = mem; + + for (size_t i = 0; i < n; i++) { + v[i] = 0; + } +} diff --git a/crypto_kem/kyber1024/clean/Makefile b/crypto_kem/kyber1024/clean/Makefile index e00741f7..d6ae930c 100644 --- a/crypto_kem/kyber1024/clean/Makefile +++ b/crypto_kem/kyber1024/clean/Makefile @@ -4,7 +4,7 @@ LIB=libkyber1024_clean.a HEADERS=api.h cbd.h indcpa.h ntt.h params.h poly.h polyvec.h reduce.h verify.h symmetric.h OBJECTS=cbd.o indcpa.o kem.o ntt.o poly.o polyvec.o reduce.o verify.o symmetric-fips202.o -CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_kem/kyber1024/clean/symmetric-fips202.c b/crypto_kem/kyber1024/clean/symmetric-fips202.c index b1dbf478..8b5c7d8d 100644 --- a/crypto_kem/kyber1024/clean/symmetric-fips202.c +++ b/crypto_kem/kyber1024/clean/symmetric-fips202.c @@ -13,7 +13,7 @@ * - unsigned char i additional byte of input * - unsigned char j additional byte of input **************************************************/ -void PQCLEAN_KYBER1024_CLEAN_kyber_shake128_absorb(keccak_state *s, const unsigned char *input, unsigned char x, unsigned char y) { +void PQCLEAN_KYBER1024_CLEAN_kyber_shake128_absorb(shake128ctx *s, const unsigned char *input, unsigned char x, unsigned char y) { unsigned char extseed[KYBER_SYMBYTES + 2]; int i; @@ -22,7 +22,7 @@ void PQCLEAN_KYBER1024_CLEAN_kyber_shake128_absorb(keccak_state *s, const unsign } extseed[i++] = x; extseed[i] = y; - shake128_absorb(s->s, extseed, KYBER_SYMBYTES + 2); + shake128_absorb(s, extseed, KYBER_SYMBYTES + 2); } /************************************************* @@ -34,10 +34,10 @@ void PQCLEAN_KYBER1024_CLEAN_kyber_shake128_absorb(keccak_state *s, const unsign * * Arguments: - unsigned char *output: pointer to output blocks * - size_t nblocks: number of blocks to be squeezed (written to output) -* - keccak_state *s: pointer to in/output Keccak state +* - shake128ctx *s: pointer to in/output Keccak state **************************************************/ -void PQCLEAN_KYBER1024_CLEAN_kyber_shake128_squeezeblocks(unsigned char *output, size_t nblocks, keccak_state *s) { - shake128_squeezeblocks(output, nblocks, s->s); +void PQCLEAN_KYBER1024_CLEAN_kyber_shake128_squeezeblocks(unsigned char *output, size_t nblocks, shake128ctx *s) { + shake128_squeezeblocks(output, nblocks, s); } /************************************************* diff --git a/crypto_kem/kyber1024/clean/symmetric.h b/crypto_kem/kyber1024/clean/symmetric.h index c67fbd6a..e79560e3 100644 --- a/crypto_kem/kyber1024/clean/symmetric.h +++ b/crypto_kem/kyber1024/clean/symmetric.h @@ -6,12 +6,8 @@ #include -typedef struct { - uint64_t s[25]; -} keccak_state; - -void PQCLEAN_KYBER1024_CLEAN_kyber_shake128_absorb(keccak_state *s, const unsigned char *input, unsigned char x, unsigned char y); -void PQCLEAN_KYBER1024_CLEAN_kyber_shake128_squeezeblocks(unsigned char *output, size_t nblocks, keccak_state *s); +void PQCLEAN_KYBER1024_CLEAN_kyber_shake128_absorb(shake128ctx *s, const unsigned char *input, unsigned char x, unsigned char y); +void PQCLEAN_KYBER1024_CLEAN_kyber_shake128_squeezeblocks(unsigned char *output, size_t nblocks, shake128ctx *s); void PQCLEAN_KYBER1024_CLEAN_shake256_prf(unsigned char *output, size_t outlen, const unsigned char *key, unsigned char nonce); #define hash_h(OUT, IN, INBYTES) sha3_256(OUT, IN, INBYTES) @@ -23,6 +19,6 @@ void PQCLEAN_KYBER1024_CLEAN_shake256_prf(unsigned char *output, size_t outlen, #define XOF_BLOCKBYTES 168 -typedef keccak_state xof_state; +typedef shake128ctx xof_state; #endif /* SYMMETRIC_H */ diff --git a/crypto_kem/kyber512/clean/Makefile b/crypto_kem/kyber512/clean/Makefile index 84dc881b..0b0678ee 100644 --- a/crypto_kem/kyber512/clean/Makefile +++ b/crypto_kem/kyber512/clean/Makefile @@ -4,7 +4,7 @@ LIB=libkyber512_clean.a HEADERS=api.h cbd.h indcpa.h ntt.h params.h poly.h polyvec.h reduce.h verify.h symmetric.h OBJECTS=cbd.o indcpa.o kem.o ntt.o poly.o polyvec.o reduce.o verify.o symmetric-fips202.o -CFLAGS=-Wall -O3 -Wmissing-prototypes -Wextra -Wpedantic -Werror -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_kem/kyber512/clean/symmetric-fips202.c b/crypto_kem/kyber512/clean/symmetric-fips202.c index 345cebb4..cb17e0c2 100644 --- a/crypto_kem/kyber512/clean/symmetric-fips202.c +++ b/crypto_kem/kyber512/clean/symmetric-fips202.c @@ -8,12 +8,12 @@ * * Description: Absorb step of the SHAKE128 specialized for the Kyber context. * -* Arguments: - uint64_t *s: pointer to (uninitialized) output Keccak state +* Arguments: - shake128ctx *s: pointer to (uninitialized) output Keccak state * - const unsigned char *input: pointer to KYBER_SYMBYTES input to be absorbed into s * - unsigned char i additional byte of input * - unsigned char j additional byte of input **************************************************/ -void PQCLEAN_KYBER512_CLEAN_kyber_shake128_absorb(keccak_state *s, const unsigned char *input, unsigned char x, unsigned char y) { +void PQCLEAN_KYBER512_CLEAN_kyber_shake128_absorb(shake128ctx *s, const unsigned char *input, unsigned char x, unsigned char y) { unsigned char extseed[KYBER_SYMBYTES + 2]; int i; @@ -22,7 +22,7 @@ void PQCLEAN_KYBER512_CLEAN_kyber_shake128_absorb(keccak_state *s, const unsigne } extseed[i++] = x; extseed[i] = y; - shake128_absorb(s->s, extseed, KYBER_SYMBYTES + 2); + shake128_absorb(s, extseed, KYBER_SYMBYTES + 2); } /************************************************* @@ -34,10 +34,10 @@ void PQCLEAN_KYBER512_CLEAN_kyber_shake128_absorb(keccak_state *s, const unsigne * * Arguments: - unsigned char *output: pointer to output blocks * - size_t nblocks: number of blocks to be squeezed (written to output) -* - keccak_state *s: pointer to in/output Keccak state +* - shake128ctx *s: pointer to in/output Keccak state **************************************************/ -void PQCLEAN_KYBER512_CLEAN_kyber_shake128_squeezeblocks(unsigned char *output, size_t nblocks, keccak_state *s) { - shake128_squeezeblocks(output, nblocks, s->s); +void PQCLEAN_KYBER512_CLEAN_kyber_shake128_squeezeblocks(unsigned char *output, size_t nblocks, shake128ctx *s) { + shake128_squeezeblocks(output, nblocks, s); } /************************************************* diff --git a/crypto_kem/kyber512/clean/symmetric.h b/crypto_kem/kyber512/clean/symmetric.h index b0f61aeb..7ad121e1 100644 --- a/crypto_kem/kyber512/clean/symmetric.h +++ b/crypto_kem/kyber512/clean/symmetric.h @@ -4,12 +4,8 @@ #include "fips202.h" #include "params.h" -typedef struct { - uint64_t s[25]; -} keccak_state; - -void PQCLEAN_KYBER512_CLEAN_kyber_shake128_absorb(keccak_state *s, const unsigned char *input, unsigned char x, unsigned char y); -void PQCLEAN_KYBER512_CLEAN_kyber_shake128_squeezeblocks(unsigned char *output, size_t nblocks, keccak_state *s); +void PQCLEAN_KYBER512_CLEAN_kyber_shake128_absorb(shake128ctx *s, const unsigned char *input, unsigned char x, unsigned char y); +void PQCLEAN_KYBER512_CLEAN_kyber_shake128_squeezeblocks(unsigned char *output, size_t nblocks, shake128ctx *s); void PQCLEAN_KYBER512_CLEAN_shake256_prf(unsigned char *output, size_t outlen, const unsigned char *key, unsigned char nonce); #define hash_h(OUT, IN, INBYTES) sha3_256(OUT, IN, INBYTES) @@ -21,6 +17,6 @@ void PQCLEAN_KYBER512_CLEAN_shake256_prf(unsigned char *output, size_t outlen, c #define XOF_BLOCKBYTES 168 -typedef keccak_state xof_state; +typedef shake128ctx xof_state; #endif /* SYMMETRIC_H */ diff --git a/crypto_kem/kyber768/clean/Makefile b/crypto_kem/kyber768/clean/Makefile index c98f6e49..33864abd 100644 --- a/crypto_kem/kyber768/clean/Makefile +++ b/crypto_kem/kyber768/clean/Makefile @@ -4,7 +4,7 @@ LIB=libkyber768_clean.a HEADERS=api.h cbd.h indcpa.h ntt.h params.h poly.h polyvec.h reduce.h verify.h symmetric.h OBJECTS=cbd.o indcpa.o kem.o ntt.o poly.o polyvec.o reduce.o verify.o symmetric-fips202.o -CFLAGS=-O3 -Wall -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_kem/kyber768/clean/symmetric-fips202.c b/crypto_kem/kyber768/clean/symmetric-fips202.c index 3d4e858c..c9e16068 100644 --- a/crypto_kem/kyber768/clean/symmetric-fips202.c +++ b/crypto_kem/kyber768/clean/symmetric-fips202.c @@ -8,12 +8,12 @@ * * Description: Absorb step of the SHAKE128 specialized for the Kyber context. * -* Arguments: - uint64_t *s: pointer to (uninitialized) output Keccak state +* Arguments: - shake128ctx *s: pointer to (uninitialized) output Keccak state * - const unsigned char *input: pointer to KYBER_SYMBYTES input to be absorbed into s * - unsigned char i additional byte of input * - unsigned char j additional byte of input **************************************************/ -void PQCLEAN_KYBER768_CLEAN_kyber_shake128_absorb(keccak_state *s, const unsigned char *input, unsigned char x, unsigned char y) { +void PQCLEAN_KYBER768_CLEAN_kyber_shake128_absorb(shake128ctx *s, const unsigned char *input, unsigned char x, unsigned char y) { unsigned char extseed[KYBER_SYMBYTES + 2]; int i; @@ -22,7 +22,7 @@ void PQCLEAN_KYBER768_CLEAN_kyber_shake128_absorb(keccak_state *s, const unsigne } extseed[i++] = x; extseed[i] = y; - shake128_absorb(s->s, extseed, KYBER_SYMBYTES + 2); + shake128_absorb(s, extseed, KYBER_SYMBYTES + 2); } /************************************************* @@ -34,10 +34,10 @@ void PQCLEAN_KYBER768_CLEAN_kyber_shake128_absorb(keccak_state *s, const unsigne * * Arguments: - unsigned char *output: pointer to output blocks * - size_t nblocks: number of blocks to be squeezed (written to output) -* - keccak_state *s: pointer to in/output Keccak state +* - shake128ctx *s: pointer to in/output Keccak state **************************************************/ -void PQCLEAN_KYBER768_CLEAN_kyber_shake128_squeezeblocks(unsigned char *output, size_t nblocks, keccak_state *s) { - shake128_squeezeblocks(output, nblocks, s->s); +void PQCLEAN_KYBER768_CLEAN_kyber_shake128_squeezeblocks(unsigned char *output, size_t nblocks, shake128ctx *s) { + shake128_squeezeblocks(output, nblocks, s); } /************************************************* diff --git a/crypto_kem/kyber768/clean/symmetric.h b/crypto_kem/kyber768/clean/symmetric.h index 7cdff295..b2c5126a 100644 --- a/crypto_kem/kyber768/clean/symmetric.h +++ b/crypto_kem/kyber768/clean/symmetric.h @@ -4,12 +4,8 @@ #include "fips202.h" #include "params.h" -typedef struct { - uint64_t s[25]; -} keccak_state; - -void PQCLEAN_KYBER768_CLEAN_kyber_shake128_absorb(keccak_state *s, const unsigned char *input, unsigned char x, unsigned char y); -void PQCLEAN_KYBER768_CLEAN_kyber_shake128_squeezeblocks(unsigned char *output, size_t nblocks, keccak_state *s); +void PQCLEAN_KYBER768_CLEAN_kyber_shake128_absorb(shake128ctx *s, const unsigned char *input, unsigned char x, unsigned char y); +void PQCLEAN_KYBER768_CLEAN_kyber_shake128_squeezeblocks(unsigned char *output, size_t nblocks, shake128ctx *s); void PQCLEAN_KYBER768_CLEAN_shake256_prf(unsigned char *output, size_t outlen, const unsigned char *key, unsigned char nonce); #define hash_h(OUT, IN, INBYTES) sha3_256(OUT, IN, INBYTES) @@ -21,6 +17,6 @@ void PQCLEAN_KYBER768_CLEAN_shake256_prf(unsigned char *output, size_t outlen, c #define XOF_BLOCKBYTES 168 -typedef keccak_state xof_state; +typedef shake128ctx xof_state; #endif /* SYMMETRIC_H */ diff --git a/crypto_kem/newhope1024cca/META.yml b/crypto_kem/newhope1024cca/META.yml new file mode 100644 index 00000000..2912288a --- /dev/null +++ b/crypto_kem/newhope1024cca/META.yml @@ -0,0 +1,21 @@ +name: NewHope1024CCA +type: kem +claimed-nist-level: 5 +claimed-security: IND-CCA2 +length-public-key: 1824 +length-secret-key: 3680 +length-ciphertext: 2208 +length-shared-secret: 32 +nistkat-sha256: 8500b88222b3a62e57a6ecaac57f79258f08af49211e0c3f2ca7eab8089c0ce0 +principal-submitter: Thomas Pöppelmann +auxiliary-submitters: +- Erdem Alkim +- Roberto Avanzi +- Joppe Bos +- Léo Ducas +- Antonio de la Piedra +- Peter Schwabe +- Douglas Stebila +implementations: +- name: clean + version: https://github.com/newhopecrypto/newhope/commit/3fc68c6090b23c56cc190a78af2f43ee8900e9d0 diff --git a/crypto_kem/newhope1024cca/clean/LICENSE b/crypto_kem/newhope1024cca/clean/LICENSE new file mode 100644 index 00000000..d5d21fff --- /dev/null +++ b/crypto_kem/newhope1024cca/clean/LICENSE @@ -0,0 +1 @@ +Public Domain diff --git a/crypto_kem/newhope1024cca/clean/Makefile b/crypto_kem/newhope1024cca/clean/Makefile new file mode 100644 index 00000000..0d011039 --- /dev/null +++ b/crypto_kem/newhope1024cca/clean/Makefile @@ -0,0 +1,19 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libnewhope1024cca_clean.a +HEADERS=api.h cpapke.h ntt.h params.h poly.h reduce.h verify.h +OBJECTS=cpapke.o kem.o ntt.o poly.o precomp.o reduce.o verify.o + +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Wvla -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/newhope1024cca/clean/Makefile.Microsoft_nmake b/crypto_kem/newhope1024cca/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..f6dca8d7 --- /dev/null +++ b/crypto_kem/newhope1024cca/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=libnewhope1024cca_clean.lib +OBJECTS=cpapke.obj kem.obj ntt.obj poly.obj precomp.obj reduce.obj verify.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/newhope1024cca/clean/api.h b/crypto_kem/newhope1024cca/clean/api.h new file mode 100644 index 00000000..62139de0 --- /dev/null +++ b/crypto_kem/newhope1024cca/clean/api.h @@ -0,0 +1,15 @@ +#ifndef PQCLEAN_NEWHOPE1024CCA_CLEAN_API_H +#define PQCLEAN_NEWHOPE1024CCA_CLEAN_API_H + + +#define PQCLEAN_NEWHOPE1024CCA_CLEAN_CRYPTO_SECRETKEYBYTES 3680 +#define PQCLEAN_NEWHOPE1024CCA_CLEAN_CRYPTO_PUBLICKEYBYTES 1824 +#define PQCLEAN_NEWHOPE1024CCA_CLEAN_CRYPTO_CIPHERTEXTBYTES 2208 +#define PQCLEAN_NEWHOPE1024CCA_CLEAN_CRYPTO_BYTES 32 +#define PQCLEAN_NEWHOPE1024CCA_CLEAN_CRYPTO_ALGNAME "NewHope1024-CCAKEM" + +int PQCLEAN_NEWHOPE1024CCA_CLEAN_crypto_kem_keypair(unsigned char *pk, unsigned char *sk); +int PQCLEAN_NEWHOPE1024CCA_CLEAN_crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk); +int PQCLEAN_NEWHOPE1024CCA_CLEAN_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk); + +#endif diff --git a/crypto_kem/newhope1024cca/clean/cpapke.c b/crypto_kem/newhope1024cca/clean/cpapke.c new file mode 100644 index 00000000..09986223 --- /dev/null +++ b/crypto_kem/newhope1024cca/clean/cpapke.c @@ -0,0 +1,192 @@ +#include "api.h" +#include "cpapke.h" +#include "fips202.h" +#include "poly.h" +#include "randombytes.h" +#include + +/************************************************* +* Name: encode_pk +* +* Description: Serialize the public key as concatenation of the +* serialization of the polynomial pk and the public seed +* used to generete the polynomial a. +* +* Arguments: unsigned char *r: pointer to the output serialized public key +* const poly *pk: pointer to the input public-key polynomial +* const unsigned char *seed: pointer to the input public seed +**************************************************/ +static void encode_pk(unsigned char *r, const poly *pk, const unsigned char *seed) { + int i; + PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_tobytes(r, pk); + for (i = 0; i < NEWHOPE_SYMBYTES; i++) { + r[NEWHOPE_POLYBYTES + i] = seed[i]; + } +} + +/************************************************* +* Name: decode_pk +* +* Description: De-serialize the public key; inverse of encode_pk +* +* Arguments: poly *pk: pointer to output public-key polynomial +* unsigned char *seed: pointer to output public seed +* const unsigned char *r: pointer to input byte array +**************************************************/ +static void decode_pk(poly *pk, unsigned char *seed, const unsigned char *r) { + int i; + PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_frombytes(pk, r); + for (i = 0; i < NEWHOPE_SYMBYTES; i++) { + seed[i] = r[NEWHOPE_POLYBYTES + i]; + } +} + +/************************************************* +* Name: encode_c +* +* Description: Serialize the ciphertext as concatenation of the +* serialization of the polynomial b and serialization +* of the compressed polynomial v +* +* Arguments: - unsigned char *r: pointer to the output serialized ciphertext +* - const poly *b: pointer to the input polynomial b +* - const poly *v: pointer to the input polynomial v +**************************************************/ +static void encode_c(unsigned char *r, const poly *b, const poly *v) { + PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_tobytes(r, b); + PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_compress(r + NEWHOPE_POLYBYTES, v); +} + +/************************************************* +* Name: decode_c +* +* Description: de-serialize the ciphertext; inverse of encode_c +* +* Arguments: - poly *b: pointer to output polynomial b +* - poly *v: pointer to output polynomial v +* - const unsigned char *r: pointer to input byte array +**************************************************/ +static void decode_c(poly *b, poly *v, const unsigned char *r) { + PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_frombytes(b, r); + PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_decompress(v, r + NEWHOPE_POLYBYTES); +} + +/************************************************* +* Name: gen_a +* +* Description: Deterministically generate public polynomial a from seed +* +* Arguments: - poly *a: pointer to output polynomial a +* - const unsigned char *seed: pointer to input seed +**************************************************/ +static void gen_a(poly *a, const unsigned char *seed) { + PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_uniform(a, seed); +} + + +/************************************************* +* Name: cpapke_keypair +* +* Description: Generates public and private key +* for the CPA public-key encryption scheme underlying +* the NewHope KEMs +* +* Arguments: - unsigned char *pk: pointer to output public key +* - unsigned char *sk: pointer to output private key +**************************************************/ +void PQCLEAN_NEWHOPE1024CCA_CLEAN_cpapke_keypair(unsigned char *pk, + unsigned char *sk) { + poly ahat, ehat, ahat_shat, bhat, shat; + unsigned char z[2 * NEWHOPE_SYMBYTES]; + unsigned char *publicseed = z; + unsigned char *noiseseed = z + NEWHOPE_SYMBYTES; + + randombytes(z, NEWHOPE_SYMBYTES); + shake256(z, 2 * NEWHOPE_SYMBYTES, z, NEWHOPE_SYMBYTES); + + gen_a(&ahat, publicseed); + + PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_sample(&shat, noiseseed, 0); + PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_ntt(&shat); + + PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_sample(&ehat, noiseseed, 1); + PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_ntt(&ehat); + + PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_mul_pointwise(&ahat_shat, &shat, &ahat); + PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_add(&bhat, &ehat, &ahat_shat); + + PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_tobytes(sk, &shat); + encode_pk(pk, &bhat, publicseed); +} + +/************************************************* +* Name: cpapke_enc +* +* Description: Encryption function of +* the CPA public-key encryption scheme underlying +* the NewHope KEMs +* +* Arguments: - unsigned char *c: pointer to output ciphertext +* - const unsigned char *m: pointer to input message (of length NEWHOPE_SYMBYTES bytes) +* - const unsigned char *pk: pointer to input public key +* - const unsigned char *coin: pointer to input random coins used as seed +* to deterministically generate all randomness +**************************************************/ +void PQCLEAN_NEWHOPE1024CCA_CLEAN_cpapke_enc(unsigned char *c, + const unsigned char *m, + const unsigned char *pk, + const unsigned char *coin) { + poly sprime, eprime, vprime, ahat, bhat, eprimeprime, uhat, v; + unsigned char publicseed[NEWHOPE_SYMBYTES]; + + PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_frommsg(&v, m); + + decode_pk(&bhat, publicseed, pk); + gen_a(&ahat, publicseed); + + PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_sample(&sprime, coin, 0); + PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_sample(&eprime, coin, 1); + PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_sample(&eprimeprime, coin, 2); + + PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_ntt(&sprime); + PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_ntt(&eprime); + + PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_mul_pointwise(&uhat, &ahat, &sprime); + PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_add(&uhat, &uhat, &eprime); + + PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_mul_pointwise(&vprime, &bhat, &sprime); + PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_invntt(&vprime); + + PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_add(&vprime, &vprime, &eprimeprime); + PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_add(&vprime, &vprime, &v); // add message + + encode_c(c, &uhat, &vprime); +} + + +/************************************************* +* Name: cpapke_dec +* +* Description: Decryption function of +* the CPA public-key encryption scheme underlying +* the NewHope KEMs +* +* Arguments: - unsigned char *m: pointer to output decrypted message +* - const unsigned char *c: pointer to input ciphertext +* - const unsigned char *sk: pointer to input secret key +**************************************************/ +void PQCLEAN_NEWHOPE1024CCA_CLEAN_cpapke_dec(unsigned char *m, + const unsigned char *c, + const unsigned char *sk) { + poly vprime, uhat, tmp, shat; + + PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_frombytes(&shat, sk); + + decode_c(&uhat, &vprime, c); + PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_mul_pointwise(&tmp, &shat, &uhat); + PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_invntt(&tmp); + + PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_sub(&tmp, &tmp, &vprime); + + PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_tomsg(m, &tmp); +} diff --git a/crypto_kem/newhope1024cca/clean/cpapke.h b/crypto_kem/newhope1024cca/clean/cpapke.h new file mode 100644 index 00000000..34be8055 --- /dev/null +++ b/crypto_kem/newhope1024cca/clean/cpapke.h @@ -0,0 +1,16 @@ +#ifndef INDCPA_H +#define INDCPA_H + +void PQCLEAN_NEWHOPE1024CCA_CLEAN_cpapke_keypair(unsigned char *pk, + unsigned char *sk); + +void PQCLEAN_NEWHOPE1024CCA_CLEAN_cpapke_enc(unsigned char *c, + const unsigned char *m, + const unsigned char *pk, + const unsigned char *coins); + +void PQCLEAN_NEWHOPE1024CCA_CLEAN_cpapke_dec(unsigned char *m, + const unsigned char *c, + const unsigned char *sk); + +#endif diff --git a/crypto_kem/newhope1024cca/clean/kem.c b/crypto_kem/newhope1024cca/clean/kem.c new file mode 100644 index 00000000..2ac276c6 --- /dev/null +++ b/crypto_kem/newhope1024cca/clean/kem.c @@ -0,0 +1,116 @@ +#include "api.h" +#include "cpapke.h" +#include "fips202.h" +#include "params.h" +#include "randombytes.h" +#include "verify.h" + +#include + +/************************************************* +* Name: crypto_kem_keypair +* +* Description: Generates public and private key +* for CCA secure NewHope key encapsulation +* mechanism +* +* Arguments: - unsigned char *pk: pointer to output public key (an already allocated array of CRYPTO_PUBLICKEYBYTES bytes) +* - unsigned char *sk: pointer to output private key (an already allocated array of CRYPTO_SECRETKEYBYTES bytes) +* +* Returns 0 (success) +**************************************************/ +int PQCLEAN_NEWHOPE1024CCA_CLEAN_crypto_kem_keypair(unsigned char *pk, unsigned char *sk) { + size_t i; + + PQCLEAN_NEWHOPE1024CCA_CLEAN_cpapke_keypair(pk, sk); /* First put the actual secret key into sk */ + sk += NEWHOPE_CPAPKE_SECRETKEYBYTES; + + for (i = 0; i < NEWHOPE_CPAPKE_PUBLICKEYBYTES; i++) { /* Append the public key for re-encryption */ + sk[i] = pk[i]; + } + sk += NEWHOPE_CPAPKE_PUBLICKEYBYTES; + + shake256(sk, NEWHOPE_SYMBYTES, pk, NEWHOPE_CPAPKE_PUBLICKEYBYTES); /* Append the hash of the public key */ + sk += NEWHOPE_SYMBYTES; + + randombytes(sk, NEWHOPE_SYMBYTES); /* Append the value s for pseudo-random output on reject */ + + return 0; +} + +/************************************************* +* Name: crypto_kem_enc +* +* Description: Generates cipher text and shared +* secret for given public key +* +* Arguments: - unsigned char *ct: pointer to output cipher text (an already allocated array of CRYPTO_CIPHERTEXTBYTES bytes) +* - unsigned char *ss: pointer to output shared secret (an already allocated array of CRYPTO_BYTES bytes) +* - const unsigned char *pk: pointer to input public key (an already allocated array of CRYPTO_PUBLICKEYBYTES bytes) +* +* Returns 0 (success) +**************************************************/ +int PQCLEAN_NEWHOPE1024CCA_CLEAN_crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk) { + unsigned char k_coins_d[3 * NEWHOPE_SYMBYTES]; /* Will contain key, coins, qrom-hash */ + unsigned char buf[2 * NEWHOPE_SYMBYTES]; + int i; + + randombytes(buf, NEWHOPE_SYMBYTES); + + shake256(buf, NEWHOPE_SYMBYTES, buf, NEWHOPE_SYMBYTES); /* Don't release system RNG output */ + shake256(buf + NEWHOPE_SYMBYTES, NEWHOPE_SYMBYTES, pk, NEWHOPE_CCAKEM_PUBLICKEYBYTES); /* Multitarget countermeasure for coins + contributory KEM */ + shake256(k_coins_d, 3 * NEWHOPE_SYMBYTES, buf, 2 * NEWHOPE_SYMBYTES); + + PQCLEAN_NEWHOPE1024CCA_CLEAN_cpapke_enc(ct, buf, pk, k_coins_d + NEWHOPE_SYMBYTES); /* coins are in k_coins_d+NEWHOPE_SYMBYTES */ + + for (i = 0; i < NEWHOPE_SYMBYTES; i++) { + ct[i + NEWHOPE_CPAPKE_CIPHERTEXTBYTES] = k_coins_d[i + 2 * NEWHOPE_SYMBYTES]; /* copy Targhi-Unruh hash into ct */ + } + + shake256(k_coins_d + NEWHOPE_SYMBYTES, NEWHOPE_SYMBYTES, ct, NEWHOPE_CCAKEM_CIPHERTEXTBYTES); /* overwrite coins in k_coins_d with h(c) */ + shake256(ss, NEWHOPE_SYMBYTES, k_coins_d, 2 * NEWHOPE_SYMBYTES); /* hash concatenation of pre-k and h(c) to ss */ + return 0; +} + +/************************************************* +* Name: crypto_kem_dec +* +* Description: Generates shared secret for given +* cipher text and private key +* +* Arguments: - unsigned char *ss: pointer to output shared secret (an already allocated array of CRYPTO_BYTES bytes) +* - const unsigned char *ct: pointer to input cipher text (an already allocated array of CRYPTO_CIPHERTEXTBYTES bytes) +* - const unsigned char *sk: pointer to input private key (an already allocated array of CRYPTO_SECRETKEYBYTES bytes) +* +* Returns 0 for sucess or -1 for failure +* +* On failure, ss will contain a randomized value. +**************************************************/ +int PQCLEAN_NEWHOPE1024CCA_CLEAN_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk) { + int i, fail; + unsigned char ct_cmp[NEWHOPE_CCAKEM_CIPHERTEXTBYTES]; + unsigned char buf[2 * NEWHOPE_SYMBYTES]; + unsigned char k_coins_d[3 * NEWHOPE_SYMBYTES]; /* Will contain key, coins, qrom-hash */ + const unsigned char *pk = sk + NEWHOPE_CPAPKE_SECRETKEYBYTES; + + PQCLEAN_NEWHOPE1024CCA_CLEAN_cpapke_dec(buf, ct, sk); + + for (i = 0; i < NEWHOPE_SYMBYTES; i++) { /* Use hash of pk stored in sk */ + buf[NEWHOPE_SYMBYTES + i] = sk[NEWHOPE_CCAKEM_SECRETKEYBYTES - 2 * NEWHOPE_SYMBYTES + i]; + } + shake256(k_coins_d, 3 * NEWHOPE_SYMBYTES, buf, 2 * NEWHOPE_SYMBYTES); + + PQCLEAN_NEWHOPE1024CCA_CLEAN_cpapke_enc(ct_cmp, buf, pk, k_coins_d + NEWHOPE_SYMBYTES); /* coins are in k_coins_d+NEWHOPE_SYMBYTES */ + + for (i = 0; i < NEWHOPE_SYMBYTES; i++) { + ct_cmp[i + NEWHOPE_CPAPKE_CIPHERTEXTBYTES] = k_coins_d[i + 2 * NEWHOPE_SYMBYTES]; + } + + fail = PQCLEAN_NEWHOPE1024CCA_CLEAN_verify(ct, ct_cmp, NEWHOPE_CCAKEM_CIPHERTEXTBYTES); + + shake256(k_coins_d + NEWHOPE_SYMBYTES, NEWHOPE_SYMBYTES, ct, NEWHOPE_CCAKEM_CIPHERTEXTBYTES); /* overwrite coins in k_coins_d with h(c) */ + PQCLEAN_NEWHOPE1024CCA_CLEAN_cmov(k_coins_d, sk + NEWHOPE_CCAKEM_SECRETKEYBYTES - NEWHOPE_SYMBYTES, NEWHOPE_SYMBYTES, (unsigned char) fail); /* Overwrite pre-k with z on re-encryption failure */ + shake256(ss, NEWHOPE_SYMBYTES, k_coins_d, 2 * NEWHOPE_SYMBYTES); /* hash concatenation of pre-k and h(c) to k */ + + return 0; +} diff --git a/crypto_kem/newhope1024cca/clean/ntt.c b/crypto_kem/newhope1024cca/clean/ntt.c new file mode 100644 index 00000000..ffefa465 --- /dev/null +++ b/crypto_kem/newhope1024cca/clean/ntt.c @@ -0,0 +1,127 @@ +#include "inttypes.h" +#include "ntt.h" +#include "params.h" +#include "reduce.h" + +/************************************************************ +* Name: bitrev_table +* +* Description: Contains bit-reversed 10-bit indices to be used to re-order +* polynomials before number theoratic transform +************************************************************/ +static uint16_t bitrev_table[NEWHOPE_N] = { + 0, 512, 256, 768, 128, 640, 384, 896, 64, 576, 320, 832, 192, 704, 448, 960, 32, 544, 288, 800, 160, 672, 416, 928, 96, 608, 352, 864, 224, 736, 480, 992, + 16, 528, 272, 784, 144, 656, 400, 912, 80, 592, 336, 848, 208, 720, 464, 976, 48, 560, 304, 816, 176, 688, 432, 944, 112, 624, 368, 880, 240, 752, 496, 1008, + 8, 520, 264, 776, 136, 648, 392, 904, 72, 584, 328, 840, 200, 712, 456, 968, 40, 552, 296, 808, 168, 680, 424, 936, 104, 616, 360, 872, 232, 744, 488, 1000, + 24, 536, 280, 792, 152, 664, 408, 920, 88, 600, 344, 856, 216, 728, 472, 984, 56, 568, 312, 824, 184, 696, 440, 952, 120, 632, 376, 888, 248, 760, 504, 1016, + 4, 516, 260, 772, 132, 644, 388, 900, 68, 580, 324, 836, 196, 708, 452, 964, 36, 548, 292, 804, 164, 676, 420, 932, 100, 612, 356, 868, 228, 740, 484, 996, + 20, 532, 276, 788, 148, 660, 404, 916, 84, 596, 340, 852, 212, 724, 468, 980, 52, 564, 308, 820, 180, 692, 436, 948, 116, 628, 372, 884, 244, 756, 500, 1012, + 12, 524, 268, 780, 140, 652, 396, 908, 76, 588, 332, 844, 204, 716, 460, 972, 44, 556, 300, 812, 172, 684, 428, 940, 108, 620, 364, 876, 236, 748, 492, 1004, + 28, 540, 284, 796, 156, 668, 412, 924, 92, 604, 348, 860, 220, 732, 476, 988, 60, 572, 316, 828, 188, 700, 444, 956, 124, 636, 380, 892, 252, 764, 508, 1020, + 2, 514, 258, 770, 130, 642, 386, 898, 66, 578, 322, 834, 194, 706, 450, 962, 34, 546, 290, 802, 162, 674, 418, 930, 98, 610, 354, 866, 226, 738, 482, 994, + 18, 530, 274, 786, 146, 658, 402, 914, 82, 594, 338, 850, 210, 722, 466, 978, 50, 562, 306, 818, 178, 690, 434, 946, 114, 626, 370, 882, 242, 754, 498, 1010, + 10, 522, 266, 778, 138, 650, 394, 906, 74, 586, 330, 842, 202, 714, 458, 970, 42, 554, 298, 810, 170, 682, 426, 938, 106, 618, 362, 874, 234, 746, 490, 1002, + 26, 538, 282, 794, 154, 666, 410, 922, 90, 602, 346, 858, 218, 730, 474, 986, 58, 570, 314, 826, 186, 698, 442, 954, 122, 634, 378, 890, 250, 762, 506, 1018, + 6, 518, 262, 774, 134, 646, 390, 902, 70, 582, 326, 838, 198, 710, 454, 966, 38, 550, 294, 806, 166, 678, 422, 934, 102, 614, 358, 870, 230, 742, 486, 998, + 22, 534, 278, 790, 150, 662, 406, 918, 86, 598, 342, 854, 214, 726, 470, 982, 54, 566, 310, 822, 182, 694, 438, 950, 118, 630, 374, 886, 246, 758, 502, 1014, + 14, 526, 270, 782, 142, 654, 398, 910, 78, 590, 334, 846, 206, 718, 462, 974, 46, 558, 302, 814, 174, 686, 430, 942, 110, 622, 366, 878, 238, 750, 494, 1006, + 30, 542, 286, 798, 158, 670, 414, 926, 94, 606, 350, 862, 222, 734, 478, 990, 62, 574, 318, 830, 190, 702, 446, 958, 126, 638, 382, 894, 254, 766, 510, 1022, + 1, 513, 257, 769, 129, 641, 385, 897, 65, 577, 321, 833, 193, 705, 449, 961, 33, 545, 289, 801, 161, 673, 417, 929, 97, 609, 353, 865, 225, 737, 481, 993, + 17, 529, 273, 785, 145, 657, 401, 913, 81, 593, 337, 849, 209, 721, 465, 977, 49, 561, 305, 817, 177, 689, 433, 945, 113, 625, 369, 881, 241, 753, 497, 1009, + 9, 521, 265, 777, 137, 649, 393, 905, 73, 585, 329, 841, 201, 713, 457, 969, 41, 553, 297, 809, 169, 681, 425, 937, 105, 617, 361, 873, 233, 745, 489, 1001, + 25, 537, 281, 793, 153, 665, 409, 921, 89, 601, 345, 857, 217, 729, 473, 985, 57, 569, 313, 825, 185, 697, 441, 953, 121, 633, 377, 889, 249, 761, 505, 1017, + 5, 517, 261, 773, 133, 645, 389, 901, 69, 581, 325, 837, 197, 709, 453, 965, 37, 549, 293, 805, 165, 677, 421, 933, 101, 613, 357, 869, 229, 741, 485, 997, + 21, 533, 277, 789, 149, 661, 405, 917, 85, 597, 341, 853, 213, 725, 469, 981, 53, 565, 309, 821, 181, 693, 437, 949, 117, 629, 373, 885, 245, 757, 501, 1013, + 13, 525, 269, 781, 141, 653, 397, 909, 77, 589, 333, 845, 205, 717, 461, 973, 45, 557, 301, 813, 173, 685, 429, 941, 109, 621, 365, 877, 237, 749, 493, 1005, + 29, 541, 285, 797, 157, 669, 413, 925, 93, 605, 349, 861, 221, 733, 477, 989, 61, 573, 317, 829, 189, 701, 445, 957, 125, 637, 381, 893, 253, 765, 509, 1021, + 3, 515, 259, 771, 131, 643, 387, 899, 67, 579, 323, 835, 195, 707, 451, 963, 35, 547, 291, 803, 163, 675, 419, 931, 99, 611, 355, 867, 227, 739, 483, 995, + 19, 531, 275, 787, 147, 659, 403, 915, 83, 595, 339, 851, 211, 723, 467, 979, 51, 563, 307, 819, 179, 691, 435, 947, 115, 627, 371, 883, 243, 755, 499, 1011, + 11, 523, 267, 779, 139, 651, 395, 907, 75, 587, 331, 843, 203, 715, 459, 971, 43, 555, 299, 811, 171, 683, 427, 939, 107, 619, 363, 875, 235, 747, 491, 1003, + 27, 539, 283, 795, 155, 667, 411, 923, 91, 603, 347, 859, 219, 731, 475, 987, 59, 571, 315, 827, 187, 699, 443, 955, 123, 635, 379, 891, 251, 763, 507, 1019, + 7, 519, 263, 775, 135, 647, 391, 903, 71, 583, 327, 839, 199, 711, 455, 967, 39, 551, 295, 807, 167, 679, 423, 935, 103, 615, 359, 871, 231, 743, 487, 999, + 23, 535, 279, 791, 151, 663, 407, 919, 87, 599, 343, 855, 215, 727, 471, 983, 55, 567, 311, 823, 183, 695, 439, 951, 119, 631, 375, 887, 247, 759, 503, 1015, + 15, 527, 271, 783, 143, 655, 399, 911, 79, 591, 335, 847, 207, 719, 463, 975, 47, 559, 303, 815, 175, 687, 431, 943, 111, 623, 367, 879, 239, 751, 495, 1007, + 31, 543, 287, 799, 159, 671, 415, 927, 95, 607, 351, 863, 223, 735, 479, 991, 63, 575, 319, 831, 191, 703, 447, 959, 127, 639, 383, 895, 255, 767, 511, 1023 +}; + +/************************************************* +* Name: bitrev_vector +* +* Description: Permutes coefficients of a polynomial into bitreversed order +* +* Arguments: - uint16_t* poly: pointer to in/output polynomial +**************************************************/ +void PQCLEAN_NEWHOPE1024CCA_CLEAN_bitrev_vector(uint16_t *poly) { + unsigned int i, r; + uint16_t tmp; + + for (i = 0; i < NEWHOPE_N; i++) { + r = bitrev_table[i]; + if (i < r) { + tmp = poly[i]; + poly[i] = poly[r]; + poly[r] = tmp; + } + } +} + +/************************************************* +* Name: mul_coefficients +* +* Description: Performs pointwise (coefficient-wise) multiplication +* of two polynomials +* Arguments: - uint16_t* poly: pointer to in/output polynomial +* - const uint16_t* factors: pointer to input polynomial, coefficients +* are assumed to be in Montgomery representation +**************************************************/ +void PQCLEAN_NEWHOPE1024CCA_CLEAN_mul_coefficients(uint16_t *poly, const uint16_t *factors) { + unsigned int i; + + for (i = 0; i < NEWHOPE_N; i++) { + poly[i] = PQCLEAN_NEWHOPE1024CCA_CLEAN_montgomery_reduce((poly[i] * factors[i])); + } +} + + +void /************************************************* +* Name: ntt +* +* Description: Computes number-theoretic transform (NTT) of +* a polynomial in place; inputs assumed to be in +* bitreversed order, output in normal order +* +* Arguments: - uint16_t * a: pointer to in/output polynomial +* - const uint16_t* omega: pointer to input powers of root of unity omega; +* assumed to be in Montgomery domain +**************************************************/ +PQCLEAN_NEWHOPE1024CCA_CLEAN_ntt(uint16_t *a, const uint16_t *omega) { + int i, start, j, jTwiddle, distance; + uint16_t temp, W; + + + for (i = 0; i < 10; i += 2) { + // Even level + distance = (1 << i); + for (start = 0; start < distance; start++) { + jTwiddle = 0; + for (j = start; j < NEWHOPE_N - 1; j += 2 * distance) { + W = omega[jTwiddle++]; + temp = a[j]; + a[j] = (temp + a[j + distance]); // Omit reduction (be lazy) + a[j + distance] = PQCLEAN_NEWHOPE1024CCA_CLEAN_montgomery_reduce((W * ((uint32_t)temp + 3 * NEWHOPE_Q - a[j + distance]))); + } + } + + // Odd level + distance <<= 1; + for (start = 0; start < distance; start++) { + jTwiddle = 0; + for (j = start; j < NEWHOPE_N - 1; j += 2 * distance) { + W = omega[jTwiddle++]; + temp = a[j]; + a[j] = (temp + a[j + distance]) % NEWHOPE_Q; + a[j + distance] = PQCLEAN_NEWHOPE1024CCA_CLEAN_montgomery_reduce((W * ((uint32_t)temp + 3 * NEWHOPE_Q - a[j + distance]))); + } + } + } +} diff --git a/crypto_kem/newhope1024cca/clean/ntt.h b/crypto_kem/newhope1024cca/clean/ntt.h new file mode 100644 index 00000000..c43ba5f1 --- /dev/null +++ b/crypto_kem/newhope1024cca/clean/ntt.h @@ -0,0 +1,14 @@ +#ifndef NTT_H +#define NTT_H + +#include "inttypes.h" + +extern const uint16_t PQCLEAN_NEWHOPE1024CCA_CLEAN_omegas_inv_bitrev_montgomery[]; +extern const uint16_t PQCLEAN_NEWHOPE1024CCA_CLEAN_gammas_bitrev_montgomery[]; +extern const uint16_t PQCLEAN_NEWHOPE1024CCA_CLEAN_gammas_inv_montgomery[]; + +void PQCLEAN_NEWHOPE1024CCA_CLEAN_bitrev_vector(uint16_t *poly); +void PQCLEAN_NEWHOPE1024CCA_CLEAN_mul_coefficients(uint16_t *poly, const uint16_t *factors); +void PQCLEAN_NEWHOPE1024CCA_CLEAN_ntt(uint16_t *a, const uint16_t *omegas); + +#endif diff --git a/crypto_kem/newhope1024cca/clean/params.h b/crypto_kem/newhope1024cca/clean/params.h new file mode 100644 index 00000000..4e5e6442 --- /dev/null +++ b/crypto_kem/newhope1024cca/clean/params.h @@ -0,0 +1,25 @@ +#ifndef PQCLEAN_NEWHOPE1024CCA_CLEAN_PARAMS_H +#define PQCLEAN_NEWHOPE1024CCA_CLEAN_PARAMS_H + +#define NEWHOPE_N 1024 +#define NEWHOPE_Q 12289 +#define NEWHOPE_K 8 /* used in noise sampling */ + +#define NEWHOPE_SYMBYTES 32 /* size of shared key, seeds/coins, and hashes */ + +#define NEWHOPE_POLYBYTES ((14*NEWHOPE_N)/8) +#define NEWHOPE_POLYCOMPRESSEDBYTES (( 3*NEWHOPE_N)/8) + +#define NEWHOPE_CPAPKE_PUBLICKEYBYTES (NEWHOPE_POLYBYTES + NEWHOPE_SYMBYTES) +#define NEWHOPE_CPAPKE_SECRETKEYBYTES (NEWHOPE_POLYBYTES) +#define NEWHOPE_CPAPKE_CIPHERTEXTBYTES (NEWHOPE_POLYBYTES + NEWHOPE_POLYCOMPRESSEDBYTES) + +#define NEWHOPE_CPAKEM_PUBLICKEYBYTES NEWHOPE_CPAPKE_PUBLICKEYBYTES +#define NEWHOPE_CPAKEM_SECRETKEYBYTES NEWHOPE_CPAPKE_SECRETKEYBYTES +#define NEWHOPE_CPAKEM_CIPHERTEXTBYTES NEWHOPE_CPAPKE_CIPHERTEXTBYTES + +#define NEWHOPE_CCAKEM_PUBLICKEYBYTES NEWHOPE_CPAPKE_PUBLICKEYBYTES +#define NEWHOPE_CCAKEM_SECRETKEYBYTES (NEWHOPE_CPAPKE_SECRETKEYBYTES + NEWHOPE_CPAPKE_PUBLICKEYBYTES + 2*NEWHOPE_SYMBYTES) +#define NEWHOPE_CCAKEM_CIPHERTEXTBYTES (NEWHOPE_CPAPKE_CIPHERTEXTBYTES + NEWHOPE_SYMBYTES) /* Second part is for Targhi-Unruh */ + +#endif diff --git a/crypto_kem/newhope1024cca/clean/poly.c b/crypto_kem/newhope1024cca/clean/poly.c new file mode 100644 index 00000000..10ec5535 --- /dev/null +++ b/crypto_kem/newhope1024cca/clean/poly.c @@ -0,0 +1,357 @@ +#include "fips202.h" +#include "ntt.h" +#include "poly.h" +#include "reduce.h" + +/************************************************* +* Name: coeff_freeze +* +* Description: Fully reduces an integer modulo q in constant time +* +* Arguments: uint16_t x: input integer to be reduced +* +* Returns integer in {0,...,q-1} congruent to x modulo q +**************************************************/ +static uint16_t coeff_freeze(uint16_t x) { + uint16_t m, r; + int16_t c; + r = x % NEWHOPE_Q; + + m = r - NEWHOPE_Q; + c = m; + c >>= 15; + r = m ^ ((r ^ m)&c); + + return r; +} + +/************************************************* +* Name: flipabs +* +* Description: Computes |(x mod q) - Q/2| +* +* Arguments: uint16_t x: input coefficient +* +* Returns |(x mod q) - Q/2| +**************************************************/ +static uint16_t flipabs(uint16_t x) { + int16_t r, m; + r = coeff_freeze(x); + + r = r - NEWHOPE_Q / 2; + m = r >> 15; + return (r + m) ^ m; +} + +/************************************************* +* Name: poly_frombytes +* +* Description: De-serialization of a polynomial +* +* Arguments: - poly *r: pointer to output polynomial +* - const unsigned char *a: pointer to input byte array +**************************************************/ +void PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_frombytes(poly *r, const unsigned char *a) { + int i; + for (i = 0; i < NEWHOPE_N / 4; i++) { + r->coeffs[4 * i + 0] = a[7 * i + 0] | (((uint16_t)a[7 * i + 1] & 0x3f) << 8); + r->coeffs[4 * i + 1] = (a[7 * i + 1] >> 6) | (((uint16_t)a[7 * i + 2]) << 2) | (((uint16_t)a[7 * i + 3] & 0x0f) << 10); + r->coeffs[4 * i + 2] = (a[7 * i + 3] >> 4) | (((uint16_t)a[7 * i + 4]) << 4) | (((uint16_t)a[7 * i + 5] & 0x03) << 12); + r->coeffs[4 * i + 3] = (a[7 * i + 5] >> 2) | (((uint16_t)a[7 * i + 6]) << 6); + } +} + +/************************************************* +* Name: poly_tobytes +* +* Description: Serialization of a polynomial +* +* Arguments: - unsigned char *r: pointer to output byte array +* - const poly *p: pointer to input polynomial +**************************************************/ +void PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_tobytes(unsigned char *r, const poly *p) { + int i; + uint16_t t0, t1, t2, t3; + for (i = 0; i < NEWHOPE_N / 4; i++) { + t0 = coeff_freeze(p->coeffs[4 * i + 0]); + t1 = coeff_freeze(p->coeffs[4 * i + 1]); + t2 = coeff_freeze(p->coeffs[4 * i + 2]); + t3 = coeff_freeze(p->coeffs[4 * i + 3]); + + r[7 * i + 0] = t0 & 0xff; + r[7 * i + 1] = (unsigned char) ((t0 >> 8) | (t1 << 6)); + r[7 * i + 2] = (unsigned char) ((t1 >> 2)); + r[7 * i + 3] = (unsigned char) ((t1 >> 10) | (t2 << 4)); + r[7 * i + 4] = (unsigned char) ((t2 >> 4)); + r[7 * i + 5] = (unsigned char) ((t2 >> 12) | (t3 << 2)); + r[7 * i + 6] = (unsigned char) ((t3 >> 6)); + } +} + +/************************************************* +* Name: poly_compress +* +* Description: Compression and subsequent serialization of a polynomial +* +* Arguments: - unsigned char *r: pointer to output byte array +* - const poly *p: pointer to input polynomial +**************************************************/ +void PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_compress(unsigned char *r, const poly *p) { + unsigned int i, j, k = 0; + + uint32_t t[8]; + + for (i = 0; i < NEWHOPE_N; i += 8) { + for (j = 0; j < 8; j++) { + t[j] = coeff_freeze(p->coeffs[i + j]); + t[j] = (((t[j] << 3) + NEWHOPE_Q / 2) / NEWHOPE_Q) & 0x7; + } + + r[k] = (unsigned char) (t[0] | (t[1] << 3) | (t[2] << 6)); + r[k + 1] = (unsigned char) ((t[2] >> 2) | (t[3] << 1) | (t[4] << 4) | (t[5] << 7)); + r[k + 2] = (unsigned char) ((t[5] >> 1) | (t[6] << 2) | (t[7] << 5)); + k += 3; + } +} + +/************************************************* +* Name: poly_decompress +* +* Description: De-serialization and subsequent decompression of a polynomial; +* approximate inverse of poly_compress +* +* Arguments: - poly *r: pointer to output polynomial +* - const unsigned char *a: pointer to input byte array +**************************************************/ +void PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_decompress(poly *r, const unsigned char *a) { + unsigned int i, j; + for (i = 0; i < NEWHOPE_N; i += 8) { + r->coeffs[i + 0] = a[0] & 7; + r->coeffs[i + 1] = (a[0] >> 3) & 7; + r->coeffs[i + 2] = (a[0] >> 6) | ((a[1] << 2) & 4); + r->coeffs[i + 3] = (a[1] >> 1) & 7; + r->coeffs[i + 4] = (a[1] >> 4) & 7; + r->coeffs[i + 5] = (a[1] >> 7) | ((a[2] << 1) & 6); + r->coeffs[i + 6] = (a[2] >> 2) & 7; + r->coeffs[i + 7] = (a[2] >> 5); + a += 3; + for (j = 0; j < 8; j++) { + r->coeffs[i + j] = ((uint32_t)r->coeffs[i + j] * NEWHOPE_Q + 4) >> 3; + } + } +} + +/************************************************* +* Name: poly_frommsg +* +* Description: Convert 32-byte message to polynomial +* +* Arguments: - poly *r: pointer to output polynomial +* - const unsigned char *msg: pointer to input message +**************************************************/ +void PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_frommsg(poly *r, const unsigned char *msg) { + unsigned int i, j, mask; + for (i = 0; i < NEWHOPE_SYMBYTES; i++) { + for (j = 0; j < 8; j++) { + mask = -((msg[i] >> j) & 1); + r->coeffs[8 * i + j + 0] = mask & (NEWHOPE_Q / 2); + r->coeffs[8 * i + j + 256] = mask & (NEWHOPE_Q / 2); + r->coeffs[8 * i + j + 512] = mask & (NEWHOPE_Q / 2); + r->coeffs[8 * i + j + 768] = mask & (NEWHOPE_Q / 2); + } + } +} + +/************************************************* +* Name: poly_tomsg +* +* Description: Convert polynomial to 32-byte message +* +* Arguments: - unsigned char *msg: pointer to output message +* - const poly *x: pointer to input polynomial +**************************************************/ +void PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_tomsg(unsigned char *msg, const poly *x) { + unsigned int i; + uint16_t t; + + for (i = 0; i < 32; i++) { + msg[i] = 0; + } + + for (i = 0; i < 256; i++) { + t = flipabs(x->coeffs[i + 0]); + t += flipabs(x->coeffs[i + 256]); + t += flipabs(x->coeffs[i + 512]); + t += flipabs(x->coeffs[i + 768]); + t = ((t - NEWHOPE_Q)); + + t >>= 15; + msg[i >> 3] |= t << (i & 7); + } +} + +/************************************************* +* Name: poly_uniform +* +* Description: Sample a polynomial deterministically from a seed, +* with output polynomial looking uniformly random +* +* Arguments: - poly *a: pointer to output polynomial +* - const unsigned char *seed: pointer to input seed +**************************************************/ +void PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_uniform(poly *a, const unsigned char *seed) { + unsigned int ctr = 0; + uint16_t val; + shake128ctx state; + uint8_t buf[SHAKE128_RATE]; + uint8_t extseed[NEWHOPE_SYMBYTES + 1]; + int i, j; + + for (i = 0; i < NEWHOPE_SYMBYTES; i++) { + extseed[i] = seed[i]; + } + + for (i = 0; i < NEWHOPE_N / 64; i++) { /* generate a in blocks of 64 coefficients */ + ctr = 0; + extseed[NEWHOPE_SYMBYTES] = (unsigned char) i; /* domain-separate the 16 independent calls */ + shake128_absorb(&state, extseed, NEWHOPE_SYMBYTES + 1); + while (ctr < 64) { /* Very unlikely to run more than once */ + shake128_squeezeblocks(buf, 1, &state); + for (j = 0; j < SHAKE128_RATE && ctr < 64; j += 2) { + val = (buf[j] | ((uint16_t) buf[j + 1] << 8)); + if (val < 5 * NEWHOPE_Q) { + a->coeffs[i * 64 + ctr] = val; + ctr++; + } + } + } + } +} + +/************************************************* +* Name: hw +* +* Description: Compute the Hamming weight of a byte +* +* Arguments: - unsigned char a: input byte +**************************************************/ +static unsigned char hw(unsigned char a) { + unsigned char i, r = 0; + for (i = 0; i < 8; i++) { + r += (a >> i) & 1; + } + return r; +} + +/************************************************* +* Name: poly_sample +* +* Description: Sample a polynomial deterministically from a seed and a nonce, +* with output polynomial close to centered binomial distribution +* with parameter k=8 +* +* Arguments: - poly *r: pointer to output polynomial +* - const unsigned char *seed: pointer to input seed +* - unsigned char nonce: one-byte input nonce +**************************************************/ +void PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_sample(poly *r, const unsigned char *seed, unsigned char nonce) { + unsigned char buf[128], a, b; + int i, j; + + unsigned char extseed[NEWHOPE_SYMBYTES + 2]; + + for (i = 0; i < NEWHOPE_SYMBYTES; i++) { + extseed[i] = seed[i]; + } + extseed[NEWHOPE_SYMBYTES] = nonce; + + for (i = 0; i < NEWHOPE_N / 64; i++) { /* Generate noise in blocks of 64 coefficients */ + extseed[NEWHOPE_SYMBYTES + 1] = (unsigned char) i; + shake256(buf, 128, extseed, NEWHOPE_SYMBYTES + 2); + for (j = 0; j < 64; j++) { + a = buf[2 * j]; + b = buf[2 * j + 1]; + r->coeffs[64 * i + j] = hw(a) + NEWHOPE_Q - hw(b); + } + } +} + +/************************************************* +* Name: poly_pointwise +* +* Description: Multiply two polynomials pointwise (i.e., coefficient-wise). +* +* Arguments: - poly *r: pointer to output polynomial +* - const poly *a: pointer to first input polynomial +* - const poly *b: pointer to second input polynomial +**************************************************/ +void PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_mul_pointwise(poly *r, const poly *a, const poly *b) { + int i; + uint16_t t; + for (i = 0; i < NEWHOPE_N; i++) { + t = PQCLEAN_NEWHOPE1024CCA_CLEAN_montgomery_reduce(3186 * b->coeffs[i]); /* t is now in Montgomery domain */ + r->coeffs[i] = PQCLEAN_NEWHOPE1024CCA_CLEAN_montgomery_reduce(a->coeffs[i] * t); /* r->coeffs[i] is back in normal domain */ + } +} + +/************************************************* +* Name: poly_add +* +* Description: Add two polynomials +* +* Arguments: - poly *r: pointer to output polynomial +* - const poly *a: pointer to first input polynomial +* - const poly *b: pointer to second input polynomial +**************************************************/ +void PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_add(poly *r, const poly *a, const poly *b) { + int i; + for (i = 0; i < NEWHOPE_N; i++) { + r->coeffs[i] = (a->coeffs[i] + b->coeffs[i]) % NEWHOPE_Q; + } +} + +/************************************************* +* Name: poly_sub +* +* Description: Subtract two polynomials +* +* Arguments: - poly *r: pointer to output polynomial +* - const poly *a: pointer to first input polynomial +* - const poly *b: pointer to second input polynomial +**************************************************/ +void PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_sub(poly *r, const poly *a, const poly *b) { + int i; + for (i = 0; i < NEWHOPE_N; i++) { + r->coeffs[i] = (a->coeffs[i] + 3 * NEWHOPE_Q - b->coeffs[i]) % NEWHOPE_Q; + } +} + +/************************************************* +* Name: poly_ntt +* +* Description: Forward NTT transform of a polynomial in place +* Input is assumed to have coefficients in bitreversed order +* Output has coefficients in normal order +* +* Arguments: - poly *r: pointer to in/output polynomial +**************************************************/ +void PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_ntt(poly *r) { + PQCLEAN_NEWHOPE1024CCA_CLEAN_mul_coefficients(r->coeffs, PQCLEAN_NEWHOPE1024CCA_CLEAN_gammas_bitrev_montgomery); + PQCLEAN_NEWHOPE1024CCA_CLEAN_ntt((uint16_t *)r->coeffs, PQCLEAN_NEWHOPE1024CCA_CLEAN_gammas_bitrev_montgomery); +} + +/************************************************* +* Name: poly_invntt +* +* Description: Inverse NTT transform of a polynomial in place +* Input is assumed to have coefficients in normal order +* Output has coefficients in normal order +* +* Arguments: - poly *r: pointer to in/output polynomial +**************************************************/ +void PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_invntt(poly *r) { + PQCLEAN_NEWHOPE1024CCA_CLEAN_bitrev_vector(r->coeffs); + PQCLEAN_NEWHOPE1024CCA_CLEAN_ntt((uint16_t *)r->coeffs, PQCLEAN_NEWHOPE1024CCA_CLEAN_omegas_inv_bitrev_montgomery); + PQCLEAN_NEWHOPE1024CCA_CLEAN_mul_coefficients(r->coeffs, PQCLEAN_NEWHOPE1024CCA_CLEAN_gammas_inv_montgomery); +} + diff --git a/crypto_kem/newhope1024cca/clean/poly.h b/crypto_kem/newhope1024cca/clean/poly.h new file mode 100644 index 00000000..7da7ee58 --- /dev/null +++ b/crypto_kem/newhope1024cca/clean/poly.h @@ -0,0 +1,32 @@ +#ifndef POLY_H +#define POLY_H + +#include "params.h" +#include + +/* + * Elements of R_q = Z_q[X]/(X^n + 1). Represents polynomial + * coeffs[0] + X*coeffs[1] + X^2*xoeffs[2] + ... + X^{n-1}*coeffs[n-1] + */ +typedef struct { + uint16_t coeffs[NEWHOPE_N]; +} poly; + +void PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_uniform(poly *a, const unsigned char *seed); +void PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_sample(poly *r, const unsigned char *seed, unsigned char nonce); +void PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_add(poly *r, const poly *a, const poly *b); + +void PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_ntt(poly *r); +void PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_invntt(poly *r); +void PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_mul_pointwise(poly *r, const poly *a, const poly *b); + +void PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_frombytes(poly *r, const unsigned char *a); +void PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_tobytes(unsigned char *r, const poly *p); +void PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_compress(unsigned char *r, const poly *p); +void PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_decompress(poly *r, const unsigned char *a); + +void PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_frommsg(poly *r, const unsigned char *msg); +void PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_tomsg(unsigned char *msg, const poly *x); +void PQCLEAN_NEWHOPE1024CCA_CLEAN_poly_sub(poly *r, const poly *a, const poly *b); + +#endif diff --git a/crypto_kem/newhope1024cca/clean/precomp.c b/crypto_kem/newhope1024cca/clean/precomp.c new file mode 100644 index 00000000..1540c6bb --- /dev/null +++ b/crypto_kem/newhope1024cca/clean/precomp.c @@ -0,0 +1,261 @@ +#include "inttypes.h" +#include "ntt.h" +#include "params.h" + +/* Precomputed NTT contants generated by Pari/GP script as follows: + * + * For n = 512: + * + * brv = [0,256,128,384,64,320,192,448,32,288,160,416,96,352,224,480,16,272,144,400,80,336,208,464,48,304,176,432,112,368,240,496,8, + * 264,136,392,72,328,200,456,40,296,168,424,104,360,232,488,24,280,152,408,88,344,216,472,56,312,184,440,120,376,248,504,4, + * 260,132,388,68,324,196,452,36,292,164,420,100,356,228,484,20,276,148,404,84,340,212,468,52,308,180,436,116,372,244,500,12, + * 268,140,396,76,332,204,460,44,300,172,428,108,364,236,492,28,284,156,412,92,348,220,476,60,316,188,444,124,380,252,508,2, + * 258,130,386,66,322,194,450,34,290,162,418,98,354,226,482,18,274,146,402,82,338,210,466,50,306,178,434,114,370,242,498,10, + * 266,138,394,74,330,202,458,42,298,170,426,106,362,234,490,26,282,154,410,90,346,218,474,58,314,186,442,122,378,250,506,6, + * 262,134,390,70,326,198,454,38,294,166,422,102,358,230,486,22,278,150,406,86,342,214,470,54,310,182,438,118,374,246,502,14, + * 270,142,398,78,334,206,462,46,302,174,430,110,366,238,494,30,286,158,414,94,350,222,478,62,318,190,446,126,382,254,510,1, + * 257,129,385,65,321,193,449,33,289,161,417,97,353,225,481,17,273,145,401,81,337,209,465,49,305,177,433,113,369,241,497,9, + * 265,137,393,73,329,201,457,41,297,169,425,105,361,233,489,25,281,153,409,89,345,217,473,57,313,185,441,121,377,249,505,5, + * 261,133,389,69,325,197,453,37,293,165,421,101,357,229,485,21,277,149,405,85,341,213,469,53,309,181,437,117,373,245,501,13, + * 269,141,397,77,333,205,461,45,301,173,429,109,365,237,493,29,285,157,413,93,349,221,477,61,317,189,445,125,381,253,509,3, + * 259,131,387,67,323,195,451,35,291,163,419,99,355,227,483,19,275,147,403,83,339,211,467,51,307,179,435,115,371,243,499,11, + * 267,139,395,75,331,203,459,43,299,171,427,107,363,235,491,27,283,155,411,91,347,219,475,59,315,187,443,123,379,251,507,7, + * 263,135,391,71,327,199,455,39,295,167,423,103,359,231,487,23,279,151,407,87,343,215,471,55,311,183,439,119,375,247,503,15, + * 271,143,399,79,335,207,463,47,303,175,431,111,367,239,495,31,287,159,415,95,351,223,479,63,319,191,447,127,383,255,511] + * n = 512; q = 12289; mont=2^18 + * g = Mod(10968, q); + * omegas_inv_bitrev_montgomery = lift(vector(n/2, i, (g^2)^(-brv[2*(i-1)+1])*mont)) + * gammas_bitrev_montgomery = lift(vector(n, i, g^(brv[i])*mont)) + * gammas_inv_montgomery = lift(vector(n, i, g^(-(i-1))/n*mont)) + * + * + * For n = 1024: + * + * brv = [0,512,256,768,128,640,384,896,64,576,320,832,192,704,448,960,32,544,288,800,160,672,416,928,96,608,352,864,224,736,480,992, \ + * 16,528,272,784,144,656,400,912,80,592,336,848,208,720,464,976,48,560,304,816,176,688,432,944,112,624,368,880,240,752,496,1008, \ + * 8,520,264,776,136,648,392,904,72,584,328,840,200,712,456,968,40,552,296,808,168,680,424,936,104,616,360,872,232,744,488,1000, \ + * 24,536,280,792,152,664,408,920,88,600,344,856,216,728,472,984,56,568,312,824,184,696,440,952,120,632,376,888,248,760,504,1016, \ + * 4,516,260,772,132,644,388,900,68,580,324,836,196,708,452,964,36,548,292,804,164,676,420,932,100,612,356,868,228,740,484,996, \ + * 20,532,276,788,148,660,404,916,84,596,340,852,212,724,468,980,52,564,308,820,180,692,436,948,116,628,372,884,244,756,500,1012, \ + * 12,524,268,780,140,652,396,908,76,588,332,844,204,716,460,972,44,556,300,812,172,684,428,940,108,620,364,876,236,748,492,1004, \ + * 28,540,284,796,156,668,412,924,92,604,348,860,220,732,476,988,60,572,316,828,188,700,444,956,124,636,380,892,252,764,508,1020, \ + * 2,514,258,770,130,642,386,898,66,578,322,834,194,706,450,962,34,546,290,802,162,674,418,930,98,610,354,866,226,738,482,994, \ + * 18,530,274,786,146,658,402,914,82,594,338,850,210,722,466,978,50,562,306,818,178,690,434,946,114,626,370,882,242,754,498,1010, \ + * 10,522,266,778,138,650,394,906,74,586,330,842,202,714,458,970,42,554,298,810,170,682,426,938,106,618,362,874,234,746,490,1002, \ + * 26,538,282,794,154,666,410,922,90,602,346,858,218,730,474,986,58,570,314,826,186,698,442,954,122,634,378,890,250,762,506,1018, \ + * 6,518,262,774,134,646,390,902,70,582,326,838,198,710,454,966,38,550,294,806,166,678,422,934,102,614,358,870,230,742,486,998, \ + * 22,534,278,790,150,662,406,918,86,598,342,854,214,726,470,982,54,566,310,822,182,694,438,950,118,630,374,886,246,758,502,1014, \ + * 14,526,270,782,142,654,398,910,78,590,334,846,206,718,462,974,46,558,302,814,174,686,430,942,110,622,366,878,238,750,494,1006, \ + * 30,542,286,798,158,670,414,926,94,606,350,862,222,734,478,990,62,574,318,830,190,702,446,958,126,638,382,894,254,766,510,1022, \ + * 1,513,257,769,129,641,385,897,65,577,321,833,193,705,449,961,33,545,289,801,161,673,417,929,97,609,353,865,225,737,481,993, \ + * 17,529,273,785,145,657,401,913,81,593,337,849,209,721,465,977,49,561,305,817,177,689,433,945,113,625,369,881,241,753,497,1009, \ + * 9,521,265,777,137,649,393,905,73,585,329,841,201,713,457,969,41,553,297,809,169,681,425,937,105,617,361,873,233,745,489,1001, \ + * 25,537,281,793,153,665,409,921,89,601,345,857,217,729,473,985,57,569,313,825,185,697,441,953,121,633,377,889,249,761,505,1017, \ + * 5,517,261,773,133,645,389,901,69,581,325,837,197,709,453,965,37,549,293,805,165,677,421,933,101,613,357,869,229,741,485,997, \ + * 21,533,277,789,149,661,405,917,85,597,341,853,213,725,469,981,53,565,309,821,181,693,437,949,117,629,373,885,245,757,501,1013, \ + * 13,525,269,781,141,653,397,909,77,589,333,845,205,717,461,973,45,557,301,813,173,685,429,941,109,621,365,877,237,749,493,1005, \ + * 29,541,285,797,157,669,413,925,93,605,349,861,221,733,477,989,61,573,317,829,189,701,445,957,125,637,381,893,253,765,509,1021, \ + * 3,515,259,771,131,643,387,899,67,579,323,835,195,707,451,963,35,547,291,803,163,675,419,931,99,611,355,867,227,739,483,995, \ + * 19,531,275,787,147,659,403,915,83,595,339,851,211,723,467,979,51,563,307,819,179,691,435,947,115,627,371,883,243,755,499,1011, \ + * 11,523,267,779,139,651,395,907,75,587,331,843,203,715,459,971,43,555,299,811,171,683,427,939,107,619,363,875,235,747,491,1003, \ + * 27,539,283,795,155,667,411,923,91,603,347,859,219,731,475,987,59,571,315,827,187,699,443,955,123,635,379,891,251,763,507,1019, \ + * 7,519,263,775,135,647,391,903,71,583,327,839,199,711,455,967,39,551,295,807,167,679,423,935,103,615,359,871,231,743,487,999, \ + * 23,535,279,791,151,663,407,919,87,599,343,855,215,727,471,983,55,567,311,823,183,695,439,951,119,631,375,887,247,759,503,1015, \ + * 15,527,271,783,143,655,399,911,79,591,335,847,207,719,463,975,47,559,303,815,175,687,431,943,111,623,367,879,239,751,495,1007, \ + * 31,543,287,799,159,671,415,927,95,607,351,863,223,735,479,991,63,575,319,831,191,703,447,959,127,639,383,895,255,767,511,1023] + * + * n = 1024; q = 12289; mont=2^18 + * g = Mod(7, q); + * omegas_inv_bitrev_montgomery = lift(vector(n/2, i, (g^2)^(-brv[2*(i-1)+1])*mont)) + * gammas_bitrev_montgomery = lift(vector(n, i, g^(brv[i])*mont)) + * gammas_inv_montgomery = lift(vector(n, i, g^(-(i-1))/n*mont)) +*/ + + +/************************************************************ +* Name: omegas_inv_bitrev_montgomery +* +* Description: Contains inverses of powers of nth root of unity +* in Montgomery domain with R=2^18 in bit-reversed order +************************************************************/ +const uint16_t PQCLEAN_NEWHOPE1024CCA_CLEAN_omegas_inv_bitrev_montgomery[NEWHOPE_N / 2] = { + 4075, 5315, 4324, 4916, 10120, 11767, 7210, 9027, 10316, 6715, 1278, 9945, 3514, 11248, 11271, 5925, + 147, 8500, 7840, 6833, 5537, 4749, 4467, 7500, 11099, 9606, 6171, 8471, 8429, 5445, 11239, 7753, + 9090, 12233, 5529, 5206, 10587, 1987, 11635, 3565, 5415, 8646, 6153, 6427, 7341, 6152, 10561, 400, + 8410, 1922, 2033, 8291, 1359, 6854, 11035, 973, 8579, 6093, 6950, 5446, 11821, 8301, 11907, 316, + 52, 3174, 10966, 9523, 6055, 8953, 11612, 6415, 2505, 5906, 10710, 11858, 8332, 9450, 10162, 151, + 3482, 787, 5468, 1010, 4169, 9162, 5241, 9369, 7509, 8844, 7232, 4698, 192, 1321, 10240, 4912, + 885, 6281, 10333, 7280, 8757, 11286, 58, 12048, 12147, 11184, 8812, 6608, 2844, 3438, 4212, 11314, + 8687, 6068, 421, 8209, 3600, 3263, 7665, 6077, 7507, 5886, 3029, 6695, 4213, 504, 11684, 2302, + 1962, 1594, 6328, 7183, 168, 2692, 8960, 4298, 5184, 11089, 6122, 9734, 10929, 3956, 5297, 6170, + 3762, 9370, 4016, 4077, 6523, 652, 11994, 6099, 1146, 11341, 11964, 10885, 6299, 1159, 8240, 8561, + 11177, 2078, 10331, 4322, 11367, 441, 4079, 11231, 3150, 1319, 8243, 709, 8049, 8719, 11454, 6224, + 3054, 6803, 3123, 10542, 4433, 6370, 7032, 3834, 8633, 12225, 9830, 683, 1566, 5782, 9786, 9341, + 12115, 723, 3009, 1693, 5735, 2655, 2738, 6421, 11942, 2925, 1975, 8532, 3315, 11863, 4754, 1858, + 1583, 6347, 2500, 10800, 6374, 1483, 12240, 1263, 1815, 5383, 10777, 350, 6920, 10232, 4493, 9087, + 8855, 8760, 9381, 218, 9928, 10446, 9259, 4115, 6147, 9842, 8326, 576, 10335, 10238, 10484, 9407, + 6381, 11836, 8517, 418, 6860, 7515, 1293, 7552, 2767, 156, 8298, 8320, 10008, 5876, 5333, 10258, + 10115, 4372, 2847, 7875, 8232, 9018, 8925, 1689, 8236, 2645, 5042, 9984, 7094, 9509, 1484, 7394, + 3, 4437, 160, 3149, 113, 7370, 10123, 3915, 6998, 2704, 8653, 4938, 1426, 7635, 10512, 1663, + 6957, 3510, 2370, 2865, 3978, 9320, 3247, 9603, 6882, 3186, 10659, 10163, 1153, 9405, 8241, 10040, + 2178, 1544, 5559, 420, 8304, 4905, 476, 3531, 5191, 9153, 2399, 8889, 3000, 671, 243, 3016, + 3763, 10849, 12262, 9223, 10657, 7205, 11272, 7404, 7575, 8146, 10752, 242, 2678, 3704, 11744, 5019, + 3833, 3778, 11899, 773, 5101, 11222, 9888, 442, 2912, 5698, 11935, 4861, 7277, 9808, 11244, 2859, + 3780, 11414, 4976, 10682, 7201, 8005, 11287, 5011, 6267, 2987, 2437, 3646, 2566, 10102, 9867, 6250, + 5444, 2381, 11796, 8193, 4337, 11854, 1912, 1378, 404, 7644, 1065, 2143, 11121, 5277, 3248, 11082, + 2548, 8058, 8907, 11934, 1759, 8582, 3694, 7110, 12144, 6747, 8652, 3459, 2731, 8357, 6378, 7399, + 10861, 1696, 9863, 334, 7657, 6534, 11029, 4388, 11560, 3241, 10276, 9000, 9408, 3284, 10200, 7197, + 6498, 544, 2468, 339, 11267, 9, 2842, 480, 5331, 7300, 1673, 4278, 4177, 8705, 9764, 1381, + 7837, 2396, 8340, 8993, 4354, 130, 6915, 2837, 11462, 5767, 953, 8541, 9813, 118, 7222, 2197, + 3006, 9545, 563, 9314, 2625, 11340, 4821, 2639, 7266, 5828, 6561, 7698, 3328, 6512, 1351, 7311, + 6553, 8155, 1305, 722, 5146, 4043, 12288, 10810, 2545, 3621, 8747, 8785, 1646, 1212, 5860, 3195, + 7203, 10963, 3201, 3014, 955, 11499, 9970, 11119, 3135, 3712, 7443, 9542, 7484, 8736, 9995, 11227, + 1635, 9521, 1177, 8034, 140, 10436, 11563, 7678, 4320, 11289, 9198, 12208, 2963, 7393, 2366, 9238 +}; + +/************************************************************ +* Name: gammas_bitrev_montgomery +* +* Description: Contains powers of nth root of -1 in Montgomery +* domain with R=2^18 in bit-reversed order +************************************************************/ +const uint16_t PQCLEAN_NEWHOPE1024CCA_CLEAN_gammas_bitrev_montgomery[NEWHOPE_N] = { + 4075, 6974, 7373, 7965, 3262, 5079, 522, 2169, 6364, 1018, 1041, 8775, 2344, 11011, 5574, 1973, + 4536, 1050, 6844, 3860, 3818, 6118, 2683, 1190, 4789, 7822, 7540, 6752, 5456, 4449, 3789, 12142, + 11973, 382, 3988, 468, 6843, 5339, 6196, 3710, 11316, 1254, 5435, 10930, 3998, 10256, 10367, 3879, + 11889, 1728, 6137, 4948, 5862, 6136, 3643, 6874, 8724, 654, 10302, 1702, 7083, 6760, 56, 3199, + 9987, 605, 11785, 8076, 5594, 9260, 6403, 4782, 6212, 4624, 9026, 8689, 4080, 11868, 6221, 3602, + 975, 8077, 8851, 9445, 5681, 3477, 1105, 142, 241, 12231, 1003, 3532, 5009, 1956, 6008, 11404, + 7377, 2049, 10968, 12097, 7591, 5057, 3445, 4780, 2920, 7048, 3127, 8120, 11279, 6821, 11502, 8807, + 12138, 2127, 2839, 3957, 431, 1579, 6383, 9784, 5874, 677, 3336, 6234, 2766, 1323, 9115, 12237, + 2031, 6956, 6413, 2281, 3969, 3991, 12133, 9522, 4737, 10996, 4774, 5429, 11871, 3772, 453, 5908, + 2882, 1805, 2051, 1954, 11713, 3963, 2447, 6142, 8174, 3030, 1843, 2361, 12071, 2908, 3529, 3434, + 3202, 7796, 2057, 5369, 11939, 1512, 6906, 10474, 11026, 49, 10806, 5915, 1489, 9789, 5942, 10706, + 10431, 7535, 426, 8974, 3757, 10314, 9364, 347, 5868, 9551, 9634, 6554, 10596, 9280, 11566, 174, + 2948, 2503, 6507, 10723, 11606, 2459, 64, 3656, 8455, 5257, 5919, 7856, 1747, 9166, 5486, 9235, + 6065, 835, 3570, 4240, 11580, 4046, 10970, 9139, 1058, 8210, 11848, 922, 7967, 1958, 10211, 1112, + 3728, 4049, 11130, 5990, 1404, 325, 948, 11143, 6190, 295, 11637, 5766, 8212, 8273, 2919, 8527, + 6119, 6992, 8333, 1360, 2555, 6167, 1200, 7105, 7991, 3329, 9597, 12121, 5106, 5961, 10695, 10327, + 3051, 9923, 4896, 9326, 81, 3091, 1000, 7969, 4611, 726, 1853, 12149, 4255, 11112, 2768, 10654, + 1062, 2294, 3553, 4805, 2747, 4846, 8577, 9154, 1170, 2319, 790, 11334, 9275, 9088, 1326, 5086, + 9094, 6429, 11077, 10643, 3504, 3542, 8668, 9744, 1479, 1, 8246, 7143, 11567, 10984, 4134, 5736, + 4978, 10938, 5777, 8961, 4591, 5728, 6461, 5023, 9650, 7468, 949, 9664, 2975, 11726, 2744, 9283, + 10092, 5067, 12171, 2476, 3748, 11336, 6522, 827, 9452, 5374, 12159, 7935, 3296, 3949, 9893, 4452, + 10908, 2525, 3584, 8112, 8011, 10616, 4989, 6958, 11809, 9447, 12280, 1022, 11950, 9821, 11745, 5791, + 5092, 2089, 9005, 2881, 3289, 2013, 9048, 729, 7901, 1260, 5755, 4632, 11955, 2426, 10593, 1428, + 4890, 5911, 3932, 9558, 8830, 3637, 5542, 145, 5179, 8595, 3707, 10530, 355, 3382, 4231, 9741, + 1207, 9041, 7012, 1168, 10146, 11224, 4645, 11885, 10911, 10377, 435, 7952, 4096, 493, 9908, 6845, + 6039, 2422, 2187, 9723, 8643, 9852, 9302, 6022, 7278, 1002, 4284, 5088, 1607, 7313, 875, 8509, + 9430, 1045, 2481, 5012, 7428, 354, 6591, 9377, 11847, 2401, 1067, 7188, 11516, 390, 8511, 8456, + 7270, 545, 8585, 9611, 12047, 1537, 4143, 4714, 4885, 1017, 5084, 1632, 3066, 27, 1440, 8526, + 9273, 12046, 11618, 9289, 3400, 9890, 3136, 7098, 8758, 11813, 7384, 3985, 11869, 6730, 10745, 10111, + 2249, 4048, 2884, 11136, 2126, 1630, 9103, 5407, 2686, 9042, 2969, 8311, 9424, 9919, 8779, 5332, + 10626, 1777, 4654, 10863, 7351, 3636, 9585, 5291, 8374, 2166, 4919, 12176, 9140, 12129, 7852, 12286, + 4895, 10805, 2780, 5195, 2305, 7247, 9644, 4053, 10600, 3364, 3271, 4057, 4414, 9442, 7917, 2174, + 3947, 11951, 2455, 6599, 10545, 10975, 3654, 2894, 7681, 7126, 7287, 12269, 4119, 3343, 2151, 1522, + 7174, 7350, 11041, 2442, 2148, 5959, 6492, 8330, 8945, 5598, 3624, 10397, 1325, 6565, 1945, 11260, + 10077, 2674, 3338, 3276, 11034, 506, 6505, 1392, 5478, 8778, 1178, 2776, 3408, 10347, 11124, 2575, + 9489, 12096, 6092, 10058, 4167, 6085, 923, 11251, 11912, 4578, 10669, 11914, 425, 10453, 392, 10104, + 8464, 4235, 8761, 7376, 2291, 3375, 7954, 8896, 6617, 7790, 1737, 11667, 3982, 9342, 6680, 636, + 6825, 7383, 512, 4670, 2900, 12050, 7735, 994, 1687, 11883, 7021, 146, 10485, 1403, 5189, 6094, + 2483, 2054, 3042, 10945, 3981, 10821, 11826, 8882, 8151, 180, 9600, 7684, 5219, 10880, 6780, 204, + 11232, 2600, 7584, 3121, 3017, 11053, 7814, 7043, 4251, 4739, 11063, 6771, 7073, 9261, 2360, 11925, + 1928, 11825, 8024, 3678, 3205, 3359, 11197, 5209, 8581, 3238, 8840, 1136, 9363, 1826, 3171, 4489, + 7885, 346, 2068, 1389, 8257, 3163, 4840, 6127, 8062, 8921, 612, 4238, 10763, 8067, 125, 11749, + 10125, 5416, 2110, 716, 9839, 10584, 11475, 11873, 3448, 343, 1908, 4538, 10423, 7078, 4727, 1208, + 11572, 3589, 2982, 1373, 1721, 10753, 4103, 2429, 4209, 5412, 5993, 9011, 438, 3515, 7228, 1218, + 8347, 5232, 8682, 1327, 7508, 4924, 448, 1014, 10029, 12221, 4566, 5836, 12229, 2717, 1535, 3200, + 5588, 5845, 412, 5102, 7326, 3744, 3056, 2528, 7406, 8314, 9202, 6454, 6613, 1417, 10032, 7784, + 1518, 3765, 4176, 5063, 9828, 2275, 6636, 4267, 6463, 2065, 7725, 3495, 8328, 8755, 8144, 10533, + 5966, 12077, 9175, 9520, 5596, 6302, 8400, 579, 6781, 11014, 5734, 11113, 11164, 4860, 1131, 10844, + 9068, 8016, 9694, 3837, 567, 9348, 7000, 6627, 7699, 5082, 682, 11309, 5207, 4050, 7087, 844, + 7434, 3769, 293, 9057, 6940, 9344, 10883, 2633, 8190, 3944, 5530, 5604, 3480, 2171, 9282, 11024, + 2213, 8136, 3805, 767, 12239, 216, 11520, 6763, 10353, 7, 8566, 845, 7235, 3154, 4360, 3285, + 10268, 2832, 3572, 1282, 7559, 3229, 8360, 10583, 6105, 3120, 6643, 6203, 8536, 8348, 6919, 3536, + 9199, 10891, 11463, 5043, 1658, 5618, 8787, 5789, 4719, 751, 11379, 6389, 10783, 3065, 7806, 6586, + 2622, 5386, 510, 7628, 6921, 578, 10345, 11839, 8929, 4684, 12226, 7154, 9916, 7302, 8481, 3670, + 11066, 2334, 1590, 7878, 10734, 1802, 1891, 5103, 6151, 8820, 3418, 7846, 9951, 4693, 417, 9996, + 9652, 4510, 2946, 5461, 365, 881, 1927, 1015, 11675, 11009, 1371, 12265, 2485, 11385, 5039, 6742, + 8449, 1842, 12217, 8176, 9577, 4834, 7937, 9461, 2643, 11194, 3045, 6508, 4094, 3451, 7911, 11048, + 5406, 4665, 3020, 6616, 11345, 7519, 3669, 5287, 1790, 7014, 5410, 11038, 11249, 2035, 6125, 10407, + 4565, 7315, 5078, 10506, 2840, 2478, 9270, 4194, 9195, 4518, 7469, 1160, 6878, 2730, 10421, 10036, + 1734, 3815, 10939, 5832, 10595, 10759, 4423, 8420, 9617, 7119, 11010, 11424, 9173, 189, 10080, 10526, + 3466, 10588, 7592, 3578, 11511, 7785, 9663, 530, 12150, 8957, 2532, 3317, 9349, 10243, 1481, 9332, + 3454, 3758, 7899, 4218, 2593, 11410, 2276, 982, 6513, 1849, 8494, 9021, 4523, 7988, 8, 457, + 648, 150, 8000, 2307, 2301, 874, 5650, 170, 9462, 2873, 9855, 11498, 2535, 11169, 5808, 12268, + 9687, 1901, 7171, 11787, 3846, 1573, 6063, 3793, 466, 11259, 10608, 3821, 6320, 4649, 6263, 2929 +}; + +/************************************************************ +* Name: gammas_inv_montgomery +* +* Description: Contains inverses of powers of nth root of -1 +* divided by n in Montgomery domain with R=2^18 +************************************************************/ +const uint16_t PQCLEAN_NEWHOPE1024CCA_CLEAN_gammas_inv_montgomery[NEWHOPE_N] = { + 256, 10570, 1510, 7238, 1034, 7170, 6291, 7921, 11665, 3422, 4000, 2327, 2088, 5565, 795, 10647, + 1521, 5484, 2539, 7385, 1055, 7173, 8047, 11683, 1669, 1994, 3796, 5809, 4341, 9398, 11876, 12230, + 10525, 12037, 12253, 3506, 4012, 9351, 4847, 2448, 7372, 9831, 3160, 2207, 5582, 2553, 7387, 6322, + 9681, 1383, 10731, 1533, 219, 5298, 4268, 7632, 6357, 9686, 8406, 4712, 9451, 10128, 4958, 5975, + 11387, 8649, 11769, 6948, 11526, 12180, 1740, 10782, 6807, 2728, 7412, 4570, 4164, 4106, 11120, 12122, + 8754, 11784, 3439, 5758, 11356, 6889, 9762, 11928, 1704, 1999, 10819, 12079, 12259, 7018, 11536, 1648, + 1991, 2040, 2047, 2048, 10826, 12080, 8748, 8272, 8204, 1172, 1923, 7297, 2798, 7422, 6327, 4415, + 7653, 6360, 11442, 12168, 7005, 8023, 9924, 8440, 8228, 2931, 7441, 1063, 3663, 5790, 9605, 10150, + 1450, 8985, 11817, 10466, 10273, 12001, 3470, 7518, 1074, 1909, 7295, 9820, 4914, 702, 5367, 7789, + 8135, 9940, 1420, 3714, 11064, 12114, 12264, 1752, 5517, 9566, 11900, 1700, 3754, 5803, 829, 1874, + 7290, 2797, 10933, 5073, 7747, 8129, 6428, 6185, 11417, 1631, 233, 5300, 9535, 10140, 11982, 8734, + 8270, 2937, 10953, 8587, 8249, 2934, 9197, 4825, 5956, 4362, 9401, 1343, 3703, 529, 10609, 12049, + 6988, 6265, 895, 3639, 4031, 4087, 4095, 585, 10617, 8539, 4731, 4187, 9376, 3095, 9220, 10095, + 10220, 1460, 10742, 12068, 1724, 5513, 11321, 6884, 2739, 5658, 6075, 4379, 11159, 10372, 8504, 4726, + 9453, 3106, 7466, 11600, 10435, 8513, 9994, 8450, 9985, 3182, 10988, 8592, 2983, 9204, 4826, 2445, + 5616, 6069, 867, 3635, 5786, 11360, 5134, 2489, 10889, 12089, 1727, 7269, 2794, 9177, 1311, 5454, + 9557, 6632, 2703, 9164, 10087, 1441, 3717, 531, 3587, 2268, 324, 5313, 759, 1864, 5533, 2546, + 7386, 9833, 8427, 4715, 11207, 1601, 7251, 4547, 11183, 12131, 1733, 10781, 10318, 1474, 10744, 5046, + 4232, 11138, 10369, 6748, 964, 7160, 4534, 7670, 8118, 8182, 4680, 11202, 6867, 981, 8918, 1274, + 182, 26, 7026, 8026, 11680, 12202, 10521, 1503, 7237, 4545, 5916, 9623, 8397, 11733, 10454, 3249, + 9242, 6587, 941, 1890, 270, 10572, 6777, 9746, 6659, 6218, 6155, 6146, 878, 1881, 7291, 11575, + 12187, 1741, 7271, 8061, 11685, 6936, 4502, 9421, 4857, 4205, 7623, 1089, 10689, 1527, 8996, 10063, + 11971, 10488, 6765, 2722, 3900, 9335, 11867, 6962, 11528, 5158, 4248, 4118, 5855, 2592, 5637, 6072, + 2623, 7397, 8079, 9932, 4930, 5971, 853, 3633, 519, 8852, 11798, 3441, 11025, 1575, 225, 8810, + 11792, 12218, 3501, 9278, 3081, 9218, 4828, 7712, 8124, 11694, 12204, 3499, 4011, 573, 3593, 5780, + 7848, 9899, 10192, 1456, 208, 7052, 2763, 7417, 11593, 10434, 12024, 8740, 11782, 10461, 3250, 5731, + 7841, 9898, 1414, 202, 3540, 7528, 2831, 2160, 10842, 5060, 4234, 4116, 588, 84, 12, 7024, + 2759, 9172, 6577, 11473, 1639, 9012, 3043, 7457, 6332, 11438, 1634, 1989, 9062, 11828, 8712, 11778, + 12216, 10523, 6770, 9745, 10170, 4964, 9487, 6622, 946, 8913, 6540, 6201, 4397, 9406, 8366, 9973, + 8447, 8229, 11709, 8695, 10020, 3187, 5722, 2573, 10901, 6824, 4486, 4152, 9371, 8361, 2950, 2177, + 311, 1800, 9035, 8313, 11721, 3430, 490, 70, 10, 1757, 251, 3547, 7529, 11609, 3414, 7510, + 4584, 4166, 9373, 1339, 5458, 7802, 11648, 1664, 7260, 9815, 10180, 6721, 9738, 10169, 8475, 8233, + 9954, 1422, 8981, 1283, 5450, 11312, 1616, 3742, 11068, 10359, 4991, 713, 3613, 9294, 8350, 4704, + 672, 96, 7036, 9783, 11931, 3460, 5761, 823, 10651, 12055, 10500, 1500, 5481, 783, 3623, 11051, + 8601, 8251, 8201, 11705, 10450, 5004, 4226, 7626, 2845, 2162, 3820, 7568, 9859, 3164, 452, 10598, + 1514, 5483, 6050, 6131, 4387, 7649, 8115, 6426, 918, 8909, 8295, 1185, 5436, 11310, 8638, 1234, + 5443, 11311, 5127, 2488, 2111, 10835, 5059, 7745, 2862, 3920, 560, 80, 1767, 2008, 3798, 11076, + 6849, 2734, 10924, 12094, 8750, 1250, 10712, 6797, 971, 7161, 1023, 8924, 4786, 7706, 4612, 4170, + 7618, 6355, 4419, 5898, 11376, 10403, 10264, 6733, 4473, 639, 5358, 2521, 9138, 3061, 5704, 4326, + 618, 5355, 765, 5376, 768, 7132, 4530, 9425, 3102, 9221, 6584, 11474, 10417, 10266, 12000, 6981, + 6264, 4406, 2385, 7363, 4563, 4163, 7617, 9866, 3165, 9230, 11852, 10471, 5007, 5982, 11388, 5138, + 734, 3616, 11050, 12112, 6997, 11533, 12181, 10518, 12036, 3475, 2252, 7344, 9827, 4915, 9480, 6621, + 4457, 7659, 9872, 6677, 4465, 4149, 7615, 4599, 657, 3605, 515, 10607, 6782, 4480, 640, 1847, + 3775, 5806, 2585, 5636, 9583, 1369, 10729, 8555, 10000, 11962, 5220, 7768, 8132, 8184, 9947, 1421, + 203, 29, 8782, 11788, 1684, 10774, 10317, 4985, 9490, 8378, 4708, 11206, 5112, 5997, 7879, 11659, + 12199, 8765, 10030, 4944, 5973, 6120, 6141, 6144, 7900, 11662, 1666, 238, 34, 3516, 5769, 9602, + 8394, 9977, 6692, 956, 10670, 6791, 9748, 11926, 8726, 11780, 5194, 742, 106, 8793, 10034, 3189, + 10989, 5081, 4237, 5872, 4350, 2377, 10873, 6820, 6241, 11425, 10410, 10265, 3222, 5727, 9596, 4882, + 2453, 2106, 3812, 11078, 12116, 5242, 4260, 11142, 8614, 11764, 12214, 5256, 4262, 4120, 11122, 5100, + 11262, 5120, 2487, 5622, 9581, 8391, 8221, 2930, 10952, 12098, 6995, 6266, 9673, 4893, 699, 3611, + 4027, 5842, 11368, 1624, 232, 8811, 8281, 1183, 169, 8802, 3013, 2186, 5579, 797, 3625, 4029, + 11109, 1587, 7249, 11569, 8675, 6506, 2685, 10917, 12093, 12261, 12285, 1755, 7273, 1039, 1904, 272, + 3550, 9285, 3082, 5707, 6082, 4380, 7648, 11626, 5172, 4250, 9385, 8363, 8217, 4685, 5936, 848, + 8899, 6538, 934, 1889, 3781, 9318, 10109, 10222, 6727, 961, 5404, 772, 5377, 9546, 8386, 1198, + 8949, 3034, 2189, 7335, 4559, 5918, 2601, 10905, 5069, 9502, 3113, 7467, 8089, 11689, 5181, 9518, + 8382, 2953, 3933, 4073, 4093, 7607, 8109, 2914, 5683, 4323, 11151, 1593, 10761, 6804, 972, 3650, + 2277, 5592, 4310, 7638, 9869, 4921, 703, 1856, 9043, 4803, 9464, 1352, 8971, 11815, 5199, 7765, + 6376, 4422, 7654, 2849, 407, 8836, 6529, 7955, 2892, 9191, 1313, 10721, 12065, 12257, 1751, 9028, + 8312, 2943, 2176, 3822, 546, 78, 8789, 11789, 10462, 12028, 6985, 4509, 9422, 1346, 5459, 4291, + 613, 10621, 6784, 9747, 3148, 7472, 2823, 5670, 810, 7138, 8042, 4660, 7688, 6365, 6176, 6149, + 2634, 5643, 9584, 10147, 11983, 5223, 9524, 11894, 10477, 8519, 1217, 3685, 2282, 326, 10580, 3267, + 7489, 4581, 2410, 5611, 11335, 6886, 8006, 8166, 11700, 3427, 11023, 8597, 10006, 3185, 455, 65, + 5276, 7776, 4622, 5927, 7869, 9902, 11948, 5218, 2501, 5624, 2559, 10899, 1557, 1978, 10816, 10323, + 8497, 4725, 675, 1852, 10798, 12076, 10503, 3256, 9243, 3076, 2195, 10847, 12083, 10504, 12034, 10497 +}; + diff --git a/crypto_kem/newhope1024cca/clean/reduce.c b/crypto_kem/newhope1024cca/clean/reduce.c new file mode 100644 index 00000000..a024f7ea --- /dev/null +++ b/crypto_kem/newhope1024cca/clean/reduce.c @@ -0,0 +1,26 @@ +#include "reduce.h" +#include "params.h" + +static const uint32_t qinv = 12287; // -inverse_mod(p,2^18) +static const uint32_t rlog = 18; + +/************************************************* +* Name: verify +* +* Description: Montgomery reduction; given a 32-bit integer a, computes +* 16-bit integer congruent to a * R^-1 mod q, +* where R=2^18 (see value of rlog) +* +* Arguments: - uint32_t a: input unsigned integer to be reduced; has to be in {0,...,1073491968} +* +* Returns: unsigned integer in {0,...,2^14-1} congruent to a * R^-1 modulo q. +**************************************************/ +uint16_t PQCLEAN_NEWHOPE1024CCA_CLEAN_montgomery_reduce(uint32_t a) { + uint32_t u; + + u = (a * qinv); + u &= ((1 << rlog) - 1); + u *= NEWHOPE_Q; + a = a + u; + return a >> 18; +} diff --git a/crypto_kem/newhope1024cca/clean/reduce.h b/crypto_kem/newhope1024cca/clean/reduce.h new file mode 100644 index 00000000..268b049b --- /dev/null +++ b/crypto_kem/newhope1024cca/clean/reduce.h @@ -0,0 +1,8 @@ +#ifndef REDUCE_H +#define REDUCE_H + +#include + +uint16_t PQCLEAN_NEWHOPE1024CCA_CLEAN_montgomery_reduce(uint32_t a); + +#endif diff --git a/crypto_kem/newhope1024cca/clean/verify.c b/crypto_kem/newhope1024cca/clean/verify.c new file mode 100644 index 00000000..0cb31049 --- /dev/null +++ b/crypto_kem/newhope1024cca/clean/verify.c @@ -0,0 +1,49 @@ +#include "verify.h" +#include +#include + +/************************************************* +* Name: verify +* +* Description: Compare two arrays for equality in constant time. +* +* Arguments: const unsigned char *a: pointer to first byte array +* const unsigned char *b: pointer to second byte array +* size_t len: length of the byte arrays +* +* Returns 0 if the byte arrays are equal, 1 otherwise +**************************************************/ +int PQCLEAN_NEWHOPE1024CCA_CLEAN_verify(const unsigned char *a, const unsigned char *b, size_t len) { + uint64_t r; + size_t i; + r = 0; + + for (i = 0; i < len; i++) { + r |= a[i] ^ b[i]; + } + + r = (-(int64_t)r) >> 63; + return (int)r; +} + +/************************************************* +* Name: cmov +* +* Description: Copy len bytes from x to r if b is 1; +* don't modify x if b is 0. Requires b to be in {0,1}; +* assumes two's complement representation of negative integers. +* Runs in constant time. +* +* Arguments: unsigned char *r: pointer to output byte array +* const unsigned char *x: pointer to input byte array +* size_t len: Amount of bytes to be copied +* unsigned char b: Condition bit; has to be in {0,1} +**************************************************/ +void PQCLEAN_NEWHOPE1024CCA_CLEAN_cmov(unsigned char *r, const unsigned char *x, size_t len, unsigned char b) { + size_t i; + + b = -b; + for (i = 0; i < len; i++) { + r[i] ^= b & (x[i] ^ r[i]); + } +} diff --git a/crypto_kem/newhope1024cca/clean/verify.h b/crypto_kem/newhope1024cca/clean/verify.h new file mode 100644 index 00000000..e5819338 --- /dev/null +++ b/crypto_kem/newhope1024cca/clean/verify.h @@ -0,0 +1,12 @@ +#ifndef VERIFY_H +#define VERIFY_H + +#include + +/* returns 0 for equal strings, 1 for non-equal strings */ +int PQCLEAN_NEWHOPE1024CCA_CLEAN_verify(const unsigned char *a, const unsigned char *b, size_t len); + +/* b = 1 means mov, b = 0 means don't mov*/ +void PQCLEAN_NEWHOPE1024CCA_CLEAN_cmov(unsigned char *r, const unsigned char *x, size_t len, unsigned char b); + +#endif diff --git a/crypto_kem/newhope1024cpa/META.yml b/crypto_kem/newhope1024cpa/META.yml new file mode 100644 index 00000000..43dfa5f9 --- /dev/null +++ b/crypto_kem/newhope1024cpa/META.yml @@ -0,0 +1,21 @@ +name: NewHope1024CPA +type: kem +claimed-nist-level: 5 +claimed-security: IND-CPA +length-public-key: 1824 +length-secret-key: 1792 +length-ciphertext: 2176 +length-shared-secret: 32 +nistkat-sha256: f48b42b21a51d7f9325abc5fbda74872d62feaa8cbf818bee87f29bf96630a2f +principal-submitter: Thomas Pöppelmann +auxiliary-submitters: +- Erdem Alkim +- Roberto Avanzi +- Joppe Bos +- Léo Ducas +- Antonio de la Piedra +- Peter Schwabe +- Douglas Stebila +implementations: +- name: clean + version: https://github.com/newhopecrypto/newhope/commit/3fc68c6090b23c56cc190a78af2f43ee8900e9d0 diff --git a/crypto_kem/newhope1024cpa/clean/LICENSE b/crypto_kem/newhope1024cpa/clean/LICENSE new file mode 100644 index 00000000..d5d21fff --- /dev/null +++ b/crypto_kem/newhope1024cpa/clean/LICENSE @@ -0,0 +1 @@ +Public Domain diff --git a/crypto_kem/newhope1024cpa/clean/Makefile b/crypto_kem/newhope1024cpa/clean/Makefile new file mode 100644 index 00000000..46b0b736 --- /dev/null +++ b/crypto_kem/newhope1024cpa/clean/Makefile @@ -0,0 +1,19 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libnewhope1024cpa_clean.a +HEADERS=api.h cpapke.h ntt.h params.h poly.h reduce.h verify.h +OBJECTS=cpapke.o kem.o ntt.o poly.o precomp.o reduce.o verify.o + +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Wvla -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/newhope1024cpa/clean/Makefile.Microsoft_nmake b/crypto_kem/newhope1024cpa/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..1aa986f0 --- /dev/null +++ b/crypto_kem/newhope1024cpa/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=libnewhope1024cpa_clean.lib +OBJECTS=cpapke.obj kem.obj ntt.obj poly.obj precomp.obj reduce.obj verify.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/newhope1024cpa/clean/api.h b/crypto_kem/newhope1024cpa/clean/api.h new file mode 100644 index 00000000..683aa8a7 --- /dev/null +++ b/crypto_kem/newhope1024cpa/clean/api.h @@ -0,0 +1,15 @@ +#ifndef PQCLEAN_NEWHOPE1024CPA_CLEAN_API_H +#define PQCLEAN_NEWHOPE1024CPA_CLEAN_API_H + + +#define PQCLEAN_NEWHOPE1024CPA_CLEAN_CRYPTO_SECRETKEYBYTES 1792 +#define PQCLEAN_NEWHOPE1024CPA_CLEAN_CRYPTO_PUBLICKEYBYTES 1824 +#define PQCLEAN_NEWHOPE1024CPA_CLEAN_CRYPTO_CIPHERTEXTBYTES 2176 +#define PQCLEAN_NEWHOPE1024CPA_CLEAN_CRYPTO_BYTES 32 +#define PQCLEAN_NEWHOPE1024CPA_CLEAN_CRYPTO_ALGNAME "NewHope1024-CPAKEM" + +int PQCLEAN_NEWHOPE1024CPA_CLEAN_crypto_kem_keypair(unsigned char *pk, unsigned char *sk); +int PQCLEAN_NEWHOPE1024CPA_CLEAN_crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk); +int PQCLEAN_NEWHOPE1024CPA_CLEAN_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk); + +#endif diff --git a/crypto_kem/newhope1024cpa/clean/cpapke.c b/crypto_kem/newhope1024cpa/clean/cpapke.c new file mode 100644 index 00000000..ec5a5b07 --- /dev/null +++ b/crypto_kem/newhope1024cpa/clean/cpapke.c @@ -0,0 +1,192 @@ +#include "api.h" +#include "cpapke.h" +#include "fips202.h" +#include "poly.h" +#include "randombytes.h" +#include + +/************************************************* +* Name: encode_pk +* +* Description: Serialize the public key as concatenation of the +* serialization of the polynomial pk and the public seed +* used to generete the polynomial a. +* +* Arguments: unsigned char *r: pointer to the output serialized public key +* const poly *pk: pointer to the input public-key polynomial +* const unsigned char *seed: pointer to the input public seed +**************************************************/ +static void encode_pk(unsigned char *r, const poly *pk, const unsigned char *seed) { + int i; + PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_tobytes(r, pk); + for (i = 0; i < NEWHOPE_SYMBYTES; i++) { + r[NEWHOPE_POLYBYTES + i] = seed[i]; + } +} + +/************************************************* +* Name: decode_pk +* +* Description: De-serialize the public key; inverse of encode_pk +* +* Arguments: poly *pk: pointer to output public-key polynomial +* unsigned char *seed: pointer to output public seed +* const unsigned char *r: pointer to input byte array +**************************************************/ +static void decode_pk(poly *pk, unsigned char *seed, const unsigned char *r) { + int i; + PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_frombytes(pk, r); + for (i = 0; i < NEWHOPE_SYMBYTES; i++) { + seed[i] = r[NEWHOPE_POLYBYTES + i]; + } +} + +/************************************************* +* Name: encode_c +* +* Description: Serialize the ciphertext as concatenation of the +* serialization of the polynomial b and serialization +* of the compressed polynomial v +* +* Arguments: - unsigned char *r: pointer to the output serialized ciphertext +* - const poly *b: pointer to the input polynomial b +* - const poly *v: pointer to the input polynomial v +**************************************************/ +static void encode_c(unsigned char *r, const poly *b, const poly *v) { + PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_tobytes(r, b); + PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_compress(r + NEWHOPE_POLYBYTES, v); +} + +/************************************************* +* Name: decode_c +* +* Description: de-serialize the ciphertext; inverse of encode_c +* +* Arguments: - poly *b: pointer to output polynomial b +* - poly *v: pointer to output polynomial v +* - const unsigned char *r: pointer to input byte array +**************************************************/ +static void decode_c(poly *b, poly *v, const unsigned char *r) { + PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_frombytes(b, r); + PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_decompress(v, r + NEWHOPE_POLYBYTES); +} + +/************************************************* +* Name: gen_a +* +* Description: Deterministically generate public polynomial a from seed +* +* Arguments: - poly *a: pointer to output polynomial a +* - const unsigned char *seed: pointer to input seed +**************************************************/ +static void gen_a(poly *a, const unsigned char *seed) { + PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_uniform(a, seed); +} + + +/************************************************* +* Name: cpapke_keypair +* +* Description: Generates public and private key +* for the CPA public-key encryption scheme underlying +* the NewHope KEMs +* +* Arguments: - unsigned char *pk: pointer to output public key +* - unsigned char *sk: pointer to output private key +**************************************************/ +void PQCLEAN_NEWHOPE1024CPA_CLEAN_cpapke_keypair(unsigned char *pk, + unsigned char *sk) { + poly ahat, ehat, ahat_shat, bhat, shat; + unsigned char z[2 * NEWHOPE_SYMBYTES]; + unsigned char *publicseed = z; + unsigned char *noiseseed = z + NEWHOPE_SYMBYTES; + + randombytes(z, NEWHOPE_SYMBYTES); + shake256(z, 2 * NEWHOPE_SYMBYTES, z, NEWHOPE_SYMBYTES); + + gen_a(&ahat, publicseed); + + PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_sample(&shat, noiseseed, 0); + PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_ntt(&shat); + + PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_sample(&ehat, noiseseed, 1); + PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_ntt(&ehat); + + PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_mul_pointwise(&ahat_shat, &shat, &ahat); + PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_add(&bhat, &ehat, &ahat_shat); + + PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_tobytes(sk, &shat); + encode_pk(pk, &bhat, publicseed); +} + +/************************************************* +* Name: cpapke_enc +* +* Description: Encryption function of +* the CPA public-key encryption scheme underlying +* the NewHope KEMs +* +* Arguments: - unsigned char *c: pointer to output ciphertext +* - const unsigned char *m: pointer to input message (of length NEWHOPE_SYMBYTES bytes) +* - const unsigned char *pk: pointer to input public key +* - const unsigned char *coin: pointer to input random coins used as seed +* to deterministically generate all randomness +**************************************************/ +void PQCLEAN_NEWHOPE1024CPA_CLEAN_cpapke_enc(unsigned char *c, + const unsigned char *m, + const unsigned char *pk, + const unsigned char *coin) { + poly sprime, eprime, vprime, ahat, bhat, eprimeprime, uhat, v; + unsigned char publicseed[NEWHOPE_SYMBYTES]; + + PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_frommsg(&v, m); + + decode_pk(&bhat, publicseed, pk); + gen_a(&ahat, publicseed); + + PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_sample(&sprime, coin, 0); + PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_sample(&eprime, coin, 1); + PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_sample(&eprimeprime, coin, 2); + + PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_ntt(&sprime); + PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_ntt(&eprime); + + PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_mul_pointwise(&uhat, &ahat, &sprime); + PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_add(&uhat, &uhat, &eprime); + + PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_mul_pointwise(&vprime, &bhat, &sprime); + PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_invntt(&vprime); + + PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_add(&vprime, &vprime, &eprimeprime); + PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_add(&vprime, &vprime, &v); // add message + + encode_c(c, &uhat, &vprime); +} + + +/************************************************* +* Name: cpapke_dec +* +* Description: Decryption function of +* the CPA public-key encryption scheme underlying +* the NewHope KEMs +* +* Arguments: - unsigned char *m: pointer to output decrypted message +* - const unsigned char *c: pointer to input ciphertext +* - const unsigned char *sk: pointer to input secret key +**************************************************/ +void PQCLEAN_NEWHOPE1024CPA_CLEAN_cpapke_dec(unsigned char *m, + const unsigned char *c, + const unsigned char *sk) { + poly vprime, uhat, tmp, shat; + + PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_frombytes(&shat, sk); + + decode_c(&uhat, &vprime, c); + PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_mul_pointwise(&tmp, &shat, &uhat); + PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_invntt(&tmp); + + PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_sub(&tmp, &tmp, &vprime); + + PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_tomsg(m, &tmp); +} diff --git a/crypto_kem/newhope1024cpa/clean/cpapke.h b/crypto_kem/newhope1024cpa/clean/cpapke.h new file mode 100644 index 00000000..ea284e10 --- /dev/null +++ b/crypto_kem/newhope1024cpa/clean/cpapke.h @@ -0,0 +1,16 @@ +#ifndef INDCPA_H +#define INDCPA_H + +void PQCLEAN_NEWHOPE1024CPA_CLEAN_cpapke_keypair(unsigned char *pk, + unsigned char *sk); + +void PQCLEAN_NEWHOPE1024CPA_CLEAN_cpapke_enc(unsigned char *c, + const unsigned char *m, + const unsigned char *pk, + const unsigned char *coins); + +void PQCLEAN_NEWHOPE1024CPA_CLEAN_cpapke_dec(unsigned char *m, + const unsigned char *c, + const unsigned char *sk); + +#endif diff --git a/crypto_kem/newhope1024cpa/clean/kem.c b/crypto_kem/newhope1024cpa/clean/kem.c new file mode 100644 index 00000000..54f5a2f3 --- /dev/null +++ b/crypto_kem/newhope1024cpa/clean/kem.c @@ -0,0 +1,71 @@ +#include "api.h" +#include "cpapke.h" +#include "fips202.h" +#include "params.h" +#include "randombytes.h" +#include "verify.h" +#include + +/************************************************* +* Name: crypto_kem_keypair +* +* Description: Generates public and private key +* for CCA secure NewHope key encapsulation +* mechanism +* +* Arguments: - unsigned char *pk: pointer to output public key (an already allocated array of CRYPTO_PUBLICKEYBYTES bytes) +* - unsigned char *sk: pointer to output private key (an already allocated array of CRYPTO_SECRETKEYBYTES bytes) +* +* Returns 0 (success) +**************************************************/ +int PQCLEAN_NEWHOPE1024CPA_CLEAN_crypto_kem_keypair(unsigned char *pk, unsigned char *sk) { + PQCLEAN_NEWHOPE1024CPA_CLEAN_cpapke_keypair(pk, sk); /* First put the actual secret key into sk */ + + return 0; +} + +/************************************************* +* Name: crypto_kem_enc +* +* Description: Generates cipher text and shared +* secret for given public key +* +* Arguments: - unsigned char *ct: pointer to output cipher text (an already allocated array of CRYPTO_CIPHERTEXTBYTES bytes) +* - unsigned char *ss: pointer to output shared secret (an already allocated array of CRYPTO_BYTES bytes) +* - const unsigned char *pk: pointer to input public key (an already allocated array of CRYPTO_PUBLICKEYBYTES bytes) +* +* Returns 0 (success) +**************************************************/ +int PQCLEAN_NEWHOPE1024CPA_CLEAN_crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk) { + unsigned char buf[2 * NEWHOPE_SYMBYTES]; + + randombytes(buf, NEWHOPE_SYMBYTES); + + shake256(buf, 2 * NEWHOPE_SYMBYTES, buf, NEWHOPE_SYMBYTES); /* Don't release system RNG output */ + + PQCLEAN_NEWHOPE1024CPA_CLEAN_cpapke_enc(ct, buf, pk, buf + NEWHOPE_SYMBYTES); /* coins are in buf+NEWHOPE_SYMBYTES */ + + shake256(ss, NEWHOPE_SYMBYTES, buf, NEWHOPE_SYMBYTES); /* hash pre-k to ss */ + return 0; +} + + +/************************************************* +* Name: crypto_kem_dec +* +* Description: Generates shared secret for given +* cipher text and private key +* +* Arguments: - unsigned char *ss: pointer to output shared secret (an already allocated array of CRYPTO_BYTES bytes) +* - const unsigned char *ct: pointer to input cipher text (an already allocated array of CRYPTO_CIPHERTEXTBYTES bytes) +* - const unsigned char *sk: pointer to input private key (an already allocated array of CRYPTO_SECRETKEYBYTES bytes) +* +* Returns 0 (success) +**************************************************/ +int PQCLEAN_NEWHOPE1024CPA_CLEAN_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk) { + PQCLEAN_NEWHOPE1024CPA_CLEAN_cpapke_dec(ss, ct, sk); + + shake256(ss, NEWHOPE_SYMBYTES, ss, NEWHOPE_SYMBYTES); /* hash pre-k to ss */ + + return 0; +} diff --git a/crypto_kem/newhope1024cpa/clean/ntt.c b/crypto_kem/newhope1024cpa/clean/ntt.c new file mode 100644 index 00000000..4680c81c --- /dev/null +++ b/crypto_kem/newhope1024cpa/clean/ntt.c @@ -0,0 +1,127 @@ +#include "inttypes.h" +#include "ntt.h" +#include "params.h" +#include "reduce.h" + +/************************************************************ +* Name: bitrev_table +* +* Description: Contains bit-reversed 10-bit indices to be used to re-order +* polynomials before number theoratic transform +************************************************************/ +static uint16_t bitrev_table[NEWHOPE_N] = { + 0, 512, 256, 768, 128, 640, 384, 896, 64, 576, 320, 832, 192, 704, 448, 960, 32, 544, 288, 800, 160, 672, 416, 928, 96, 608, 352, 864, 224, 736, 480, 992, + 16, 528, 272, 784, 144, 656, 400, 912, 80, 592, 336, 848, 208, 720, 464, 976, 48, 560, 304, 816, 176, 688, 432, 944, 112, 624, 368, 880, 240, 752, 496, 1008, + 8, 520, 264, 776, 136, 648, 392, 904, 72, 584, 328, 840, 200, 712, 456, 968, 40, 552, 296, 808, 168, 680, 424, 936, 104, 616, 360, 872, 232, 744, 488, 1000, + 24, 536, 280, 792, 152, 664, 408, 920, 88, 600, 344, 856, 216, 728, 472, 984, 56, 568, 312, 824, 184, 696, 440, 952, 120, 632, 376, 888, 248, 760, 504, 1016, + 4, 516, 260, 772, 132, 644, 388, 900, 68, 580, 324, 836, 196, 708, 452, 964, 36, 548, 292, 804, 164, 676, 420, 932, 100, 612, 356, 868, 228, 740, 484, 996, + 20, 532, 276, 788, 148, 660, 404, 916, 84, 596, 340, 852, 212, 724, 468, 980, 52, 564, 308, 820, 180, 692, 436, 948, 116, 628, 372, 884, 244, 756, 500, 1012, + 12, 524, 268, 780, 140, 652, 396, 908, 76, 588, 332, 844, 204, 716, 460, 972, 44, 556, 300, 812, 172, 684, 428, 940, 108, 620, 364, 876, 236, 748, 492, 1004, + 28, 540, 284, 796, 156, 668, 412, 924, 92, 604, 348, 860, 220, 732, 476, 988, 60, 572, 316, 828, 188, 700, 444, 956, 124, 636, 380, 892, 252, 764, 508, 1020, + 2, 514, 258, 770, 130, 642, 386, 898, 66, 578, 322, 834, 194, 706, 450, 962, 34, 546, 290, 802, 162, 674, 418, 930, 98, 610, 354, 866, 226, 738, 482, 994, + 18, 530, 274, 786, 146, 658, 402, 914, 82, 594, 338, 850, 210, 722, 466, 978, 50, 562, 306, 818, 178, 690, 434, 946, 114, 626, 370, 882, 242, 754, 498, 1010, + 10, 522, 266, 778, 138, 650, 394, 906, 74, 586, 330, 842, 202, 714, 458, 970, 42, 554, 298, 810, 170, 682, 426, 938, 106, 618, 362, 874, 234, 746, 490, 1002, + 26, 538, 282, 794, 154, 666, 410, 922, 90, 602, 346, 858, 218, 730, 474, 986, 58, 570, 314, 826, 186, 698, 442, 954, 122, 634, 378, 890, 250, 762, 506, 1018, + 6, 518, 262, 774, 134, 646, 390, 902, 70, 582, 326, 838, 198, 710, 454, 966, 38, 550, 294, 806, 166, 678, 422, 934, 102, 614, 358, 870, 230, 742, 486, 998, + 22, 534, 278, 790, 150, 662, 406, 918, 86, 598, 342, 854, 214, 726, 470, 982, 54, 566, 310, 822, 182, 694, 438, 950, 118, 630, 374, 886, 246, 758, 502, 1014, + 14, 526, 270, 782, 142, 654, 398, 910, 78, 590, 334, 846, 206, 718, 462, 974, 46, 558, 302, 814, 174, 686, 430, 942, 110, 622, 366, 878, 238, 750, 494, 1006, + 30, 542, 286, 798, 158, 670, 414, 926, 94, 606, 350, 862, 222, 734, 478, 990, 62, 574, 318, 830, 190, 702, 446, 958, 126, 638, 382, 894, 254, 766, 510, 1022, + 1, 513, 257, 769, 129, 641, 385, 897, 65, 577, 321, 833, 193, 705, 449, 961, 33, 545, 289, 801, 161, 673, 417, 929, 97, 609, 353, 865, 225, 737, 481, 993, + 17, 529, 273, 785, 145, 657, 401, 913, 81, 593, 337, 849, 209, 721, 465, 977, 49, 561, 305, 817, 177, 689, 433, 945, 113, 625, 369, 881, 241, 753, 497, 1009, + 9, 521, 265, 777, 137, 649, 393, 905, 73, 585, 329, 841, 201, 713, 457, 969, 41, 553, 297, 809, 169, 681, 425, 937, 105, 617, 361, 873, 233, 745, 489, 1001, + 25, 537, 281, 793, 153, 665, 409, 921, 89, 601, 345, 857, 217, 729, 473, 985, 57, 569, 313, 825, 185, 697, 441, 953, 121, 633, 377, 889, 249, 761, 505, 1017, + 5, 517, 261, 773, 133, 645, 389, 901, 69, 581, 325, 837, 197, 709, 453, 965, 37, 549, 293, 805, 165, 677, 421, 933, 101, 613, 357, 869, 229, 741, 485, 997, + 21, 533, 277, 789, 149, 661, 405, 917, 85, 597, 341, 853, 213, 725, 469, 981, 53, 565, 309, 821, 181, 693, 437, 949, 117, 629, 373, 885, 245, 757, 501, 1013, + 13, 525, 269, 781, 141, 653, 397, 909, 77, 589, 333, 845, 205, 717, 461, 973, 45, 557, 301, 813, 173, 685, 429, 941, 109, 621, 365, 877, 237, 749, 493, 1005, + 29, 541, 285, 797, 157, 669, 413, 925, 93, 605, 349, 861, 221, 733, 477, 989, 61, 573, 317, 829, 189, 701, 445, 957, 125, 637, 381, 893, 253, 765, 509, 1021, + 3, 515, 259, 771, 131, 643, 387, 899, 67, 579, 323, 835, 195, 707, 451, 963, 35, 547, 291, 803, 163, 675, 419, 931, 99, 611, 355, 867, 227, 739, 483, 995, + 19, 531, 275, 787, 147, 659, 403, 915, 83, 595, 339, 851, 211, 723, 467, 979, 51, 563, 307, 819, 179, 691, 435, 947, 115, 627, 371, 883, 243, 755, 499, 1011, + 11, 523, 267, 779, 139, 651, 395, 907, 75, 587, 331, 843, 203, 715, 459, 971, 43, 555, 299, 811, 171, 683, 427, 939, 107, 619, 363, 875, 235, 747, 491, 1003, + 27, 539, 283, 795, 155, 667, 411, 923, 91, 603, 347, 859, 219, 731, 475, 987, 59, 571, 315, 827, 187, 699, 443, 955, 123, 635, 379, 891, 251, 763, 507, 1019, + 7, 519, 263, 775, 135, 647, 391, 903, 71, 583, 327, 839, 199, 711, 455, 967, 39, 551, 295, 807, 167, 679, 423, 935, 103, 615, 359, 871, 231, 743, 487, 999, + 23, 535, 279, 791, 151, 663, 407, 919, 87, 599, 343, 855, 215, 727, 471, 983, 55, 567, 311, 823, 183, 695, 439, 951, 119, 631, 375, 887, 247, 759, 503, 1015, + 15, 527, 271, 783, 143, 655, 399, 911, 79, 591, 335, 847, 207, 719, 463, 975, 47, 559, 303, 815, 175, 687, 431, 943, 111, 623, 367, 879, 239, 751, 495, 1007, + 31, 543, 287, 799, 159, 671, 415, 927, 95, 607, 351, 863, 223, 735, 479, 991, 63, 575, 319, 831, 191, 703, 447, 959, 127, 639, 383, 895, 255, 767, 511, 1023 +}; + +/************************************************* +* Name: bitrev_vector +* +* Description: Permutes coefficients of a polynomial into bitreversed order +* +* Arguments: - uint16_t* poly: pointer to in/output polynomial +**************************************************/ +void PQCLEAN_NEWHOPE1024CPA_CLEAN_bitrev_vector(uint16_t *poly) { + unsigned int i, r; + uint16_t tmp; + + for (i = 0; i < NEWHOPE_N; i++) { + r = bitrev_table[i]; + if (i < r) { + tmp = poly[i]; + poly[i] = poly[r]; + poly[r] = tmp; + } + } +} + +/************************************************* +* Name: mul_coefficients +* +* Description: Performs pointwise (coefficient-wise) multiplication +* of two polynomials +* Arguments: - uint16_t* poly: pointer to in/output polynomial +* - const uint16_t* factors: pointer to input polynomial, coefficients +* are assumed to be in Montgomery representation +**************************************************/ +void PQCLEAN_NEWHOPE1024CPA_CLEAN_mul_coefficients(uint16_t *poly, const uint16_t *factors) { + unsigned int i; + + for (i = 0; i < NEWHOPE_N; i++) { + poly[i] = PQCLEAN_NEWHOPE1024CPA_CLEAN_montgomery_reduce((poly[i] * factors[i])); + } +} + + +void /************************************************* +* Name: ntt +* +* Description: Computes number-theoretic transform (NTT) of +* a polynomial in place; inputs assumed to be in +* bitreversed order, output in normal order +* +* Arguments: - uint16_t * a: pointer to in/output polynomial +* - const uint16_t* omega: pointer to input powers of root of unity omega; +* assumed to be in Montgomery domain +**************************************************/ +PQCLEAN_NEWHOPE1024CPA_CLEAN_ntt(uint16_t *a, const uint16_t *omega) { + int i, start, j, jTwiddle, distance; + uint16_t temp, W; + + + for (i = 0; i < 10; i += 2) { + // Even level + distance = (1 << i); + for (start = 0; start < distance; start++) { + jTwiddle = 0; + for (j = start; j < NEWHOPE_N - 1; j += 2 * distance) { + W = omega[jTwiddle++]; + temp = a[j]; + a[j] = (temp + a[j + distance]); // Omit reduction (be lazy) + a[j + distance] = PQCLEAN_NEWHOPE1024CPA_CLEAN_montgomery_reduce((W * ((uint32_t)temp + 3 * NEWHOPE_Q - a[j + distance]))); + } + } + + // Odd level + distance <<= 1; + for (start = 0; start < distance; start++) { + jTwiddle = 0; + for (j = start; j < NEWHOPE_N - 1; j += 2 * distance) { + W = omega[jTwiddle++]; + temp = a[j]; + a[j] = (temp + a[j + distance]) % NEWHOPE_Q; + a[j + distance] = PQCLEAN_NEWHOPE1024CPA_CLEAN_montgomery_reduce((W * ((uint32_t)temp + 3 * NEWHOPE_Q - a[j + distance]))); + } + } + } +} diff --git a/crypto_kem/newhope1024cpa/clean/ntt.h b/crypto_kem/newhope1024cpa/clean/ntt.h new file mode 100644 index 00000000..42e41df0 --- /dev/null +++ b/crypto_kem/newhope1024cpa/clean/ntt.h @@ -0,0 +1,14 @@ +#ifndef NTT_H +#define NTT_H + +#include "inttypes.h" + +extern const uint16_t PQCLEAN_NEWHOPE1024CPA_CLEAN_omegas_inv_bitrev_montgomery[]; +extern const uint16_t PQCLEAN_NEWHOPE1024CPA_CLEAN_gammas_bitrev_montgomery[]; +extern const uint16_t PQCLEAN_NEWHOPE1024CPA_CLEAN_gammas_inv_montgomery[]; + +void PQCLEAN_NEWHOPE1024CPA_CLEAN_bitrev_vector(uint16_t *poly); +void PQCLEAN_NEWHOPE1024CPA_CLEAN_mul_coefficients(uint16_t *poly, const uint16_t *factors); +void PQCLEAN_NEWHOPE1024CPA_CLEAN_ntt(uint16_t *a, const uint16_t *omegas); + +#endif diff --git a/crypto_kem/newhope1024cpa/clean/params.h b/crypto_kem/newhope1024cpa/clean/params.h new file mode 100644 index 00000000..64d582b7 --- /dev/null +++ b/crypto_kem/newhope1024cpa/clean/params.h @@ -0,0 +1,25 @@ +#ifndef PQCLEAN_NEWHOPE1024CPA_CLEAN_PARAMS_H +#define PQCLEAN_NEWHOPE1024CPA_CLEAN_PARAMS_H + +#define NEWHOPE_N 1024 +#define NEWHOPE_Q 12289 +#define NEWHOPE_K 8 /* used in noise sampling */ + +#define NEWHOPE_SYMBYTES 32 /* size of shared key, seeds/coins, and hashes */ + +#define NEWHOPE_POLYBYTES ((14*NEWHOPE_N)/8) +#define NEWHOPE_POLYCOMPRESSEDBYTES (( 3*NEWHOPE_N)/8) + +#define NEWHOPE_CPAPKE_PUBLICKEYBYTES (NEWHOPE_POLYBYTES + NEWHOPE_SYMBYTES) +#define NEWHOPE_CPAPKE_SECRETKEYBYTES (NEWHOPE_POLYBYTES) +#define NEWHOPE_CPAPKE_CIPHERTEXTBYTES (NEWHOPE_POLYBYTES + NEWHOPE_POLYCOMPRESSEDBYTES) + +#define NEWHOPE_CPAKEM_PUBLICKEYBYTES NEWHOPE_CPAPKE_PUBLICKEYBYTES +#define NEWHOPE_CPAKEM_SECRETKEYBYTES NEWHOPE_CPAPKE_SECRETKEYBYTES +#define NEWHOPE_CPAKEM_CIPHERTEXTBYTES NEWHOPE_CPAPKE_CIPHERTEXTBYTES + +#define NEWHOPE_CCAKEM_PUBLICKEYBYTES NEWHOPE_CPAPKE_PUBLICKEYBYTES +#define NEWHOPE_CCAKEM_SECRETKEYBYTES (NEWHOPE_CPAPKE_SECRETKEYBYTES + NEWHOPE_CPAPKE_PUBLICKEYBYTES + 2*NEWHOPE_SYMBYTES) +#define NEWHOPE_CCAKEM_CIPHERTEXTBYTES (NEWHOPE_CPAPKE_CIPHERTEXTBYTES + NEWHOPE_SYMBYTES) /* Second part is for Targhi-Unruh */ + +#endif diff --git a/crypto_kem/newhope1024cpa/clean/poly.c b/crypto_kem/newhope1024cpa/clean/poly.c new file mode 100644 index 00000000..f9b4cce8 --- /dev/null +++ b/crypto_kem/newhope1024cpa/clean/poly.c @@ -0,0 +1,357 @@ +#include "fips202.h" +#include "ntt.h" +#include "poly.h" +#include "reduce.h" + +/************************************************* +* Name: coeff_freeze +* +* Description: Fully reduces an integer modulo q in constant time +* +* Arguments: uint16_t x: input integer to be reduced +* +* Returns integer in {0,...,q-1} congruent to x modulo q +**************************************************/ +static uint16_t coeff_freeze(uint16_t x) { + uint16_t m, r; + int16_t c; + r = x % NEWHOPE_Q; + + m = r - NEWHOPE_Q; + c = m; + c >>= 15; + r = m ^ ((r ^ m)&c); + + return r; +} + +/************************************************* +* Name: flipabs +* +* Description: Computes |(x mod q) - Q/2| +* +* Arguments: uint16_t x: input coefficient +* +* Returns |(x mod q) - Q/2| +**************************************************/ +static uint16_t flipabs(uint16_t x) { + int16_t r, m; + r = coeff_freeze(x); + + r = r - NEWHOPE_Q / 2; + m = r >> 15; + return (r + m) ^ m; +} + +/************************************************* +* Name: poly_frombytes +* +* Description: De-serialization of a polynomial +* +* Arguments: - poly *r: pointer to output polynomial +* - const unsigned char *a: pointer to input byte array +**************************************************/ +void PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_frombytes(poly *r, const unsigned char *a) { + int i; + for (i = 0; i < NEWHOPE_N / 4; i++) { + r->coeffs[4 * i + 0] = a[7 * i + 0] | (((uint16_t)a[7 * i + 1] & 0x3f) << 8); + r->coeffs[4 * i + 1] = (a[7 * i + 1] >> 6) | (((uint16_t)a[7 * i + 2]) << 2) | (((uint16_t)a[7 * i + 3] & 0x0f) << 10); + r->coeffs[4 * i + 2] = (a[7 * i + 3] >> 4) | (((uint16_t)a[7 * i + 4]) << 4) | (((uint16_t)a[7 * i + 5] & 0x03) << 12); + r->coeffs[4 * i + 3] = (a[7 * i + 5] >> 2) | (((uint16_t)a[7 * i + 6]) << 6); + } +} + +/************************************************* +* Name: poly_tobytes +* +* Description: Serialization of a polynomial +* +* Arguments: - unsigned char *r: pointer to output byte array +* - const poly *p: pointer to input polynomial +**************************************************/ +void PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_tobytes(unsigned char *r, const poly *p) { + int i; + uint16_t t0, t1, t2, t3; + for (i = 0; i < NEWHOPE_N / 4; i++) { + t0 = coeff_freeze(p->coeffs[4 * i + 0]); + t1 = coeff_freeze(p->coeffs[4 * i + 1]); + t2 = coeff_freeze(p->coeffs[4 * i + 2]); + t3 = coeff_freeze(p->coeffs[4 * i + 3]); + + r[7 * i + 0] = t0 & 0xff; + r[7 * i + 1] = (unsigned char) ((t0 >> 8) | (t1 << 6)); + r[7 * i + 2] = (unsigned char) ((t1 >> 2)); + r[7 * i + 3] = (unsigned char) ((t1 >> 10) | (t2 << 4)); + r[7 * i + 4] = (unsigned char) ((t2 >> 4)); + r[7 * i + 5] = (unsigned char) ((t2 >> 12) | (t3 << 2)); + r[7 * i + 6] = (unsigned char) ((t3 >> 6)); + } +} + +/************************************************* +* Name: poly_compress +* +* Description: Compression and subsequent serialization of a polynomial +* +* Arguments: - unsigned char *r: pointer to output byte array +* - const poly *p: pointer to input polynomial +**************************************************/ +void PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_compress(unsigned char *r, const poly *p) { + unsigned int i, j, k = 0; + + uint32_t t[8]; + + for (i = 0; i < NEWHOPE_N; i += 8) { + for (j = 0; j < 8; j++) { + t[j] = coeff_freeze(p->coeffs[i + j]); + t[j] = (((t[j] << 3) + NEWHOPE_Q / 2) / NEWHOPE_Q) & 0x7; + } + + r[k] = (unsigned char) (t[0] | (t[1] << 3) | (t[2] << 6)); + r[k + 1] = (unsigned char) ((t[2] >> 2) | (t[3] << 1) | (t[4] << 4) | (t[5] << 7)); + r[k + 2] = (unsigned char) ((t[5] >> 1) | (t[6] << 2) | (t[7] << 5)); + k += 3; + } +} + +/************************************************* +* Name: poly_decompress +* +* Description: De-serialization and subsequent decompression of a polynomial; +* approximate inverse of poly_compress +* +* Arguments: - poly *r: pointer to output polynomial +* - const unsigned char *a: pointer to input byte array +**************************************************/ +void PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_decompress(poly *r, const unsigned char *a) { + unsigned int i, j; + for (i = 0; i < NEWHOPE_N; i += 8) { + r->coeffs[i + 0] = a[0] & 7; + r->coeffs[i + 1] = (a[0] >> 3) & 7; + r->coeffs[i + 2] = (a[0] >> 6) | ((a[1] << 2) & 4); + r->coeffs[i + 3] = (a[1] >> 1) & 7; + r->coeffs[i + 4] = (a[1] >> 4) & 7; + r->coeffs[i + 5] = (a[1] >> 7) | ((a[2] << 1) & 6); + r->coeffs[i + 6] = (a[2] >> 2) & 7; + r->coeffs[i + 7] = (a[2] >> 5); + a += 3; + for (j = 0; j < 8; j++) { + r->coeffs[i + j] = ((uint32_t)r->coeffs[i + j] * NEWHOPE_Q + 4) >> 3; + } + } +} + +/************************************************* +* Name: poly_frommsg +* +* Description: Convert 32-byte message to polynomial +* +* Arguments: - poly *r: pointer to output polynomial +* - const unsigned char *msg: pointer to input message +**************************************************/ +void PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_frommsg(poly *r, const unsigned char *msg) { + unsigned int i, j, mask; + for (i = 0; i < NEWHOPE_SYMBYTES; i++) { + for (j = 0; j < 8; j++) { + mask = -((msg[i] >> j) & 1); + r->coeffs[8 * i + j + 0] = mask & (NEWHOPE_Q / 2); + r->coeffs[8 * i + j + 256] = mask & (NEWHOPE_Q / 2); + r->coeffs[8 * i + j + 512] = mask & (NEWHOPE_Q / 2); + r->coeffs[8 * i + j + 768] = mask & (NEWHOPE_Q / 2); + } + } +} + +/************************************************* +* Name: poly_tomsg +* +* Description: Convert polynomial to 32-byte message +* +* Arguments: - unsigned char *msg: pointer to output message +* - const poly *x: pointer to input polynomial +**************************************************/ +void PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_tomsg(unsigned char *msg, const poly *x) { + unsigned int i; + uint16_t t; + + for (i = 0; i < 32; i++) { + msg[i] = 0; + } + + for (i = 0; i < 256; i++) { + t = flipabs(x->coeffs[i + 0]); + t += flipabs(x->coeffs[i + 256]); + t += flipabs(x->coeffs[i + 512]); + t += flipabs(x->coeffs[i + 768]); + t = ((t - NEWHOPE_Q)); + + t >>= 15; + msg[i >> 3] |= t << (i & 7); + } +} + +/************************************************* +* Name: poly_uniform +* +* Description: Sample a polynomial deterministically from a seed, +* with output polynomial looking uniformly random +* +* Arguments: - poly *a: pointer to output polynomial +* - const unsigned char *seed: pointer to input seed +**************************************************/ +void PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_uniform(poly *a, const unsigned char *seed) { + unsigned int ctr = 0; + uint16_t val; + shake128ctx state; + uint8_t buf[SHAKE128_RATE]; + uint8_t extseed[NEWHOPE_SYMBYTES + 1]; + int i, j; + + for (i = 0; i < NEWHOPE_SYMBYTES; i++) { + extseed[i] = seed[i]; + } + + for (i = 0; i < NEWHOPE_N / 64; i++) { /* generate a in blocks of 64 coefficients */ + ctr = 0; + extseed[NEWHOPE_SYMBYTES] = (unsigned char) i; /* domain-separate the 16 independent calls */ + shake128_absorb(&state, extseed, NEWHOPE_SYMBYTES + 1); + while (ctr < 64) { /* Very unlikely to run more than once */ + shake128_squeezeblocks(buf, 1, &state); + for (j = 0; j < SHAKE128_RATE && ctr < 64; j += 2) { + val = (buf[j] | ((uint16_t) buf[j + 1] << 8)); + if (val < 5 * NEWHOPE_Q) { + a->coeffs[i * 64 + ctr] = val; + ctr++; + } + } + } + } +} + +/************************************************* +* Name: hw +* +* Description: Compute the Hamming weight of a byte +* +* Arguments: - unsigned char a: input byte +**************************************************/ +static unsigned char hw(unsigned char a) { + unsigned char i, r = 0; + for (i = 0; i < 8; i++) { + r += (a >> i) & 1; + } + return r; +} + +/************************************************* +* Name: poly_sample +* +* Description: Sample a polynomial deterministically from a seed and a nonce, +* with output polynomial close to centered binomial distribution +* with parameter k=8 +* +* Arguments: - poly *r: pointer to output polynomial +* - const unsigned char *seed: pointer to input seed +* - unsigned char nonce: one-byte input nonce +**************************************************/ +void PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_sample(poly *r, const unsigned char *seed, unsigned char nonce) { + unsigned char buf[128], a, b; + int i, j; + + unsigned char extseed[NEWHOPE_SYMBYTES + 2]; + + for (i = 0; i < NEWHOPE_SYMBYTES; i++) { + extseed[i] = seed[i]; + } + extseed[NEWHOPE_SYMBYTES] = nonce; + + for (i = 0; i < NEWHOPE_N / 64; i++) { /* Generate noise in blocks of 64 coefficients */ + extseed[NEWHOPE_SYMBYTES + 1] = (unsigned char) i; + shake256(buf, 128, extseed, NEWHOPE_SYMBYTES + 2); + for (j = 0; j < 64; j++) { + a = buf[2 * j]; + b = buf[2 * j + 1]; + r->coeffs[64 * i + j] = hw(a) + NEWHOPE_Q - hw(b); + } + } +} + +/************************************************* +* Name: poly_pointwise +* +* Description: Multiply two polynomials pointwise (i.e., coefficient-wise). +* +* Arguments: - poly *r: pointer to output polynomial +* - const poly *a: pointer to first input polynomial +* - const poly *b: pointer to second input polynomial +**************************************************/ +void PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_mul_pointwise(poly *r, const poly *a, const poly *b) { + int i; + uint16_t t; + for (i = 0; i < NEWHOPE_N; i++) { + t = PQCLEAN_NEWHOPE1024CPA_CLEAN_montgomery_reduce(3186 * b->coeffs[i]); /* t is now in Montgomery domain */ + r->coeffs[i] = PQCLEAN_NEWHOPE1024CPA_CLEAN_montgomery_reduce(a->coeffs[i] * t); /* r->coeffs[i] is back in normal domain */ + } +} + +/************************************************* +* Name: poly_add +* +* Description: Add two polynomials +* +* Arguments: - poly *r: pointer to output polynomial +* - const poly *a: pointer to first input polynomial +* - const poly *b: pointer to second input polynomial +**************************************************/ +void PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_add(poly *r, const poly *a, const poly *b) { + int i; + for (i = 0; i < NEWHOPE_N; i++) { + r->coeffs[i] = (a->coeffs[i] + b->coeffs[i]) % NEWHOPE_Q; + } +} + +/************************************************* +* Name: poly_sub +* +* Description: Subtract two polynomials +* +* Arguments: - poly *r: pointer to output polynomial +* - const poly *a: pointer to first input polynomial +* - const poly *b: pointer to second input polynomial +**************************************************/ +void PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_sub(poly *r, const poly *a, const poly *b) { + int i; + for (i = 0; i < NEWHOPE_N; i++) { + r->coeffs[i] = (a->coeffs[i] + 3 * NEWHOPE_Q - b->coeffs[i]) % NEWHOPE_Q; + } +} + +/************************************************* +* Name: poly_ntt +* +* Description: Forward NTT transform of a polynomial in place +* Input is assumed to have coefficients in bitreversed order +* Output has coefficients in normal order +* +* Arguments: - poly *r: pointer to in/output polynomial +**************************************************/ +void PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_ntt(poly *r) { + PQCLEAN_NEWHOPE1024CPA_CLEAN_mul_coefficients(r->coeffs, PQCLEAN_NEWHOPE1024CPA_CLEAN_gammas_bitrev_montgomery); + PQCLEAN_NEWHOPE1024CPA_CLEAN_ntt((uint16_t *)r->coeffs, PQCLEAN_NEWHOPE1024CPA_CLEAN_gammas_bitrev_montgomery); +} + +/************************************************* +* Name: poly_invntt +* +* Description: Inverse NTT transform of a polynomial in place +* Input is assumed to have coefficients in normal order +* Output has coefficients in normal order +* +* Arguments: - poly *r: pointer to in/output polynomial +**************************************************/ +void PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_invntt(poly *r) { + PQCLEAN_NEWHOPE1024CPA_CLEAN_bitrev_vector(r->coeffs); + PQCLEAN_NEWHOPE1024CPA_CLEAN_ntt((uint16_t *)r->coeffs, PQCLEAN_NEWHOPE1024CPA_CLEAN_omegas_inv_bitrev_montgomery); + PQCLEAN_NEWHOPE1024CPA_CLEAN_mul_coefficients(r->coeffs, PQCLEAN_NEWHOPE1024CPA_CLEAN_gammas_inv_montgomery); +} + diff --git a/crypto_kem/newhope1024cpa/clean/poly.h b/crypto_kem/newhope1024cpa/clean/poly.h new file mode 100644 index 00000000..349d1ed9 --- /dev/null +++ b/crypto_kem/newhope1024cpa/clean/poly.h @@ -0,0 +1,32 @@ +#ifndef POLY_H +#define POLY_H + +#include "params.h" +#include + +/* + * Elements of R_q = Z_q[X]/(X^n + 1). Represents polynomial + * coeffs[0] + X*coeffs[1] + X^2*xoeffs[2] + ... + X^{n-1}*coeffs[n-1] + */ +typedef struct { + uint16_t coeffs[NEWHOPE_N]; +} poly; + +void PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_uniform(poly *a, const unsigned char *seed); +void PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_sample(poly *r, const unsigned char *seed, unsigned char nonce); +void PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_add(poly *r, const poly *a, const poly *b); + +void PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_ntt(poly *r); +void PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_invntt(poly *r); +void PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_mul_pointwise(poly *r, const poly *a, const poly *b); + +void PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_frombytes(poly *r, const unsigned char *a); +void PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_tobytes(unsigned char *r, const poly *p); +void PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_compress(unsigned char *r, const poly *p); +void PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_decompress(poly *r, const unsigned char *a); + +void PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_frommsg(poly *r, const unsigned char *msg); +void PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_tomsg(unsigned char *msg, const poly *x); +void PQCLEAN_NEWHOPE1024CPA_CLEAN_poly_sub(poly *r, const poly *a, const poly *b); + +#endif diff --git a/crypto_kem/newhope1024cpa/clean/precomp.c b/crypto_kem/newhope1024cpa/clean/precomp.c new file mode 100644 index 00000000..19eda045 --- /dev/null +++ b/crypto_kem/newhope1024cpa/clean/precomp.c @@ -0,0 +1,261 @@ +#include "inttypes.h" +#include "ntt.h" +#include "params.h" + +/* Precomputed NTT contants generated by Pari/GP script as follows: + * + * For n = 512: + * + * brv = [0,256,128,384,64,320,192,448,32,288,160,416,96,352,224,480,16,272,144,400,80,336,208,464,48,304,176,432,112,368,240,496,8, + * 264,136,392,72,328,200,456,40,296,168,424,104,360,232,488,24,280,152,408,88,344,216,472,56,312,184,440,120,376,248,504,4, + * 260,132,388,68,324,196,452,36,292,164,420,100,356,228,484,20,276,148,404,84,340,212,468,52,308,180,436,116,372,244,500,12, + * 268,140,396,76,332,204,460,44,300,172,428,108,364,236,492,28,284,156,412,92,348,220,476,60,316,188,444,124,380,252,508,2, + * 258,130,386,66,322,194,450,34,290,162,418,98,354,226,482,18,274,146,402,82,338,210,466,50,306,178,434,114,370,242,498,10, + * 266,138,394,74,330,202,458,42,298,170,426,106,362,234,490,26,282,154,410,90,346,218,474,58,314,186,442,122,378,250,506,6, + * 262,134,390,70,326,198,454,38,294,166,422,102,358,230,486,22,278,150,406,86,342,214,470,54,310,182,438,118,374,246,502,14, + * 270,142,398,78,334,206,462,46,302,174,430,110,366,238,494,30,286,158,414,94,350,222,478,62,318,190,446,126,382,254,510,1, + * 257,129,385,65,321,193,449,33,289,161,417,97,353,225,481,17,273,145,401,81,337,209,465,49,305,177,433,113,369,241,497,9, + * 265,137,393,73,329,201,457,41,297,169,425,105,361,233,489,25,281,153,409,89,345,217,473,57,313,185,441,121,377,249,505,5, + * 261,133,389,69,325,197,453,37,293,165,421,101,357,229,485,21,277,149,405,85,341,213,469,53,309,181,437,117,373,245,501,13, + * 269,141,397,77,333,205,461,45,301,173,429,109,365,237,493,29,285,157,413,93,349,221,477,61,317,189,445,125,381,253,509,3, + * 259,131,387,67,323,195,451,35,291,163,419,99,355,227,483,19,275,147,403,83,339,211,467,51,307,179,435,115,371,243,499,11, + * 267,139,395,75,331,203,459,43,299,171,427,107,363,235,491,27,283,155,411,91,347,219,475,59,315,187,443,123,379,251,507,7, + * 263,135,391,71,327,199,455,39,295,167,423,103,359,231,487,23,279,151,407,87,343,215,471,55,311,183,439,119,375,247,503,15, + * 271,143,399,79,335,207,463,47,303,175,431,111,367,239,495,31,287,159,415,95,351,223,479,63,319,191,447,127,383,255,511] + * n = 512; q = 12289; mont=2^18 + * g = Mod(10968, q); + * omegas_inv_bitrev_montgomery = lift(vector(n/2, i, (g^2)^(-brv[2*(i-1)+1])*mont)) + * gammas_bitrev_montgomery = lift(vector(n, i, g^(brv[i])*mont)) + * gammas_inv_montgomery = lift(vector(n, i, g^(-(i-1))/n*mont)) + * + * + * For n = 1024: + * + * brv = [0,512,256,768,128,640,384,896,64,576,320,832,192,704,448,960,32,544,288,800,160,672,416,928,96,608,352,864,224,736,480,992, \ + * 16,528,272,784,144,656,400,912,80,592,336,848,208,720,464,976,48,560,304,816,176,688,432,944,112,624,368,880,240,752,496,1008, \ + * 8,520,264,776,136,648,392,904,72,584,328,840,200,712,456,968,40,552,296,808,168,680,424,936,104,616,360,872,232,744,488,1000, \ + * 24,536,280,792,152,664,408,920,88,600,344,856,216,728,472,984,56,568,312,824,184,696,440,952,120,632,376,888,248,760,504,1016, \ + * 4,516,260,772,132,644,388,900,68,580,324,836,196,708,452,964,36,548,292,804,164,676,420,932,100,612,356,868,228,740,484,996, \ + * 20,532,276,788,148,660,404,916,84,596,340,852,212,724,468,980,52,564,308,820,180,692,436,948,116,628,372,884,244,756,500,1012, \ + * 12,524,268,780,140,652,396,908,76,588,332,844,204,716,460,972,44,556,300,812,172,684,428,940,108,620,364,876,236,748,492,1004, \ + * 28,540,284,796,156,668,412,924,92,604,348,860,220,732,476,988,60,572,316,828,188,700,444,956,124,636,380,892,252,764,508,1020, \ + * 2,514,258,770,130,642,386,898,66,578,322,834,194,706,450,962,34,546,290,802,162,674,418,930,98,610,354,866,226,738,482,994, \ + * 18,530,274,786,146,658,402,914,82,594,338,850,210,722,466,978,50,562,306,818,178,690,434,946,114,626,370,882,242,754,498,1010, \ + * 10,522,266,778,138,650,394,906,74,586,330,842,202,714,458,970,42,554,298,810,170,682,426,938,106,618,362,874,234,746,490,1002, \ + * 26,538,282,794,154,666,410,922,90,602,346,858,218,730,474,986,58,570,314,826,186,698,442,954,122,634,378,890,250,762,506,1018, \ + * 6,518,262,774,134,646,390,902,70,582,326,838,198,710,454,966,38,550,294,806,166,678,422,934,102,614,358,870,230,742,486,998, \ + * 22,534,278,790,150,662,406,918,86,598,342,854,214,726,470,982,54,566,310,822,182,694,438,950,118,630,374,886,246,758,502,1014, \ + * 14,526,270,782,142,654,398,910,78,590,334,846,206,718,462,974,46,558,302,814,174,686,430,942,110,622,366,878,238,750,494,1006, \ + * 30,542,286,798,158,670,414,926,94,606,350,862,222,734,478,990,62,574,318,830,190,702,446,958,126,638,382,894,254,766,510,1022, \ + * 1,513,257,769,129,641,385,897,65,577,321,833,193,705,449,961,33,545,289,801,161,673,417,929,97,609,353,865,225,737,481,993, \ + * 17,529,273,785,145,657,401,913,81,593,337,849,209,721,465,977,49,561,305,817,177,689,433,945,113,625,369,881,241,753,497,1009, \ + * 9,521,265,777,137,649,393,905,73,585,329,841,201,713,457,969,41,553,297,809,169,681,425,937,105,617,361,873,233,745,489,1001, \ + * 25,537,281,793,153,665,409,921,89,601,345,857,217,729,473,985,57,569,313,825,185,697,441,953,121,633,377,889,249,761,505,1017, \ + * 5,517,261,773,133,645,389,901,69,581,325,837,197,709,453,965,37,549,293,805,165,677,421,933,101,613,357,869,229,741,485,997, \ + * 21,533,277,789,149,661,405,917,85,597,341,853,213,725,469,981,53,565,309,821,181,693,437,949,117,629,373,885,245,757,501,1013, \ + * 13,525,269,781,141,653,397,909,77,589,333,845,205,717,461,973,45,557,301,813,173,685,429,941,109,621,365,877,237,749,493,1005, \ + * 29,541,285,797,157,669,413,925,93,605,349,861,221,733,477,989,61,573,317,829,189,701,445,957,125,637,381,893,253,765,509,1021, \ + * 3,515,259,771,131,643,387,899,67,579,323,835,195,707,451,963,35,547,291,803,163,675,419,931,99,611,355,867,227,739,483,995, \ + * 19,531,275,787,147,659,403,915,83,595,339,851,211,723,467,979,51,563,307,819,179,691,435,947,115,627,371,883,243,755,499,1011, \ + * 11,523,267,779,139,651,395,907,75,587,331,843,203,715,459,971,43,555,299,811,171,683,427,939,107,619,363,875,235,747,491,1003, \ + * 27,539,283,795,155,667,411,923,91,603,347,859,219,731,475,987,59,571,315,827,187,699,443,955,123,635,379,891,251,763,507,1019, \ + * 7,519,263,775,135,647,391,903,71,583,327,839,199,711,455,967,39,551,295,807,167,679,423,935,103,615,359,871,231,743,487,999, \ + * 23,535,279,791,151,663,407,919,87,599,343,855,215,727,471,983,55,567,311,823,183,695,439,951,119,631,375,887,247,759,503,1015, \ + * 15,527,271,783,143,655,399,911,79,591,335,847,207,719,463,975,47,559,303,815,175,687,431,943,111,623,367,879,239,751,495,1007, \ + * 31,543,287,799,159,671,415,927,95,607,351,863,223,735,479,991,63,575,319,831,191,703,447,959,127,639,383,895,255,767,511,1023] + * + * n = 1024; q = 12289; mont=2^18 + * g = Mod(7, q); + * omegas_inv_bitrev_montgomery = lift(vector(n/2, i, (g^2)^(-brv[2*(i-1)+1])*mont)) + * gammas_bitrev_montgomery = lift(vector(n, i, g^(brv[i])*mont)) + * gammas_inv_montgomery = lift(vector(n, i, g^(-(i-1))/n*mont)) +*/ + + +/************************************************************ +* Name: omegas_inv_bitrev_montgomery +* +* Description: Contains inverses of powers of nth root of unity +* in Montgomery domain with R=2^18 in bit-reversed order +************************************************************/ +const uint16_t PQCLEAN_NEWHOPE1024CPA_CLEAN_omegas_inv_bitrev_montgomery[NEWHOPE_N / 2] = { + 4075, 5315, 4324, 4916, 10120, 11767, 7210, 9027, 10316, 6715, 1278, 9945, 3514, 11248, 11271, 5925, + 147, 8500, 7840, 6833, 5537, 4749, 4467, 7500, 11099, 9606, 6171, 8471, 8429, 5445, 11239, 7753, + 9090, 12233, 5529, 5206, 10587, 1987, 11635, 3565, 5415, 8646, 6153, 6427, 7341, 6152, 10561, 400, + 8410, 1922, 2033, 8291, 1359, 6854, 11035, 973, 8579, 6093, 6950, 5446, 11821, 8301, 11907, 316, + 52, 3174, 10966, 9523, 6055, 8953, 11612, 6415, 2505, 5906, 10710, 11858, 8332, 9450, 10162, 151, + 3482, 787, 5468, 1010, 4169, 9162, 5241, 9369, 7509, 8844, 7232, 4698, 192, 1321, 10240, 4912, + 885, 6281, 10333, 7280, 8757, 11286, 58, 12048, 12147, 11184, 8812, 6608, 2844, 3438, 4212, 11314, + 8687, 6068, 421, 8209, 3600, 3263, 7665, 6077, 7507, 5886, 3029, 6695, 4213, 504, 11684, 2302, + 1962, 1594, 6328, 7183, 168, 2692, 8960, 4298, 5184, 11089, 6122, 9734, 10929, 3956, 5297, 6170, + 3762, 9370, 4016, 4077, 6523, 652, 11994, 6099, 1146, 11341, 11964, 10885, 6299, 1159, 8240, 8561, + 11177, 2078, 10331, 4322, 11367, 441, 4079, 11231, 3150, 1319, 8243, 709, 8049, 8719, 11454, 6224, + 3054, 6803, 3123, 10542, 4433, 6370, 7032, 3834, 8633, 12225, 9830, 683, 1566, 5782, 9786, 9341, + 12115, 723, 3009, 1693, 5735, 2655, 2738, 6421, 11942, 2925, 1975, 8532, 3315, 11863, 4754, 1858, + 1583, 6347, 2500, 10800, 6374, 1483, 12240, 1263, 1815, 5383, 10777, 350, 6920, 10232, 4493, 9087, + 8855, 8760, 9381, 218, 9928, 10446, 9259, 4115, 6147, 9842, 8326, 576, 10335, 10238, 10484, 9407, + 6381, 11836, 8517, 418, 6860, 7515, 1293, 7552, 2767, 156, 8298, 8320, 10008, 5876, 5333, 10258, + 10115, 4372, 2847, 7875, 8232, 9018, 8925, 1689, 8236, 2645, 5042, 9984, 7094, 9509, 1484, 7394, + 3, 4437, 160, 3149, 113, 7370, 10123, 3915, 6998, 2704, 8653, 4938, 1426, 7635, 10512, 1663, + 6957, 3510, 2370, 2865, 3978, 9320, 3247, 9603, 6882, 3186, 10659, 10163, 1153, 9405, 8241, 10040, + 2178, 1544, 5559, 420, 8304, 4905, 476, 3531, 5191, 9153, 2399, 8889, 3000, 671, 243, 3016, + 3763, 10849, 12262, 9223, 10657, 7205, 11272, 7404, 7575, 8146, 10752, 242, 2678, 3704, 11744, 5019, + 3833, 3778, 11899, 773, 5101, 11222, 9888, 442, 2912, 5698, 11935, 4861, 7277, 9808, 11244, 2859, + 3780, 11414, 4976, 10682, 7201, 8005, 11287, 5011, 6267, 2987, 2437, 3646, 2566, 10102, 9867, 6250, + 5444, 2381, 11796, 8193, 4337, 11854, 1912, 1378, 404, 7644, 1065, 2143, 11121, 5277, 3248, 11082, + 2548, 8058, 8907, 11934, 1759, 8582, 3694, 7110, 12144, 6747, 8652, 3459, 2731, 8357, 6378, 7399, + 10861, 1696, 9863, 334, 7657, 6534, 11029, 4388, 11560, 3241, 10276, 9000, 9408, 3284, 10200, 7197, + 6498, 544, 2468, 339, 11267, 9, 2842, 480, 5331, 7300, 1673, 4278, 4177, 8705, 9764, 1381, + 7837, 2396, 8340, 8993, 4354, 130, 6915, 2837, 11462, 5767, 953, 8541, 9813, 118, 7222, 2197, + 3006, 9545, 563, 9314, 2625, 11340, 4821, 2639, 7266, 5828, 6561, 7698, 3328, 6512, 1351, 7311, + 6553, 8155, 1305, 722, 5146, 4043, 12288, 10810, 2545, 3621, 8747, 8785, 1646, 1212, 5860, 3195, + 7203, 10963, 3201, 3014, 955, 11499, 9970, 11119, 3135, 3712, 7443, 9542, 7484, 8736, 9995, 11227, + 1635, 9521, 1177, 8034, 140, 10436, 11563, 7678, 4320, 11289, 9198, 12208, 2963, 7393, 2366, 9238 +}; + +/************************************************************ +* Name: gammas_bitrev_montgomery +* +* Description: Contains powers of nth root of -1 in Montgomery +* domain with R=2^18 in bit-reversed order +************************************************************/ +const uint16_t PQCLEAN_NEWHOPE1024CPA_CLEAN_gammas_bitrev_montgomery[NEWHOPE_N] = { + 4075, 6974, 7373, 7965, 3262, 5079, 522, 2169, 6364, 1018, 1041, 8775, 2344, 11011, 5574, 1973, + 4536, 1050, 6844, 3860, 3818, 6118, 2683, 1190, 4789, 7822, 7540, 6752, 5456, 4449, 3789, 12142, + 11973, 382, 3988, 468, 6843, 5339, 6196, 3710, 11316, 1254, 5435, 10930, 3998, 10256, 10367, 3879, + 11889, 1728, 6137, 4948, 5862, 6136, 3643, 6874, 8724, 654, 10302, 1702, 7083, 6760, 56, 3199, + 9987, 605, 11785, 8076, 5594, 9260, 6403, 4782, 6212, 4624, 9026, 8689, 4080, 11868, 6221, 3602, + 975, 8077, 8851, 9445, 5681, 3477, 1105, 142, 241, 12231, 1003, 3532, 5009, 1956, 6008, 11404, + 7377, 2049, 10968, 12097, 7591, 5057, 3445, 4780, 2920, 7048, 3127, 8120, 11279, 6821, 11502, 8807, + 12138, 2127, 2839, 3957, 431, 1579, 6383, 9784, 5874, 677, 3336, 6234, 2766, 1323, 9115, 12237, + 2031, 6956, 6413, 2281, 3969, 3991, 12133, 9522, 4737, 10996, 4774, 5429, 11871, 3772, 453, 5908, + 2882, 1805, 2051, 1954, 11713, 3963, 2447, 6142, 8174, 3030, 1843, 2361, 12071, 2908, 3529, 3434, + 3202, 7796, 2057, 5369, 11939, 1512, 6906, 10474, 11026, 49, 10806, 5915, 1489, 9789, 5942, 10706, + 10431, 7535, 426, 8974, 3757, 10314, 9364, 347, 5868, 9551, 9634, 6554, 10596, 9280, 11566, 174, + 2948, 2503, 6507, 10723, 11606, 2459, 64, 3656, 8455, 5257, 5919, 7856, 1747, 9166, 5486, 9235, + 6065, 835, 3570, 4240, 11580, 4046, 10970, 9139, 1058, 8210, 11848, 922, 7967, 1958, 10211, 1112, + 3728, 4049, 11130, 5990, 1404, 325, 948, 11143, 6190, 295, 11637, 5766, 8212, 8273, 2919, 8527, + 6119, 6992, 8333, 1360, 2555, 6167, 1200, 7105, 7991, 3329, 9597, 12121, 5106, 5961, 10695, 10327, + 3051, 9923, 4896, 9326, 81, 3091, 1000, 7969, 4611, 726, 1853, 12149, 4255, 11112, 2768, 10654, + 1062, 2294, 3553, 4805, 2747, 4846, 8577, 9154, 1170, 2319, 790, 11334, 9275, 9088, 1326, 5086, + 9094, 6429, 11077, 10643, 3504, 3542, 8668, 9744, 1479, 1, 8246, 7143, 11567, 10984, 4134, 5736, + 4978, 10938, 5777, 8961, 4591, 5728, 6461, 5023, 9650, 7468, 949, 9664, 2975, 11726, 2744, 9283, + 10092, 5067, 12171, 2476, 3748, 11336, 6522, 827, 9452, 5374, 12159, 7935, 3296, 3949, 9893, 4452, + 10908, 2525, 3584, 8112, 8011, 10616, 4989, 6958, 11809, 9447, 12280, 1022, 11950, 9821, 11745, 5791, + 5092, 2089, 9005, 2881, 3289, 2013, 9048, 729, 7901, 1260, 5755, 4632, 11955, 2426, 10593, 1428, + 4890, 5911, 3932, 9558, 8830, 3637, 5542, 145, 5179, 8595, 3707, 10530, 355, 3382, 4231, 9741, + 1207, 9041, 7012, 1168, 10146, 11224, 4645, 11885, 10911, 10377, 435, 7952, 4096, 493, 9908, 6845, + 6039, 2422, 2187, 9723, 8643, 9852, 9302, 6022, 7278, 1002, 4284, 5088, 1607, 7313, 875, 8509, + 9430, 1045, 2481, 5012, 7428, 354, 6591, 9377, 11847, 2401, 1067, 7188, 11516, 390, 8511, 8456, + 7270, 545, 8585, 9611, 12047, 1537, 4143, 4714, 4885, 1017, 5084, 1632, 3066, 27, 1440, 8526, + 9273, 12046, 11618, 9289, 3400, 9890, 3136, 7098, 8758, 11813, 7384, 3985, 11869, 6730, 10745, 10111, + 2249, 4048, 2884, 11136, 2126, 1630, 9103, 5407, 2686, 9042, 2969, 8311, 9424, 9919, 8779, 5332, + 10626, 1777, 4654, 10863, 7351, 3636, 9585, 5291, 8374, 2166, 4919, 12176, 9140, 12129, 7852, 12286, + 4895, 10805, 2780, 5195, 2305, 7247, 9644, 4053, 10600, 3364, 3271, 4057, 4414, 9442, 7917, 2174, + 3947, 11951, 2455, 6599, 10545, 10975, 3654, 2894, 7681, 7126, 7287, 12269, 4119, 3343, 2151, 1522, + 7174, 7350, 11041, 2442, 2148, 5959, 6492, 8330, 8945, 5598, 3624, 10397, 1325, 6565, 1945, 11260, + 10077, 2674, 3338, 3276, 11034, 506, 6505, 1392, 5478, 8778, 1178, 2776, 3408, 10347, 11124, 2575, + 9489, 12096, 6092, 10058, 4167, 6085, 923, 11251, 11912, 4578, 10669, 11914, 425, 10453, 392, 10104, + 8464, 4235, 8761, 7376, 2291, 3375, 7954, 8896, 6617, 7790, 1737, 11667, 3982, 9342, 6680, 636, + 6825, 7383, 512, 4670, 2900, 12050, 7735, 994, 1687, 11883, 7021, 146, 10485, 1403, 5189, 6094, + 2483, 2054, 3042, 10945, 3981, 10821, 11826, 8882, 8151, 180, 9600, 7684, 5219, 10880, 6780, 204, + 11232, 2600, 7584, 3121, 3017, 11053, 7814, 7043, 4251, 4739, 11063, 6771, 7073, 9261, 2360, 11925, + 1928, 11825, 8024, 3678, 3205, 3359, 11197, 5209, 8581, 3238, 8840, 1136, 9363, 1826, 3171, 4489, + 7885, 346, 2068, 1389, 8257, 3163, 4840, 6127, 8062, 8921, 612, 4238, 10763, 8067, 125, 11749, + 10125, 5416, 2110, 716, 9839, 10584, 11475, 11873, 3448, 343, 1908, 4538, 10423, 7078, 4727, 1208, + 11572, 3589, 2982, 1373, 1721, 10753, 4103, 2429, 4209, 5412, 5993, 9011, 438, 3515, 7228, 1218, + 8347, 5232, 8682, 1327, 7508, 4924, 448, 1014, 10029, 12221, 4566, 5836, 12229, 2717, 1535, 3200, + 5588, 5845, 412, 5102, 7326, 3744, 3056, 2528, 7406, 8314, 9202, 6454, 6613, 1417, 10032, 7784, + 1518, 3765, 4176, 5063, 9828, 2275, 6636, 4267, 6463, 2065, 7725, 3495, 8328, 8755, 8144, 10533, + 5966, 12077, 9175, 9520, 5596, 6302, 8400, 579, 6781, 11014, 5734, 11113, 11164, 4860, 1131, 10844, + 9068, 8016, 9694, 3837, 567, 9348, 7000, 6627, 7699, 5082, 682, 11309, 5207, 4050, 7087, 844, + 7434, 3769, 293, 9057, 6940, 9344, 10883, 2633, 8190, 3944, 5530, 5604, 3480, 2171, 9282, 11024, + 2213, 8136, 3805, 767, 12239, 216, 11520, 6763, 10353, 7, 8566, 845, 7235, 3154, 4360, 3285, + 10268, 2832, 3572, 1282, 7559, 3229, 8360, 10583, 6105, 3120, 6643, 6203, 8536, 8348, 6919, 3536, + 9199, 10891, 11463, 5043, 1658, 5618, 8787, 5789, 4719, 751, 11379, 6389, 10783, 3065, 7806, 6586, + 2622, 5386, 510, 7628, 6921, 578, 10345, 11839, 8929, 4684, 12226, 7154, 9916, 7302, 8481, 3670, + 11066, 2334, 1590, 7878, 10734, 1802, 1891, 5103, 6151, 8820, 3418, 7846, 9951, 4693, 417, 9996, + 9652, 4510, 2946, 5461, 365, 881, 1927, 1015, 11675, 11009, 1371, 12265, 2485, 11385, 5039, 6742, + 8449, 1842, 12217, 8176, 9577, 4834, 7937, 9461, 2643, 11194, 3045, 6508, 4094, 3451, 7911, 11048, + 5406, 4665, 3020, 6616, 11345, 7519, 3669, 5287, 1790, 7014, 5410, 11038, 11249, 2035, 6125, 10407, + 4565, 7315, 5078, 10506, 2840, 2478, 9270, 4194, 9195, 4518, 7469, 1160, 6878, 2730, 10421, 10036, + 1734, 3815, 10939, 5832, 10595, 10759, 4423, 8420, 9617, 7119, 11010, 11424, 9173, 189, 10080, 10526, + 3466, 10588, 7592, 3578, 11511, 7785, 9663, 530, 12150, 8957, 2532, 3317, 9349, 10243, 1481, 9332, + 3454, 3758, 7899, 4218, 2593, 11410, 2276, 982, 6513, 1849, 8494, 9021, 4523, 7988, 8, 457, + 648, 150, 8000, 2307, 2301, 874, 5650, 170, 9462, 2873, 9855, 11498, 2535, 11169, 5808, 12268, + 9687, 1901, 7171, 11787, 3846, 1573, 6063, 3793, 466, 11259, 10608, 3821, 6320, 4649, 6263, 2929 +}; + +/************************************************************ +* Name: gammas_inv_montgomery +* +* Description: Contains inverses of powers of nth root of -1 +* divided by n in Montgomery domain with R=2^18 +************************************************************/ +const uint16_t PQCLEAN_NEWHOPE1024CPA_CLEAN_gammas_inv_montgomery[NEWHOPE_N] = { + 256, 10570, 1510, 7238, 1034, 7170, 6291, 7921, 11665, 3422, 4000, 2327, 2088, 5565, 795, 10647, + 1521, 5484, 2539, 7385, 1055, 7173, 8047, 11683, 1669, 1994, 3796, 5809, 4341, 9398, 11876, 12230, + 10525, 12037, 12253, 3506, 4012, 9351, 4847, 2448, 7372, 9831, 3160, 2207, 5582, 2553, 7387, 6322, + 9681, 1383, 10731, 1533, 219, 5298, 4268, 7632, 6357, 9686, 8406, 4712, 9451, 10128, 4958, 5975, + 11387, 8649, 11769, 6948, 11526, 12180, 1740, 10782, 6807, 2728, 7412, 4570, 4164, 4106, 11120, 12122, + 8754, 11784, 3439, 5758, 11356, 6889, 9762, 11928, 1704, 1999, 10819, 12079, 12259, 7018, 11536, 1648, + 1991, 2040, 2047, 2048, 10826, 12080, 8748, 8272, 8204, 1172, 1923, 7297, 2798, 7422, 6327, 4415, + 7653, 6360, 11442, 12168, 7005, 8023, 9924, 8440, 8228, 2931, 7441, 1063, 3663, 5790, 9605, 10150, + 1450, 8985, 11817, 10466, 10273, 12001, 3470, 7518, 1074, 1909, 7295, 9820, 4914, 702, 5367, 7789, + 8135, 9940, 1420, 3714, 11064, 12114, 12264, 1752, 5517, 9566, 11900, 1700, 3754, 5803, 829, 1874, + 7290, 2797, 10933, 5073, 7747, 8129, 6428, 6185, 11417, 1631, 233, 5300, 9535, 10140, 11982, 8734, + 8270, 2937, 10953, 8587, 8249, 2934, 9197, 4825, 5956, 4362, 9401, 1343, 3703, 529, 10609, 12049, + 6988, 6265, 895, 3639, 4031, 4087, 4095, 585, 10617, 8539, 4731, 4187, 9376, 3095, 9220, 10095, + 10220, 1460, 10742, 12068, 1724, 5513, 11321, 6884, 2739, 5658, 6075, 4379, 11159, 10372, 8504, 4726, + 9453, 3106, 7466, 11600, 10435, 8513, 9994, 8450, 9985, 3182, 10988, 8592, 2983, 9204, 4826, 2445, + 5616, 6069, 867, 3635, 5786, 11360, 5134, 2489, 10889, 12089, 1727, 7269, 2794, 9177, 1311, 5454, + 9557, 6632, 2703, 9164, 10087, 1441, 3717, 531, 3587, 2268, 324, 5313, 759, 1864, 5533, 2546, + 7386, 9833, 8427, 4715, 11207, 1601, 7251, 4547, 11183, 12131, 1733, 10781, 10318, 1474, 10744, 5046, + 4232, 11138, 10369, 6748, 964, 7160, 4534, 7670, 8118, 8182, 4680, 11202, 6867, 981, 8918, 1274, + 182, 26, 7026, 8026, 11680, 12202, 10521, 1503, 7237, 4545, 5916, 9623, 8397, 11733, 10454, 3249, + 9242, 6587, 941, 1890, 270, 10572, 6777, 9746, 6659, 6218, 6155, 6146, 878, 1881, 7291, 11575, + 12187, 1741, 7271, 8061, 11685, 6936, 4502, 9421, 4857, 4205, 7623, 1089, 10689, 1527, 8996, 10063, + 11971, 10488, 6765, 2722, 3900, 9335, 11867, 6962, 11528, 5158, 4248, 4118, 5855, 2592, 5637, 6072, + 2623, 7397, 8079, 9932, 4930, 5971, 853, 3633, 519, 8852, 11798, 3441, 11025, 1575, 225, 8810, + 11792, 12218, 3501, 9278, 3081, 9218, 4828, 7712, 8124, 11694, 12204, 3499, 4011, 573, 3593, 5780, + 7848, 9899, 10192, 1456, 208, 7052, 2763, 7417, 11593, 10434, 12024, 8740, 11782, 10461, 3250, 5731, + 7841, 9898, 1414, 202, 3540, 7528, 2831, 2160, 10842, 5060, 4234, 4116, 588, 84, 12, 7024, + 2759, 9172, 6577, 11473, 1639, 9012, 3043, 7457, 6332, 11438, 1634, 1989, 9062, 11828, 8712, 11778, + 12216, 10523, 6770, 9745, 10170, 4964, 9487, 6622, 946, 8913, 6540, 6201, 4397, 9406, 8366, 9973, + 8447, 8229, 11709, 8695, 10020, 3187, 5722, 2573, 10901, 6824, 4486, 4152, 9371, 8361, 2950, 2177, + 311, 1800, 9035, 8313, 11721, 3430, 490, 70, 10, 1757, 251, 3547, 7529, 11609, 3414, 7510, + 4584, 4166, 9373, 1339, 5458, 7802, 11648, 1664, 7260, 9815, 10180, 6721, 9738, 10169, 8475, 8233, + 9954, 1422, 8981, 1283, 5450, 11312, 1616, 3742, 11068, 10359, 4991, 713, 3613, 9294, 8350, 4704, + 672, 96, 7036, 9783, 11931, 3460, 5761, 823, 10651, 12055, 10500, 1500, 5481, 783, 3623, 11051, + 8601, 8251, 8201, 11705, 10450, 5004, 4226, 7626, 2845, 2162, 3820, 7568, 9859, 3164, 452, 10598, + 1514, 5483, 6050, 6131, 4387, 7649, 8115, 6426, 918, 8909, 8295, 1185, 5436, 11310, 8638, 1234, + 5443, 11311, 5127, 2488, 2111, 10835, 5059, 7745, 2862, 3920, 560, 80, 1767, 2008, 3798, 11076, + 6849, 2734, 10924, 12094, 8750, 1250, 10712, 6797, 971, 7161, 1023, 8924, 4786, 7706, 4612, 4170, + 7618, 6355, 4419, 5898, 11376, 10403, 10264, 6733, 4473, 639, 5358, 2521, 9138, 3061, 5704, 4326, + 618, 5355, 765, 5376, 768, 7132, 4530, 9425, 3102, 9221, 6584, 11474, 10417, 10266, 12000, 6981, + 6264, 4406, 2385, 7363, 4563, 4163, 7617, 9866, 3165, 9230, 11852, 10471, 5007, 5982, 11388, 5138, + 734, 3616, 11050, 12112, 6997, 11533, 12181, 10518, 12036, 3475, 2252, 7344, 9827, 4915, 9480, 6621, + 4457, 7659, 9872, 6677, 4465, 4149, 7615, 4599, 657, 3605, 515, 10607, 6782, 4480, 640, 1847, + 3775, 5806, 2585, 5636, 9583, 1369, 10729, 8555, 10000, 11962, 5220, 7768, 8132, 8184, 9947, 1421, + 203, 29, 8782, 11788, 1684, 10774, 10317, 4985, 9490, 8378, 4708, 11206, 5112, 5997, 7879, 11659, + 12199, 8765, 10030, 4944, 5973, 6120, 6141, 6144, 7900, 11662, 1666, 238, 34, 3516, 5769, 9602, + 8394, 9977, 6692, 956, 10670, 6791, 9748, 11926, 8726, 11780, 5194, 742, 106, 8793, 10034, 3189, + 10989, 5081, 4237, 5872, 4350, 2377, 10873, 6820, 6241, 11425, 10410, 10265, 3222, 5727, 9596, 4882, + 2453, 2106, 3812, 11078, 12116, 5242, 4260, 11142, 8614, 11764, 12214, 5256, 4262, 4120, 11122, 5100, + 11262, 5120, 2487, 5622, 9581, 8391, 8221, 2930, 10952, 12098, 6995, 6266, 9673, 4893, 699, 3611, + 4027, 5842, 11368, 1624, 232, 8811, 8281, 1183, 169, 8802, 3013, 2186, 5579, 797, 3625, 4029, + 11109, 1587, 7249, 11569, 8675, 6506, 2685, 10917, 12093, 12261, 12285, 1755, 7273, 1039, 1904, 272, + 3550, 9285, 3082, 5707, 6082, 4380, 7648, 11626, 5172, 4250, 9385, 8363, 8217, 4685, 5936, 848, + 8899, 6538, 934, 1889, 3781, 9318, 10109, 10222, 6727, 961, 5404, 772, 5377, 9546, 8386, 1198, + 8949, 3034, 2189, 7335, 4559, 5918, 2601, 10905, 5069, 9502, 3113, 7467, 8089, 11689, 5181, 9518, + 8382, 2953, 3933, 4073, 4093, 7607, 8109, 2914, 5683, 4323, 11151, 1593, 10761, 6804, 972, 3650, + 2277, 5592, 4310, 7638, 9869, 4921, 703, 1856, 9043, 4803, 9464, 1352, 8971, 11815, 5199, 7765, + 6376, 4422, 7654, 2849, 407, 8836, 6529, 7955, 2892, 9191, 1313, 10721, 12065, 12257, 1751, 9028, + 8312, 2943, 2176, 3822, 546, 78, 8789, 11789, 10462, 12028, 6985, 4509, 9422, 1346, 5459, 4291, + 613, 10621, 6784, 9747, 3148, 7472, 2823, 5670, 810, 7138, 8042, 4660, 7688, 6365, 6176, 6149, + 2634, 5643, 9584, 10147, 11983, 5223, 9524, 11894, 10477, 8519, 1217, 3685, 2282, 326, 10580, 3267, + 7489, 4581, 2410, 5611, 11335, 6886, 8006, 8166, 11700, 3427, 11023, 8597, 10006, 3185, 455, 65, + 5276, 7776, 4622, 5927, 7869, 9902, 11948, 5218, 2501, 5624, 2559, 10899, 1557, 1978, 10816, 10323, + 8497, 4725, 675, 1852, 10798, 12076, 10503, 3256, 9243, 3076, 2195, 10847, 12083, 10504, 12034, 10497 +}; + diff --git a/crypto_kem/newhope1024cpa/clean/reduce.c b/crypto_kem/newhope1024cpa/clean/reduce.c new file mode 100644 index 00000000..f975bf92 --- /dev/null +++ b/crypto_kem/newhope1024cpa/clean/reduce.c @@ -0,0 +1,26 @@ +#include "reduce.h" +#include "params.h" + +static const uint32_t qinv = 12287; // -inverse_mod(p,2^18) +static const uint32_t rlog = 18; + +/************************************************* +* Name: verify +* +* Description: Montgomery reduction; given a 32-bit integer a, computes +* 16-bit integer congruent to a * R^-1 mod q, +* where R=2^18 (see value of rlog) +* +* Arguments: - uint32_t a: input unsigned integer to be reduced; has to be in {0,...,1073491968} +* +* Returns: unsigned integer in {0,...,2^14-1} congruent to a * R^-1 modulo q. +**************************************************/ +uint16_t PQCLEAN_NEWHOPE1024CPA_CLEAN_montgomery_reduce(uint32_t a) { + uint32_t u; + + u = (a * qinv); + u &= ((1 << rlog) - 1); + u *= NEWHOPE_Q; + a = a + u; + return a >> 18; +} diff --git a/crypto_kem/newhope1024cpa/clean/reduce.h b/crypto_kem/newhope1024cpa/clean/reduce.h new file mode 100644 index 00000000..724e20fe --- /dev/null +++ b/crypto_kem/newhope1024cpa/clean/reduce.h @@ -0,0 +1,8 @@ +#ifndef REDUCE_H +#define REDUCE_H + +#include + +uint16_t PQCLEAN_NEWHOPE1024CPA_CLEAN_montgomery_reduce(uint32_t a); + +#endif diff --git a/crypto_kem/newhope1024cpa/clean/verify.c b/crypto_kem/newhope1024cpa/clean/verify.c new file mode 100644 index 00000000..53276b93 --- /dev/null +++ b/crypto_kem/newhope1024cpa/clean/verify.c @@ -0,0 +1,49 @@ +#include "verify.h" +#include +#include + +/************************************************* +* Name: verify +* +* Description: Compare two arrays for equality in constant time. +* +* Arguments: const unsigned char *a: pointer to first byte array +* const unsigned char *b: pointer to second byte array +* size_t len: length of the byte arrays +* +* Returns 0 if the byte arrays are equal, 1 otherwise +**************************************************/ +int PQCLEAN_NEWHOPE1024CPA_CLEAN_verify(const unsigned char *a, const unsigned char *b, size_t len) { + uint64_t r; + size_t i; + r = 0; + + for (i = 0; i < len; i++) { + r |= a[i] ^ b[i]; + } + + r = (-(int64_t)r) >> 63; + return (int)r; +} + +/************************************************* +* Name: cmov +* +* Description: Copy len bytes from x to r if b is 1; +* don't modify x if b is 0. Requires b to be in {0,1}; +* assumes two's complement representation of negative integers. +* Runs in constant time. +* +* Arguments: unsigned char *r: pointer to output byte array +* const unsigned char *x: pointer to input byte array +* size_t len: Amount of bytes to be copied +* unsigned char b: Condition bit; has to be in {0,1} +**************************************************/ +void PQCLEAN_NEWHOPE1024CPA_CLEAN_cmov(unsigned char *r, const unsigned char *x, size_t len, unsigned char b) { + size_t i; + + b = -b; + for (i = 0; i < len; i++) { + r[i] ^= b & (x[i] ^ r[i]); + } +} diff --git a/crypto_kem/newhope1024cpa/clean/verify.h b/crypto_kem/newhope1024cpa/clean/verify.h new file mode 100644 index 00000000..9cdd0e95 --- /dev/null +++ b/crypto_kem/newhope1024cpa/clean/verify.h @@ -0,0 +1,12 @@ +#ifndef VERIFY_H +#define VERIFY_H + +#include + +/* returns 0 for equal strings, 1 for non-equal strings */ +int PQCLEAN_NEWHOPE1024CPA_CLEAN_verify(const unsigned char *a, const unsigned char *b, size_t len); + +/* b = 1 means mov, b = 0 means don't mov*/ +void PQCLEAN_NEWHOPE1024CPA_CLEAN_cmov(unsigned char *r, const unsigned char *x, size_t len, unsigned char b); + +#endif diff --git a/crypto_kem/newhope512cca/META.yml b/crypto_kem/newhope512cca/META.yml new file mode 100644 index 00000000..721dfa78 --- /dev/null +++ b/crypto_kem/newhope512cca/META.yml @@ -0,0 +1,21 @@ +name: NewHope512CCA +type: kem +claimed-nist-level: 1 +claimed-security: IND-CCA2 +length-public-key: 928 +length-secret-key: 1888 +length-ciphertext: 1120 +length-shared-secret: 32 +nistkat-sha256: 5b0389f8d9c30055ad0fb83da540ca36969dde041bebe6f1018c37768c5e1479 +principal-submitter: Thomas Pöppelmann +auxiliary-submitters: +- Erdem Alkim +- Roberto Avanzi +- Joppe Bos +- Léo Ducas +- Antonio de la Piedra +- Peter Schwabe +- Douglas Stebila +implementations: +- name: clean + version: https://github.com/newhopecrypto/newhope/commit/3fc68c6090b23c56cc190a78af2f43ee8900e9d0 diff --git a/crypto_kem/newhope512cca/clean/LICENSE b/crypto_kem/newhope512cca/clean/LICENSE new file mode 100644 index 00000000..d5d21fff --- /dev/null +++ b/crypto_kem/newhope512cca/clean/LICENSE @@ -0,0 +1 @@ +Public Domain diff --git a/crypto_kem/newhope512cca/clean/Makefile b/crypto_kem/newhope512cca/clean/Makefile new file mode 100644 index 00000000..73a193d0 --- /dev/null +++ b/crypto_kem/newhope512cca/clean/Makefile @@ -0,0 +1,19 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libnewhope512cca_clean.a +HEADERS=api.h cpapke.h ntt.h params.h poly.h reduce.h verify.h +OBJECTS=cpapke.o kem.o ntt.o poly.o precomp.o reduce.o verify.o + +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Wvla -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/newhope512cca/clean/Makefile.Microsoft_nmake b/crypto_kem/newhope512cca/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..321e4e6a --- /dev/null +++ b/crypto_kem/newhope512cca/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=libnewhope512cca_clean.lib +OBJECTS=cpapke.obj kem.obj ntt.obj poly.obj precomp.obj reduce.obj verify.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/newhope512cca/clean/api.h b/crypto_kem/newhope512cca/clean/api.h new file mode 100644 index 00000000..6526df97 --- /dev/null +++ b/crypto_kem/newhope512cca/clean/api.h @@ -0,0 +1,15 @@ +#ifndef PQCLEAN_NEWHOPE512CCA_CLEAN_API_H +#define PQCLEAN_NEWHOPE512CCA_CLEAN_API_H + + +#define PQCLEAN_NEWHOPE512CCA_CLEAN_CRYPTO_SECRETKEYBYTES 1888 +#define PQCLEAN_NEWHOPE512CCA_CLEAN_CRYPTO_PUBLICKEYBYTES 928 +#define PQCLEAN_NEWHOPE512CCA_CLEAN_CRYPTO_CIPHERTEXTBYTES 1120 +#define PQCLEAN_NEWHOPE512CCA_CLEAN_CRYPTO_BYTES 32 +#define PQCLEAN_NEWHOPE512CCA_CLEAN_CRYPTO_ALGNAME "NewHope512-CCAKEM" + +int PQCLEAN_NEWHOPE512CCA_CLEAN_crypto_kem_keypair(unsigned char *pk, unsigned char *sk); +int PQCLEAN_NEWHOPE512CCA_CLEAN_crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk); +int PQCLEAN_NEWHOPE512CCA_CLEAN_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk); + +#endif diff --git a/crypto_kem/newhope512cca/clean/cpapke.c b/crypto_kem/newhope512cca/clean/cpapke.c new file mode 100644 index 00000000..f965a213 --- /dev/null +++ b/crypto_kem/newhope512cca/clean/cpapke.c @@ -0,0 +1,192 @@ +#include "api.h" +#include "cpapke.h" +#include "fips202.h" +#include "poly.h" +#include "randombytes.h" +#include + +/************************************************* +* Name: encode_pk +* +* Description: Serialize the public key as concatenation of the +* serialization of the polynomial pk and the public seed +* used to generete the polynomial a. +* +* Arguments: unsigned char *r: pointer to the output serialized public key +* const poly *pk: pointer to the input public-key polynomial +* const unsigned char *seed: pointer to the input public seed +**************************************************/ +static void encode_pk(unsigned char *r, const poly *pk, const unsigned char *seed) { + int i; + PQCLEAN_NEWHOPE512CCA_CLEAN_poly_tobytes(r, pk); + for (i = 0; i < NEWHOPE_SYMBYTES; i++) { + r[NEWHOPE_POLYBYTES + i] = seed[i]; + } +} + +/************************************************* +* Name: decode_pk +* +* Description: De-serialize the public key; inverse of encode_pk +* +* Arguments: poly *pk: pointer to output public-key polynomial +* unsigned char *seed: pointer to output public seed +* const unsigned char *r: pointer to input byte array +**************************************************/ +static void decode_pk(poly *pk, unsigned char *seed, const unsigned char *r) { + int i; + PQCLEAN_NEWHOPE512CCA_CLEAN_poly_frombytes(pk, r); + for (i = 0; i < NEWHOPE_SYMBYTES; i++) { + seed[i] = r[NEWHOPE_POLYBYTES + i]; + } +} + +/************************************************* +* Name: encode_c +* +* Description: Serialize the ciphertext as concatenation of the +* serialization of the polynomial b and serialization +* of the compressed polynomial v +* +* Arguments: - unsigned char *r: pointer to the output serialized ciphertext +* - const poly *b: pointer to the input polynomial b +* - const poly *v: pointer to the input polynomial v +**************************************************/ +static void encode_c(unsigned char *r, const poly *b, const poly *v) { + PQCLEAN_NEWHOPE512CCA_CLEAN_poly_tobytes(r, b); + PQCLEAN_NEWHOPE512CCA_CLEAN_poly_compress(r + NEWHOPE_POLYBYTES, v); +} + +/************************************************* +* Name: decode_c +* +* Description: de-serialize the ciphertext; inverse of encode_c +* +* Arguments: - poly *b: pointer to output polynomial b +* - poly *v: pointer to output polynomial v +* - const unsigned char *r: pointer to input byte array +**************************************************/ +static void decode_c(poly *b, poly *v, const unsigned char *r) { + PQCLEAN_NEWHOPE512CCA_CLEAN_poly_frombytes(b, r); + PQCLEAN_NEWHOPE512CCA_CLEAN_poly_decompress(v, r + NEWHOPE_POLYBYTES); +} + +/************************************************* +* Name: gen_a +* +* Description: Deterministically generate public polynomial a from seed +* +* Arguments: - poly *a: pointer to output polynomial a +* - const unsigned char *seed: pointer to input seed +**************************************************/ +static void gen_a(poly *a, const unsigned char *seed) { + PQCLEAN_NEWHOPE512CCA_CLEAN_poly_uniform(a, seed); +} + + +/************************************************* +* Name: cpapke_keypair +* +* Description: Generates public and private key +* for the CPA public-key encryption scheme underlying +* the NewHope KEMs +* +* Arguments: - unsigned char *pk: pointer to output public key +* - unsigned char *sk: pointer to output private key +**************************************************/ +void PQCLEAN_NEWHOPE512CCA_CLEAN_cpapke_keypair(unsigned char *pk, + unsigned char *sk) { + poly ahat, ehat, ahat_shat, bhat, shat; + unsigned char z[2 * NEWHOPE_SYMBYTES]; + unsigned char *publicseed = z; + unsigned char *noiseseed = z + NEWHOPE_SYMBYTES; + + randombytes(z, NEWHOPE_SYMBYTES); + shake256(z, 2 * NEWHOPE_SYMBYTES, z, NEWHOPE_SYMBYTES); + + gen_a(&ahat, publicseed); + + PQCLEAN_NEWHOPE512CCA_CLEAN_poly_sample(&shat, noiseseed, 0); + PQCLEAN_NEWHOPE512CCA_CLEAN_poly_ntt(&shat); + + PQCLEAN_NEWHOPE512CCA_CLEAN_poly_sample(&ehat, noiseseed, 1); + PQCLEAN_NEWHOPE512CCA_CLEAN_poly_ntt(&ehat); + + PQCLEAN_NEWHOPE512CCA_CLEAN_poly_mul_pointwise(&ahat_shat, &shat, &ahat); + PQCLEAN_NEWHOPE512CCA_CLEAN_poly_add(&bhat, &ehat, &ahat_shat); + + PQCLEAN_NEWHOPE512CCA_CLEAN_poly_tobytes(sk, &shat); + encode_pk(pk, &bhat, publicseed); +} + +/************************************************* +* Name: cpapke_enc +* +* Description: Encryption function of +* the CPA public-key encryption scheme underlying +* the NewHope KEMs +* +* Arguments: - unsigned char *c: pointer to output ciphertext +* - const unsigned char *m: pointer to input message (of length NEWHOPE_SYMBYTES bytes) +* - const unsigned char *pk: pointer to input public key +* - const unsigned char *coin: pointer to input random coins used as seed +* to deterministically generate all randomness +**************************************************/ +void PQCLEAN_NEWHOPE512CCA_CLEAN_cpapke_enc(unsigned char *c, + const unsigned char *m, + const unsigned char *pk, + const unsigned char *coin) { + poly sprime, eprime, vprime, ahat, bhat, eprimeprime, uhat, v; + unsigned char publicseed[NEWHOPE_SYMBYTES]; + + PQCLEAN_NEWHOPE512CCA_CLEAN_poly_frommsg(&v, m); + + decode_pk(&bhat, publicseed, pk); + gen_a(&ahat, publicseed); + + PQCLEAN_NEWHOPE512CCA_CLEAN_poly_sample(&sprime, coin, 0); + PQCLEAN_NEWHOPE512CCA_CLEAN_poly_sample(&eprime, coin, 1); + PQCLEAN_NEWHOPE512CCA_CLEAN_poly_sample(&eprimeprime, coin, 2); + + PQCLEAN_NEWHOPE512CCA_CLEAN_poly_ntt(&sprime); + PQCLEAN_NEWHOPE512CCA_CLEAN_poly_ntt(&eprime); + + PQCLEAN_NEWHOPE512CCA_CLEAN_poly_mul_pointwise(&uhat, &ahat, &sprime); + PQCLEAN_NEWHOPE512CCA_CLEAN_poly_add(&uhat, &uhat, &eprime); + + PQCLEAN_NEWHOPE512CCA_CLEAN_poly_mul_pointwise(&vprime, &bhat, &sprime); + PQCLEAN_NEWHOPE512CCA_CLEAN_poly_invntt(&vprime); + + PQCLEAN_NEWHOPE512CCA_CLEAN_poly_add(&vprime, &vprime, &eprimeprime); + PQCLEAN_NEWHOPE512CCA_CLEAN_poly_add(&vprime, &vprime, &v); // add message + + encode_c(c, &uhat, &vprime); +} + + +/************************************************* +* Name: cpapke_dec +* +* Description: Decryption function of +* the CPA public-key encryption scheme underlying +* the NewHope KEMs +* +* Arguments: - unsigned char *m: pointer to output decrypted message +* - const unsigned char *c: pointer to input ciphertext +* - const unsigned char *sk: pointer to input secret key +**************************************************/ +void PQCLEAN_NEWHOPE512CCA_CLEAN_cpapke_dec(unsigned char *m, + const unsigned char *c, + const unsigned char *sk) { + poly vprime, uhat, tmp, shat; + + PQCLEAN_NEWHOPE512CCA_CLEAN_poly_frombytes(&shat, sk); + + decode_c(&uhat, &vprime, c); + PQCLEAN_NEWHOPE512CCA_CLEAN_poly_mul_pointwise(&tmp, &shat, &uhat); + PQCLEAN_NEWHOPE512CCA_CLEAN_poly_invntt(&tmp); + + PQCLEAN_NEWHOPE512CCA_CLEAN_poly_sub(&tmp, &tmp, &vprime); + + PQCLEAN_NEWHOPE512CCA_CLEAN_poly_tomsg(m, &tmp); +} diff --git a/crypto_kem/newhope512cca/clean/cpapke.h b/crypto_kem/newhope512cca/clean/cpapke.h new file mode 100644 index 00000000..4b99524b --- /dev/null +++ b/crypto_kem/newhope512cca/clean/cpapke.h @@ -0,0 +1,16 @@ +#ifndef INDCPA_H +#define INDCPA_H + +void PQCLEAN_NEWHOPE512CCA_CLEAN_cpapke_keypair(unsigned char *pk, + unsigned char *sk); + +void PQCLEAN_NEWHOPE512CCA_CLEAN_cpapke_enc(unsigned char *c, + const unsigned char *m, + const unsigned char *pk, + const unsigned char *coins); + +void PQCLEAN_NEWHOPE512CCA_CLEAN_cpapke_dec(unsigned char *m, + const unsigned char *c, + const unsigned char *sk); + +#endif diff --git a/crypto_kem/newhope512cca/clean/kem.c b/crypto_kem/newhope512cca/clean/kem.c new file mode 100644 index 00000000..a9d5da8c --- /dev/null +++ b/crypto_kem/newhope512cca/clean/kem.c @@ -0,0 +1,116 @@ +#include "api.h" +#include "cpapke.h" +#include "fips202.h" +#include "params.h" +#include "randombytes.h" +#include "verify.h" + +#include + +/************************************************* +* Name: crypto_kem_keypair +* +* Description: Generates public and private key +* for CCA secure NewHope key encapsulation +* mechanism +* +* Arguments: - unsigned char *pk: pointer to output public key (an already allocated array of CRYPTO_PUBLICKEYBYTES bytes) +* - unsigned char *sk: pointer to output private key (an already allocated array of CRYPTO_SECRETKEYBYTES bytes) +* +* Returns 0 (success) +**************************************************/ +int PQCLEAN_NEWHOPE512CCA_CLEAN_crypto_kem_keypair(unsigned char *pk, unsigned char *sk) { + size_t i; + + PQCLEAN_NEWHOPE512CCA_CLEAN_cpapke_keypair(pk, sk); /* First put the actual secret key into sk */ + sk += NEWHOPE_CPAPKE_SECRETKEYBYTES; + + for (i = 0; i < NEWHOPE_CPAPKE_PUBLICKEYBYTES; i++) { /* Append the public key for re-encryption */ + sk[i] = pk[i]; + } + sk += NEWHOPE_CPAPKE_PUBLICKEYBYTES; + + shake256(sk, NEWHOPE_SYMBYTES, pk, NEWHOPE_CPAPKE_PUBLICKEYBYTES); /* Append the hash of the public key */ + sk += NEWHOPE_SYMBYTES; + + randombytes(sk, NEWHOPE_SYMBYTES); /* Append the value s for pseudo-random output on reject */ + + return 0; +} + +/************************************************* +* Name: crypto_kem_enc +* +* Description: Generates cipher text and shared +* secret for given public key +* +* Arguments: - unsigned char *ct: pointer to output cipher text (an already allocated array of CRYPTO_CIPHERTEXTBYTES bytes) +* - unsigned char *ss: pointer to output shared secret (an already allocated array of CRYPTO_BYTES bytes) +* - const unsigned char *pk: pointer to input public key (an already allocated array of CRYPTO_PUBLICKEYBYTES bytes) +* +* Returns 0 (success) +**************************************************/ +int PQCLEAN_NEWHOPE512CCA_CLEAN_crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk) { + unsigned char k_coins_d[3 * NEWHOPE_SYMBYTES]; /* Will contain key, coins, qrom-hash */ + unsigned char buf[2 * NEWHOPE_SYMBYTES]; + int i; + + randombytes(buf, NEWHOPE_SYMBYTES); + + shake256(buf, NEWHOPE_SYMBYTES, buf, NEWHOPE_SYMBYTES); /* Don't release system RNG output */ + shake256(buf + NEWHOPE_SYMBYTES, NEWHOPE_SYMBYTES, pk, NEWHOPE_CCAKEM_PUBLICKEYBYTES); /* Multitarget countermeasure for coins + contributory KEM */ + shake256(k_coins_d, 3 * NEWHOPE_SYMBYTES, buf, 2 * NEWHOPE_SYMBYTES); + + PQCLEAN_NEWHOPE512CCA_CLEAN_cpapke_enc(ct, buf, pk, k_coins_d + NEWHOPE_SYMBYTES); /* coins are in k_coins_d+NEWHOPE_SYMBYTES */ + + for (i = 0; i < NEWHOPE_SYMBYTES; i++) { + ct[i + NEWHOPE_CPAPKE_CIPHERTEXTBYTES] = k_coins_d[i + 2 * NEWHOPE_SYMBYTES]; /* copy Targhi-Unruh hash into ct */ + } + + shake256(k_coins_d + NEWHOPE_SYMBYTES, NEWHOPE_SYMBYTES, ct, NEWHOPE_CCAKEM_CIPHERTEXTBYTES); /* overwrite coins in k_coins_d with h(c) */ + shake256(ss, NEWHOPE_SYMBYTES, k_coins_d, 2 * NEWHOPE_SYMBYTES); /* hash concatenation of pre-k and h(c) to ss */ + return 0; +} + +/************************************************* +* Name: crypto_kem_dec +* +* Description: Generates shared secret for given +* cipher text and private key +* +* Arguments: - unsigned char *ss: pointer to output shared secret (an already allocated array of CRYPTO_BYTES bytes) +* - const unsigned char *ct: pointer to input cipher text (an already allocated array of CRYPTO_CIPHERTEXTBYTES bytes) +* - const unsigned char *sk: pointer to input private key (an already allocated array of CRYPTO_SECRETKEYBYTES bytes) +* +* Returns 0 for sucess or -1 for failure +* +* On failure, ss will contain a randomized value. +**************************************************/ +int PQCLEAN_NEWHOPE512CCA_CLEAN_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk) { + int i, fail; + unsigned char ct_cmp[NEWHOPE_CCAKEM_CIPHERTEXTBYTES]; + unsigned char buf[2 * NEWHOPE_SYMBYTES]; + unsigned char k_coins_d[3 * NEWHOPE_SYMBYTES]; /* Will contain key, coins, qrom-hash */ + const unsigned char *pk = sk + NEWHOPE_CPAPKE_SECRETKEYBYTES; + + PQCLEAN_NEWHOPE512CCA_CLEAN_cpapke_dec(buf, ct, sk); + + for (i = 0; i < NEWHOPE_SYMBYTES; i++) { /* Use hash of pk stored in sk */ + buf[NEWHOPE_SYMBYTES + i] = sk[NEWHOPE_CCAKEM_SECRETKEYBYTES - 2 * NEWHOPE_SYMBYTES + i]; + } + shake256(k_coins_d, 3 * NEWHOPE_SYMBYTES, buf, 2 * NEWHOPE_SYMBYTES); + + PQCLEAN_NEWHOPE512CCA_CLEAN_cpapke_enc(ct_cmp, buf, pk, k_coins_d + NEWHOPE_SYMBYTES); /* coins are in k_coins_d+NEWHOPE_SYMBYTES */ + + for (i = 0; i < NEWHOPE_SYMBYTES; i++) { + ct_cmp[i + NEWHOPE_CPAPKE_CIPHERTEXTBYTES] = k_coins_d[i + 2 * NEWHOPE_SYMBYTES]; + } + + fail = PQCLEAN_NEWHOPE512CCA_CLEAN_verify(ct, ct_cmp, NEWHOPE_CCAKEM_CIPHERTEXTBYTES); + + shake256(k_coins_d + NEWHOPE_SYMBYTES, NEWHOPE_SYMBYTES, ct, NEWHOPE_CCAKEM_CIPHERTEXTBYTES); /* overwrite coins in k_coins_d with h(c) */ + PQCLEAN_NEWHOPE512CCA_CLEAN_cmov(k_coins_d, sk + NEWHOPE_CCAKEM_SECRETKEYBYTES - NEWHOPE_SYMBYTES, NEWHOPE_SYMBYTES, (unsigned char) fail); /* Overwrite pre-k with z on re-encryption failure */ + shake256(ss, NEWHOPE_SYMBYTES, k_coins_d, 2 * NEWHOPE_SYMBYTES); /* hash concatenation of pre-k and h(c) to k */ + + return 0; +} diff --git a/crypto_kem/newhope512cca/clean/ntt.c b/crypto_kem/newhope512cca/clean/ntt.c new file mode 100644 index 00000000..17cad0a0 --- /dev/null +++ b/crypto_kem/newhope512cca/clean/ntt.c @@ -0,0 +1,112 @@ +#include "inttypes.h" +#include "ntt.h" +#include "params.h" +#include "reduce.h" + +/************************************************************ +* Name: bitrev_table +* +* Description: Contains bit-reversed 9-bit indices to be used to re-order +* polynomials before number theoratic transform +************************************************************/ +static uint16_t bitrev_table [512] = { + 0, 256, 128, 384, 64, 320, 192, 448, 32, 288, 160, 416, 96, 352, 224, 480, 16, 272, 144, 400, 80, 336, 208, 464, 48, 304, 176, 432, 112, 368, 240, 496, 8, + 264, 136, 392, 72, 328, 200, 456, 40, 296, 168, 424, 104, 360, 232, 488, 24, 280, 152, 408, 88, 344, 216, 472, 56, 312, 184, 440, 120, 376, 248, 504, 4, + 260, 132, 388, 68, 324, 196, 452, 36, 292, 164, 420, 100, 356, 228, 484, 20, 276, 148, 404, 84, 340, 212, 468, 52, 308, 180, 436, 116, 372, 244, 500, 12, + 268, 140, 396, 76, 332, 204, 460, 44, 300, 172, 428, 108, 364, 236, 492, 28, 284, 156, 412, 92, 348, 220, 476, 60, 316, 188, 444, 124, 380, 252, 508, 2, + 258, 130, 386, 66, 322, 194, 450, 34, 290, 162, 418, 98, 354, 226, 482, 18, 274, 146, 402, 82, 338, 210, 466, 50, 306, 178, 434, 114, 370, 242, 498, 10, + 266, 138, 394, 74, 330, 202, 458, 42, 298, 170, 426, 106, 362, 234, 490, 26, 282, 154, 410, 90, 346, 218, 474, 58, 314, 186, 442, 122, 378, 250, 506, 6, + 262, 134, 390, 70, 326, 198, 454, 38, 294, 166, 422, 102, 358, 230, 486, 22, 278, 150, 406, 86, 342, 214, 470, 54, 310, 182, 438, 118, 374, 246, 502, 14, + 270, 142, 398, 78, 334, 206, 462, 46, 302, 174, 430, 110, 366, 238, 494, 30, 286, 158, 414, 94, 350, 222, 478, 62, 318, 190, 446, 126, 382, 254, 510, 1, + 257, 129, 385, 65, 321, 193, 449, 33, 289, 161, 417, 97, 353, 225, 481, 17, 273, 145, 401, 81, 337, 209, 465, 49, 305, 177, 433, 113, 369, 241, 497, 9, + 265, 137, 393, 73, 329, 201, 457, 41, 297, 169, 425, 105, 361, 233, 489, 25, 281, 153, 409, 89, 345, 217, 473, 57, 313, 185, 441, 121, 377, 249, 505, 5, + 261, 133, 389, 69, 325, 197, 453, 37, 293, 165, 421, 101, 357, 229, 485, 21, 277, 149, 405, 85, 341, 213, 469, 53, 309, 181, 437, 117, 373, 245, 501, 13, + 269, 141, 397, 77, 333, 205, 461, 45, 301, 173, 429, 109, 365, 237, 493, 29, 285, 157, 413, 93, 349, 221, 477, 61, 317, 189, 445, 125, 381, 253, 509, 3, + 259, 131, 387, 67, 323, 195, 451, 35, 291, 163, 419, 99, 355, 227, 483, 19, 275, 147, 403, 83, 339, 211, 467, 51, 307, 179, 435, 115, 371, 243, 499, 11, + 267, 139, 395, 75, 331, 203, 459, 43, 299, 171, 427, 107, 363, 235, 491, 27, 283, 155, 411, 91, 347, 219, 475, 59, 315, 187, 443, 123, 379, 251, 507, 7, + 263, 135, 391, 71, 327, 199, 455, 39, 295, 167, 423, 103, 359, 231, 487, 23, 279, 151, 407, 87, 343, 215, 471, 55, 311, 183, 439, 119, 375, 247, 503, 15, + 271, 143, 399, 79, 335, 207, 463, 47, 303, 175, 431, 111, 367, 239, 495, 31, 287, 159, 415, 95, 351, 223, 479, 63, 319, 191, 447, 127, 383, 255, 511 +}; + +/************************************************* +* Name: bitrev_vector +* +* Description: Permutes coefficients of a polynomial into bitreversed order +* +* Arguments: - uint16_t* poly: pointer to in/output polynomial +**************************************************/ +void PQCLEAN_NEWHOPE512CCA_CLEAN_bitrev_vector(uint16_t *poly) { + unsigned int i, r; + uint16_t tmp; + + for (i = 0; i < NEWHOPE_N; i++) { + r = bitrev_table[i]; + if (i < r) { + tmp = poly[i]; + poly[i] = poly[r]; + poly[r] = tmp; + } + } +} + +/************************************************* +* Name: mul_coefficients +* +* Description: Performs pointwise (coefficient-wise) multiplication +* of two polynomials +* Arguments: - uint16_t* poly: pointer to in/output polynomial +* - const uint16_t* factors: pointer to input polynomial, coefficients +* are assumed to be in Montgomery representation +**************************************************/ +void PQCLEAN_NEWHOPE512CCA_CLEAN_mul_coefficients(uint16_t *poly, const uint16_t *factors) { + unsigned int i; + + for (i = 0; i < NEWHOPE_N; i++) { + poly[i] = PQCLEAN_NEWHOPE512CCA_CLEAN_montgomery_reduce((poly[i] * factors[i])); + } +} + + +/************************************************* +* Name: ntt +* +* Description: Computes number-theoretic transform (NTT) of +* a polynomial in place; inputs assumed to be in +* bitreversed order, output in normal order +* +* Arguments: - uint16_t * a: pointer to in/output polynomial +* - const uint16_t* omega: pointer to input powers of root of unity omega; +* assumed to be in Montgomery domain +**************************************************/ +void PQCLEAN_NEWHOPE512CCA_CLEAN_ntt(uint16_t *a, const uint16_t *omega) { + int i, start, j, jTwiddle, distance; + uint16_t temp, W; + + + for (i = 0; i < 9; i += 2) { + // Even level + distance = (1 << i); + for (start = 0; start < distance; start++) { + jTwiddle = 0; + for (j = start; j < NEWHOPE_N - 1; j += 2 * distance) { + W = omega[jTwiddle++]; + temp = a[j]; + a[j] = (temp + a[j + distance]); // Omit reduction (be lazy) + a[j + distance] = PQCLEAN_NEWHOPE512CCA_CLEAN_montgomery_reduce((W * ((uint32_t)temp + 3 * NEWHOPE_Q - a[j + distance]))); + } + } + if (i + 1 < 9) { + // Odd level + distance <<= 1; + for (start = 0; start < distance; start++) { + jTwiddle = 0; + for (j = start; j < NEWHOPE_N - 1; j += 2 * distance) { + W = omega[jTwiddle++]; + temp = a[j]; + a[j] = (temp + a[j + distance]) % NEWHOPE_Q; + a[j + distance] = PQCLEAN_NEWHOPE512CCA_CLEAN_montgomery_reduce((W * ((uint32_t)temp + 3 * NEWHOPE_Q - a[j + distance]))); + } + } + } + } +} diff --git a/crypto_kem/newhope512cca/clean/ntt.h b/crypto_kem/newhope512cca/clean/ntt.h new file mode 100644 index 00000000..ecc7b993 --- /dev/null +++ b/crypto_kem/newhope512cca/clean/ntt.h @@ -0,0 +1,14 @@ +#ifndef NTT_H +#define NTT_H + +#include "inttypes.h" + +extern const uint16_t PQCLEAN_NEWHOPE512CCA_CLEAN_omegas_inv_bitrev_montgomery[]; +extern const uint16_t PQCLEAN_NEWHOPE512CCA_CLEAN_gammas_bitrev_montgomery[]; +extern const uint16_t PQCLEAN_NEWHOPE512CCA_CLEAN_gammas_inv_montgomery[]; + +void PQCLEAN_NEWHOPE512CCA_CLEAN_bitrev_vector(uint16_t *poly); +void PQCLEAN_NEWHOPE512CCA_CLEAN_mul_coefficients(uint16_t *poly, const uint16_t *factors); +void PQCLEAN_NEWHOPE512CCA_CLEAN_ntt(uint16_t *a, const uint16_t *omegas); + +#endif diff --git a/crypto_kem/newhope512cca/clean/params.h b/crypto_kem/newhope512cca/clean/params.h new file mode 100644 index 00000000..6526ba90 --- /dev/null +++ b/crypto_kem/newhope512cca/clean/params.h @@ -0,0 +1,25 @@ +#ifndef PQCLEAN_NEWHOPE512CCA_CLEAN_PARAMS_H +#define PQCLEAN_NEWHOPE512CCA_CLEAN_PARAMS_H + +#define NEWHOPE_N 512 +#define NEWHOPE_Q 12289 +#define NEWHOPE_K 8 /* used in noise sampling */ + +#define NEWHOPE_SYMBYTES 32 /* size of shared key, seeds/coins, and hashes */ + +#define NEWHOPE_POLYBYTES ((14*NEWHOPE_N)/8) +#define NEWHOPE_POLYCOMPRESSEDBYTES (( 3*NEWHOPE_N)/8) + +#define NEWHOPE_CPAPKE_PUBLICKEYBYTES (NEWHOPE_POLYBYTES + NEWHOPE_SYMBYTES) +#define NEWHOPE_CPAPKE_SECRETKEYBYTES (NEWHOPE_POLYBYTES) +#define NEWHOPE_CPAPKE_CIPHERTEXTBYTES (NEWHOPE_POLYBYTES + NEWHOPE_POLYCOMPRESSEDBYTES) + +#define NEWHOPE_CPAKEM_PUBLICKEYBYTES NEWHOPE_CPAPKE_PUBLICKEYBYTES +#define NEWHOPE_CPAKEM_SECRETKEYBYTES NEWHOPE_CPAPKE_SECRETKEYBYTES +#define NEWHOPE_CPAKEM_CIPHERTEXTBYTES NEWHOPE_CPAPKE_CIPHERTEXTBYTES + +#define NEWHOPE_CCAKEM_PUBLICKEYBYTES NEWHOPE_CPAPKE_PUBLICKEYBYTES +#define NEWHOPE_CCAKEM_SECRETKEYBYTES (NEWHOPE_CPAPKE_SECRETKEYBYTES + NEWHOPE_CPAPKE_PUBLICKEYBYTES + 2*NEWHOPE_SYMBYTES) +#define NEWHOPE_CCAKEM_CIPHERTEXTBYTES (NEWHOPE_CPAPKE_CIPHERTEXTBYTES + NEWHOPE_SYMBYTES) /* Second part is for Targhi-Unruh */ + +#endif diff --git a/crypto_kem/newhope512cca/clean/poly.c b/crypto_kem/newhope512cca/clean/poly.c new file mode 100644 index 00000000..aa3175f0 --- /dev/null +++ b/crypto_kem/newhope512cca/clean/poly.c @@ -0,0 +1,353 @@ +#include "fips202.h" +#include "ntt.h" +#include "poly.h" +#include "reduce.h" + +/************************************************* +* Name: coeff_freeze +* +* Description: Fully reduces an integer modulo q in constant time +* +* Arguments: uint16_t x: input integer to be reduced +* +* Returns integer in {0,...,q-1} congruent to x modulo q +**************************************************/ +static uint16_t coeff_freeze(uint16_t x) { + uint16_t m, r; + int16_t c; + r = x % NEWHOPE_Q; + + m = r - NEWHOPE_Q; + c = m; + c >>= 15; + r = m ^ ((r ^ m)&c); + + return r; +} + +/************************************************* +* Name: flipabs +* +* Description: Computes |(x mod q) - Q/2| +* +* Arguments: uint16_t x: input coefficient +* +* Returns |(x mod q) - Q/2| +**************************************************/ +static uint16_t flipabs(uint16_t x) { + int16_t r, m; + r = coeff_freeze(x); + + r = r - NEWHOPE_Q / 2; + m = r >> 15; + return (r + m) ^ m; +} + +/************************************************* +* Name: poly_frombytes +* +* Description: De-serialization of a polynomial +* +* Arguments: - poly *r: pointer to output polynomial +* - const unsigned char *a: pointer to input byte array +**************************************************/ +void PQCLEAN_NEWHOPE512CCA_CLEAN_poly_frombytes(poly *r, const unsigned char *a) { + int i; + for (i = 0; i < NEWHOPE_N / 4; i++) { + r->coeffs[4 * i + 0] = a[7 * i + 0] | (((uint16_t)a[7 * i + 1] & 0x3f) << 8); + r->coeffs[4 * i + 1] = (a[7 * i + 1] >> 6) | (((uint16_t)a[7 * i + 2]) << 2) | (((uint16_t)a[7 * i + 3] & 0x0f) << 10); + r->coeffs[4 * i + 2] = (a[7 * i + 3] >> 4) | (((uint16_t)a[7 * i + 4]) << 4) | (((uint16_t)a[7 * i + 5] & 0x03) << 12); + r->coeffs[4 * i + 3] = (a[7 * i + 5] >> 2) | (((uint16_t)a[7 * i + 6]) << 6); + } +} + +/************************************************* +* Name: poly_tobytes +* +* Description: Serialization of a polynomial +* +* Arguments: - unsigned char *r: pointer to output byte array +* - const poly *p: pointer to input polynomial +**************************************************/ +void PQCLEAN_NEWHOPE512CCA_CLEAN_poly_tobytes(unsigned char *r, const poly *p) { + int i; + uint16_t t0, t1, t2, t3; + for (i = 0; i < NEWHOPE_N / 4; i++) { + t0 = coeff_freeze(p->coeffs[4 * i + 0]); + t1 = coeff_freeze(p->coeffs[4 * i + 1]); + t2 = coeff_freeze(p->coeffs[4 * i + 2]); + t3 = coeff_freeze(p->coeffs[4 * i + 3]); + + r[7 * i + 0] = t0 & 0xff; + r[7 * i + 1] = (unsigned char) ((t0 >> 8) | (t1 << 6)); + r[7 * i + 2] = (unsigned char) ((t1 >> 2)); + r[7 * i + 3] = (unsigned char) ((t1 >> 10) | (t2 << 4)); + r[7 * i + 4] = (unsigned char) ((t2 >> 4)); + r[7 * i + 5] = (unsigned char) ((t2 >> 12) | (t3 << 2)); + r[7 * i + 6] = (unsigned char) ((t3 >> 6)); + } +} + +/************************************************* +* Name: poly_compress +* +* Description: Compression and subsequent serialization of a polynomial +* +* Arguments: - unsigned char *r: pointer to output byte array +* - const poly *p: pointer to input polynomial +**************************************************/ +void PQCLEAN_NEWHOPE512CCA_CLEAN_poly_compress(unsigned char *r, const poly *p) { + unsigned int i, j, k = 0; + + uint32_t t[8]; + + for (i = 0; i < NEWHOPE_N; i += 8) { + for (j = 0; j < 8; j++) { + t[j] = coeff_freeze(p->coeffs[i + j]); + t[j] = (((t[j] << 3) + NEWHOPE_Q / 2) / NEWHOPE_Q) & 0x7; + } + + r[k] = (unsigned char) (t[0] | (t[1] << 3) | (t[2] << 6)); + r[k + 1] = (unsigned char) ((t[2] >> 2) | (t[3] << 1) | (t[4] << 4) | (t[5] << 7)); + r[k + 2] = (unsigned char) ((t[5] >> 1) | (t[6] << 2) | (t[7] << 5)); + k += 3; + } +} + +/************************************************* +* Name: poly_decompress +* +* Description: De-serialization and subsequent decompression of a polynomial; +* approximate inverse of poly_compress +* +* Arguments: - poly *r: pointer to output polynomial +* - const unsigned char *a: pointer to input byte array +**************************************************/ +void PQCLEAN_NEWHOPE512CCA_CLEAN_poly_decompress(poly *r, const unsigned char *a) { + unsigned int i, j; + for (i = 0; i < NEWHOPE_N; i += 8) { + r->coeffs[i + 0] = a[0] & 7; + r->coeffs[i + 1] = (a[0] >> 3) & 7; + r->coeffs[i + 2] = (a[0] >> 6) | ((a[1] << 2) & 4); + r->coeffs[i + 3] = (a[1] >> 1) & 7; + r->coeffs[i + 4] = (a[1] >> 4) & 7; + r->coeffs[i + 5] = (a[1] >> 7) | ((a[2] << 1) & 6); + r->coeffs[i + 6] = (a[2] >> 2) & 7; + r->coeffs[i + 7] = (a[2] >> 5); + a += 3; + for (j = 0; j < 8; j++) { + r->coeffs[i + j] = ((uint32_t)r->coeffs[i + j] * NEWHOPE_Q + 4) >> 3; + } + } +} + +/************************************************* +* Name: poly_frommsg +* +* Description: Convert 32-byte message to polynomial +* +* Arguments: - poly *r: pointer to output polynomial +* - const unsigned char *msg: pointer to input message +**************************************************/ +void PQCLEAN_NEWHOPE512CCA_CLEAN_poly_frommsg(poly *r, const unsigned char *msg) { + unsigned int i, j, mask; + for (i = 0; i < NEWHOPE_SYMBYTES; i++) { + for (j = 0; j < 8; j++) { + mask = -((msg[i] >> j) & 1); + r->coeffs[8 * i + j + 0] = mask & (NEWHOPE_Q / 2); + r->coeffs[8 * i + j + 256] = mask & (NEWHOPE_Q / 2); + } + } +} + +/************************************************* +* Name: poly_tomsg +* +* Description: Convert polynomial to 32-byte message +* +* Arguments: - unsigned char *msg: pointer to output message +* - const poly *x: pointer to input polynomial +**************************************************/ +void PQCLEAN_NEWHOPE512CCA_CLEAN_poly_tomsg(unsigned char *msg, const poly *x) { + unsigned int i; + uint16_t t; + + for (i = 0; i < 32; i++) { + msg[i] = 0; + } + + for (i = 0; i < 256; i++) { + t = flipabs(x->coeffs[i + 0]); + t += flipabs(x->coeffs[i + 256]); + t = ((t - NEWHOPE_Q / 2)); + + t >>= 15; + msg[i >> 3] |= t << (i & 7); + } +} + +/************************************************* +* Name: poly_uniform +* +* Description: Sample a polynomial deterministically from a seed, +* with output polynomial looking uniformly random +* +* Arguments: - poly *a: pointer to output polynomial +* - const unsigned char *seed: pointer to input seed +**************************************************/ +void PQCLEAN_NEWHOPE512CCA_CLEAN_poly_uniform(poly *a, const unsigned char *seed) { + unsigned int ctr = 0; + uint16_t val; + shake128ctx state; + uint8_t buf[SHAKE128_RATE]; + uint8_t extseed[NEWHOPE_SYMBYTES + 1]; + int i, j; + + for (i = 0; i < NEWHOPE_SYMBYTES; i++) { + extseed[i] = seed[i]; + } + + for (i = 0; i < NEWHOPE_N / 64; i++) { /* generate a in blocks of 64 coefficients */ + ctr = 0; + extseed[NEWHOPE_SYMBYTES] = (unsigned char) i; /* domain-separate the 16 independent calls */ + shake128_absorb(&state, extseed, NEWHOPE_SYMBYTES + 1); + while (ctr < 64) { /* Very unlikely to run more than once */ + shake128_squeezeblocks(buf, 1, &state); + for (j = 0; j < SHAKE128_RATE && ctr < 64; j += 2) { + val = (buf[j] | ((uint16_t) buf[j + 1] << 8)); + if (val < 5 * NEWHOPE_Q) { + a->coeffs[i * 64 + ctr] = val; + ctr++; + } + } + } + } +} + +/************************************************* +* Name: hw +* +* Description: Compute the Hamming weight of a byte +* +* Arguments: - unsigned char a: input byte +**************************************************/ +static unsigned char hw(unsigned char a) { + unsigned char i, r = 0; + for (i = 0; i < 8; i++) { + r += (a >> i) & 1; + } + return r; +} + +/************************************************* +* Name: poly_sample +* +* Description: Sample a polynomial deterministically from a seed and a nonce, +* with output polynomial close to centered binomial distribution +* with parameter k=8 +* +* Arguments: - poly *r: pointer to output polynomial +* - const unsigned char *seed: pointer to input seed +* - unsigned char nonce: one-byte input nonce +**************************************************/ +void PQCLEAN_NEWHOPE512CCA_CLEAN_poly_sample(poly *r, const unsigned char *seed, unsigned char nonce) { + unsigned char buf[128], a, b; + int i, j; + + unsigned char extseed[NEWHOPE_SYMBYTES + 2]; + + for (i = 0; i < NEWHOPE_SYMBYTES; i++) { + extseed[i] = seed[i]; + } + extseed[NEWHOPE_SYMBYTES] = nonce; + + for (i = 0; i < NEWHOPE_N / 64; i++) { /* Generate noise in blocks of 64 coefficients */ + extseed[NEWHOPE_SYMBYTES + 1] = (unsigned char) i; + shake256(buf, 128, extseed, NEWHOPE_SYMBYTES + 2); + for (j = 0; j < 64; j++) { + a = buf[2 * j]; + b = buf[2 * j + 1]; + r->coeffs[64 * i + j] = hw(a) + NEWHOPE_Q - hw(b); + } + } +} + +/************************************************* +* Name: poly_pointwise +* +* Description: Multiply two polynomials pointwise (i.e., coefficient-wise). +* +* Arguments: - poly *r: pointer to output polynomial +* - const poly *a: pointer to first input polynomial +* - const poly *b: pointer to second input polynomial +**************************************************/ +void PQCLEAN_NEWHOPE512CCA_CLEAN_poly_mul_pointwise(poly *r, const poly *a, const poly *b) { + int i; + uint16_t t; + for (i = 0; i < NEWHOPE_N; i++) { + t = PQCLEAN_NEWHOPE512CCA_CLEAN_montgomery_reduce(3186 * b->coeffs[i]); /* t is now in Montgomery domain */ + r->coeffs[i] = PQCLEAN_NEWHOPE512CCA_CLEAN_montgomery_reduce(a->coeffs[i] * t); /* r->coeffs[i] is back in normal domain */ + } +} + +/************************************************* +* Name: poly_add +* +* Description: Add two polynomials +* +* Arguments: - poly *r: pointer to output polynomial +* - const poly *a: pointer to first input polynomial +* - const poly *b: pointer to second input polynomial +**************************************************/ +void PQCLEAN_NEWHOPE512CCA_CLEAN_poly_add(poly *r, const poly *a, const poly *b) { + int i; + for (i = 0; i < NEWHOPE_N; i++) { + r->coeffs[i] = (a->coeffs[i] + b->coeffs[i]) % NEWHOPE_Q; + } +} + +/************************************************* +* Name: poly_sub +* +* Description: Subtract two polynomials +* +* Arguments: - poly *r: pointer to output polynomial +* - const poly *a: pointer to first input polynomial +* - const poly *b: pointer to second input polynomial +**************************************************/ +void PQCLEAN_NEWHOPE512CCA_CLEAN_poly_sub(poly *r, const poly *a, const poly *b) { + int i; + for (i = 0; i < NEWHOPE_N; i++) { + r->coeffs[i] = (a->coeffs[i] + 3 * NEWHOPE_Q - b->coeffs[i]) % NEWHOPE_Q; + } +} + +/************************************************* +* Name: poly_ntt +* +* Description: Forward NTT transform of a polynomial in place +* Input is assumed to have coefficients in bitreversed order +* Output has coefficients in normal order +* +* Arguments: - poly *r: pointer to in/output polynomial +**************************************************/ +void PQCLEAN_NEWHOPE512CCA_CLEAN_poly_ntt(poly *r) { + PQCLEAN_NEWHOPE512CCA_CLEAN_mul_coefficients(r->coeffs, PQCLEAN_NEWHOPE512CCA_CLEAN_gammas_bitrev_montgomery); + PQCLEAN_NEWHOPE512CCA_CLEAN_ntt((uint16_t *)r->coeffs, PQCLEAN_NEWHOPE512CCA_CLEAN_gammas_bitrev_montgomery); +} + +/************************************************* +* Name: poly_invntt +* +* Description: Inverse NTT transform of a polynomial in place +* Input is assumed to have coefficients in normal order +* Output has coefficients in normal order +* +* Arguments: - poly *r: pointer to in/output polynomial +**************************************************/ +void PQCLEAN_NEWHOPE512CCA_CLEAN_poly_invntt(poly *r) { + PQCLEAN_NEWHOPE512CCA_CLEAN_bitrev_vector(r->coeffs); + PQCLEAN_NEWHOPE512CCA_CLEAN_ntt((uint16_t *)r->coeffs, PQCLEAN_NEWHOPE512CCA_CLEAN_omegas_inv_bitrev_montgomery); + PQCLEAN_NEWHOPE512CCA_CLEAN_mul_coefficients(r->coeffs, PQCLEAN_NEWHOPE512CCA_CLEAN_gammas_inv_montgomery); +} + diff --git a/crypto_kem/newhope512cca/clean/poly.h b/crypto_kem/newhope512cca/clean/poly.h new file mode 100644 index 00000000..cdf9e98f --- /dev/null +++ b/crypto_kem/newhope512cca/clean/poly.h @@ -0,0 +1,32 @@ +#ifndef POLY_H +#define POLY_H + +#include "params.h" +#include + +/* + * Elements of R_q = Z_q[X]/(X^n + 1). Represents polynomial + * coeffs[0] + X*coeffs[1] + X^2*xoeffs[2] + ... + X^{n-1}*coeffs[n-1] + */ +typedef struct { + uint16_t coeffs[NEWHOPE_N]; +} poly; + +void PQCLEAN_NEWHOPE512CCA_CLEAN_poly_uniform(poly *a, const unsigned char *seed); +void PQCLEAN_NEWHOPE512CCA_CLEAN_poly_sample(poly *r, const unsigned char *seed, unsigned char nonce); +void PQCLEAN_NEWHOPE512CCA_CLEAN_poly_add(poly *r, const poly *a, const poly *b); + +void PQCLEAN_NEWHOPE512CCA_CLEAN_poly_ntt(poly *r); +void PQCLEAN_NEWHOPE512CCA_CLEAN_poly_invntt(poly *r); +void PQCLEAN_NEWHOPE512CCA_CLEAN_poly_mul_pointwise(poly *r, const poly *a, const poly *b); + +void PQCLEAN_NEWHOPE512CCA_CLEAN_poly_frombytes(poly *r, const unsigned char *a); +void PQCLEAN_NEWHOPE512CCA_CLEAN_poly_tobytes(unsigned char *r, const poly *p); +void PQCLEAN_NEWHOPE512CCA_CLEAN_poly_compress(unsigned char *r, const poly *p); +void PQCLEAN_NEWHOPE512CCA_CLEAN_poly_decompress(poly *r, const unsigned char *a); + +void PQCLEAN_NEWHOPE512CCA_CLEAN_poly_frommsg(poly *r, const unsigned char *msg); +void PQCLEAN_NEWHOPE512CCA_CLEAN_poly_tomsg(unsigned char *msg, const poly *x); +void PQCLEAN_NEWHOPE512CCA_CLEAN_poly_sub(poly *r, const poly *a, const poly *b); + +#endif diff --git a/crypto_kem/newhope512cca/clean/precomp.c b/crypto_kem/newhope512cca/clean/precomp.c new file mode 100644 index 00000000..20d5a9e1 --- /dev/null +++ b/crypto_kem/newhope512cca/clean/precomp.c @@ -0,0 +1,179 @@ +#include "inttypes.h" +#include "ntt.h" +#include "params.h" + +/* Precomputed NTT contants generated by Pari/GP script as follows: + * + * For n = 512: + * + * brv = [0,256,128,384,64,320,192,448,32,288,160,416,96,352,224,480,16,272,144,400,80,336,208,464,48,304,176,432,112,368,240,496,8, + * 264,136,392,72,328,200,456,40,296,168,424,104,360,232,488,24,280,152,408,88,344,216,472,56,312,184,440,120,376,248,504,4, + * 260,132,388,68,324,196,452,36,292,164,420,100,356,228,484,20,276,148,404,84,340,212,468,52,308,180,436,116,372,244,500,12, + * 268,140,396,76,332,204,460,44,300,172,428,108,364,236,492,28,284,156,412,92,348,220,476,60,316,188,444,124,380,252,508,2, + * 258,130,386,66,322,194,450,34,290,162,418,98,354,226,482,18,274,146,402,82,338,210,466,50,306,178,434,114,370,242,498,10, + * 266,138,394,74,330,202,458,42,298,170,426,106,362,234,490,26,282,154,410,90,346,218,474,58,314,186,442,122,378,250,506,6, + * 262,134,390,70,326,198,454,38,294,166,422,102,358,230,486,22,278,150,406,86,342,214,470,54,310,182,438,118,374,246,502,14, + * 270,142,398,78,334,206,462,46,302,174,430,110,366,238,494,30,286,158,414,94,350,222,478,62,318,190,446,126,382,254,510,1, + * 257,129,385,65,321,193,449,33,289,161,417,97,353,225,481,17,273,145,401,81,337,209,465,49,305,177,433,113,369,241,497,9, + * 265,137,393,73,329,201,457,41,297,169,425,105,361,233,489,25,281,153,409,89,345,217,473,57,313,185,441,121,377,249,505,5, + * 261,133,389,69,325,197,453,37,293,165,421,101,357,229,485,21,277,149,405,85,341,213,469,53,309,181,437,117,373,245,501,13, + * 269,141,397,77,333,205,461,45,301,173,429,109,365,237,493,29,285,157,413,93,349,221,477,61,317,189,445,125,381,253,509,3, + * 259,131,387,67,323,195,451,35,291,163,419,99,355,227,483,19,275,147,403,83,339,211,467,51,307,179,435,115,371,243,499,11, + * 267,139,395,75,331,203,459,43,299,171,427,107,363,235,491,27,283,155,411,91,347,219,475,59,315,187,443,123,379,251,507,7, + * 263,135,391,71,327,199,455,39,295,167,423,103,359,231,487,23,279,151,407,87,343,215,471,55,311,183,439,119,375,247,503,15, + * 271,143,399,79,335,207,463,47,303,175,431,111,367,239,495,31,287,159,415,95,351,223,479,63,319,191,447,127,383,255,511] + * n = 512; q = 12289; mont=2^18 + * g = Mod(10968, q); + * omegas_inv_bitrev_montgomery = lift(vector(n/2, i, (g^2)^(-brv[2*(i-1)+1])*mont)) + * gammas_bitrev_montgomery = lift(vector(n, i, g^(brv[i])*mont)) + * gammas_inv_montgomery = lift(vector(n, i, g^(-(i-1))/n*mont)) + * + * + * For n = 1024: + * + * brv = [0,512,256,768,128,640,384,896,64,576,320,832,192,704,448,960,32,544,288,800,160,672,416,928,96,608,352,864,224,736,480,992, \ + * 16,528,272,784,144,656,400,912,80,592,336,848,208,720,464,976,48,560,304,816,176,688,432,944,112,624,368,880,240,752,496,1008, \ + * 8,520,264,776,136,648,392,904,72,584,328,840,200,712,456,968,40,552,296,808,168,680,424,936,104,616,360,872,232,744,488,1000, \ + * 24,536,280,792,152,664,408,920,88,600,344,856,216,728,472,984,56,568,312,824,184,696,440,952,120,632,376,888,248,760,504,1016, \ + * 4,516,260,772,132,644,388,900,68,580,324,836,196,708,452,964,36,548,292,804,164,676,420,932,100,612,356,868,228,740,484,996, \ + * 20,532,276,788,148,660,404,916,84,596,340,852,212,724,468,980,52,564,308,820,180,692,436,948,116,628,372,884,244,756,500,1012, \ + * 12,524,268,780,140,652,396,908,76,588,332,844,204,716,460,972,44,556,300,812,172,684,428,940,108,620,364,876,236,748,492,1004, \ + * 28,540,284,796,156,668,412,924,92,604,348,860,220,732,476,988,60,572,316,828,188,700,444,956,124,636,380,892,252,764,508,1020, \ + * 2,514,258,770,130,642,386,898,66,578,322,834,194,706,450,962,34,546,290,802,162,674,418,930,98,610,354,866,226,738,482,994, \ + * 18,530,274,786,146,658,402,914,82,594,338,850,210,722,466,978,50,562,306,818,178,690,434,946,114,626,370,882,242,754,498,1010, \ + * 10,522,266,778,138,650,394,906,74,586,330,842,202,714,458,970,42,554,298,810,170,682,426,938,106,618,362,874,234,746,490,1002, \ + * 26,538,282,794,154,666,410,922,90,602,346,858,218,730,474,986,58,570,314,826,186,698,442,954,122,634,378,890,250,762,506,1018, \ + * 6,518,262,774,134,646,390,902,70,582,326,838,198,710,454,966,38,550,294,806,166,678,422,934,102,614,358,870,230,742,486,998, \ + * 22,534,278,790,150,662,406,918,86,598,342,854,214,726,470,982,54,566,310,822,182,694,438,950,118,630,374,886,246,758,502,1014, \ + * 14,526,270,782,142,654,398,910,78,590,334,846,206,718,462,974,46,558,302,814,174,686,430,942,110,622,366,878,238,750,494,1006, \ + * 30,542,286,798,158,670,414,926,94,606,350,862,222,734,478,990,62,574,318,830,190,702,446,958,126,638,382,894,254,766,510,1022, \ + * 1,513,257,769,129,641,385,897,65,577,321,833,193,705,449,961,33,545,289,801,161,673,417,929,97,609,353,865,225,737,481,993, \ + * 17,529,273,785,145,657,401,913,81,593,337,849,209,721,465,977,49,561,305,817,177,689,433,945,113,625,369,881,241,753,497,1009, \ + * 9,521,265,777,137,649,393,905,73,585,329,841,201,713,457,969,41,553,297,809,169,681,425,937,105,617,361,873,233,745,489,1001, \ + * 25,537,281,793,153,665,409,921,89,601,345,857,217,729,473,985,57,569,313,825,185,697,441,953,121,633,377,889,249,761,505,1017, \ + * 5,517,261,773,133,645,389,901,69,581,325,837,197,709,453,965,37,549,293,805,165,677,421,933,101,613,357,869,229,741,485,997, \ + * 21,533,277,789,149,661,405,917,85,597,341,853,213,725,469,981,53,565,309,821,181,693,437,949,117,629,373,885,245,757,501,1013, \ + * 13,525,269,781,141,653,397,909,77,589,333,845,205,717,461,973,45,557,301,813,173,685,429,941,109,621,365,877,237,749,493,1005, \ + * 29,541,285,797,157,669,413,925,93,605,349,861,221,733,477,989,61,573,317,829,189,701,445,957,125,637,381,893,253,765,509,1021, \ + * 3,515,259,771,131,643,387,899,67,579,323,835,195,707,451,963,35,547,291,803,163,675,419,931,99,611,355,867,227,739,483,995, \ + * 19,531,275,787,147,659,403,915,83,595,339,851,211,723,467,979,51,563,307,819,179,691,435,947,115,627,371,883,243,755,499,1011, \ + * 11,523,267,779,139,651,395,907,75,587,331,843,203,715,459,971,43,555,299,811,171,683,427,939,107,619,363,875,235,747,491,1003, \ + * 27,539,283,795,155,667,411,923,91,603,347,859,219,731,475,987,59,571,315,827,187,699,443,955,123,635,379,891,251,763,507,1019, \ + * 7,519,263,775,135,647,391,903,71,583,327,839,199,711,455,967,39,551,295,807,167,679,423,935,103,615,359,871,231,743,487,999, \ + * 23,535,279,791,151,663,407,919,87,599,343,855,215,727,471,983,55,567,311,823,183,695,439,951,119,631,375,887,247,759,503,1015, \ + * 15,527,271,783,143,655,399,911,79,591,335,847,207,719,463,975,47,559,303,815,175,687,431,943,111,623,367,879,239,751,495,1007, \ + * 31,543,287,799,159,671,415,927,95,607,351,863,223,735,479,991,63,575,319,831,191,703,447,959,127,639,383,895,255,767,511,1023] + * + * n = 1024; q = 12289; mont=2^18 + * g = Mod(7, q); + * omegas_inv_bitrev_montgomery = lift(vector(n/2, i, (g^2)^(-brv[2*(i-1)+1])*mont)) + * gammas_bitrev_montgomery = lift(vector(n, i, g^(brv[i])*mont)) + * gammas_inv_montgomery = lift(vector(n, i, g^(-(i-1))/n*mont)) +*/ + +/************************************************************ +* Name: omegas_inv_bitrev_montgomery +* +* Description: Contains inverses of powers of nth root of unity +* in Montgomery domain with R=2^18 in bit-reversed order +************************************************************/ +const uint16_t PQCLEAN_NEWHOPE512CCA_CLEAN_omegas_inv_bitrev_montgomery[NEWHOPE_N / 2] = { + 4075, 6974, 4916, 4324, 7210, 3262, 2169, 11767, 3514, 1041, 5925, 11271, 6715, 10316, 11011, 9945, + 1190, 9606, 3818, 6118, 1050, 7753, 8429, 6844, 4449, 6833, 147, 3789, 7540, 6752, 4467, 4789, + 10367, 3879, 2033, 3998, 11316, 1254, 6854, 1359, 3988, 468, 11907, 11973, 8579, 6196, 5446, 6950, + 1987, 10587, 654, 3565, 3199, 12233, 7083, 6760, 6427, 6153, 3643, 6874, 4948, 6152, 11889, 1728, + 7280, 10333, 6008, 11404, 3532, 11286, 241, 12231, 11314, 4212, 8851, 9445, 3477, 6608, 12147, 1105, + 5594, 9260, 5886, 7507, 4213, 11785, 2302, 11684, 8687, 6221, 8209, 421, 7665, 6212, 8689, 3263, + 10710, 431, 9784, 5906, 9450, 8332, 2127, 151, 3174, 52, 1323, 9523, 6415, 11612, 3336, 6234, + 7048, 9369, 4169, 3127, 11279, 6821, 787, 3482, 3445, 4780, 7232, 7591, 7377, 2049, 1321, 192, + 9551, 6421, 5735, 9634, 10596, 9280, 723, 12115, 9364, 347, 1975, 3757, 10431, 7535, 11863, 3315, + 4493, 3202, 5369, 10232, 350, 10777, 6906, 10474, 1483, 6374, 49, 1263, 10706, 6347, 1489, 9789, + 7552, 1293, 4774, 5429, 3772, 418, 6381, 453, 9522, 156, 3969, 3991, 6956, 10258, 10008, 6413, + 8855, 3529, 218, 9381, 9259, 8174, 2361, 10446, 10335, 2051, 9407, 10484, 9842, 6147, 3963, 576, + 6523, 11637, 6099, 11994, 9370, 3762, 8273, 4077, 11964, 1404, 11143, 11341, 1159, 6299, 4049, 8561, + 5961, 7183, 1962, 10695, 9597, 12121, 8960, 7991, 6992, 6170, 10929, 8333, 2555, 6167, 11089, 5184, + 3570, 4240, 11454, 6065, 3150, 10970, 709, 8243, 1058, 8210, 441, 11367, 10331, 7967, 1112, 2078, + 10542, 3123, 5486, 9235, 7856, 6370, 8455, 5257, 9341, 9786, 6507, 10723, 2459, 683, 8633, 64, +}; + +/************************************************************ +* Name: gammas_bitrev_montgomery +* +* Description: Contains powers of nth root of -1 in Montgomery +* domain with R=2^18 in bit-reversed order +************************************************************/ +const uint16_t PQCLEAN_NEWHOPE512CCA_CLEAN_gammas_bitrev_montgomery[NEWHOPE_N] = { + 4075, 5315, 7965, 7373, 522, 10120, 9027, 5079, 2344, 1278, 1973, 5574, 1018, 6364, 11248, 8775, + 7500, 7822, 5537, 4749, 8500, 12142, 5456, 7840, 5445, 3860, 4536, 11239, 6171, 8471, 2683, 11099, + 10561, 400, 6137, 7341, 5415, 8646, 6136, 5862, 5529, 5206, 56, 9090, 8724, 11635, 1702, 10302, + 5339, 6843, 6093, 3710, 316, 382, 11821, 8301, 10930, 5435, 11035, 973, 8291, 10256, 8410, 1922, + 12097, 10968, 10240, 4912, 4698, 5057, 7509, 8844, 8807, 11502, 5468, 1010, 9162, 8120, 2920, 5241, + 6055, 8953, 677, 5874, 2766, 10966, 12237, 9115, 12138, 10162, 3957, 2839, 6383, 2505, 11858, 1579, + 9026, 3600, 6077, 4624, 11868, 4080, 6068, 3602, 605, 9987, 504, 8076, 4782, 6403, 3029, 6695, + 11184, 142, 5681, 8812, 2844, 3438, 8077, 975, 58, 12048, 1003, 8757, 885, 6281, 1956, 5009, + 12225, 3656, 11606, 9830, 1566, 5782, 2503, 2948, 7032, 3834, 5919, 4433, 3054, 6803, 9166, 1747, + 10211, 11177, 4322, 1958, 922, 11848, 4079, 11231, 4046, 11580, 1319, 9139, 6224, 835, 8049, 8719, + 7105, 1200, 6122, 9734, 3956, 1360, 6119, 5297, 4298, 3329, 168, 2692, 1594, 10327, 5106, 6328, + 3728, 8240, 5990, 11130, 948, 1146, 10885, 325, 8212, 4016, 8527, 2919, 295, 6190, 652, 5766, + 11713, 8326, 6142, 2447, 1805, 2882, 10238, 1954, 1843, 9928, 4115, 3030, 2908, 12071, 8760, 3434, + 5876, 2281, 2031, 5333, 8298, 8320, 12133, 2767, 11836, 5908, 11871, 8517, 6860, 7515, 10996, 4737, + 2500, 10800, 5942, 1583, 11026, 12240, 5915, 10806, 1815, 5383, 1512, 11939, 2057, 6920, 9087, 7796, + 8974, 426, 4754, 1858, 8532, 10314, 11942, 2925, 174, 11566, 3009, 1693, 2655, 6554, 5868, 2738, + 11796, 8193, 9908, 5444, 10911, 1912, 7952, 435, 404, 7644, 11224, 10146, 7012, 11121, 11082, 9041, + 9723, 2187, 9867, 6250, 3646, 9852, 6267, 2987, 8509, 875, 4976, 10682, 8005, 5088, 7278, 11287, + 9223, 27, 3763, 10849, 11272, 7404, 5084, 10657, 8146, 4714, 12047, 10752, 2678, 3704, 545, 7270, + 1067, 5101, 442, 2401, 390, 11516, 3778, 8456, 1045, 9430, 9808, 5012, 9377, 6591, 11935, 4861, + 7852, 3, 3149, 12129, 12176, 4919, 10123, 3915, 3636, 7351, 2704, 5291, 1663, 1777, 1426, 7635, + 1484, 7394, 2780, 7094, 8236, 2645, 7247, 2305, 2847, 7875, 7917, 10115, 10600, 8925, 4057, 3271, + 9273, 243, 9289, 11618, 3136, 5191, 8889, 9890, 11869, 5559, 10111, 10745, 11813, 8758, 4905, 3985, + 9603, 9042, 3978, 9320, 3510, 5332, 9424, 2370, 9405, 11136, 2249, 8241, 10659, 10163, 9103, 6882, + 10810, 1, 5146, 4043, 8155, 5736, 11567, 1305, 1212, 10643, 9094, 5860, 8747, 8785, 8668, 2545, + 4591, 6561, 5023, 6461, 10938, 4978, 6512, 8961, 949, 2625, 2639, 7468, 11726, 2975, 9545, 9283, + 3091, 81, 11289, 7969, 9238, 9923, 2963, 7393, 12149, 1853, 11563, 7678, 8034, 11112, 1635, 9521, + 3201, 3014, 1326, 7203, 1170, 9970, 11334, 790, 3135, 3712, 4846, 2747, 3553, 7484, 11227, 2294, + 11267, 9, 9447, 11809, 11950, 2468, 5791, 11745, 10908, 9764, 8112, 3584, 4989, 5331, 4278, 10616, + 4452, 9893, 8340, 8993, 130, 7935, 9452, 6915, 8541, 11336, 11462, 5767, 7222, 2197, 12171, 9813, + 3241, 729, 3289, 10276, 9408, 3284, 2089, 5092, 11029, 4388, 5755, 7657, 10861, 1696, 2426, 11955, + 4231, 2548, 11934, 3382, 10530, 3707, 3694, 7110, 3637, 8830, 6747, 145, 7399, 5911, 2731, 8357, +}; + +/************************************************************ +* Name: gammas_inv_montgomery +* +* Description: Contains inverses of powers of nth root of -1 +* divided by n in Montgomery domain with R=2^18 +************************************************************/ +const uint16_t PQCLEAN_NEWHOPE512CCA_CLEAN_gammas_inv_montgomery[NEWHOPE_N] = { + 512, 3944, 4267, 5411, 9615, 5900, 3205, 6063, 9261, 2021, 3087, 4770, 1029, 1590, 343, 530, + 8307, 4273, 2769, 9617, 923, 7302, 4404, 2434, 1468, 9004, 8682, 11194, 2894, 11924, 5061, 8071, + 1687, 10883, 8755, 7724, 11111, 6671, 7800, 6320, 2600, 6203, 4963, 6164, 9847, 6151, 11475, 10243, + 3825, 11607, 1275, 3869, 425, 5386, 4238, 9988, 5509, 11522, 10029, 7937, 3343, 6742, 9307, 10440, + 11295, 3480, 3765, 1160, 1255, 4483, 8611, 9687, 11063, 3229, 7784, 9269, 6691, 7186, 10423, 10588, + 11667, 11722, 3889, 12100, 9489, 12226, 3163, 12268, 9247, 12282, 11275, 4094, 11951, 5461, 8080, 10013, + 10886, 7434, 7725, 2478, 2575, 826, 9051, 8468, 3017, 6919, 5102, 10499, 5797, 7596, 10125, 2532, + 3375, 844, 1125, 8474, 375, 6921, 125, 2307, 4138, 769, 9572, 8449, 7287, 11009, 2429, 7766, + 4906, 6685, 9828, 10421, 3276, 7570, 1092, 10716, 364, 3572, 8314, 5287, 10964, 9955, 7751, 11511, + 6680, 3837, 6323, 1279, 6204, 8619, 2068, 2873, 8882, 5054, 7057, 5781, 10545, 1927, 3515, 8835, + 5268, 2945, 1756, 5078, 8778, 5789, 2926, 6026, 9168, 6105, 3056, 2035, 5115, 8871, 1705, 2957, + 8761, 5082, 11113, 1694, 11897, 4661, 8062, 5650, 10880, 10076, 7723, 7455, 10767, 2485, 3589, 9021, + 9389, 3007, 7226, 9195, 6505, 3065, 10361, 5118, 7550, 1706, 6613, 4665, 10397, 1555, 7562, 8711, + 6617, 7000, 6302, 10526, 6197, 7605, 6162, 2535, 2054, 845, 4781, 4378, 5690, 9652, 5993, 11410, + 6094, 11996, 10224, 8095, 3408, 10891, 1136, 11823, 4475, 3941, 5588, 5410, 5959, 9996, 10179, 3332, + 3393, 5207, 1131, 5832, 377, 1944, 4222, 648, 9600, 216, 3200, 72, 5163, 24, 1721, 8, + 4670, 4099, 5653, 9559, 10077, 11379, 3359, 3793, 5216, 9457, 5835, 11345, 1945, 7878, 8841, 2626, + 2947, 9068, 9175, 7119, 11251, 2373, 11943, 791, 3981, 4360, 1327, 9646, 8635, 11408, 11071, 7899, + 11883, 2633, 3961, 4974, 9513, 1658, 3171, 4649, 1057, 5646, 8545, 1882, 11041, 8820, 11873, 2940, + 8054, 980, 6781, 4423, 10453, 9667, 11677, 11415, 12085, 3805, 12221, 9461, 8170, 7250, 10916, 6513, + 7735, 2171, 10771, 4820, 11783, 5703, 8024, 1901, 6771, 4730, 2257, 5673, 8945, 1891, 7078, 8823, + 10552, 2941, 11710, 9173, 12096, 7154, 4032, 6481, 1344, 10353, 448, 3451, 8342, 9343, 6877, 11307, + 10485, 3769, 3495, 9449, 1165, 7246, 8581, 10608, 11053, 3536, 11877, 5275, 3959, 9951, 5416, 3317, + 9998, 5202, 7429, 1734, 10669, 578, 11749, 4289, 12109, 5526, 12229, 1842, 12269, 614, 8186, 4301, + 6825, 5530, 2275, 10036, 8951, 11538, 7080, 3846, 2360, 1282, 4883, 8620, 5724, 11066, 1908, 7785, + 636, 2595, 212, 865, 4167, 8481, 1389, 2827, 463, 9135, 8347, 3045, 10975, 1015, 11851, 8531, + 12143, 6940, 8144, 10506, 6811, 3502, 10463, 9360, 7584, 3120, 2528, 1040, 4939, 4443, 9839, 1481, + 7376, 4590, 6555, 1530, 2185, 510, 8921, 170, 7070, 4153, 6453, 9577, 2151, 11385, 717, 3795, + 239, 1265, 4176, 4518, 1392, 1506, 464, 502, 4251, 8360, 1417, 6883, 8665, 10487, 11081, 7592, + 7790, 6627, 6693, 2209, 2231, 8929, 4840, 11169, 9806, 3723, 7365, 1241, 2455, 4510, 9011, 9696, + 7100, 3232, 6463, 9270, 10347, 3090, 3449, 1030, 5246, 8536, 5845, 11038, 10141, 11872, 11573, 12150, + 7954, 4050, 10844, 1350, 7711, 450, 10763, 150, 7684, 50, 10754, 4113, 7681, 1371, 10753, 457, +}; diff --git a/crypto_kem/newhope512cca/clean/reduce.c b/crypto_kem/newhope512cca/clean/reduce.c new file mode 100644 index 00000000..cdaffba7 --- /dev/null +++ b/crypto_kem/newhope512cca/clean/reduce.c @@ -0,0 +1,26 @@ +#include "reduce.h" +#include "params.h" + +static const uint32_t qinv = 12287; // -inverse_mod(p,2^18) +static const uint32_t rlog = 18; + +/************************************************* +* Name: verify +* +* Description: Montgomery reduction; given a 32-bit integer a, computes +* 16-bit integer congruent to a * R^-1 mod q, +* where R=2^18 (see value of rlog) +* +* Arguments: - uint32_t a: input unsigned integer to be reduced; has to be in {0,...,1073491968} +* +* Returns: unsigned integer in {0,...,2^14-1} congruent to a * R^-1 modulo q. +**************************************************/ +uint16_t PQCLEAN_NEWHOPE512CCA_CLEAN_montgomery_reduce(uint32_t a) { + uint32_t u; + + u = (a * qinv); + u &= ((1 << rlog) - 1); + u *= NEWHOPE_Q; + a = a + u; + return a >> 18; +} diff --git a/crypto_kem/newhope512cca/clean/reduce.h b/crypto_kem/newhope512cca/clean/reduce.h new file mode 100644 index 00000000..7e98ce2e --- /dev/null +++ b/crypto_kem/newhope512cca/clean/reduce.h @@ -0,0 +1,8 @@ +#ifndef REDUCE_H +#define REDUCE_H + +#include + +uint16_t PQCLEAN_NEWHOPE512CCA_CLEAN_montgomery_reduce(uint32_t a); + +#endif diff --git a/crypto_kem/newhope512cca/clean/verify.c b/crypto_kem/newhope512cca/clean/verify.c new file mode 100644 index 00000000..553c0e50 --- /dev/null +++ b/crypto_kem/newhope512cca/clean/verify.c @@ -0,0 +1,49 @@ +#include "verify.h" +#include +#include + +/************************************************* +* Name: verify +* +* Description: Compare two arrays for equality in constant time. +* +* Arguments: const unsigned char *a: pointer to first byte array +* const unsigned char *b: pointer to second byte array +* size_t len: length of the byte arrays +* +* Returns 0 if the byte arrays are equal, 1 otherwise +**************************************************/ +int PQCLEAN_NEWHOPE512CCA_CLEAN_verify(const unsigned char *a, const unsigned char *b, size_t len) { + uint64_t r; + size_t i; + r = 0; + + for (i = 0; i < len; i++) { + r |= a[i] ^ b[i]; + } + + r = (-(int64_t)r) >> 63; + return (int)r; +} + +/************************************************* +* Name: cmov +* +* Description: Copy len bytes from x to r if b is 1; +* don't modify x if b is 0. Requires b to be in {0,1}; +* assumes two's complement representation of negative integers. +* Runs in constant time. +* +* Arguments: unsigned char *r: pointer to output byte array +* const unsigned char *x: pointer to input byte array +* size_t len: Amount of bytes to be copied +* unsigned char b: Condition bit; has to be in {0,1} +**************************************************/ +void PQCLEAN_NEWHOPE512CCA_CLEAN_cmov(unsigned char *r, const unsigned char *x, size_t len, unsigned char b) { + size_t i; + + b = -b; + for (i = 0; i < len; i++) { + r[i] ^= b & (x[i] ^ r[i]); + } +} diff --git a/crypto_kem/newhope512cca/clean/verify.h b/crypto_kem/newhope512cca/clean/verify.h new file mode 100644 index 00000000..5db88072 --- /dev/null +++ b/crypto_kem/newhope512cca/clean/verify.h @@ -0,0 +1,12 @@ +#ifndef VERIFY_H +#define VERIFY_H + +#include + +/* returns 0 for equal strings, 1 for non-equal strings */ +int PQCLEAN_NEWHOPE512CCA_CLEAN_verify(const unsigned char *a, const unsigned char *b, size_t len); + +/* b = 1 means mov, b = 0 means don't mov*/ +void PQCLEAN_NEWHOPE512CCA_CLEAN_cmov(unsigned char *r, const unsigned char *x, size_t len, unsigned char b); + +#endif diff --git a/crypto_kem/newhope512cpa/META.yml b/crypto_kem/newhope512cpa/META.yml new file mode 100644 index 00000000..695f4be9 --- /dev/null +++ b/crypto_kem/newhope512cpa/META.yml @@ -0,0 +1,21 @@ +name: NewHope512CPA +type: kem +claimed-nist-level: 1 +claimed-security: IND-CPA +length-public-key: 928 +length-secret-key: 896 +length-ciphertext: 1088 +length-shared-secret: 32 +nistkat-sha256: 42444446b96f45c9b7221c4fde8afd5dfc0b3c2ff05b9a88ff12ea3949fbb76c +principal-submitter: Thomas Pöppelmann +auxiliary-submitters: +- Erdem Alkim +- Roberto Avanzi +- Joppe Bos +- Léo Ducas +- Antonio de la Piedra +- Peter Schwabe +- Douglas Stebila +implementations: +- name: clean + version: https://github.com/newhopecrypto/newhope/commit/3fc68c6090b23c56cc190a78af2f43ee8900e9d0 diff --git a/crypto_kem/newhope512cpa/clean/LICENSE b/crypto_kem/newhope512cpa/clean/LICENSE new file mode 100644 index 00000000..d5d21fff --- /dev/null +++ b/crypto_kem/newhope512cpa/clean/LICENSE @@ -0,0 +1 @@ +Public Domain diff --git a/crypto_kem/newhope512cpa/clean/Makefile b/crypto_kem/newhope512cpa/clean/Makefile new file mode 100644 index 00000000..8659694c --- /dev/null +++ b/crypto_kem/newhope512cpa/clean/Makefile @@ -0,0 +1,19 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libnewhope512cpa_clean.a +HEADERS=api.h cpapke.h ntt.h params.h poly.h reduce.h verify.h +OBJECTS=cpapke.o kem.o ntt.o poly.o precomp.o reduce.o verify.o + +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Wvla -Werror -Wredundant-decls -Wmissing-prototypes -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/newhope512cpa/clean/Makefile.Microsoft_nmake b/crypto_kem/newhope512cpa/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..249a7d1f --- /dev/null +++ b/crypto_kem/newhope512cpa/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=libnewhope512cpa_clean.lib +OBJECTS=cpapke.obj kem.obj ntt.obj poly.obj precomp.obj reduce.obj verify.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/newhope512cpa/clean/api.h b/crypto_kem/newhope512cpa/clean/api.h new file mode 100644 index 00000000..791d72af --- /dev/null +++ b/crypto_kem/newhope512cpa/clean/api.h @@ -0,0 +1,15 @@ +#ifndef PQCLEAN_NEWHOPE512CPA_CLEAN_API_H +#define PQCLEAN_NEWHOPE512CPA_CLEAN_API_H + + +#define PQCLEAN_NEWHOPE512CPA_CLEAN_CRYPTO_SECRETKEYBYTES 896 +#define PQCLEAN_NEWHOPE512CPA_CLEAN_CRYPTO_PUBLICKEYBYTES 928 +#define PQCLEAN_NEWHOPE512CPA_CLEAN_CRYPTO_CIPHERTEXTBYTES 1088 +#define PQCLEAN_NEWHOPE512CPA_CLEAN_CRYPTO_BYTES 32 +#define PQCLEAN_NEWHOPE512CPA_CLEAN_CRYPTO_ALGNAME "NewHope512-CPAKEM" + +int PQCLEAN_NEWHOPE512CPA_CLEAN_crypto_kem_keypair(unsigned char *pk, unsigned char *sk); +int PQCLEAN_NEWHOPE512CPA_CLEAN_crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk); +int PQCLEAN_NEWHOPE512CPA_CLEAN_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk); + +#endif diff --git a/crypto_kem/newhope512cpa/clean/cpapke.c b/crypto_kem/newhope512cpa/clean/cpapke.c new file mode 100644 index 00000000..dbcc3434 --- /dev/null +++ b/crypto_kem/newhope512cpa/clean/cpapke.c @@ -0,0 +1,192 @@ +#include "api.h" +#include "cpapke.h" +#include "fips202.h" +#include "poly.h" +#include "randombytes.h" +#include + +/************************************************* +* Name: encode_pk +* +* Description: Serialize the public key as concatenation of the +* serialization of the polynomial pk and the public seed +* used to generete the polynomial a. +* +* Arguments: unsigned char *r: pointer to the output serialized public key +* const poly *pk: pointer to the input public-key polynomial +* const unsigned char *seed: pointer to the input public seed +**************************************************/ +static void encode_pk(unsigned char *r, const poly *pk, const unsigned char *seed) { + int i; + PQCLEAN_NEWHOPE512CPA_CLEAN_poly_tobytes(r, pk); + for (i = 0; i < NEWHOPE_SYMBYTES; i++) { + r[NEWHOPE_POLYBYTES + i] = seed[i]; + } +} + +/************************************************* +* Name: decode_pk +* +* Description: De-serialize the public key; inverse of encode_pk +* +* Arguments: poly *pk: pointer to output public-key polynomial +* unsigned char *seed: pointer to output public seed +* const unsigned char *r: pointer to input byte array +**************************************************/ +static void decode_pk(poly *pk, unsigned char *seed, const unsigned char *r) { + int i; + PQCLEAN_NEWHOPE512CPA_CLEAN_poly_frombytes(pk, r); + for (i = 0; i < NEWHOPE_SYMBYTES; i++) { + seed[i] = r[NEWHOPE_POLYBYTES + i]; + } +} + +/************************************************* +* Name: encode_c +* +* Description: Serialize the ciphertext as concatenation of the +* serialization of the polynomial b and serialization +* of the compressed polynomial v +* +* Arguments: - unsigned char *r: pointer to the output serialized ciphertext +* - const poly *b: pointer to the input polynomial b +* - const poly *v: pointer to the input polynomial v +**************************************************/ +static void encode_c(unsigned char *r, const poly *b, const poly *v) { + PQCLEAN_NEWHOPE512CPA_CLEAN_poly_tobytes(r, b); + PQCLEAN_NEWHOPE512CPA_CLEAN_poly_compress(r + NEWHOPE_POLYBYTES, v); +} + +/************************************************* +* Name: decode_c +* +* Description: de-serialize the ciphertext; inverse of encode_c +* +* Arguments: - poly *b: pointer to output polynomial b +* - poly *v: pointer to output polynomial v +* - const unsigned char *r: pointer to input byte array +**************************************************/ +static void decode_c(poly *b, poly *v, const unsigned char *r) { + PQCLEAN_NEWHOPE512CPA_CLEAN_poly_frombytes(b, r); + PQCLEAN_NEWHOPE512CPA_CLEAN_poly_decompress(v, r + NEWHOPE_POLYBYTES); +} + +/************************************************* +* Name: gen_a +* +* Description: Deterministically generate public polynomial a from seed +* +* Arguments: - poly *a: pointer to output polynomial a +* - const unsigned char *seed: pointer to input seed +**************************************************/ +static void gen_a(poly *a, const unsigned char *seed) { + PQCLEAN_NEWHOPE512CPA_CLEAN_poly_uniform(a, seed); +} + + +/************************************************* +* Name: cpapke_keypair +* +* Description: Generates public and private key +* for the CPA public-key encryption scheme underlying +* the NewHope KEMs +* +* Arguments: - unsigned char *pk: pointer to output public key +* - unsigned char *sk: pointer to output private key +**************************************************/ +void PQCLEAN_NEWHOPE512CPA_CLEAN_cpapke_keypair(unsigned char *pk, + unsigned char *sk) { + poly ahat, ehat, ahat_shat, bhat, shat; + unsigned char z[2 * NEWHOPE_SYMBYTES]; + unsigned char *publicseed = z; + unsigned char *noiseseed = z + NEWHOPE_SYMBYTES; + + randombytes(z, NEWHOPE_SYMBYTES); + shake256(z, 2 * NEWHOPE_SYMBYTES, z, NEWHOPE_SYMBYTES); + + gen_a(&ahat, publicseed); + + PQCLEAN_NEWHOPE512CPA_CLEAN_poly_sample(&shat, noiseseed, 0); + PQCLEAN_NEWHOPE512CPA_CLEAN_poly_ntt(&shat); + + PQCLEAN_NEWHOPE512CPA_CLEAN_poly_sample(&ehat, noiseseed, 1); + PQCLEAN_NEWHOPE512CPA_CLEAN_poly_ntt(&ehat); + + PQCLEAN_NEWHOPE512CPA_CLEAN_poly_mul_pointwise(&ahat_shat, &shat, &ahat); + PQCLEAN_NEWHOPE512CPA_CLEAN_poly_add(&bhat, &ehat, &ahat_shat); + + PQCLEAN_NEWHOPE512CPA_CLEAN_poly_tobytes(sk, &shat); + encode_pk(pk, &bhat, publicseed); +} + +/************************************************* +* Name: cpapke_enc +* +* Description: Encryption function of +* the CPA public-key encryption scheme underlying +* the NewHope KEMs +* +* Arguments: - unsigned char *c: pointer to output ciphertext +* - const unsigned char *m: pointer to input message (of length NEWHOPE_SYMBYTES bytes) +* - const unsigned char *pk: pointer to input public key +* - const unsigned char *coin: pointer to input random coins used as seed +* to deterministically generate all randomness +**************************************************/ +void PQCLEAN_NEWHOPE512CPA_CLEAN_cpapke_enc(unsigned char *c, + const unsigned char *m, + const unsigned char *pk, + const unsigned char *coin) { + poly sprime, eprime, vprime, ahat, bhat, eprimeprime, uhat, v; + unsigned char publicseed[NEWHOPE_SYMBYTES]; + + PQCLEAN_NEWHOPE512CPA_CLEAN_poly_frommsg(&v, m); + + decode_pk(&bhat, publicseed, pk); + gen_a(&ahat, publicseed); + + PQCLEAN_NEWHOPE512CPA_CLEAN_poly_sample(&sprime, coin, 0); + PQCLEAN_NEWHOPE512CPA_CLEAN_poly_sample(&eprime, coin, 1); + PQCLEAN_NEWHOPE512CPA_CLEAN_poly_sample(&eprimeprime, coin, 2); + + PQCLEAN_NEWHOPE512CPA_CLEAN_poly_ntt(&sprime); + PQCLEAN_NEWHOPE512CPA_CLEAN_poly_ntt(&eprime); + + PQCLEAN_NEWHOPE512CPA_CLEAN_poly_mul_pointwise(&uhat, &ahat, &sprime); + PQCLEAN_NEWHOPE512CPA_CLEAN_poly_add(&uhat, &uhat, &eprime); + + PQCLEAN_NEWHOPE512CPA_CLEAN_poly_mul_pointwise(&vprime, &bhat, &sprime); + PQCLEAN_NEWHOPE512CPA_CLEAN_poly_invntt(&vprime); + + PQCLEAN_NEWHOPE512CPA_CLEAN_poly_add(&vprime, &vprime, &eprimeprime); + PQCLEAN_NEWHOPE512CPA_CLEAN_poly_add(&vprime, &vprime, &v); // add message + + encode_c(c, &uhat, &vprime); +} + + +/************************************************* +* Name: cpapke_dec +* +* Description: Decryption function of +* the CPA public-key encryption scheme underlying +* the NewHope KEMs +* +* Arguments: - unsigned char *m: pointer to output decrypted message +* - const unsigned char *c: pointer to input ciphertext +* - const unsigned char *sk: pointer to input secret key +**************************************************/ +void PQCLEAN_NEWHOPE512CPA_CLEAN_cpapke_dec(unsigned char *m, + const unsigned char *c, + const unsigned char *sk) { + poly vprime, uhat, tmp, shat; + + PQCLEAN_NEWHOPE512CPA_CLEAN_poly_frombytes(&shat, sk); + + decode_c(&uhat, &vprime, c); + PQCLEAN_NEWHOPE512CPA_CLEAN_poly_mul_pointwise(&tmp, &shat, &uhat); + PQCLEAN_NEWHOPE512CPA_CLEAN_poly_invntt(&tmp); + + PQCLEAN_NEWHOPE512CPA_CLEAN_poly_sub(&tmp, &tmp, &vprime); + + PQCLEAN_NEWHOPE512CPA_CLEAN_poly_tomsg(m, &tmp); +} diff --git a/crypto_kem/newhope512cpa/clean/cpapke.h b/crypto_kem/newhope512cpa/clean/cpapke.h new file mode 100644 index 00000000..43539e07 --- /dev/null +++ b/crypto_kem/newhope512cpa/clean/cpapke.h @@ -0,0 +1,16 @@ +#ifndef INDCPA_H +#define INDCPA_H + +void PQCLEAN_NEWHOPE512CPA_CLEAN_cpapke_keypair(unsigned char *pk, + unsigned char *sk); + +void PQCLEAN_NEWHOPE512CPA_CLEAN_cpapke_enc(unsigned char *c, + const unsigned char *m, + const unsigned char *pk, + const unsigned char *coins); + +void PQCLEAN_NEWHOPE512CPA_CLEAN_cpapke_dec(unsigned char *m, + const unsigned char *c, + const unsigned char *sk); + +#endif diff --git a/crypto_kem/newhope512cpa/clean/kem.c b/crypto_kem/newhope512cpa/clean/kem.c new file mode 100644 index 00000000..95fbd4ff --- /dev/null +++ b/crypto_kem/newhope512cpa/clean/kem.c @@ -0,0 +1,71 @@ +#include "api.h" +#include "cpapke.h" +#include "fips202.h" +#include "params.h" +#include "randombytes.h" +#include "verify.h" +#include + +/************************************************* +* Name: crypto_kem_keypair +* +* Description: Generates public and private key +* for CCA secure NewHope key encapsulation +* mechanism +* +* Arguments: - unsigned char *pk: pointer to output public key (an already allocated array of CRYPTO_PUBLICKEYBYTES bytes) +* - unsigned char *sk: pointer to output private key (an already allocated array of CRYPTO_SECRETKEYBYTES bytes) +* +* Returns 0 (success) +**************************************************/ +int PQCLEAN_NEWHOPE512CPA_CLEAN_crypto_kem_keypair(unsigned char *pk, unsigned char *sk) { + PQCLEAN_NEWHOPE512CPA_CLEAN_cpapke_keypair(pk, sk); /* First put the actual secret key into sk */ + + return 0; +} + +/************************************************* +* Name: crypto_kem_enc +* +* Description: Generates cipher text and shared +* secret for given public key +* +* Arguments: - unsigned char *ct: pointer to output cipher text (an already allocated array of CRYPTO_CIPHERTEXTBYTES bytes) +* - unsigned char *ss: pointer to output shared secret (an already allocated array of CRYPTO_BYTES bytes) +* - const unsigned char *pk: pointer to input public key (an already allocated array of CRYPTO_PUBLICKEYBYTES bytes) +* +* Returns 0 (success) +**************************************************/ +int PQCLEAN_NEWHOPE512CPA_CLEAN_crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk) { + unsigned char buf[2 * NEWHOPE_SYMBYTES]; + + randombytes(buf, NEWHOPE_SYMBYTES); + + shake256(buf, 2 * NEWHOPE_SYMBYTES, buf, NEWHOPE_SYMBYTES); /* Don't release system RNG output */ + + PQCLEAN_NEWHOPE512CPA_CLEAN_cpapke_enc(ct, buf, pk, buf + NEWHOPE_SYMBYTES); /* coins are in buf+NEWHOPE_SYMBYTES */ + + shake256(ss, NEWHOPE_SYMBYTES, buf, NEWHOPE_SYMBYTES); /* hash pre-k to ss */ + return 0; +} + + +/************************************************* +* Name: crypto_kem_dec +* +* Description: Generates shared secret for given +* cipher text and private key +* +* Arguments: - unsigned char *ss: pointer to output shared secret (an already allocated array of CRYPTO_BYTES bytes) +* - const unsigned char *ct: pointer to input cipher text (an already allocated array of CRYPTO_CIPHERTEXTBYTES bytes) +* - const unsigned char *sk: pointer to input private key (an already allocated array of CRYPTO_SECRETKEYBYTES bytes) +* +* Returns 0 (success) +**************************************************/ +int PQCLEAN_NEWHOPE512CPA_CLEAN_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk) { + PQCLEAN_NEWHOPE512CPA_CLEAN_cpapke_dec(ss, ct, sk); + + shake256(ss, NEWHOPE_SYMBYTES, ss, NEWHOPE_SYMBYTES); /* hash pre-k to ss */ + + return 0; +} diff --git a/crypto_kem/newhope512cpa/clean/ntt.c b/crypto_kem/newhope512cpa/clean/ntt.c new file mode 100644 index 00000000..7a449088 --- /dev/null +++ b/crypto_kem/newhope512cpa/clean/ntt.c @@ -0,0 +1,112 @@ +#include "inttypes.h" +#include "ntt.h" +#include "params.h" +#include "reduce.h" + +/************************************************************ +* Name: bitrev_table +* +* Description: Contains bit-reversed 9-bit indices to be used to re-order +* polynomials before number theoratic transform +************************************************************/ +static uint16_t bitrev_table [512] = { + 0, 256, 128, 384, 64, 320, 192, 448, 32, 288, 160, 416, 96, 352, 224, 480, 16, 272, 144, 400, 80, 336, 208, 464, 48, 304, 176, 432, 112, 368, 240, 496, 8, + 264, 136, 392, 72, 328, 200, 456, 40, 296, 168, 424, 104, 360, 232, 488, 24, 280, 152, 408, 88, 344, 216, 472, 56, 312, 184, 440, 120, 376, 248, 504, 4, + 260, 132, 388, 68, 324, 196, 452, 36, 292, 164, 420, 100, 356, 228, 484, 20, 276, 148, 404, 84, 340, 212, 468, 52, 308, 180, 436, 116, 372, 244, 500, 12, + 268, 140, 396, 76, 332, 204, 460, 44, 300, 172, 428, 108, 364, 236, 492, 28, 284, 156, 412, 92, 348, 220, 476, 60, 316, 188, 444, 124, 380, 252, 508, 2, + 258, 130, 386, 66, 322, 194, 450, 34, 290, 162, 418, 98, 354, 226, 482, 18, 274, 146, 402, 82, 338, 210, 466, 50, 306, 178, 434, 114, 370, 242, 498, 10, + 266, 138, 394, 74, 330, 202, 458, 42, 298, 170, 426, 106, 362, 234, 490, 26, 282, 154, 410, 90, 346, 218, 474, 58, 314, 186, 442, 122, 378, 250, 506, 6, + 262, 134, 390, 70, 326, 198, 454, 38, 294, 166, 422, 102, 358, 230, 486, 22, 278, 150, 406, 86, 342, 214, 470, 54, 310, 182, 438, 118, 374, 246, 502, 14, + 270, 142, 398, 78, 334, 206, 462, 46, 302, 174, 430, 110, 366, 238, 494, 30, 286, 158, 414, 94, 350, 222, 478, 62, 318, 190, 446, 126, 382, 254, 510, 1, + 257, 129, 385, 65, 321, 193, 449, 33, 289, 161, 417, 97, 353, 225, 481, 17, 273, 145, 401, 81, 337, 209, 465, 49, 305, 177, 433, 113, 369, 241, 497, 9, + 265, 137, 393, 73, 329, 201, 457, 41, 297, 169, 425, 105, 361, 233, 489, 25, 281, 153, 409, 89, 345, 217, 473, 57, 313, 185, 441, 121, 377, 249, 505, 5, + 261, 133, 389, 69, 325, 197, 453, 37, 293, 165, 421, 101, 357, 229, 485, 21, 277, 149, 405, 85, 341, 213, 469, 53, 309, 181, 437, 117, 373, 245, 501, 13, + 269, 141, 397, 77, 333, 205, 461, 45, 301, 173, 429, 109, 365, 237, 493, 29, 285, 157, 413, 93, 349, 221, 477, 61, 317, 189, 445, 125, 381, 253, 509, 3, + 259, 131, 387, 67, 323, 195, 451, 35, 291, 163, 419, 99, 355, 227, 483, 19, 275, 147, 403, 83, 339, 211, 467, 51, 307, 179, 435, 115, 371, 243, 499, 11, + 267, 139, 395, 75, 331, 203, 459, 43, 299, 171, 427, 107, 363, 235, 491, 27, 283, 155, 411, 91, 347, 219, 475, 59, 315, 187, 443, 123, 379, 251, 507, 7, + 263, 135, 391, 71, 327, 199, 455, 39, 295, 167, 423, 103, 359, 231, 487, 23, 279, 151, 407, 87, 343, 215, 471, 55, 311, 183, 439, 119, 375, 247, 503, 15, + 271, 143, 399, 79, 335, 207, 463, 47, 303, 175, 431, 111, 367, 239, 495, 31, 287, 159, 415, 95, 351, 223, 479, 63, 319, 191, 447, 127, 383, 255, 511 +}; + +/************************************************* +* Name: bitrev_vector +* +* Description: Permutes coefficients of a polynomial into bitreversed order +* +* Arguments: - uint16_t* poly: pointer to in/output polynomial +**************************************************/ +void PQCLEAN_NEWHOPE512CPA_CLEAN_bitrev_vector(uint16_t *poly) { + unsigned int i, r; + uint16_t tmp; + + for (i = 0; i < NEWHOPE_N; i++) { + r = bitrev_table[i]; + if (i < r) { + tmp = poly[i]; + poly[i] = poly[r]; + poly[r] = tmp; + } + } +} + +/************************************************* +* Name: mul_coefficients +* +* Description: Performs pointwise (coefficient-wise) multiplication +* of two polynomials +* Arguments: - uint16_t* poly: pointer to in/output polynomial +* - const uint16_t* factors: pointer to input polynomial, coefficients +* are assumed to be in Montgomery representation +**************************************************/ +void PQCLEAN_NEWHOPE512CPA_CLEAN_mul_coefficients(uint16_t *poly, const uint16_t *factors) { + unsigned int i; + + for (i = 0; i < NEWHOPE_N; i++) { + poly[i] = PQCLEAN_NEWHOPE512CPA_CLEAN_montgomery_reduce((poly[i] * factors[i])); + } +} + + +/************************************************* +* Name: ntt +* +* Description: Computes number-theoretic transform (NTT) of +* a polynomial in place; inputs assumed to be in +* bitreversed order, output in normal order +* +* Arguments: - uint16_t * a: pointer to in/output polynomial +* - const uint16_t* omega: pointer to input powers of root of unity omega; +* assumed to be in Montgomery domain +**************************************************/ +void PQCLEAN_NEWHOPE512CPA_CLEAN_ntt(uint16_t *a, const uint16_t *omega) { + int i, start, j, jTwiddle, distance; + uint16_t temp, W; + + + for (i = 0; i < 9; i += 2) { + // Even level + distance = (1 << i); + for (start = 0; start < distance; start++) { + jTwiddle = 0; + for (j = start; j < NEWHOPE_N - 1; j += 2 * distance) { + W = omega[jTwiddle++]; + temp = a[j]; + a[j] = (temp + a[j + distance]); // Omit reduction (be lazy) + a[j + distance] = PQCLEAN_NEWHOPE512CPA_CLEAN_montgomery_reduce((W * ((uint32_t)temp + 3 * NEWHOPE_Q - a[j + distance]))); + } + } + if (i + 1 < 9) { + // Odd level + distance <<= 1; + for (start = 0; start < distance; start++) { + jTwiddle = 0; + for (j = start; j < NEWHOPE_N - 1; j += 2 * distance) { + W = omega[jTwiddle++]; + temp = a[j]; + a[j] = (temp + a[j + distance]) % NEWHOPE_Q; + a[j + distance] = PQCLEAN_NEWHOPE512CPA_CLEAN_montgomery_reduce((W * ((uint32_t)temp + 3 * NEWHOPE_Q - a[j + distance]))); + } + } + } + } +} diff --git a/crypto_kem/newhope512cpa/clean/ntt.h b/crypto_kem/newhope512cpa/clean/ntt.h new file mode 100644 index 00000000..6d17c247 --- /dev/null +++ b/crypto_kem/newhope512cpa/clean/ntt.h @@ -0,0 +1,14 @@ +#ifndef NTT_H +#define NTT_H + +#include "inttypes.h" + +extern const uint16_t PQCLEAN_NEWHOPE512CPA_CLEAN_omegas_inv_bitrev_montgomery[]; +extern const uint16_t PQCLEAN_NEWHOPE512CPA_CLEAN_gammas_bitrev_montgomery[]; +extern const uint16_t PQCLEAN_NEWHOPE512CPA_CLEAN_gammas_inv_montgomery[]; + +void PQCLEAN_NEWHOPE512CPA_CLEAN_bitrev_vector(uint16_t *poly); +void PQCLEAN_NEWHOPE512CPA_CLEAN_mul_coefficients(uint16_t *poly, const uint16_t *factors); +void PQCLEAN_NEWHOPE512CPA_CLEAN_ntt(uint16_t *a, const uint16_t *omegas); + +#endif diff --git a/crypto_kem/newhope512cpa/clean/params.h b/crypto_kem/newhope512cpa/clean/params.h new file mode 100644 index 00000000..f9de0856 --- /dev/null +++ b/crypto_kem/newhope512cpa/clean/params.h @@ -0,0 +1,25 @@ +#ifndef PQCLEAN_NEWHOPE512CPA_CLEAN_PARAMS_H +#define PQCLEAN_NEWHOPE512CPA_CLEAN_PARAMS_H + +#define NEWHOPE_N 512 +#define NEWHOPE_Q 12289 +#define NEWHOPE_K 8 /* used in noise sampling */ + +#define NEWHOPE_SYMBYTES 32 /* size of shared key, seeds/coins, and hashes */ + +#define NEWHOPE_POLYBYTES ((14*NEWHOPE_N)/8) +#define NEWHOPE_POLYCOMPRESSEDBYTES (( 3*NEWHOPE_N)/8) + +#define NEWHOPE_CPAPKE_PUBLICKEYBYTES (NEWHOPE_POLYBYTES + NEWHOPE_SYMBYTES) +#define NEWHOPE_CPAPKE_SECRETKEYBYTES (NEWHOPE_POLYBYTES) +#define NEWHOPE_CPAPKE_CIPHERTEXTBYTES (NEWHOPE_POLYBYTES + NEWHOPE_POLYCOMPRESSEDBYTES) + +#define NEWHOPE_CPAKEM_PUBLICKEYBYTES NEWHOPE_CPAPKE_PUBLICKEYBYTES +#define NEWHOPE_CPAKEM_SECRETKEYBYTES NEWHOPE_CPAPKE_SECRETKEYBYTES +#define NEWHOPE_CPAKEM_CIPHERTEXTBYTES NEWHOPE_CPAPKE_CIPHERTEXTBYTES + +#define NEWHOPE_CCAKEM_PUBLICKEYBYTES NEWHOPE_CPAPKE_PUBLICKEYBYTES +#define NEWHOPE_CCAKEM_SECRETKEYBYTES (NEWHOPE_CPAPKE_SECRETKEYBYTES + NEWHOPE_CPAPKE_PUBLICKEYBYTES + 2*NEWHOPE_SYMBYTES) +#define NEWHOPE_CCAKEM_CIPHERTEXTBYTES (NEWHOPE_CPAPKE_CIPHERTEXTBYTES + NEWHOPE_SYMBYTES) /* Second part is for Targhi-Unruh */ + +#endif diff --git a/crypto_kem/newhope512cpa/clean/poly.c b/crypto_kem/newhope512cpa/clean/poly.c new file mode 100644 index 00000000..6bd47ae6 --- /dev/null +++ b/crypto_kem/newhope512cpa/clean/poly.c @@ -0,0 +1,353 @@ +#include "fips202.h" +#include "ntt.h" +#include "poly.h" +#include "reduce.h" + +/************************************************* +* Name: coeff_freeze +* +* Description: Fully reduces an integer modulo q in constant time +* +* Arguments: uint16_t x: input integer to be reduced +* +* Returns integer in {0,...,q-1} congruent to x modulo q +**************************************************/ +static uint16_t coeff_freeze(uint16_t x) { + uint16_t m, r; + int16_t c; + r = x % NEWHOPE_Q; + + m = r - NEWHOPE_Q; + c = m; + c >>= 15; + r = m ^ ((r ^ m)&c); + + return r; +} + +/************************************************* +* Name: flipabs +* +* Description: Computes |(x mod q) - Q/2| +* +* Arguments: uint16_t x: input coefficient +* +* Returns |(x mod q) - Q/2| +**************************************************/ +static uint16_t flipabs(uint16_t x) { + int16_t r, m; + r = coeff_freeze(x); + + r = r - NEWHOPE_Q / 2; + m = r >> 15; + return (r + m) ^ m; +} + +/************************************************* +* Name: poly_frombytes +* +* Description: De-serialization of a polynomial +* +* Arguments: - poly *r: pointer to output polynomial +* - const unsigned char *a: pointer to input byte array +**************************************************/ +void PQCLEAN_NEWHOPE512CPA_CLEAN_poly_frombytes(poly *r, const unsigned char *a) { + int i; + for (i = 0; i < NEWHOPE_N / 4; i++) { + r->coeffs[4 * i + 0] = a[7 * i + 0] | (((uint16_t)a[7 * i + 1] & 0x3f) << 8); + r->coeffs[4 * i + 1] = (a[7 * i + 1] >> 6) | (((uint16_t)a[7 * i + 2]) << 2) | (((uint16_t)a[7 * i + 3] & 0x0f) << 10); + r->coeffs[4 * i + 2] = (a[7 * i + 3] >> 4) | (((uint16_t)a[7 * i + 4]) << 4) | (((uint16_t)a[7 * i + 5] & 0x03) << 12); + r->coeffs[4 * i + 3] = (a[7 * i + 5] >> 2) | (((uint16_t)a[7 * i + 6]) << 6); + } +} + +/************************************************* +* Name: poly_tobytes +* +* Description: Serialization of a polynomial +* +* Arguments: - unsigned char *r: pointer to output byte array +* - const poly *p: pointer to input polynomial +**************************************************/ +void PQCLEAN_NEWHOPE512CPA_CLEAN_poly_tobytes(unsigned char *r, const poly *p) { + int i; + uint16_t t0, t1, t2, t3; + for (i = 0; i < NEWHOPE_N / 4; i++) { + t0 = coeff_freeze(p->coeffs[4 * i + 0]); + t1 = coeff_freeze(p->coeffs[4 * i + 1]); + t2 = coeff_freeze(p->coeffs[4 * i + 2]); + t3 = coeff_freeze(p->coeffs[4 * i + 3]); + + r[7 * i + 0] = t0 & 0xff; + r[7 * i + 1] = (unsigned char) ((t0 >> 8) | (t1 << 6)); + r[7 * i + 2] = (unsigned char) ((t1 >> 2)); + r[7 * i + 3] = (unsigned char) ((t1 >> 10) | (t2 << 4)); + r[7 * i + 4] = (unsigned char) ((t2 >> 4)); + r[7 * i + 5] = (unsigned char) ((t2 >> 12) | (t3 << 2)); + r[7 * i + 6] = (unsigned char) ((t3 >> 6)); + } +} + +/************************************************* +* Name: poly_compress +* +* Description: Compression and subsequent serialization of a polynomial +* +* Arguments: - unsigned char *r: pointer to output byte array +* - const poly *p: pointer to input polynomial +**************************************************/ +void PQCLEAN_NEWHOPE512CPA_CLEAN_poly_compress(unsigned char *r, const poly *p) { + unsigned int i, j, k = 0; + + uint32_t t[8]; + + for (i = 0; i < NEWHOPE_N; i += 8) { + for (j = 0; j < 8; j++) { + t[j] = coeff_freeze(p->coeffs[i + j]); + t[j] = (((t[j] << 3) + NEWHOPE_Q / 2) / NEWHOPE_Q) & 0x7; + } + + r[k] = (unsigned char) (t[0] | (t[1] << 3) | (t[2] << 6)); + r[k + 1] = (unsigned char) ((t[2] >> 2) | (t[3] << 1) | (t[4] << 4) | (t[5] << 7)); + r[k + 2] = (unsigned char) ((t[5] >> 1) | (t[6] << 2) | (t[7] << 5)); + k += 3; + } +} + +/************************************************* +* Name: poly_decompress +* +* Description: De-serialization and subsequent decompression of a polynomial; +* approximate inverse of poly_compress +* +* Arguments: - poly *r: pointer to output polynomial +* - const unsigned char *a: pointer to input byte array +**************************************************/ +void PQCLEAN_NEWHOPE512CPA_CLEAN_poly_decompress(poly *r, const unsigned char *a) { + unsigned int i, j; + for (i = 0; i < NEWHOPE_N; i += 8) { + r->coeffs[i + 0] = a[0] & 7; + r->coeffs[i + 1] = (a[0] >> 3) & 7; + r->coeffs[i + 2] = (a[0] >> 6) | ((a[1] << 2) & 4); + r->coeffs[i + 3] = (a[1] >> 1) & 7; + r->coeffs[i + 4] = (a[1] >> 4) & 7; + r->coeffs[i + 5] = (a[1] >> 7) | ((a[2] << 1) & 6); + r->coeffs[i + 6] = (a[2] >> 2) & 7; + r->coeffs[i + 7] = (a[2] >> 5); + a += 3; + for (j = 0; j < 8; j++) { + r->coeffs[i + j] = ((uint32_t)r->coeffs[i + j] * NEWHOPE_Q + 4) >> 3; + } + } +} + +/************************************************* +* Name: poly_frommsg +* +* Description: Convert 32-byte message to polynomial +* +* Arguments: - poly *r: pointer to output polynomial +* - const unsigned char *msg: pointer to input message +**************************************************/ +void PQCLEAN_NEWHOPE512CPA_CLEAN_poly_frommsg(poly *r, const unsigned char *msg) { + unsigned int i, j, mask; + for (i = 0; i < NEWHOPE_SYMBYTES; i++) { + for (j = 0; j < 8; j++) { + mask = -((msg[i] >> j) & 1); + r->coeffs[8 * i + j + 0] = mask & (NEWHOPE_Q / 2); + r->coeffs[8 * i + j + 256] = mask & (NEWHOPE_Q / 2); + } + } +} + +/************************************************* +* Name: poly_tomsg +* +* Description: Convert polynomial to 32-byte message +* +* Arguments: - unsigned char *msg: pointer to output message +* - const poly *x: pointer to input polynomial +**************************************************/ +void PQCLEAN_NEWHOPE512CPA_CLEAN_poly_tomsg(unsigned char *msg, const poly *x) { + unsigned int i; + uint16_t t; + + for (i = 0; i < 32; i++) { + msg[i] = 0; + } + + for (i = 0; i < 256; i++) { + t = flipabs(x->coeffs[i + 0]); + t += flipabs(x->coeffs[i + 256]); + t = ((t - NEWHOPE_Q / 2)); + + t >>= 15; + msg[i >> 3] |= t << (i & 7); + } +} + +/************************************************* +* Name: poly_uniform +* +* Description: Sample a polynomial deterministically from a seed, +* with output polynomial looking uniformly random +* +* Arguments: - poly *a: pointer to output polynomial +* - const unsigned char *seed: pointer to input seed +**************************************************/ +void PQCLEAN_NEWHOPE512CPA_CLEAN_poly_uniform(poly *a, const unsigned char *seed) { + unsigned int ctr = 0; + uint16_t val; + shake128ctx state; + uint8_t buf[SHAKE128_RATE]; + uint8_t extseed[NEWHOPE_SYMBYTES + 1]; + int i, j; + + for (i = 0; i < NEWHOPE_SYMBYTES; i++) { + extseed[i] = seed[i]; + } + + for (i = 0; i < NEWHOPE_N / 64; i++) { /* generate a in blocks of 64 coefficients */ + ctr = 0; + extseed[NEWHOPE_SYMBYTES] = (unsigned char) i; /* domain-separate the 16 independent calls */ + shake128_absorb(&state, extseed, NEWHOPE_SYMBYTES + 1); + while (ctr < 64) { /* Very unlikely to run more than once */ + shake128_squeezeblocks(buf, 1, &state); + for (j = 0; j < SHAKE128_RATE && ctr < 64; j += 2) { + val = (buf[j] | ((uint16_t) buf[j + 1] << 8)); + if (val < 5 * NEWHOPE_Q) { + a->coeffs[i * 64 + ctr] = val; + ctr++; + } + } + } + } +} + +/************************************************* +* Name: hw +* +* Description: Compute the Hamming weight of a byte +* +* Arguments: - unsigned char a: input byte +**************************************************/ +static unsigned char hw(unsigned char a) { + unsigned char i, r = 0; + for (i = 0; i < 8; i++) { + r += (a >> i) & 1; + } + return r; +} + +/************************************************* +* Name: poly_sample +* +* Description: Sample a polynomial deterministically from a seed and a nonce, +* with output polynomial close to centered binomial distribution +* with parameter k=8 +* +* Arguments: - poly *r: pointer to output polynomial +* - const unsigned char *seed: pointer to input seed +* - unsigned char nonce: one-byte input nonce +**************************************************/ +void PQCLEAN_NEWHOPE512CPA_CLEAN_poly_sample(poly *r, const unsigned char *seed, unsigned char nonce) { + unsigned char buf[128], a, b; + int i, j; + + unsigned char extseed[NEWHOPE_SYMBYTES + 2]; + + for (i = 0; i < NEWHOPE_SYMBYTES; i++) { + extseed[i] = seed[i]; + } + extseed[NEWHOPE_SYMBYTES] = nonce; + + for (i = 0; i < NEWHOPE_N / 64; i++) { /* Generate noise in blocks of 64 coefficients */ + extseed[NEWHOPE_SYMBYTES + 1] = (unsigned char) i; + shake256(buf, 128, extseed, NEWHOPE_SYMBYTES + 2); + for (j = 0; j < 64; j++) { + a = buf[2 * j]; + b = buf[2 * j + 1]; + r->coeffs[64 * i + j] = hw(a) + NEWHOPE_Q - hw(b); + } + } +} + +/************************************************* +* Name: poly_pointwise +* +* Description: Multiply two polynomials pointwise (i.e., coefficient-wise). +* +* Arguments: - poly *r: pointer to output polynomial +* - const poly *a: pointer to first input polynomial +* - const poly *b: pointer to second input polynomial +**************************************************/ +void PQCLEAN_NEWHOPE512CPA_CLEAN_poly_mul_pointwise(poly *r, const poly *a, const poly *b) { + int i; + uint16_t t; + for (i = 0; i < NEWHOPE_N; i++) { + t = PQCLEAN_NEWHOPE512CPA_CLEAN_montgomery_reduce(3186 * b->coeffs[i]); /* t is now in Montgomery domain */ + r->coeffs[i] = PQCLEAN_NEWHOPE512CPA_CLEAN_montgomery_reduce(a->coeffs[i] * t); /* r->coeffs[i] is back in normal domain */ + } +} + +/************************************************* +* Name: poly_add +* +* Description: Add two polynomials +* +* Arguments: - poly *r: pointer to output polynomial +* - const poly *a: pointer to first input polynomial +* - const poly *b: pointer to second input polynomial +**************************************************/ +void PQCLEAN_NEWHOPE512CPA_CLEAN_poly_add(poly *r, const poly *a, const poly *b) { + int i; + for (i = 0; i < NEWHOPE_N; i++) { + r->coeffs[i] = (a->coeffs[i] + b->coeffs[i]) % NEWHOPE_Q; + } +} + +/************************************************* +* Name: poly_sub +* +* Description: Subtract two polynomials +* +* Arguments: - poly *r: pointer to output polynomial +* - const poly *a: pointer to first input polynomial +* - const poly *b: pointer to second input polynomial +**************************************************/ +void PQCLEAN_NEWHOPE512CPA_CLEAN_poly_sub(poly *r, const poly *a, const poly *b) { + int i; + for (i = 0; i < NEWHOPE_N; i++) { + r->coeffs[i] = (a->coeffs[i] + 3 * NEWHOPE_Q - b->coeffs[i]) % NEWHOPE_Q; + } +} + +/************************************************* +* Name: poly_ntt +* +* Description: Forward NTT transform of a polynomial in place +* Input is assumed to have coefficients in bitreversed order +* Output has coefficients in normal order +* +* Arguments: - poly *r: pointer to in/output polynomial +**************************************************/ +void PQCLEAN_NEWHOPE512CPA_CLEAN_poly_ntt(poly *r) { + PQCLEAN_NEWHOPE512CPA_CLEAN_mul_coefficients(r->coeffs, PQCLEAN_NEWHOPE512CPA_CLEAN_gammas_bitrev_montgomery); + PQCLEAN_NEWHOPE512CPA_CLEAN_ntt((uint16_t *)r->coeffs, PQCLEAN_NEWHOPE512CPA_CLEAN_gammas_bitrev_montgomery); +} + +/************************************************* +* Name: poly_invntt +* +* Description: Inverse NTT transform of a polynomial in place +* Input is assumed to have coefficients in normal order +* Output has coefficients in normal order +* +* Arguments: - poly *r: pointer to in/output polynomial +**************************************************/ +void PQCLEAN_NEWHOPE512CPA_CLEAN_poly_invntt(poly *r) { + PQCLEAN_NEWHOPE512CPA_CLEAN_bitrev_vector(r->coeffs); + PQCLEAN_NEWHOPE512CPA_CLEAN_ntt((uint16_t *)r->coeffs, PQCLEAN_NEWHOPE512CPA_CLEAN_omegas_inv_bitrev_montgomery); + PQCLEAN_NEWHOPE512CPA_CLEAN_mul_coefficients(r->coeffs, PQCLEAN_NEWHOPE512CPA_CLEAN_gammas_inv_montgomery); +} + diff --git a/crypto_kem/newhope512cpa/clean/poly.h b/crypto_kem/newhope512cpa/clean/poly.h new file mode 100644 index 00000000..18b5e9a9 --- /dev/null +++ b/crypto_kem/newhope512cpa/clean/poly.h @@ -0,0 +1,32 @@ +#ifndef POLY_H +#define POLY_H + +#include "params.h" +#include + +/* + * Elements of R_q = Z_q[X]/(X^n + 1). Represents polynomial + * coeffs[0] + X*coeffs[1] + X^2*xoeffs[2] + ... + X^{n-1}*coeffs[n-1] + */ +typedef struct { + uint16_t coeffs[NEWHOPE_N]; +} poly; + +void PQCLEAN_NEWHOPE512CPA_CLEAN_poly_uniform(poly *a, const unsigned char *seed); +void PQCLEAN_NEWHOPE512CPA_CLEAN_poly_sample(poly *r, const unsigned char *seed, unsigned char nonce); +void PQCLEAN_NEWHOPE512CPA_CLEAN_poly_add(poly *r, const poly *a, const poly *b); + +void PQCLEAN_NEWHOPE512CPA_CLEAN_poly_ntt(poly *r); +void PQCLEAN_NEWHOPE512CPA_CLEAN_poly_invntt(poly *r); +void PQCLEAN_NEWHOPE512CPA_CLEAN_poly_mul_pointwise(poly *r, const poly *a, const poly *b); + +void PQCLEAN_NEWHOPE512CPA_CLEAN_poly_frombytes(poly *r, const unsigned char *a); +void PQCLEAN_NEWHOPE512CPA_CLEAN_poly_tobytes(unsigned char *r, const poly *p); +void PQCLEAN_NEWHOPE512CPA_CLEAN_poly_compress(unsigned char *r, const poly *p); +void PQCLEAN_NEWHOPE512CPA_CLEAN_poly_decompress(poly *r, const unsigned char *a); + +void PQCLEAN_NEWHOPE512CPA_CLEAN_poly_frommsg(poly *r, const unsigned char *msg); +void PQCLEAN_NEWHOPE512CPA_CLEAN_poly_tomsg(unsigned char *msg, const poly *x); +void PQCLEAN_NEWHOPE512CPA_CLEAN_poly_sub(poly *r, const poly *a, const poly *b); + +#endif diff --git a/crypto_kem/newhope512cpa/clean/precomp.c b/crypto_kem/newhope512cpa/clean/precomp.c new file mode 100644 index 00000000..039d671b --- /dev/null +++ b/crypto_kem/newhope512cpa/clean/precomp.c @@ -0,0 +1,179 @@ +#include "inttypes.h" +#include "ntt.h" +#include "params.h" + +/* Precomputed NTT contants generated by Pari/GP script as follows: + * + * For n = 512: + * + * brv = [0,256,128,384,64,320,192,448,32,288,160,416,96,352,224,480,16,272,144,400,80,336,208,464,48,304,176,432,112,368,240,496,8, + * 264,136,392,72,328,200,456,40,296,168,424,104,360,232,488,24,280,152,408,88,344,216,472,56,312,184,440,120,376,248,504,4, + * 260,132,388,68,324,196,452,36,292,164,420,100,356,228,484,20,276,148,404,84,340,212,468,52,308,180,436,116,372,244,500,12, + * 268,140,396,76,332,204,460,44,300,172,428,108,364,236,492,28,284,156,412,92,348,220,476,60,316,188,444,124,380,252,508,2, + * 258,130,386,66,322,194,450,34,290,162,418,98,354,226,482,18,274,146,402,82,338,210,466,50,306,178,434,114,370,242,498,10, + * 266,138,394,74,330,202,458,42,298,170,426,106,362,234,490,26,282,154,410,90,346,218,474,58,314,186,442,122,378,250,506,6, + * 262,134,390,70,326,198,454,38,294,166,422,102,358,230,486,22,278,150,406,86,342,214,470,54,310,182,438,118,374,246,502,14, + * 270,142,398,78,334,206,462,46,302,174,430,110,366,238,494,30,286,158,414,94,350,222,478,62,318,190,446,126,382,254,510,1, + * 257,129,385,65,321,193,449,33,289,161,417,97,353,225,481,17,273,145,401,81,337,209,465,49,305,177,433,113,369,241,497,9, + * 265,137,393,73,329,201,457,41,297,169,425,105,361,233,489,25,281,153,409,89,345,217,473,57,313,185,441,121,377,249,505,5, + * 261,133,389,69,325,197,453,37,293,165,421,101,357,229,485,21,277,149,405,85,341,213,469,53,309,181,437,117,373,245,501,13, + * 269,141,397,77,333,205,461,45,301,173,429,109,365,237,493,29,285,157,413,93,349,221,477,61,317,189,445,125,381,253,509,3, + * 259,131,387,67,323,195,451,35,291,163,419,99,355,227,483,19,275,147,403,83,339,211,467,51,307,179,435,115,371,243,499,11, + * 267,139,395,75,331,203,459,43,299,171,427,107,363,235,491,27,283,155,411,91,347,219,475,59,315,187,443,123,379,251,507,7, + * 263,135,391,71,327,199,455,39,295,167,423,103,359,231,487,23,279,151,407,87,343,215,471,55,311,183,439,119,375,247,503,15, + * 271,143,399,79,335,207,463,47,303,175,431,111,367,239,495,31,287,159,415,95,351,223,479,63,319,191,447,127,383,255,511] + * n = 512; q = 12289; mont=2^18 + * g = Mod(10968, q); + * omegas_inv_bitrev_montgomery = lift(vector(n/2, i, (g^2)^(-brv[2*(i-1)+1])*mont)) + * gammas_bitrev_montgomery = lift(vector(n, i, g^(brv[i])*mont)) + * gammas_inv_montgomery = lift(vector(n, i, g^(-(i-1))/n*mont)) + * + * + * For n = 1024: + * + * brv = [0,512,256,768,128,640,384,896,64,576,320,832,192,704,448,960,32,544,288,800,160,672,416,928,96,608,352,864,224,736,480,992, \ + * 16,528,272,784,144,656,400,912,80,592,336,848,208,720,464,976,48,560,304,816,176,688,432,944,112,624,368,880,240,752,496,1008, \ + * 8,520,264,776,136,648,392,904,72,584,328,840,200,712,456,968,40,552,296,808,168,680,424,936,104,616,360,872,232,744,488,1000, \ + * 24,536,280,792,152,664,408,920,88,600,344,856,216,728,472,984,56,568,312,824,184,696,440,952,120,632,376,888,248,760,504,1016, \ + * 4,516,260,772,132,644,388,900,68,580,324,836,196,708,452,964,36,548,292,804,164,676,420,932,100,612,356,868,228,740,484,996, \ + * 20,532,276,788,148,660,404,916,84,596,340,852,212,724,468,980,52,564,308,820,180,692,436,948,116,628,372,884,244,756,500,1012, \ + * 12,524,268,780,140,652,396,908,76,588,332,844,204,716,460,972,44,556,300,812,172,684,428,940,108,620,364,876,236,748,492,1004, \ + * 28,540,284,796,156,668,412,924,92,604,348,860,220,732,476,988,60,572,316,828,188,700,444,956,124,636,380,892,252,764,508,1020, \ + * 2,514,258,770,130,642,386,898,66,578,322,834,194,706,450,962,34,546,290,802,162,674,418,930,98,610,354,866,226,738,482,994, \ + * 18,530,274,786,146,658,402,914,82,594,338,850,210,722,466,978,50,562,306,818,178,690,434,946,114,626,370,882,242,754,498,1010, \ + * 10,522,266,778,138,650,394,906,74,586,330,842,202,714,458,970,42,554,298,810,170,682,426,938,106,618,362,874,234,746,490,1002, \ + * 26,538,282,794,154,666,410,922,90,602,346,858,218,730,474,986,58,570,314,826,186,698,442,954,122,634,378,890,250,762,506,1018, \ + * 6,518,262,774,134,646,390,902,70,582,326,838,198,710,454,966,38,550,294,806,166,678,422,934,102,614,358,870,230,742,486,998, \ + * 22,534,278,790,150,662,406,918,86,598,342,854,214,726,470,982,54,566,310,822,182,694,438,950,118,630,374,886,246,758,502,1014, \ + * 14,526,270,782,142,654,398,910,78,590,334,846,206,718,462,974,46,558,302,814,174,686,430,942,110,622,366,878,238,750,494,1006, \ + * 30,542,286,798,158,670,414,926,94,606,350,862,222,734,478,990,62,574,318,830,190,702,446,958,126,638,382,894,254,766,510,1022, \ + * 1,513,257,769,129,641,385,897,65,577,321,833,193,705,449,961,33,545,289,801,161,673,417,929,97,609,353,865,225,737,481,993, \ + * 17,529,273,785,145,657,401,913,81,593,337,849,209,721,465,977,49,561,305,817,177,689,433,945,113,625,369,881,241,753,497,1009, \ + * 9,521,265,777,137,649,393,905,73,585,329,841,201,713,457,969,41,553,297,809,169,681,425,937,105,617,361,873,233,745,489,1001, \ + * 25,537,281,793,153,665,409,921,89,601,345,857,217,729,473,985,57,569,313,825,185,697,441,953,121,633,377,889,249,761,505,1017, \ + * 5,517,261,773,133,645,389,901,69,581,325,837,197,709,453,965,37,549,293,805,165,677,421,933,101,613,357,869,229,741,485,997, \ + * 21,533,277,789,149,661,405,917,85,597,341,853,213,725,469,981,53,565,309,821,181,693,437,949,117,629,373,885,245,757,501,1013, \ + * 13,525,269,781,141,653,397,909,77,589,333,845,205,717,461,973,45,557,301,813,173,685,429,941,109,621,365,877,237,749,493,1005, \ + * 29,541,285,797,157,669,413,925,93,605,349,861,221,733,477,989,61,573,317,829,189,701,445,957,125,637,381,893,253,765,509,1021, \ + * 3,515,259,771,131,643,387,899,67,579,323,835,195,707,451,963,35,547,291,803,163,675,419,931,99,611,355,867,227,739,483,995, \ + * 19,531,275,787,147,659,403,915,83,595,339,851,211,723,467,979,51,563,307,819,179,691,435,947,115,627,371,883,243,755,499,1011, \ + * 11,523,267,779,139,651,395,907,75,587,331,843,203,715,459,971,43,555,299,811,171,683,427,939,107,619,363,875,235,747,491,1003, \ + * 27,539,283,795,155,667,411,923,91,603,347,859,219,731,475,987,59,571,315,827,187,699,443,955,123,635,379,891,251,763,507,1019, \ + * 7,519,263,775,135,647,391,903,71,583,327,839,199,711,455,967,39,551,295,807,167,679,423,935,103,615,359,871,231,743,487,999, \ + * 23,535,279,791,151,663,407,919,87,599,343,855,215,727,471,983,55,567,311,823,183,695,439,951,119,631,375,887,247,759,503,1015, \ + * 15,527,271,783,143,655,399,911,79,591,335,847,207,719,463,975,47,559,303,815,175,687,431,943,111,623,367,879,239,751,495,1007, \ + * 31,543,287,799,159,671,415,927,95,607,351,863,223,735,479,991,63,575,319,831,191,703,447,959,127,639,383,895,255,767,511,1023] + * + * n = 1024; q = 12289; mont=2^18 + * g = Mod(7, q); + * omegas_inv_bitrev_montgomery = lift(vector(n/2, i, (g^2)^(-brv[2*(i-1)+1])*mont)) + * gammas_bitrev_montgomery = lift(vector(n, i, g^(brv[i])*mont)) + * gammas_inv_montgomery = lift(vector(n, i, g^(-(i-1))/n*mont)) +*/ + +/************************************************************ +* Name: omegas_inv_bitrev_montgomery +* +* Description: Contains inverses of powers of nth root of unity +* in Montgomery domain with R=2^18 in bit-reversed order +************************************************************/ +const uint16_t PQCLEAN_NEWHOPE512CPA_CLEAN_omegas_inv_bitrev_montgomery[NEWHOPE_N / 2] = { + 4075, 6974, 4916, 4324, 7210, 3262, 2169, 11767, 3514, 1041, 5925, 11271, 6715, 10316, 11011, 9945, + 1190, 9606, 3818, 6118, 1050, 7753, 8429, 6844, 4449, 6833, 147, 3789, 7540, 6752, 4467, 4789, + 10367, 3879, 2033, 3998, 11316, 1254, 6854, 1359, 3988, 468, 11907, 11973, 8579, 6196, 5446, 6950, + 1987, 10587, 654, 3565, 3199, 12233, 7083, 6760, 6427, 6153, 3643, 6874, 4948, 6152, 11889, 1728, + 7280, 10333, 6008, 11404, 3532, 11286, 241, 12231, 11314, 4212, 8851, 9445, 3477, 6608, 12147, 1105, + 5594, 9260, 5886, 7507, 4213, 11785, 2302, 11684, 8687, 6221, 8209, 421, 7665, 6212, 8689, 3263, + 10710, 431, 9784, 5906, 9450, 8332, 2127, 151, 3174, 52, 1323, 9523, 6415, 11612, 3336, 6234, + 7048, 9369, 4169, 3127, 11279, 6821, 787, 3482, 3445, 4780, 7232, 7591, 7377, 2049, 1321, 192, + 9551, 6421, 5735, 9634, 10596, 9280, 723, 12115, 9364, 347, 1975, 3757, 10431, 7535, 11863, 3315, + 4493, 3202, 5369, 10232, 350, 10777, 6906, 10474, 1483, 6374, 49, 1263, 10706, 6347, 1489, 9789, + 7552, 1293, 4774, 5429, 3772, 418, 6381, 453, 9522, 156, 3969, 3991, 6956, 10258, 10008, 6413, + 8855, 3529, 218, 9381, 9259, 8174, 2361, 10446, 10335, 2051, 9407, 10484, 9842, 6147, 3963, 576, + 6523, 11637, 6099, 11994, 9370, 3762, 8273, 4077, 11964, 1404, 11143, 11341, 1159, 6299, 4049, 8561, + 5961, 7183, 1962, 10695, 9597, 12121, 8960, 7991, 6992, 6170, 10929, 8333, 2555, 6167, 11089, 5184, + 3570, 4240, 11454, 6065, 3150, 10970, 709, 8243, 1058, 8210, 441, 11367, 10331, 7967, 1112, 2078, + 10542, 3123, 5486, 9235, 7856, 6370, 8455, 5257, 9341, 9786, 6507, 10723, 2459, 683, 8633, 64, +}; + +/************************************************************ +* Name: gammas_bitrev_montgomery +* +* Description: Contains powers of nth root of -1 in Montgomery +* domain with R=2^18 in bit-reversed order +************************************************************/ +const uint16_t PQCLEAN_NEWHOPE512CPA_CLEAN_gammas_bitrev_montgomery[NEWHOPE_N] = { + 4075, 5315, 7965, 7373, 522, 10120, 9027, 5079, 2344, 1278, 1973, 5574, 1018, 6364, 11248, 8775, + 7500, 7822, 5537, 4749, 8500, 12142, 5456, 7840, 5445, 3860, 4536, 11239, 6171, 8471, 2683, 11099, + 10561, 400, 6137, 7341, 5415, 8646, 6136, 5862, 5529, 5206, 56, 9090, 8724, 11635, 1702, 10302, + 5339, 6843, 6093, 3710, 316, 382, 11821, 8301, 10930, 5435, 11035, 973, 8291, 10256, 8410, 1922, + 12097, 10968, 10240, 4912, 4698, 5057, 7509, 8844, 8807, 11502, 5468, 1010, 9162, 8120, 2920, 5241, + 6055, 8953, 677, 5874, 2766, 10966, 12237, 9115, 12138, 10162, 3957, 2839, 6383, 2505, 11858, 1579, + 9026, 3600, 6077, 4624, 11868, 4080, 6068, 3602, 605, 9987, 504, 8076, 4782, 6403, 3029, 6695, + 11184, 142, 5681, 8812, 2844, 3438, 8077, 975, 58, 12048, 1003, 8757, 885, 6281, 1956, 5009, + 12225, 3656, 11606, 9830, 1566, 5782, 2503, 2948, 7032, 3834, 5919, 4433, 3054, 6803, 9166, 1747, + 10211, 11177, 4322, 1958, 922, 11848, 4079, 11231, 4046, 11580, 1319, 9139, 6224, 835, 8049, 8719, + 7105, 1200, 6122, 9734, 3956, 1360, 6119, 5297, 4298, 3329, 168, 2692, 1594, 10327, 5106, 6328, + 3728, 8240, 5990, 11130, 948, 1146, 10885, 325, 8212, 4016, 8527, 2919, 295, 6190, 652, 5766, + 11713, 8326, 6142, 2447, 1805, 2882, 10238, 1954, 1843, 9928, 4115, 3030, 2908, 12071, 8760, 3434, + 5876, 2281, 2031, 5333, 8298, 8320, 12133, 2767, 11836, 5908, 11871, 8517, 6860, 7515, 10996, 4737, + 2500, 10800, 5942, 1583, 11026, 12240, 5915, 10806, 1815, 5383, 1512, 11939, 2057, 6920, 9087, 7796, + 8974, 426, 4754, 1858, 8532, 10314, 11942, 2925, 174, 11566, 3009, 1693, 2655, 6554, 5868, 2738, + 11796, 8193, 9908, 5444, 10911, 1912, 7952, 435, 404, 7644, 11224, 10146, 7012, 11121, 11082, 9041, + 9723, 2187, 9867, 6250, 3646, 9852, 6267, 2987, 8509, 875, 4976, 10682, 8005, 5088, 7278, 11287, + 9223, 27, 3763, 10849, 11272, 7404, 5084, 10657, 8146, 4714, 12047, 10752, 2678, 3704, 545, 7270, + 1067, 5101, 442, 2401, 390, 11516, 3778, 8456, 1045, 9430, 9808, 5012, 9377, 6591, 11935, 4861, + 7852, 3, 3149, 12129, 12176, 4919, 10123, 3915, 3636, 7351, 2704, 5291, 1663, 1777, 1426, 7635, + 1484, 7394, 2780, 7094, 8236, 2645, 7247, 2305, 2847, 7875, 7917, 10115, 10600, 8925, 4057, 3271, + 9273, 243, 9289, 11618, 3136, 5191, 8889, 9890, 11869, 5559, 10111, 10745, 11813, 8758, 4905, 3985, + 9603, 9042, 3978, 9320, 3510, 5332, 9424, 2370, 9405, 11136, 2249, 8241, 10659, 10163, 9103, 6882, + 10810, 1, 5146, 4043, 8155, 5736, 11567, 1305, 1212, 10643, 9094, 5860, 8747, 8785, 8668, 2545, + 4591, 6561, 5023, 6461, 10938, 4978, 6512, 8961, 949, 2625, 2639, 7468, 11726, 2975, 9545, 9283, + 3091, 81, 11289, 7969, 9238, 9923, 2963, 7393, 12149, 1853, 11563, 7678, 8034, 11112, 1635, 9521, + 3201, 3014, 1326, 7203, 1170, 9970, 11334, 790, 3135, 3712, 4846, 2747, 3553, 7484, 11227, 2294, + 11267, 9, 9447, 11809, 11950, 2468, 5791, 11745, 10908, 9764, 8112, 3584, 4989, 5331, 4278, 10616, + 4452, 9893, 8340, 8993, 130, 7935, 9452, 6915, 8541, 11336, 11462, 5767, 7222, 2197, 12171, 9813, + 3241, 729, 3289, 10276, 9408, 3284, 2089, 5092, 11029, 4388, 5755, 7657, 10861, 1696, 2426, 11955, + 4231, 2548, 11934, 3382, 10530, 3707, 3694, 7110, 3637, 8830, 6747, 145, 7399, 5911, 2731, 8357, +}; + +/************************************************************ +* Name: gammas_inv_montgomery +* +* Description: Contains inverses of powers of nth root of -1 +* divided by n in Montgomery domain with R=2^18 +************************************************************/ +const uint16_t PQCLEAN_NEWHOPE512CPA_CLEAN_gammas_inv_montgomery[NEWHOPE_N] = { + 512, 3944, 4267, 5411, 9615, 5900, 3205, 6063, 9261, 2021, 3087, 4770, 1029, 1590, 343, 530, + 8307, 4273, 2769, 9617, 923, 7302, 4404, 2434, 1468, 9004, 8682, 11194, 2894, 11924, 5061, 8071, + 1687, 10883, 8755, 7724, 11111, 6671, 7800, 6320, 2600, 6203, 4963, 6164, 9847, 6151, 11475, 10243, + 3825, 11607, 1275, 3869, 425, 5386, 4238, 9988, 5509, 11522, 10029, 7937, 3343, 6742, 9307, 10440, + 11295, 3480, 3765, 1160, 1255, 4483, 8611, 9687, 11063, 3229, 7784, 9269, 6691, 7186, 10423, 10588, + 11667, 11722, 3889, 12100, 9489, 12226, 3163, 12268, 9247, 12282, 11275, 4094, 11951, 5461, 8080, 10013, + 10886, 7434, 7725, 2478, 2575, 826, 9051, 8468, 3017, 6919, 5102, 10499, 5797, 7596, 10125, 2532, + 3375, 844, 1125, 8474, 375, 6921, 125, 2307, 4138, 769, 9572, 8449, 7287, 11009, 2429, 7766, + 4906, 6685, 9828, 10421, 3276, 7570, 1092, 10716, 364, 3572, 8314, 5287, 10964, 9955, 7751, 11511, + 6680, 3837, 6323, 1279, 6204, 8619, 2068, 2873, 8882, 5054, 7057, 5781, 10545, 1927, 3515, 8835, + 5268, 2945, 1756, 5078, 8778, 5789, 2926, 6026, 9168, 6105, 3056, 2035, 5115, 8871, 1705, 2957, + 8761, 5082, 11113, 1694, 11897, 4661, 8062, 5650, 10880, 10076, 7723, 7455, 10767, 2485, 3589, 9021, + 9389, 3007, 7226, 9195, 6505, 3065, 10361, 5118, 7550, 1706, 6613, 4665, 10397, 1555, 7562, 8711, + 6617, 7000, 6302, 10526, 6197, 7605, 6162, 2535, 2054, 845, 4781, 4378, 5690, 9652, 5993, 11410, + 6094, 11996, 10224, 8095, 3408, 10891, 1136, 11823, 4475, 3941, 5588, 5410, 5959, 9996, 10179, 3332, + 3393, 5207, 1131, 5832, 377, 1944, 4222, 648, 9600, 216, 3200, 72, 5163, 24, 1721, 8, + 4670, 4099, 5653, 9559, 10077, 11379, 3359, 3793, 5216, 9457, 5835, 11345, 1945, 7878, 8841, 2626, + 2947, 9068, 9175, 7119, 11251, 2373, 11943, 791, 3981, 4360, 1327, 9646, 8635, 11408, 11071, 7899, + 11883, 2633, 3961, 4974, 9513, 1658, 3171, 4649, 1057, 5646, 8545, 1882, 11041, 8820, 11873, 2940, + 8054, 980, 6781, 4423, 10453, 9667, 11677, 11415, 12085, 3805, 12221, 9461, 8170, 7250, 10916, 6513, + 7735, 2171, 10771, 4820, 11783, 5703, 8024, 1901, 6771, 4730, 2257, 5673, 8945, 1891, 7078, 8823, + 10552, 2941, 11710, 9173, 12096, 7154, 4032, 6481, 1344, 10353, 448, 3451, 8342, 9343, 6877, 11307, + 10485, 3769, 3495, 9449, 1165, 7246, 8581, 10608, 11053, 3536, 11877, 5275, 3959, 9951, 5416, 3317, + 9998, 5202, 7429, 1734, 10669, 578, 11749, 4289, 12109, 5526, 12229, 1842, 12269, 614, 8186, 4301, + 6825, 5530, 2275, 10036, 8951, 11538, 7080, 3846, 2360, 1282, 4883, 8620, 5724, 11066, 1908, 7785, + 636, 2595, 212, 865, 4167, 8481, 1389, 2827, 463, 9135, 8347, 3045, 10975, 1015, 11851, 8531, + 12143, 6940, 8144, 10506, 6811, 3502, 10463, 9360, 7584, 3120, 2528, 1040, 4939, 4443, 9839, 1481, + 7376, 4590, 6555, 1530, 2185, 510, 8921, 170, 7070, 4153, 6453, 9577, 2151, 11385, 717, 3795, + 239, 1265, 4176, 4518, 1392, 1506, 464, 502, 4251, 8360, 1417, 6883, 8665, 10487, 11081, 7592, + 7790, 6627, 6693, 2209, 2231, 8929, 4840, 11169, 9806, 3723, 7365, 1241, 2455, 4510, 9011, 9696, + 7100, 3232, 6463, 9270, 10347, 3090, 3449, 1030, 5246, 8536, 5845, 11038, 10141, 11872, 11573, 12150, + 7954, 4050, 10844, 1350, 7711, 450, 10763, 150, 7684, 50, 10754, 4113, 7681, 1371, 10753, 457, +}; diff --git a/crypto_kem/newhope512cpa/clean/reduce.c b/crypto_kem/newhope512cpa/clean/reduce.c new file mode 100644 index 00000000..75d23570 --- /dev/null +++ b/crypto_kem/newhope512cpa/clean/reduce.c @@ -0,0 +1,26 @@ +#include "reduce.h" +#include "params.h" + +static const uint32_t qinv = 12287; // -inverse_mod(p,2^18) +static const uint32_t rlog = 18; + +/************************************************* +* Name: verify +* +* Description: Montgomery reduction; given a 32-bit integer a, computes +* 16-bit integer congruent to a * R^-1 mod q, +* where R=2^18 (see value of rlog) +* +* Arguments: - uint32_t a: input unsigned integer to be reduced; has to be in {0,...,1073491968} +* +* Returns: unsigned integer in {0,...,2^14-1} congruent to a * R^-1 modulo q. +**************************************************/ +uint16_t PQCLEAN_NEWHOPE512CPA_CLEAN_montgomery_reduce(uint32_t a) { + uint32_t u; + + u = (a * qinv); + u &= ((1 << rlog) - 1); + u *= NEWHOPE_Q; + a = a + u; + return a >> 18; +} diff --git a/crypto_kem/newhope512cpa/clean/reduce.h b/crypto_kem/newhope512cpa/clean/reduce.h new file mode 100644 index 00000000..d7424375 --- /dev/null +++ b/crypto_kem/newhope512cpa/clean/reduce.h @@ -0,0 +1,8 @@ +#ifndef REDUCE_H +#define REDUCE_H + +#include + +uint16_t PQCLEAN_NEWHOPE512CPA_CLEAN_montgomery_reduce(uint32_t a); + +#endif diff --git a/crypto_kem/newhope512cpa/clean/verify.c b/crypto_kem/newhope512cpa/clean/verify.c new file mode 100644 index 00000000..449bc219 --- /dev/null +++ b/crypto_kem/newhope512cpa/clean/verify.c @@ -0,0 +1,49 @@ +#include "verify.h" +#include +#include + +/************************************************* +* Name: verify +* +* Description: Compare two arrays for equality in constant time. +* +* Arguments: const unsigned char *a: pointer to first byte array +* const unsigned char *b: pointer to second byte array +* size_t len: length of the byte arrays +* +* Returns 0 if the byte arrays are equal, 1 otherwise +**************************************************/ +int PQCLEAN_NEWHOPE512CPA_CLEAN_verify(const unsigned char *a, const unsigned char *b, size_t len) { + uint64_t r; + size_t i; + r = 0; + + for (i = 0; i < len; i++) { + r |= a[i] ^ b[i]; + } + + r = (-(int64_t)r) >> 63; + return (int)r; +} + +/************************************************* +* Name: cmov +* +* Description: Copy len bytes from x to r if b is 1; +* don't modify x if b is 0. Requires b to be in {0,1}; +* assumes two's complement representation of negative integers. +* Runs in constant time. +* +* Arguments: unsigned char *r: pointer to output byte array +* const unsigned char *x: pointer to input byte array +* size_t len: Amount of bytes to be copied +* unsigned char b: Condition bit; has to be in {0,1} +**************************************************/ +void PQCLEAN_NEWHOPE512CPA_CLEAN_cmov(unsigned char *r, const unsigned char *x, size_t len, unsigned char b) { + size_t i; + + b = -b; + for (i = 0; i < len; i++) { + r[i] ^= b & (x[i] ^ r[i]); + } +} diff --git a/crypto_kem/newhope512cpa/clean/verify.h b/crypto_kem/newhope512cpa/clean/verify.h new file mode 100644 index 00000000..64385a42 --- /dev/null +++ b/crypto_kem/newhope512cpa/clean/verify.h @@ -0,0 +1,12 @@ +#ifndef VERIFY_H +#define VERIFY_H + +#include + +/* returns 0 for equal strings, 1 for non-equal strings */ +int PQCLEAN_NEWHOPE512CPA_CLEAN_verify(const unsigned char *a, const unsigned char *b, size_t len); + +/* b = 1 means mov, b = 0 means don't mov*/ +void PQCLEAN_NEWHOPE512CPA_CLEAN_cmov(unsigned char *r, const unsigned char *x, size_t len, unsigned char b); + +#endif diff --git a/crypto_kem/ntruhps2048509/clean/Makefile b/crypto_kem/ntruhps2048509/clean/Makefile index f4d4d328..e8b20e47 100644 --- a/crypto_kem/ntruhps2048509/clean/Makefile +++ b/crypto_kem/ntruhps2048509/clean/Makefile @@ -4,7 +4,7 @@ LIB=libntruhps2048509_clean.a HEADERS=api.h crypto_sort.h owcpa.h params.h poly.h sample.h verify.h OBJECTS=crypto_sort.o kem.o owcpa.o pack3.o packq.o poly.o sample.o verify.o -CFLAGS=-O3 -Wall -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Wvla -Werror -Wredundant-decls -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_kem/ntruhps2048677/clean/Makefile b/crypto_kem/ntruhps2048677/clean/Makefile index 22ecc1f7..7e892038 100644 --- a/crypto_kem/ntruhps2048677/clean/Makefile +++ b/crypto_kem/ntruhps2048677/clean/Makefile @@ -4,7 +4,7 @@ LIB=libntruhps2048677_clean.a HEADERS=api.h crypto_sort.h owcpa.h params.h poly.h sample.h verify.h OBJECTS=crypto_sort.o kem.o owcpa.o pack3.o packq.o poly.o sample.o verify.o -CFLAGS=-Wall -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_kem/ntruhps4096821/clean/Makefile b/crypto_kem/ntruhps4096821/clean/Makefile index c04c7f38..281e99dd 100644 --- a/crypto_kem/ntruhps4096821/clean/Makefile +++ b/crypto_kem/ntruhps4096821/clean/Makefile @@ -4,7 +4,7 @@ LIB=libntruhps4096821_clean.a HEADERS=api.h crypto_sort.h owcpa.h params.h poly.h sample.h verify.h OBJECTS=crypto_sort.o kem.o owcpa.o pack3.o packq.o poly.o sample.o verify.o -CFLAGS=-Wall -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_kem/ntruhrss701/clean/Makefile b/crypto_kem/ntruhrss701/clean/Makefile index 88cc97b8..62328bc3 100644 --- a/crypto_kem/ntruhrss701/clean/Makefile +++ b/crypto_kem/ntruhrss701/clean/Makefile @@ -4,7 +4,7 @@ LIB=libntruhrss701_clean.a HEADERS=api.h owcpa.h params.h poly.h sample.h verify.h OBJECTS=kem.o owcpa.o pack3.o packq.o poly.o sample.o verify.o -CFLAGS=-Wall -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/mqdss-48/META.yml b/crypto_sign/mqdss-48/META.yml index 4c34eaa7..ab9154f5 100644 --- a/crypto_sign/mqdss-48/META.yml +++ b/crypto_sign/mqdss-48/META.yml @@ -4,6 +4,7 @@ claimed-nist-level: 1 length-public-key: 46 length-secret-key: 16 length-signature: 20854 +nistkat-sha256: 0a3754ebeb4bc41118b488c2b46499f6652398e83cb0d6eaf2929dbfd33fc8d7 testvectors-sha256: 3350a80ccf4316b32ef13060fca8880d6802b7e61150fd36f021d1c52d8edb98 principal-submitter: Simona Samardjiska auxiliary-submitters: diff --git a/crypto_sign/mqdss-48/clean/Makefile b/crypto_sign/mqdss-48/clean/Makefile index 0264ec92..258fe79e 100644 --- a/crypto_sign/mqdss-48/clean/Makefile +++ b/crypto_sign/mqdss-48/clean/Makefile @@ -5,7 +5,7 @@ LIB=libmqdss-48_clean.a HEADERS = params.h gf31.h mq.h api.h OBJECTS = gf31.o mq.o sign.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/mqdss-48/clean/gf31.c b/crypto_sign/mqdss-48/clean/gf31.c index e6c7fc4f..9a5f2df0 100644 --- a/crypto_sign/mqdss-48/clean/gf31.c +++ b/crypto_sign/mqdss-48/clean/gf31.c @@ -49,13 +49,13 @@ void PQCLEAN_MQDSS48_CLEAN_vgf31_shorten_unique(gf31 *out, const gf31 *in) { them in a vector of 16-bit elements */ void PQCLEAN_MQDSS48_CLEAN_gf31_nrand(gf31 *out, int len, const unsigned char *seed, size_t seedlen) { int i = 0, j; - uint64_t shakestate[25] = {0}; + shake256ctx shakestate; unsigned char shakeblock[SHAKE256_RATE]; - shake256_absorb(shakestate, seed, seedlen); + shake256_absorb(&shakestate, seed, seedlen); while (i < len) { - shake256_squeezeblocks(shakeblock, 1, shakestate); + shake256_squeezeblocks(shakeblock, 1, &shakestate); for (j = 0; j < SHAKE256_RATE && i < len; j++) { if ((shakeblock[j] & 31) != 31) { out[i] = (shakeblock[j] & 31); @@ -70,13 +70,13 @@ void PQCLEAN_MQDSS48_CLEAN_gf31_nrand(gf31 *out, int len, const unsigned char *s This is used for the expansion of F, which wants packed elements. */ void PQCLEAN_MQDSS48_CLEAN_gf31_nrand_schar(signed char *out, int len, const unsigned char *seed, size_t seedlen) { int i = 0, j; - uint64_t shakestate[25] = {0}; + shake256ctx shakestate; unsigned char shakeblock[SHAKE256_RATE]; - shake256_absorb(shakestate, seed, seedlen); + shake256_absorb(&shakestate, seed, seedlen); while (i < len) { - shake256_squeezeblocks(shakeblock, 1, shakestate); + shake256_squeezeblocks(shakeblock, 1, &shakestate); for (j = 0; j < SHAKE256_RATE && i < len; j++) { if ((shakeblock[j] & 31) != 31) { out[i] = (signed char)(((signed char)shakeblock[j] & 31) - 15); diff --git a/crypto_sign/mqdss-48/clean/sign.c b/crypto_sign/mqdss-48/clean/sign.c index 38de45dc..01d67ef9 100644 --- a/crypto_sign/mqdss-48/clean/sign.c +++ b/crypto_sign/mqdss-48/clean/sign.c @@ -85,7 +85,7 @@ int PQCLEAN_MQDSS48_CLEAN_crypto_sign_signature( unsigned char *h0 = D_sigma0_h0_sigma1 + 2 * HASH_BYTES; unsigned char *t1packed = D_sigma0_h0_sigma1 + 3 * HASH_BYTES; unsigned char *e1packed = D_sigma0_h0_sigma1 + 3 * HASH_BYTES + ROUNDS * NPACKED_BYTES; - uint64_t shakestate[25] = {0}; + shake256ctx shakestate; unsigned char shakeblock[SHAKE256_RATE]; unsigned char h1[((ROUNDS + 7) & ~7) >> 3]; unsigned char rnd_seed[HASH_BYTES + SEED_BYTES]; @@ -109,17 +109,17 @@ int PQCLEAN_MQDSS48_CLEAN_crypto_sign_signature( int alpha_count = 0; int b; int i, j; - uint64_t s_inc[26]; + shake256incctx state; shake256(skbuf, SEED_BYTES * 4, sk, SEED_BYTES); PQCLEAN_MQDSS48_CLEAN_gf31_nrand_schar(F, F_LEN, skbuf, SEED_BYTES); - shake256_inc_init(s_inc); - shake256_inc_absorb(s_inc, sk, SEED_BYTES); - shake256_inc_absorb(s_inc, m, mlen); - shake256_inc_finalize(s_inc); - shake256_inc_squeeze(sig, HASH_BYTES, s_inc); // Compute R. + shake256_inc_init(&state); + shake256_inc_absorb(&state, sk, SEED_BYTES); + shake256_inc_absorb(&state, m, mlen); + shake256_inc_finalize(&state); + shake256_inc_squeeze(sig, HASH_BYTES, &state); // Compute R. memcpy(pk, skbuf, SEED_BYTES); PQCLEAN_MQDSS48_CLEAN_gf31_nrand(sk_gf31, N, skbuf + SEED_BYTES, SEED_BYTES); @@ -127,12 +127,12 @@ int PQCLEAN_MQDSS48_CLEAN_crypto_sign_signature( PQCLEAN_MQDSS48_CLEAN_vgf31_unique(pk_gf31, pk_gf31); PQCLEAN_MQDSS48_CLEAN_gf31_npack(pk + SEED_BYTES, pk_gf31, M); - shake256_inc_init(s_inc); - shake256_inc_absorb(s_inc, pk, PK_BYTES); - shake256_inc_absorb(s_inc, sig, HASH_BYTES); - shake256_inc_absorb(s_inc, m, mlen); - shake256_inc_finalize(s_inc); - shake256_inc_squeeze(D, HASH_BYTES, s_inc); + shake256_inc_init(&state); + shake256_inc_absorb(&state, pk, PK_BYTES); + shake256_inc_absorb(&state, sig, HASH_BYTES); + shake256_inc_absorb(&state, m, mlen); + shake256_inc_finalize(&state); + shake256_inc_squeeze(D, HASH_BYTES, &state); sig += HASH_BYTES; // Compensate for prefixed R. @@ -166,8 +166,8 @@ int PQCLEAN_MQDSS48_CLEAN_crypto_sign_signature( } H(sigma0, c, HASH_BYTES * ROUNDS * 2); // Compute sigma_0. - shake256_absorb(shakestate, D_sigma0_h0_sigma1, 2 * HASH_BYTES); - shake256_squeezeblocks(shakeblock, 1, shakestate); + shake256_absorb(&shakestate, D_sigma0_h0_sigma1, 2 * HASH_BYTES); + shake256_squeezeblocks(shakeblock, 1, &shakestate); memcpy(h0, shakeblock, HASH_BYTES); @@ -180,7 +180,7 @@ int PQCLEAN_MQDSS48_CLEAN_crypto_sign_signature( alpha_count++; if (alpha_count == SHAKE256_RATE) { alpha_count = 0; - shake256_squeezeblocks(shakeblock, 1, shakestate); + shake256_squeezeblocks(shakeblock, 1, &shakestate); } } while (alpha == 31); for (j = 0; j < N; j++) { @@ -246,24 +246,24 @@ int PQCLEAN_MQDSS48_CLEAN_crypto_sign_verify( gf31 z[M]; unsigned char packbuf0[NPACKED_BYTES]; unsigned char packbuf1[MPACKED_BYTES]; - uint64_t shakestate[25] = {0}; + shake256ctx shakestate; unsigned char shakeblock[SHAKE256_RATE]; int i, j; gf31 alpha; int alpha_count = 0; int b; - uint64_t s_inc[26]; + shake256incctx state; if (siglen != SIG_LEN) { return -1; } - shake256_inc_init(s_inc); - shake256_inc_absorb(s_inc, pk, PK_BYTES); - shake256_inc_absorb(s_inc, sig, HASH_BYTES); - shake256_inc_absorb(s_inc, m, mlen); - shake256_inc_finalize(s_inc); - shake256_inc_squeeze(D, HASH_BYTES, s_inc); + shake256_inc_init(&state); + shake256_inc_absorb(&state, pk, PK_BYTES); + shake256_inc_absorb(&state, sig, HASH_BYTES); + shake256_inc_absorb(&state, m, mlen); + shake256_inc_finalize(&state); + shake256_inc_squeeze(D, HASH_BYTES, &state); sig += HASH_BYTES; @@ -273,8 +273,8 @@ int PQCLEAN_MQDSS48_CLEAN_crypto_sign_verify( memcpy(sigma0, sig, HASH_BYTES); - shake256_absorb(shakestate, D_sigma0_h0_sigma1, 2 * HASH_BYTES); - shake256_squeezeblocks(shakeblock, 1, shakestate); + shake256_absorb(&shakestate, D_sigma0_h0_sigma1, 2 * HASH_BYTES); + shake256_squeezeblocks(shakeblock, 1, &shakestate); memcpy(h0, shakeblock, HASH_BYTES); @@ -293,7 +293,7 @@ int PQCLEAN_MQDSS48_CLEAN_crypto_sign_verify( alpha_count++; if (alpha_count == SHAKE256_RATE) { alpha_count = 0; - shake256_squeezeblocks(shakeblock, 1, shakestate); + shake256_squeezeblocks(shakeblock, 1, &shakestate); } } while (alpha == 31); b = (h1[(i >> 3)] >> (i & 7)) & 1; diff --git a/crypto_sign/mqdss-64/META.yml b/crypto_sign/mqdss-64/META.yml index 6d6ba9a8..88df82fc 100644 --- a/crypto_sign/mqdss-64/META.yml +++ b/crypto_sign/mqdss-64/META.yml @@ -4,6 +4,7 @@ claimed-nist-level: 3 length-public-key: 64 length-secret-key: 24 length-signature: 43728 +nistkat-sha256: 2a50f067babbf4a3eed5197e87820472944d1d79fc03b1d9322a8ad8c245501e testvectors-sha256: 1edd33ca64b14f60f153b84dd25c7064cfa9b7dbf1bb5c4296f343377cb0c864 principal-submitter: Simona Samardjiska auxiliary-submitters: diff --git a/crypto_sign/mqdss-64/clean/Makefile b/crypto_sign/mqdss-64/clean/Makefile index 04c693a5..1582ef72 100644 --- a/crypto_sign/mqdss-64/clean/Makefile +++ b/crypto_sign/mqdss-64/clean/Makefile @@ -5,7 +5,7 @@ LIB=libmqdss-64_clean.a HEADERS = params.h gf31.h mq.h api.h OBJECTS = gf31.o mq.o sign.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/mqdss-64/clean/gf31.c b/crypto_sign/mqdss-64/clean/gf31.c index 2b564739..54bb7da5 100644 --- a/crypto_sign/mqdss-64/clean/gf31.c +++ b/crypto_sign/mqdss-64/clean/gf31.c @@ -49,13 +49,13 @@ void PQCLEAN_MQDSS64_CLEAN_vgf31_shorten_unique(gf31 *out, const gf31 *in) { them in a vector of 16-bit elements */ void PQCLEAN_MQDSS64_CLEAN_gf31_nrand(gf31 *out, int len, const unsigned char *seed, size_t seedlen) { int i = 0, j; - uint64_t shakestate[25] = {0}; + shake256ctx shakestate; unsigned char shakeblock[SHAKE256_RATE]; - shake256_absorb(shakestate, seed, seedlen); + shake256_absorb(&shakestate, seed, seedlen); while (i < len) { - shake256_squeezeblocks(shakeblock, 1, shakestate); + shake256_squeezeblocks(shakeblock, 1, &shakestate); for (j = 0; j < SHAKE256_RATE && i < len; j++) { if ((shakeblock[j] & 31) != 31) { out[i] = (shakeblock[j] & 31); @@ -70,13 +70,13 @@ void PQCLEAN_MQDSS64_CLEAN_gf31_nrand(gf31 *out, int len, const unsigned char *s This is used for the expansion of F, which wants packed elements. */ void PQCLEAN_MQDSS64_CLEAN_gf31_nrand_schar(signed char *out, int len, const unsigned char *seed, size_t seedlen) { int i = 0, j; - uint64_t shakestate[25] = {0}; + shake256ctx shakestate; unsigned char shakeblock[SHAKE256_RATE]; - shake256_absorb(shakestate, seed, seedlen); + shake256_absorb(&shakestate, seed, seedlen); while (i < len) { - shake256_squeezeblocks(shakeblock, 1, shakestate); + shake256_squeezeblocks(shakeblock, 1, &shakestate); for (j = 0; j < SHAKE256_RATE && i < len; j++) { if ((shakeblock[j] & 31) != 31) { out[i] = (signed char)(((signed char)shakeblock[j] & 31) - 15); diff --git a/crypto_sign/mqdss-64/clean/sign.c b/crypto_sign/mqdss-64/clean/sign.c index 681799c9..189b70f8 100644 --- a/crypto_sign/mqdss-64/clean/sign.c +++ b/crypto_sign/mqdss-64/clean/sign.c @@ -85,7 +85,7 @@ int PQCLEAN_MQDSS64_CLEAN_crypto_sign_signature( unsigned char *h0 = D_sigma0_h0_sigma1 + 2 * HASH_BYTES; unsigned char *t1packed = D_sigma0_h0_sigma1 + 3 * HASH_BYTES; unsigned char *e1packed = D_sigma0_h0_sigma1 + 3 * HASH_BYTES + ROUNDS * NPACKED_BYTES; - uint64_t shakestate[25] = {0}; + shake256ctx shakestate; unsigned char shakeblock[SHAKE256_RATE]; unsigned char h1[((ROUNDS + 7) & ~7) >> 3]; unsigned char rnd_seed[HASH_BYTES + SEED_BYTES]; @@ -109,17 +109,17 @@ int PQCLEAN_MQDSS64_CLEAN_crypto_sign_signature( int alpha_count = 0; int b; int i, j; - uint64_t s_inc[26]; + shake256incctx state; shake256(skbuf, SEED_BYTES * 4, sk, SEED_BYTES); PQCLEAN_MQDSS64_CLEAN_gf31_nrand_schar(F, F_LEN, skbuf, SEED_BYTES); - shake256_inc_init(s_inc); - shake256_inc_absorb(s_inc, sk, SEED_BYTES); - shake256_inc_absorb(s_inc, m, mlen); - shake256_inc_finalize(s_inc); - shake256_inc_squeeze(sig, HASH_BYTES, s_inc); // Compute R. + shake256_inc_init(&state); + shake256_inc_absorb(&state, sk, SEED_BYTES); + shake256_inc_absorb(&state, m, mlen); + shake256_inc_finalize(&state); + shake256_inc_squeeze(sig, HASH_BYTES, &state); // Compute R. memcpy(pk, skbuf, SEED_BYTES); PQCLEAN_MQDSS64_CLEAN_gf31_nrand(sk_gf31, N, skbuf + SEED_BYTES, SEED_BYTES); @@ -127,12 +127,12 @@ int PQCLEAN_MQDSS64_CLEAN_crypto_sign_signature( PQCLEAN_MQDSS64_CLEAN_vgf31_unique(pk_gf31, pk_gf31); PQCLEAN_MQDSS64_CLEAN_gf31_npack(pk + SEED_BYTES, pk_gf31, M); - shake256_inc_init(s_inc); - shake256_inc_absorb(s_inc, pk, PK_BYTES); - shake256_inc_absorb(s_inc, sig, HASH_BYTES); - shake256_inc_absorb(s_inc, m, mlen); - shake256_inc_finalize(s_inc); - shake256_inc_squeeze(D, HASH_BYTES, s_inc); + shake256_inc_init(&state); + shake256_inc_absorb(&state, pk, PK_BYTES); + shake256_inc_absorb(&state, sig, HASH_BYTES); + shake256_inc_absorb(&state, m, mlen); + shake256_inc_finalize(&state); + shake256_inc_squeeze(D, HASH_BYTES, &state); sig += HASH_BYTES; // Compensate for prefixed R. @@ -166,8 +166,8 @@ int PQCLEAN_MQDSS64_CLEAN_crypto_sign_signature( } H(sigma0, c, HASH_BYTES * ROUNDS * 2); // Compute sigma_0. - shake256_absorb(shakestate, D_sigma0_h0_sigma1, 2 * HASH_BYTES); - shake256_squeezeblocks(shakeblock, 1, shakestate); + shake256_absorb(&shakestate, D_sigma0_h0_sigma1, 2 * HASH_BYTES); + shake256_squeezeblocks(shakeblock, 1, &shakestate); memcpy(h0, shakeblock, HASH_BYTES); @@ -180,7 +180,7 @@ int PQCLEAN_MQDSS64_CLEAN_crypto_sign_signature( alpha_count++; if (alpha_count == SHAKE256_RATE) { alpha_count = 0; - shake256_squeezeblocks(shakeblock, 1, shakestate); + shake256_squeezeblocks(shakeblock, 1, &shakestate); } } while (alpha == 31); for (j = 0; j < N; j++) { @@ -246,24 +246,24 @@ int PQCLEAN_MQDSS64_CLEAN_crypto_sign_verify( gf31 z[M]; unsigned char packbuf0[NPACKED_BYTES]; unsigned char packbuf1[MPACKED_BYTES]; - uint64_t shakestate[25] = {0}; + shake256ctx shakestate; unsigned char shakeblock[SHAKE256_RATE]; int i, j; gf31 alpha; int alpha_count = 0; int b; - uint64_t s_inc[26]; + shake256incctx state; if (siglen != SIG_LEN) { return -1; } - shake256_inc_init(s_inc); - shake256_inc_absorb(s_inc, pk, PK_BYTES); - shake256_inc_absorb(s_inc, sig, HASH_BYTES); - shake256_inc_absorb(s_inc, m, mlen); - shake256_inc_finalize(s_inc); - shake256_inc_squeeze(D, HASH_BYTES, s_inc); + shake256_inc_init(&state); + shake256_inc_absorb(&state, pk, PK_BYTES); + shake256_inc_absorb(&state, sig, HASH_BYTES); + shake256_inc_absorb(&state, m, mlen); + shake256_inc_finalize(&state); + shake256_inc_squeeze(D, HASH_BYTES, &state); sig += HASH_BYTES; @@ -273,8 +273,8 @@ int PQCLEAN_MQDSS64_CLEAN_crypto_sign_verify( memcpy(sigma0, sig, HASH_BYTES); - shake256_absorb(shakestate, D_sigma0_h0_sigma1, 2 * HASH_BYTES); - shake256_squeezeblocks(shakeblock, 1, shakestate); + shake256_absorb(&shakestate, D_sigma0_h0_sigma1, 2 * HASH_BYTES); + shake256_squeezeblocks(shakeblock, 1, &shakestate); memcpy(h0, shakeblock, HASH_BYTES); @@ -293,7 +293,7 @@ int PQCLEAN_MQDSS64_CLEAN_crypto_sign_verify( alpha_count++; if (alpha_count == SHAKE256_RATE) { alpha_count = 0; - shake256_squeezeblocks(shakeblock, 1, shakestate); + shake256_squeezeblocks(shakeblock, 1, &shakestate); } } while (alpha == 31); b = (h1[(i >> 3)] >> (i & 7)) & 1; diff --git a/crypto_sign/sphincs-haraka-128f-robust/META.yml b/crypto_sign/sphincs-haraka-128f-robust/META.yml index d79ca253..b40b21a4 100644 --- a/crypto_sign/sphincs-haraka-128f-robust/META.yml +++ b/crypto_sign/sphincs-haraka-128f-robust/META.yml @@ -4,6 +4,7 @@ claimed-nist-level: 1 length-public-key: 32 length-secret-key: 64 length-signature: 16976 +nistkat-sha256: 4d04dcfa1ed0dcbe0af382fe1925b5031a279811f9fea298d64a9fe8eaaf2165 testvectors-sha256: f0f84722cf529a108006d84b52966cbebd92146ee33cacdd7d1bba2cdc1944fd principal-submitter: Andreas Hülsing auxiliary-submitters: diff --git a/crypto_sign/sphincs-haraka-128f-robust/clean/Makefile b/crypto_sign/sphincs-haraka-128f-robust/clean/Makefile index 8bf94024..31635e61 100644 --- a/crypto_sign/sphincs-haraka-128f-robust/clean/Makefile +++ b/crypto_sign/sphincs-haraka-128f-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-128f-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_robust.o haraka.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-128f-simple/META.yml b/crypto_sign/sphincs-haraka-128f-simple/META.yml index f7783474..76e4075c 100644 --- a/crypto_sign/sphincs-haraka-128f-simple/META.yml +++ b/crypto_sign/sphincs-haraka-128f-simple/META.yml @@ -4,6 +4,7 @@ claimed-nist-level: 1 length-public-key: 32 length-secret-key: 64 length-signature: 16976 +nistkat-sha256: 82967bdf0188ff7c6c6f5723798d3e3ec17679123f2df9c6b572ec3c0b3ffd65 testvectors-sha256: b9ea5703411a79c215a2643862bf4924ff62eeec08a0d1e328e39f47417fec8f principal-submitter: Andreas Hülsing auxiliary-submitters: diff --git a/crypto_sign/sphincs-haraka-128f-simple/clean/Makefile b/crypto_sign/sphincs-haraka-128f-simple/clean/Makefile index b99f46b6..ed71d91e 100644 --- a/crypto_sign/sphincs-haraka-128f-simple/clean/Makefile +++ b/crypto_sign/sphincs-haraka-128f-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-128f-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_simple.o haraka.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-128s-robust/META.yml b/crypto_sign/sphincs-haraka-128s-robust/META.yml index 4d28ab3b..a35dd309 100644 --- a/crypto_sign/sphincs-haraka-128s-robust/META.yml +++ b/crypto_sign/sphincs-haraka-128s-robust/META.yml @@ -4,6 +4,7 @@ claimed-nist-level: 1 length-public-key: 32 length-secret-key: 64 length-signature: 8080 +nistkat-sha256: 78c68bae7ab635195b41807bd8a6e89f740d762d5b2a7022550cb34cc79cf3b3 testvectors-sha256: a7057ca5ce0d7f01d1c1aabe474f8449796b051becbc8b148a78c84893193fcf principal-submitter: Andreas Hülsing auxiliary-submitters: diff --git a/crypto_sign/sphincs-haraka-128s-robust/clean/Makefile b/crypto_sign/sphincs-haraka-128s-robust/clean/Makefile index 630bbb51..76834753 100644 --- a/crypto_sign/sphincs-haraka-128s-robust/clean/Makefile +++ b/crypto_sign/sphincs-haraka-128s-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-128s-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_robust.o haraka.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-128s-simple/META.yml b/crypto_sign/sphincs-haraka-128s-simple/META.yml index d9907683..e15be027 100644 --- a/crypto_sign/sphincs-haraka-128s-simple/META.yml +++ b/crypto_sign/sphincs-haraka-128s-simple/META.yml @@ -4,6 +4,7 @@ claimed-nist-level: 1 length-public-key: 32 length-secret-key: 64 length-signature: 8080 +nistkat-sha256: dbded19fb5983657e93d047c61ebb0069ea7f5afb928463a308fa44f792429d4 testvectors-sha256: fcc816e14d200e212b4b955d3011f5a6b61240c7c0003e17acb1bf396ca5d4ad principal-submitter: Andreas Hülsing auxiliary-submitters: diff --git a/crypto_sign/sphincs-haraka-128s-simple/clean/Makefile b/crypto_sign/sphincs-haraka-128s-simple/clean/Makefile index 7f5c5278..ad33bc8e 100644 --- a/crypto_sign/sphincs-haraka-128s-simple/clean/Makefile +++ b/crypto_sign/sphincs-haraka-128s-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-128s-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_simple.o haraka.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-192f-robust/META.yml b/crypto_sign/sphincs-haraka-192f-robust/META.yml index a893346f..04c60bb6 100644 --- a/crypto_sign/sphincs-haraka-192f-robust/META.yml +++ b/crypto_sign/sphincs-haraka-192f-robust/META.yml @@ -4,6 +4,7 @@ claimed-nist-level: 3 length-public-key: 48 length-secret-key: 96 length-signature: 35664 +nistkat-sha256: 195f00a8c88110b333c30de6d672265d89a19d1991c107aeebe06759dfde33fc testvectors-sha256: a88d3adbeb5c1805a90e506c93f5000b266d1227f1621c0f77adf75bdbe4ba02 principal-submitter: Andreas Hülsing auxiliary-submitters: diff --git a/crypto_sign/sphincs-haraka-192f-robust/clean/Makefile b/crypto_sign/sphincs-haraka-192f-robust/clean/Makefile index aa67c3fa..7c857afb 100644 --- a/crypto_sign/sphincs-haraka-192f-robust/clean/Makefile +++ b/crypto_sign/sphincs-haraka-192f-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-192f-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_robust.o haraka.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-192f-simple/META.yml b/crypto_sign/sphincs-haraka-192f-simple/META.yml index c0473ea7..3d24628c 100644 --- a/crypto_sign/sphincs-haraka-192f-simple/META.yml +++ b/crypto_sign/sphincs-haraka-192f-simple/META.yml @@ -4,6 +4,7 @@ claimed-nist-level: 3 length-public-key: 48 length-secret-key: 96 length-signature: 35664 +nistkat-sha256: b6050873b334c67aeb7e3e3148f39479ffeab4e8c3b3481983abc44278904984 testvectors-sha256: d054d5394d578057e8264c5ef8a33627fcf194a25270a1dc6c2d7de86408876d principal-submitter: Andreas Hülsing auxiliary-submitters: diff --git a/crypto_sign/sphincs-haraka-192f-simple/clean/Makefile b/crypto_sign/sphincs-haraka-192f-simple/clean/Makefile index b6c0e316..e3dc2789 100644 --- a/crypto_sign/sphincs-haraka-192f-simple/clean/Makefile +++ b/crypto_sign/sphincs-haraka-192f-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-192f-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_simple.o haraka.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-192s-robust/META.yml b/crypto_sign/sphincs-haraka-192s-robust/META.yml index 81e2ed43..3f895cba 100644 --- a/crypto_sign/sphincs-haraka-192s-robust/META.yml +++ b/crypto_sign/sphincs-haraka-192s-robust/META.yml @@ -4,6 +4,7 @@ claimed-nist-level: 3 length-public-key: 48 length-secret-key: 96 length-signature: 17064 +nistkat-sha256: c59a79130d012b6c25546e57d6d9bb080e2721a40c71e27077bd5b793d96cbe5 testvectors-sha256: 5dd40c8ea9a81ad93e0685843ec1cabdcb6eec9f6e64fc01d928ebaf7cf377c6 principal-submitter: Andreas Hülsing auxiliary-submitters: diff --git a/crypto_sign/sphincs-haraka-192s-robust/clean/Makefile b/crypto_sign/sphincs-haraka-192s-robust/clean/Makefile index 6e7a2986..20621594 100644 --- a/crypto_sign/sphincs-haraka-192s-robust/clean/Makefile +++ b/crypto_sign/sphincs-haraka-192s-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-192s-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_robust.o haraka.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-192s-simple/META.yml b/crypto_sign/sphincs-haraka-192s-simple/META.yml index d13213bd..c81fdbac 100644 --- a/crypto_sign/sphincs-haraka-192s-simple/META.yml +++ b/crypto_sign/sphincs-haraka-192s-simple/META.yml @@ -4,6 +4,7 @@ claimed-nist-level: 3 length-public-key: 48 length-secret-key: 96 length-signature: 17064 +nistkat-sha256: 1e0b5aefda28f48fb8c4e81a0294e689211616f0748a9d9daf37be9e76b5141a testvectors-sha256: 7e50b92ec85e31260326092a62e84d2f12df84213a494d0f0527125a5e6b7ed7 principal-submitter: Andreas Hülsing auxiliary-submitters: diff --git a/crypto_sign/sphincs-haraka-192s-simple/clean/Makefile b/crypto_sign/sphincs-haraka-192s-simple/clean/Makefile index 13423bf4..67a12498 100644 --- a/crypto_sign/sphincs-haraka-192s-simple/clean/Makefile +++ b/crypto_sign/sphincs-haraka-192s-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-192s-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_simple.o haraka.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-256f-robust/META.yml b/crypto_sign/sphincs-haraka-256f-robust/META.yml index 69b7ba18..900d7e2f 100644 --- a/crypto_sign/sphincs-haraka-256f-robust/META.yml +++ b/crypto_sign/sphincs-haraka-256f-robust/META.yml @@ -4,6 +4,7 @@ claimed-nist-level: 5 length-public-key: 64 length-secret-key: 128 length-signature: 49216 +nistkat-sha256: c2d6cebdf902e168ad27d8a942b36bc6909ea643e0f2b9ab78fd474dbdc0d373 testvectors-sha256: b5e3a1c1dbb45751f2a4c9323a5d900b30f38e4c7e2943e234a5b9526de1146c principal-submitter: Andreas Hülsing auxiliary-submitters: diff --git a/crypto_sign/sphincs-haraka-256f-robust/clean/Makefile b/crypto_sign/sphincs-haraka-256f-robust/clean/Makefile index f714b735..6b0f52c1 100644 --- a/crypto_sign/sphincs-haraka-256f-robust/clean/Makefile +++ b/crypto_sign/sphincs-haraka-256f-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-256f-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_robust.o haraka.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-256f-simple/META.yml b/crypto_sign/sphincs-haraka-256f-simple/META.yml index a8decdf1..8831e1c1 100644 --- a/crypto_sign/sphincs-haraka-256f-simple/META.yml +++ b/crypto_sign/sphincs-haraka-256f-simple/META.yml @@ -4,6 +4,7 @@ claimed-nist-level: 5 length-public-key: 64 length-secret-key: 128 length-signature: 49216 +nistkat-sha256: a848b318c46f1c0a6932fd5102ca4bab43bb3c4692f97b2ee97c9e9bdbd5de36 testvectors-sha256: 3cddd379bf490efac9a8aefaa9b59e7f70fe96bb177a8bfc404f99bfc2172aee principal-submitter: Andreas Hülsing auxiliary-submitters: diff --git a/crypto_sign/sphincs-haraka-256f-simple/clean/Makefile b/crypto_sign/sphincs-haraka-256f-simple/clean/Makefile index 2db645ad..bd87aae1 100644 --- a/crypto_sign/sphincs-haraka-256f-simple/clean/Makefile +++ b/crypto_sign/sphincs-haraka-256f-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-256f-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_simple.o haraka.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-256s-robust/META.yml b/crypto_sign/sphincs-haraka-256s-robust/META.yml index 5bb978d9..8b155a56 100644 --- a/crypto_sign/sphincs-haraka-256s-robust/META.yml +++ b/crypto_sign/sphincs-haraka-256s-robust/META.yml @@ -4,6 +4,7 @@ claimed-nist-level: 5 length-public-key: 64 length-secret-key: 128 length-signature: 29792 +nistkat-sha256: 0a57c7fba38bcf56fde765a89da296ae99fda745f96845adda54b4f8fe76b6c6 testvectors-sha256: feb4f482dd5ab66dd09f2e5e02175e7109de4385da5704f78cc1dac074368c56 principal-submitter: Andreas Hülsing auxiliary-submitters: diff --git a/crypto_sign/sphincs-haraka-256s-robust/clean/Makefile b/crypto_sign/sphincs-haraka-256s-robust/clean/Makefile index c97db733..b822f639 100644 --- a/crypto_sign/sphincs-haraka-256s-robust/clean/Makefile +++ b/crypto_sign/sphincs-haraka-256s-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-256s-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_robust.o haraka.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-haraka-256s-simple/META.yml b/crypto_sign/sphincs-haraka-256s-simple/META.yml index fee133e2..7c6987fd 100644 --- a/crypto_sign/sphincs-haraka-256s-simple/META.yml +++ b/crypto_sign/sphincs-haraka-256s-simple/META.yml @@ -4,6 +4,7 @@ claimed-nist-level: 5 length-public-key: 64 length-secret-key: 128 length-signature: 29792 +nistkat-sha256: a65476425ff1a68c5d6f941fecaec6e6c00be10695f6cfff15047875bcd5f490 testvectors-sha256: 25fcc82aa371d06c8b494c2d0a3ac4920cfb8134bef9962491669ef2c6a0b820 principal-submitter: Andreas Hülsing auxiliary-submitters: diff --git a/crypto_sign/sphincs-haraka-256s-simple/clean/Makefile b/crypto_sign/sphincs-haraka-256s-simple/clean/Makefile index be89decc..39506a3f 100644 --- a/crypto_sign/sphincs-haraka-256s-simple/clean/Makefile +++ b/crypto_sign/sphincs-haraka-256s-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-haraka-256s-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h haraka.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_haraka.o thash_haraka_simple.o haraka.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-128f-robust/META.yml b/crypto_sign/sphincs-sha256-128f-robust/META.yml index a352f117..44b52785 100644 --- a/crypto_sign/sphincs-sha256-128f-robust/META.yml +++ b/crypto_sign/sphincs-sha256-128f-robust/META.yml @@ -4,6 +4,7 @@ claimed-nist-level: 1 length-public-key: 32 length-secret-key: 64 length-signature: 16976 +nistkat-sha256: cf7935fc0277099a7453f6c5dc54e40d5cf34fbe989909940a77a3fbbab6c42e testvectors-sha256: 3e7c782b25e405940160468c2d777a5ab6eb9b6cfe318efed257f3270cca8c72 principal-submitter: Andreas Hülsing auxiliary-submitters: diff --git a/crypto_sign/sphincs-sha256-128f-robust/clean/Makefile b/crypto_sign/sphincs-sha256-128f-robust/clean/Makefile index a882a93d..f316f443 100644 --- a/crypto_sign/sphincs-sha256-128f-robust/clean/Makefile +++ b/crypto_sign/sphincs-sha256-128f-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-128f-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_robust.o sha256.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-128f-robust/clean/hash_sha256.c b/crypto_sign/sphincs-sha256-128f-robust/clean/hash_sha256.c index 7af46b0b..da1fe0dd 100644 --- a/crypto_sign/sphincs-sha256-128f-robust/clean/hash_sha256.c +++ b/crypto_sign/sphincs-sha256-128f-robust/clean/hash_sha256.c @@ -45,7 +45,7 @@ void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_gen_message_random( const unsigned char *sk_prf, const unsigned char *optrand, const unsigned char *m, size_t mlen) { unsigned char buf[SPX_SHA256_BLOCK_BYTES + SPX_SHA256_OUTPUT_BYTES]; - uint8_t state[40]; + sha256ctx state; int i; /* This implements HMAC-SHA256 */ @@ -54,25 +54,25 @@ void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_gen_message_random( } memset(buf + SPX_N, 0x36, SPX_SHA256_BLOCK_BYTES - SPX_N); - sha256_inc_init(state); - sha256_inc_blocks(state, buf, 1); + sha256_inc_init(&state); + sha256_inc_blocks(&state, buf, 1); memcpy(buf, optrand, SPX_N); /* If optrand + message cannot fill up an entire block */ if (SPX_N + mlen < SPX_SHA256_BLOCK_BYTES) { memcpy(buf + SPX_N, m, mlen); - sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, state, + sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, &state, buf, mlen + SPX_N); } /* Otherwise first fill a block, so that finalize only uses the message */ else { memcpy(buf + SPX_N, m, SPX_SHA256_BLOCK_BYTES - SPX_N); - sha256_inc_blocks(state, buf, 1); + sha256_inc_blocks(&state, buf, 1); m += SPX_SHA256_BLOCK_BYTES - SPX_N; mlen -= SPX_SHA256_BLOCK_BYTES - SPX_N; - sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, state, m, mlen); + sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, &state, m, mlen); } for (i = 0; i < SPX_N; i++) { @@ -108,9 +108,9 @@ void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_hash_message( unsigned char buf[SPX_DGST_BYTES]; unsigned char *bufp = buf; - uint8_t state[40]; + sha256ctx state; - sha256_inc_init(state); + sha256_inc_init(&state); memcpy(inbuf, R, SPX_N); memcpy(inbuf + SPX_N, pk, SPX_PK_BYTES); @@ -118,17 +118,17 @@ void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_hash_message( /* If R + pk + message cannot fill up an entire block */ if (SPX_N + SPX_PK_BYTES + mlen < SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES) { memcpy(inbuf + SPX_N + SPX_PK_BYTES, m, mlen); - sha256_inc_finalize(seed, state, inbuf, SPX_N + SPX_PK_BYTES + mlen); + sha256_inc_finalize(seed, &state, inbuf, SPX_N + SPX_PK_BYTES + mlen); } /* Otherwise first fill a block, so that finalize only uses the message */ else { memcpy(inbuf + SPX_N + SPX_PK_BYTES, m, SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES); - sha256_inc_blocks(state, inbuf, SPX_INBLOCKS); + sha256_inc_blocks(&state, inbuf, SPX_INBLOCKS); m += SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES; mlen -= SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES; - sha256_inc_finalize(seed, state, m, mlen); + sha256_inc_finalize(seed, &state, m, mlen); } /* By doing this in two steps, we prevent hashing the message twice; diff --git a/crypto_sign/sphincs-sha256-128f-robust/clean/sha256.c b/crypto_sign/sphincs-sha256-128f-robust/clean/sha256.c index abecf7d7..e822cb07 100644 --- a/crypto_sign/sphincs-sha256-128f-robust/clean/sha256.c +++ b/crypto_sign/sphincs-sha256-128f-robust/clean/sha256.c @@ -50,7 +50,7 @@ void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_mgf1( } } -uint8_t PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_state_seeded[40]; +sha256ctx PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_state_seeded; /** * Absorb the constant pub_seed using one round of the compression function @@ -67,6 +67,6 @@ void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_seed_state(const unsigned char *pub_s block[i] = 0; } - sha256_inc_init(PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_state_seeded); - sha256_inc_blocks(PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_state_seeded, block, 1); + sha256_inc_init(&PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_state_seeded); + sha256_inc_blocks(&PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_state_seeded, block, 1); } diff --git a/crypto_sign/sphincs-sha256-128f-robust/clean/sha256.h b/crypto_sign/sphincs-sha256-128f-robust/clean/sha256.h index 225cd12a..86ee829d 100644 --- a/crypto_sign/sphincs-sha256-128f-robust/clean/sha256.h +++ b/crypto_sign/sphincs-sha256-128f-robust/clean/sha256.h @@ -8,13 +8,15 @@ #include #include +#include "sha2.h" + void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_compress_address(unsigned char *out, const uint32_t addr[8]); void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_mgf1( unsigned char *out, unsigned long outlen, unsigned char *input_plus_four_bytes, unsigned long inlen); -extern uint8_t PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_state_seeded[40]; +extern sha256ctx PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_state_seeded; void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_seed_state(const unsigned char *pub_seed); diff --git a/crypto_sign/sphincs-sha256-128f-robust/clean/thash_sha256_robust.c b/crypto_sign/sphincs-sha256-128f-robust/clean/thash_sha256_robust.c index c2f6688c..8c610c93 100644 --- a/crypto_sign/sphincs-sha256-128f-robust/clean/thash_sha256_robust.c +++ b/crypto_sign/sphincs-sha256-128f-robust/clean/thash_sha256_robust.c @@ -18,7 +18,7 @@ static void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash( unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; unsigned char *bitmask = buf + SPX_N + SPX_SHA256_ADDR_BYTES + 4; - uint8_t sha2_state[40]; + sha256ctx sha2_state; unsigned int i; memcpy(buf, pub_seed, SPX_N); @@ -27,13 +27,13 @@ static void PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash( PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_mgf1(bitmask, inblocks * SPX_N, buf, SPX_N + SPX_SHA256_ADDR_BYTES); /* Retrieve precomputed state containing pub_seed */ - memcpy(sha2_state, PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_state_seeded, 40 * sizeof(uint8_t)); + memcpy(&sha2_state, &PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_state_seeded, sizeof(sha256ctx)); for (i = 0; i < inblocks * SPX_N; i++) { buf[SPX_N + SPX_SHA256_ADDR_BYTES + i] = in[i] ^ bitmask[i]; } - sha256_inc_finalize(outbuf, sha2_state, buf + SPX_N, + sha256_inc_finalize(outbuf, &sha2_state, buf + SPX_N, SPX_SHA256_ADDR_BYTES + inblocks * SPX_N); memcpy(out, outbuf, SPX_N); } diff --git a/crypto_sign/sphincs-sha256-128f-simple/META.yml b/crypto_sign/sphincs-sha256-128f-simple/META.yml index b0520b3c..ab82adba 100644 --- a/crypto_sign/sphincs-sha256-128f-simple/META.yml +++ b/crypto_sign/sphincs-sha256-128f-simple/META.yml @@ -4,6 +4,7 @@ claimed-nist-level: 1 length-public-key: 32 length-secret-key: 64 length-signature: 16976 +nistkat-sha256: 4375bc4276fa44654979db0da886ba5cf754011db268fc63fa7584d50f5dfb63 testvectors-sha256: 5ce16422e028eb7a6198d0a276a1760a6bbcd4ba9457ddbbfd5e08f34985c0ce principal-submitter: Andreas Hülsing auxiliary-submitters: diff --git a/crypto_sign/sphincs-sha256-128f-simple/clean/Makefile b/crypto_sign/sphincs-sha256-128f-simple/clean/Makefile index 00341164..9b73ece1 100644 --- a/crypto_sign/sphincs-sha256-128f-simple/clean/Makefile +++ b/crypto_sign/sphincs-sha256-128f-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-128f-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_simple.o sha256.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-128f-simple/clean/hash_sha256.c b/crypto_sign/sphincs-sha256-128f-simple/clean/hash_sha256.c index 96d67fe7..b1579dbc 100644 --- a/crypto_sign/sphincs-sha256-128f-simple/clean/hash_sha256.c +++ b/crypto_sign/sphincs-sha256-128f-simple/clean/hash_sha256.c @@ -45,7 +45,7 @@ void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_gen_message_random( const unsigned char *sk_prf, const unsigned char *optrand, const unsigned char *m, size_t mlen) { unsigned char buf[SPX_SHA256_BLOCK_BYTES + SPX_SHA256_OUTPUT_BYTES]; - uint8_t state[40]; + sha256ctx state; int i; /* This implements HMAC-SHA256 */ @@ -54,25 +54,25 @@ void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_gen_message_random( } memset(buf + SPX_N, 0x36, SPX_SHA256_BLOCK_BYTES - SPX_N); - sha256_inc_init(state); - sha256_inc_blocks(state, buf, 1); + sha256_inc_init(&state); + sha256_inc_blocks(&state, buf, 1); memcpy(buf, optrand, SPX_N); /* If optrand + message cannot fill up an entire block */ if (SPX_N + mlen < SPX_SHA256_BLOCK_BYTES) { memcpy(buf + SPX_N, m, mlen); - sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, state, + sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, &state, buf, mlen + SPX_N); } /* Otherwise first fill a block, so that finalize only uses the message */ else { memcpy(buf + SPX_N, m, SPX_SHA256_BLOCK_BYTES - SPX_N); - sha256_inc_blocks(state, buf, 1); + sha256_inc_blocks(&state, buf, 1); m += SPX_SHA256_BLOCK_BYTES - SPX_N; mlen -= SPX_SHA256_BLOCK_BYTES - SPX_N; - sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, state, m, mlen); + sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, &state, m, mlen); } for (i = 0; i < SPX_N; i++) { @@ -108,9 +108,9 @@ void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_hash_message( unsigned char buf[SPX_DGST_BYTES]; unsigned char *bufp = buf; - uint8_t state[40]; + sha256ctx state; - sha256_inc_init(state); + sha256_inc_init(&state); memcpy(inbuf, R, SPX_N); memcpy(inbuf + SPX_N, pk, SPX_PK_BYTES); @@ -118,17 +118,17 @@ void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_hash_message( /* If R + pk + message cannot fill up an entire block */ if (SPX_N + SPX_PK_BYTES + mlen < SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES) { memcpy(inbuf + SPX_N + SPX_PK_BYTES, m, mlen); - sha256_inc_finalize(seed, state, inbuf, SPX_N + SPX_PK_BYTES + mlen); + sha256_inc_finalize(seed, &state, inbuf, SPX_N + SPX_PK_BYTES + mlen); } /* Otherwise first fill a block, so that finalize only uses the message */ else { memcpy(inbuf + SPX_N + SPX_PK_BYTES, m, SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES); - sha256_inc_blocks(state, inbuf, SPX_INBLOCKS); + sha256_inc_blocks(&state, inbuf, SPX_INBLOCKS); m += SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES; mlen -= SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES; - sha256_inc_finalize(seed, state, m, mlen); + sha256_inc_finalize(seed, &state, m, mlen); } /* By doing this in two steps, we prevent hashing the message twice; diff --git a/crypto_sign/sphincs-sha256-128f-simple/clean/sha256.c b/crypto_sign/sphincs-sha256-128f-simple/clean/sha256.c index f37d567b..c96445a7 100644 --- a/crypto_sign/sphincs-sha256-128f-simple/clean/sha256.c +++ b/crypto_sign/sphincs-sha256-128f-simple/clean/sha256.c @@ -50,7 +50,7 @@ void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_mgf1( } } -uint8_t PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_state_seeded[40]; +sha256ctx PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_state_seeded; /** * Absorb the constant pub_seed using one round of the compression function @@ -67,6 +67,6 @@ void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_seed_state(const unsigned char *pub_s block[i] = 0; } - sha256_inc_init(PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_state_seeded); - sha256_inc_blocks(PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_state_seeded, block, 1); + sha256_inc_init(&PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_state_seeded); + sha256_inc_blocks(&PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_state_seeded, block, 1); } diff --git a/crypto_sign/sphincs-sha256-128f-simple/clean/sha256.h b/crypto_sign/sphincs-sha256-128f-simple/clean/sha256.h index a9895c49..cd2c1cb7 100644 --- a/crypto_sign/sphincs-sha256-128f-simple/clean/sha256.h +++ b/crypto_sign/sphincs-sha256-128f-simple/clean/sha256.h @@ -8,13 +8,15 @@ #include #include +#include "sha2.h" + void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_compress_address(unsigned char *out, const uint32_t addr[8]); void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_mgf1( unsigned char *out, unsigned long outlen, unsigned char *input_plus_four_bytes, unsigned long inlen); -extern uint8_t PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_state_seeded[40]; +extern sha256ctx PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_state_seeded; void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_seed_state(const unsigned char *pub_seed); diff --git a/crypto_sign/sphincs-sha256-128f-simple/clean/thash_sha256_simple.c b/crypto_sign/sphincs-sha256-128f-simple/clean/thash_sha256_simple.c index 4c14be56..ffd2e9ed 100644 --- a/crypto_sign/sphincs-sha256-128f-simple/clean/thash_sha256_simple.c +++ b/crypto_sign/sphincs-sha256-128f-simple/clean/thash_sha256_simple.c @@ -17,17 +17,17 @@ static void PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_thash( const unsigned char *pub_seed, uint32_t addr[8]) { unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; - uint8_t sha2_state[40]; + sha256ctx sha2_state; (void)pub_seed; /* Suppress an 'unused parameter' warning. */ /* Retrieve precomputed state containing pub_seed */ - memcpy(sha2_state, PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_state_seeded, 40 * sizeof(uint8_t)); + memcpy(&sha2_state, &PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_state_seeded, sizeof(sha256ctx)); PQCLEAN_SPHINCSSHA256128FSIMPLE_CLEAN_compress_address(buf, addr); memcpy(buf + SPX_SHA256_ADDR_BYTES, in, inblocks * SPX_N); - sha256_inc_finalize(outbuf, sha2_state, buf, SPX_SHA256_ADDR_BYTES + inblocks * SPX_N); + sha256_inc_finalize(outbuf, &sha2_state, buf, SPX_SHA256_ADDR_BYTES + inblocks * SPX_N); memcpy(out, outbuf, SPX_N); } diff --git a/crypto_sign/sphincs-sha256-128s-robust/META.yml b/crypto_sign/sphincs-sha256-128s-robust/META.yml index 7f85adfd..afe78608 100644 --- a/crypto_sign/sphincs-sha256-128s-robust/META.yml +++ b/crypto_sign/sphincs-sha256-128s-robust/META.yml @@ -4,6 +4,7 @@ claimed-nist-level: 1 length-public-key: 32 length-secret-key: 64 length-signature: 8080 +nistkat-sha256: 4ddcad5141217340f9f28afdcf25cc236d7975bcfb41b39660e84568a9a461fe testvectors-sha256: 29d6d0dd732078d177779a61b7654bbe59fcf2ecb9bcd2ade8391791a6570a63 principal-submitter: Andreas Hülsing auxiliary-submitters: diff --git a/crypto_sign/sphincs-sha256-128s-robust/clean/Makefile b/crypto_sign/sphincs-sha256-128s-robust/clean/Makefile index 54dc7ba3..7008633e 100644 --- a/crypto_sign/sphincs-sha256-128s-robust/clean/Makefile +++ b/crypto_sign/sphincs-sha256-128s-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-128s-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_robust.o sha256.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-128s-robust/clean/hash_sha256.c b/crypto_sign/sphincs-sha256-128s-robust/clean/hash_sha256.c index c15b44b1..8b342c5d 100644 --- a/crypto_sign/sphincs-sha256-128s-robust/clean/hash_sha256.c +++ b/crypto_sign/sphincs-sha256-128s-robust/clean/hash_sha256.c @@ -45,7 +45,7 @@ void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_gen_message_random( const unsigned char *sk_prf, const unsigned char *optrand, const unsigned char *m, size_t mlen) { unsigned char buf[SPX_SHA256_BLOCK_BYTES + SPX_SHA256_OUTPUT_BYTES]; - uint8_t state[40]; + sha256ctx state; int i; /* This implements HMAC-SHA256 */ @@ -54,25 +54,25 @@ void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_gen_message_random( } memset(buf + SPX_N, 0x36, SPX_SHA256_BLOCK_BYTES - SPX_N); - sha256_inc_init(state); - sha256_inc_blocks(state, buf, 1); + sha256_inc_init(&state); + sha256_inc_blocks(&state, buf, 1); memcpy(buf, optrand, SPX_N); /* If optrand + message cannot fill up an entire block */ if (SPX_N + mlen < SPX_SHA256_BLOCK_BYTES) { memcpy(buf + SPX_N, m, mlen); - sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, state, + sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, &state, buf, mlen + SPX_N); } /* Otherwise first fill a block, so that finalize only uses the message */ else { memcpy(buf + SPX_N, m, SPX_SHA256_BLOCK_BYTES - SPX_N); - sha256_inc_blocks(state, buf, 1); + sha256_inc_blocks(&state, buf, 1); m += SPX_SHA256_BLOCK_BYTES - SPX_N; mlen -= SPX_SHA256_BLOCK_BYTES - SPX_N; - sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, state, m, mlen); + sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, &state, m, mlen); } for (i = 0; i < SPX_N; i++) { @@ -108,9 +108,9 @@ void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_hash_message( unsigned char buf[SPX_DGST_BYTES]; unsigned char *bufp = buf; - uint8_t state[40]; + sha256ctx state; - sha256_inc_init(state); + sha256_inc_init(&state); memcpy(inbuf, R, SPX_N); memcpy(inbuf + SPX_N, pk, SPX_PK_BYTES); @@ -118,17 +118,17 @@ void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_hash_message( /* If R + pk + message cannot fill up an entire block */ if (SPX_N + SPX_PK_BYTES + mlen < SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES) { memcpy(inbuf + SPX_N + SPX_PK_BYTES, m, mlen); - sha256_inc_finalize(seed, state, inbuf, SPX_N + SPX_PK_BYTES + mlen); + sha256_inc_finalize(seed, &state, inbuf, SPX_N + SPX_PK_BYTES + mlen); } /* Otherwise first fill a block, so that finalize only uses the message */ else { memcpy(inbuf + SPX_N + SPX_PK_BYTES, m, SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES); - sha256_inc_blocks(state, inbuf, SPX_INBLOCKS); + sha256_inc_blocks(&state, inbuf, SPX_INBLOCKS); m += SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES; mlen -= SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES; - sha256_inc_finalize(seed, state, m, mlen); + sha256_inc_finalize(seed, &state, m, mlen); } /* By doing this in two steps, we prevent hashing the message twice; diff --git a/crypto_sign/sphincs-sha256-128s-robust/clean/sha256.c b/crypto_sign/sphincs-sha256-128s-robust/clean/sha256.c index 27d2fbad..071bc2fb 100644 --- a/crypto_sign/sphincs-sha256-128s-robust/clean/sha256.c +++ b/crypto_sign/sphincs-sha256-128s-robust/clean/sha256.c @@ -50,7 +50,7 @@ void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_mgf1( } } -uint8_t PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_state_seeded[40]; +sha256ctx PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_state_seeded; /** * Absorb the constant pub_seed using one round of the compression function @@ -67,6 +67,6 @@ void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_seed_state(const unsigned char *pub_s block[i] = 0; } - sha256_inc_init(PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_state_seeded); - sha256_inc_blocks(PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_state_seeded, block, 1); + sha256_inc_init(&PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_state_seeded); + sha256_inc_blocks(&PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_state_seeded, block, 1); } diff --git a/crypto_sign/sphincs-sha256-128s-robust/clean/sha256.h b/crypto_sign/sphincs-sha256-128s-robust/clean/sha256.h index 22e85bd0..421d6fde 100644 --- a/crypto_sign/sphincs-sha256-128s-robust/clean/sha256.h +++ b/crypto_sign/sphincs-sha256-128s-robust/clean/sha256.h @@ -8,13 +8,15 @@ #include #include +#include "sha2.h" + void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_compress_address(unsigned char *out, const uint32_t addr[8]); void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_mgf1( unsigned char *out, unsigned long outlen, unsigned char *input_plus_four_bytes, unsigned long inlen); -extern uint8_t PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_state_seeded[40]; +extern sha256ctx PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_state_seeded; void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_seed_state(const unsigned char *pub_seed); diff --git a/crypto_sign/sphincs-sha256-128s-robust/clean/thash_sha256_robust.c b/crypto_sign/sphincs-sha256-128s-robust/clean/thash_sha256_robust.c index 5c468dae..d9474ab4 100644 --- a/crypto_sign/sphincs-sha256-128s-robust/clean/thash_sha256_robust.c +++ b/crypto_sign/sphincs-sha256-128s-robust/clean/thash_sha256_robust.c @@ -18,7 +18,7 @@ static void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash( unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; unsigned char *bitmask = buf + SPX_N + SPX_SHA256_ADDR_BYTES + 4; - uint8_t sha2_state[40]; + sha256ctx sha2_state; unsigned int i; memcpy(buf, pub_seed, SPX_N); @@ -27,13 +27,13 @@ static void PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_thash( PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_mgf1(bitmask, inblocks * SPX_N, buf, SPX_N + SPX_SHA256_ADDR_BYTES); /* Retrieve precomputed state containing pub_seed */ - memcpy(sha2_state, PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_state_seeded, 40 * sizeof(uint8_t)); + memcpy(&sha2_state, &PQCLEAN_SPHINCSSHA256128SROBUST_CLEAN_state_seeded, sizeof(sha256ctx)); for (i = 0; i < inblocks * SPX_N; i++) { buf[SPX_N + SPX_SHA256_ADDR_BYTES + i] = in[i] ^ bitmask[i]; } - sha256_inc_finalize(outbuf, sha2_state, buf + SPX_N, + sha256_inc_finalize(outbuf, &sha2_state, buf + SPX_N, SPX_SHA256_ADDR_BYTES + inblocks * SPX_N); memcpy(out, outbuf, SPX_N); } diff --git a/crypto_sign/sphincs-sha256-128s-simple/META.yml b/crypto_sign/sphincs-sha256-128s-simple/META.yml index 2f2e6b53..fd7f29ed 100644 --- a/crypto_sign/sphincs-sha256-128s-simple/META.yml +++ b/crypto_sign/sphincs-sha256-128s-simple/META.yml @@ -4,6 +4,7 @@ claimed-nist-level: 1 length-public-key: 32 length-secret-key: 64 length-signature: 8080 +nistkat-sha256: 8ae7a91b321cd18bd855710eea9d13deea1a53bb7858baee5f77d0237d1897eb testvectors-sha256: edf1b76246ac560558d7938f8ac7bbf820f1e697ef4f5b5e1962f04fadb84a76 principal-submitter: Andreas Hülsing auxiliary-submitters: diff --git a/crypto_sign/sphincs-sha256-128s-simple/clean/Makefile b/crypto_sign/sphincs-sha256-128s-simple/clean/Makefile index 4264ce00..c4d4ee71 100644 --- a/crypto_sign/sphincs-sha256-128s-simple/clean/Makefile +++ b/crypto_sign/sphincs-sha256-128s-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-128s-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_simple.o sha256.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-128s-simple/clean/hash_sha256.c b/crypto_sign/sphincs-sha256-128s-simple/clean/hash_sha256.c index 154c489e..35237406 100644 --- a/crypto_sign/sphincs-sha256-128s-simple/clean/hash_sha256.c +++ b/crypto_sign/sphincs-sha256-128s-simple/clean/hash_sha256.c @@ -45,7 +45,7 @@ void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_gen_message_random( const unsigned char *sk_prf, const unsigned char *optrand, const unsigned char *m, size_t mlen) { unsigned char buf[SPX_SHA256_BLOCK_BYTES + SPX_SHA256_OUTPUT_BYTES]; - uint8_t state[40]; + sha256ctx state; int i; /* This implements HMAC-SHA256 */ @@ -54,25 +54,25 @@ void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_gen_message_random( } memset(buf + SPX_N, 0x36, SPX_SHA256_BLOCK_BYTES - SPX_N); - sha256_inc_init(state); - sha256_inc_blocks(state, buf, 1); + sha256_inc_init(&state); + sha256_inc_blocks(&state, buf, 1); memcpy(buf, optrand, SPX_N); /* If optrand + message cannot fill up an entire block */ if (SPX_N + mlen < SPX_SHA256_BLOCK_BYTES) { memcpy(buf + SPX_N, m, mlen); - sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, state, + sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, &state, buf, mlen + SPX_N); } /* Otherwise first fill a block, so that finalize only uses the message */ else { memcpy(buf + SPX_N, m, SPX_SHA256_BLOCK_BYTES - SPX_N); - sha256_inc_blocks(state, buf, 1); + sha256_inc_blocks(&state, buf, 1); m += SPX_SHA256_BLOCK_BYTES - SPX_N; mlen -= SPX_SHA256_BLOCK_BYTES - SPX_N; - sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, state, m, mlen); + sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, &state, m, mlen); } for (i = 0; i < SPX_N; i++) { @@ -108,9 +108,9 @@ void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_hash_message( unsigned char buf[SPX_DGST_BYTES]; unsigned char *bufp = buf; - uint8_t state[40]; + sha256ctx state; - sha256_inc_init(state); + sha256_inc_init(&state); memcpy(inbuf, R, SPX_N); memcpy(inbuf + SPX_N, pk, SPX_PK_BYTES); @@ -118,17 +118,17 @@ void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_hash_message( /* If R + pk + message cannot fill up an entire block */ if (SPX_N + SPX_PK_BYTES + mlen < SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES) { memcpy(inbuf + SPX_N + SPX_PK_BYTES, m, mlen); - sha256_inc_finalize(seed, state, inbuf, SPX_N + SPX_PK_BYTES + mlen); + sha256_inc_finalize(seed, &state, inbuf, SPX_N + SPX_PK_BYTES + mlen); } /* Otherwise first fill a block, so that finalize only uses the message */ else { memcpy(inbuf + SPX_N + SPX_PK_BYTES, m, SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES); - sha256_inc_blocks(state, inbuf, SPX_INBLOCKS); + sha256_inc_blocks(&state, inbuf, SPX_INBLOCKS); m += SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES; mlen -= SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES; - sha256_inc_finalize(seed, state, m, mlen); + sha256_inc_finalize(seed, &state, m, mlen); } /* By doing this in two steps, we prevent hashing the message twice; diff --git a/crypto_sign/sphincs-sha256-128s-simple/clean/sha256.c b/crypto_sign/sphincs-sha256-128s-simple/clean/sha256.c index b52f6c49..9d241b6a 100644 --- a/crypto_sign/sphincs-sha256-128s-simple/clean/sha256.c +++ b/crypto_sign/sphincs-sha256-128s-simple/clean/sha256.c @@ -50,7 +50,7 @@ void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_mgf1( } } -uint8_t PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_state_seeded[40]; +sha256ctx PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_state_seeded; /** * Absorb the constant pub_seed using one round of the compression function @@ -67,6 +67,6 @@ void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_seed_state(const unsigned char *pub_s block[i] = 0; } - sha256_inc_init(PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_state_seeded); - sha256_inc_blocks(PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_state_seeded, block, 1); + sha256_inc_init(&PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_state_seeded); + sha256_inc_blocks(&PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_state_seeded, block, 1); } diff --git a/crypto_sign/sphincs-sha256-128s-simple/clean/sha256.h b/crypto_sign/sphincs-sha256-128s-simple/clean/sha256.h index f3f2c3dc..245c60b6 100644 --- a/crypto_sign/sphincs-sha256-128s-simple/clean/sha256.h +++ b/crypto_sign/sphincs-sha256-128s-simple/clean/sha256.h @@ -8,13 +8,15 @@ #include #include +#include "sha2.h" + void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_compress_address(unsigned char *out, const uint32_t addr[8]); void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_mgf1( unsigned char *out, unsigned long outlen, unsigned char *input_plus_four_bytes, unsigned long inlen); -extern uint8_t PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_state_seeded[40]; +extern sha256ctx PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_state_seeded; void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_seed_state(const unsigned char *pub_seed); diff --git a/crypto_sign/sphincs-sha256-128s-simple/clean/thash_sha256_simple.c b/crypto_sign/sphincs-sha256-128s-simple/clean/thash_sha256_simple.c index b6303756..34f7d485 100644 --- a/crypto_sign/sphincs-sha256-128s-simple/clean/thash_sha256_simple.c +++ b/crypto_sign/sphincs-sha256-128s-simple/clean/thash_sha256_simple.c @@ -17,17 +17,17 @@ static void PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_thash( const unsigned char *pub_seed, uint32_t addr[8]) { unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; - uint8_t sha2_state[40]; + sha256ctx sha2_state; (void)pub_seed; /* Suppress an 'unused parameter' warning. */ /* Retrieve precomputed state containing pub_seed */ - memcpy(sha2_state, PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_state_seeded, 40 * sizeof(uint8_t)); + memcpy(&sha2_state, &PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_state_seeded, sizeof(sha256ctx)); PQCLEAN_SPHINCSSHA256128SSIMPLE_CLEAN_compress_address(buf, addr); memcpy(buf + SPX_SHA256_ADDR_BYTES, in, inblocks * SPX_N); - sha256_inc_finalize(outbuf, sha2_state, buf, SPX_SHA256_ADDR_BYTES + inblocks * SPX_N); + sha256_inc_finalize(outbuf, &sha2_state, buf, SPX_SHA256_ADDR_BYTES + inblocks * SPX_N); memcpy(out, outbuf, SPX_N); } diff --git a/crypto_sign/sphincs-sha256-192f-robust/META.yml b/crypto_sign/sphincs-sha256-192f-robust/META.yml index 8ede894f..dacf29d1 100644 --- a/crypto_sign/sphincs-sha256-192f-robust/META.yml +++ b/crypto_sign/sphincs-sha256-192f-robust/META.yml @@ -4,6 +4,7 @@ claimed-nist-level: 3 length-public-key: 48 length-secret-key: 96 length-signature: 35664 +nistkat-sha256: 9d0898cb264172c31d0fb4901dd56d46728e83e0bf008abccb8b0912c2ebbc52 testvectors-sha256: ca61e66c0377fd367ab0c920d2190855a64348668a336d300ec7f2c72e721be4 principal-submitter: Andreas Hülsing auxiliary-submitters: diff --git a/crypto_sign/sphincs-sha256-192f-robust/clean/Makefile b/crypto_sign/sphincs-sha256-192f-robust/clean/Makefile index a06d5196..fe77f6ae 100644 --- a/crypto_sign/sphincs-sha256-192f-robust/clean/Makefile +++ b/crypto_sign/sphincs-sha256-192f-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-192f-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_robust.o sha256.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-192f-robust/clean/hash_sha256.c b/crypto_sign/sphincs-sha256-192f-robust/clean/hash_sha256.c index 73d3bbd1..dbe22075 100644 --- a/crypto_sign/sphincs-sha256-192f-robust/clean/hash_sha256.c +++ b/crypto_sign/sphincs-sha256-192f-robust/clean/hash_sha256.c @@ -45,7 +45,7 @@ void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_gen_message_random( const unsigned char *sk_prf, const unsigned char *optrand, const unsigned char *m, size_t mlen) { unsigned char buf[SPX_SHA256_BLOCK_BYTES + SPX_SHA256_OUTPUT_BYTES]; - uint8_t state[40]; + sha256ctx state; int i; /* This implements HMAC-SHA256 */ @@ -54,25 +54,25 @@ void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_gen_message_random( } memset(buf + SPX_N, 0x36, SPX_SHA256_BLOCK_BYTES - SPX_N); - sha256_inc_init(state); - sha256_inc_blocks(state, buf, 1); + sha256_inc_init(&state); + sha256_inc_blocks(&state, buf, 1); memcpy(buf, optrand, SPX_N); /* If optrand + message cannot fill up an entire block */ if (SPX_N + mlen < SPX_SHA256_BLOCK_BYTES) { memcpy(buf + SPX_N, m, mlen); - sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, state, + sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, &state, buf, mlen + SPX_N); } /* Otherwise first fill a block, so that finalize only uses the message */ else { memcpy(buf + SPX_N, m, SPX_SHA256_BLOCK_BYTES - SPX_N); - sha256_inc_blocks(state, buf, 1); + sha256_inc_blocks(&state, buf, 1); m += SPX_SHA256_BLOCK_BYTES - SPX_N; mlen -= SPX_SHA256_BLOCK_BYTES - SPX_N; - sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, state, m, mlen); + sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, &state, m, mlen); } for (i = 0; i < SPX_N; i++) { @@ -108,9 +108,9 @@ void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_hash_message( unsigned char buf[SPX_DGST_BYTES]; unsigned char *bufp = buf; - uint8_t state[40]; + sha256ctx state; - sha256_inc_init(state); + sha256_inc_init(&state); memcpy(inbuf, R, SPX_N); memcpy(inbuf + SPX_N, pk, SPX_PK_BYTES); @@ -118,17 +118,17 @@ void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_hash_message( /* If R + pk + message cannot fill up an entire block */ if (SPX_N + SPX_PK_BYTES + mlen < SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES) { memcpy(inbuf + SPX_N + SPX_PK_BYTES, m, mlen); - sha256_inc_finalize(seed, state, inbuf, SPX_N + SPX_PK_BYTES + mlen); + sha256_inc_finalize(seed, &state, inbuf, SPX_N + SPX_PK_BYTES + mlen); } /* Otherwise first fill a block, so that finalize only uses the message */ else { memcpy(inbuf + SPX_N + SPX_PK_BYTES, m, SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES); - sha256_inc_blocks(state, inbuf, SPX_INBLOCKS); + sha256_inc_blocks(&state, inbuf, SPX_INBLOCKS); m += SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES; mlen -= SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES; - sha256_inc_finalize(seed, state, m, mlen); + sha256_inc_finalize(seed, &state, m, mlen); } /* By doing this in two steps, we prevent hashing the message twice; diff --git a/crypto_sign/sphincs-sha256-192f-robust/clean/sha256.c b/crypto_sign/sphincs-sha256-192f-robust/clean/sha256.c index 4f112ae9..22ce5960 100644 --- a/crypto_sign/sphincs-sha256-192f-robust/clean/sha256.c +++ b/crypto_sign/sphincs-sha256-192f-robust/clean/sha256.c @@ -50,7 +50,7 @@ void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_mgf1( } } -uint8_t PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_state_seeded[40]; +sha256ctx PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_state_seeded; /** * Absorb the constant pub_seed using one round of the compression function @@ -67,6 +67,6 @@ void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_seed_state(const unsigned char *pub_s block[i] = 0; } - sha256_inc_init(PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_state_seeded); - sha256_inc_blocks(PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_state_seeded, block, 1); + sha256_inc_init(&PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_state_seeded); + sha256_inc_blocks(&PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_state_seeded, block, 1); } diff --git a/crypto_sign/sphincs-sha256-192f-robust/clean/sha256.h b/crypto_sign/sphincs-sha256-192f-robust/clean/sha256.h index 1ee273f2..2ddfb42c 100644 --- a/crypto_sign/sphincs-sha256-192f-robust/clean/sha256.h +++ b/crypto_sign/sphincs-sha256-192f-robust/clean/sha256.h @@ -8,13 +8,15 @@ #include #include +#include "sha2.h" + void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_compress_address(unsigned char *out, const uint32_t addr[8]); void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_mgf1( unsigned char *out, unsigned long outlen, unsigned char *input_plus_four_bytes, unsigned long inlen); -extern uint8_t PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_state_seeded[40]; +extern sha256ctx PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_state_seeded; void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_seed_state(const unsigned char *pub_seed); diff --git a/crypto_sign/sphincs-sha256-192f-robust/clean/thash_sha256_robust.c b/crypto_sign/sphincs-sha256-192f-robust/clean/thash_sha256_robust.c index 32924361..69ba05ed 100644 --- a/crypto_sign/sphincs-sha256-192f-robust/clean/thash_sha256_robust.c +++ b/crypto_sign/sphincs-sha256-192f-robust/clean/thash_sha256_robust.c @@ -18,7 +18,7 @@ static void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash( unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; unsigned char *bitmask = buf + SPX_N + SPX_SHA256_ADDR_BYTES + 4; - uint8_t sha2_state[40]; + sha256ctx sha2_state; unsigned int i; memcpy(buf, pub_seed, SPX_N); @@ -27,13 +27,13 @@ static void PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_thash( PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_mgf1(bitmask, inblocks * SPX_N, buf, SPX_N + SPX_SHA256_ADDR_BYTES); /* Retrieve precomputed state containing pub_seed */ - memcpy(sha2_state, PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_state_seeded, 40 * sizeof(uint8_t)); + memcpy(&sha2_state, &PQCLEAN_SPHINCSSHA256192FROBUST_CLEAN_state_seeded, sizeof(sha256ctx)); for (i = 0; i < inblocks * SPX_N; i++) { buf[SPX_N + SPX_SHA256_ADDR_BYTES + i] = in[i] ^ bitmask[i]; } - sha256_inc_finalize(outbuf, sha2_state, buf + SPX_N, + sha256_inc_finalize(outbuf, &sha2_state, buf + SPX_N, SPX_SHA256_ADDR_BYTES + inblocks * SPX_N); memcpy(out, outbuf, SPX_N); } diff --git a/crypto_sign/sphincs-sha256-192f-simple/META.yml b/crypto_sign/sphincs-sha256-192f-simple/META.yml index 22134e40..bd15076f 100644 --- a/crypto_sign/sphincs-sha256-192f-simple/META.yml +++ b/crypto_sign/sphincs-sha256-192f-simple/META.yml @@ -4,6 +4,7 @@ claimed-nist-level: 3 length-public-key: 48 length-secret-key: 96 length-signature: 35664 +nistkat-sha256: 306fef951d07b17b27c67ffe9e63185ae5d5fde87619b76872a3ca969299d47c testvectors-sha256: b25e0f2560f500d8988809522c72ea3ab0f81be52476a6cdf9d05a890a2d2ce0 principal-submitter: Andreas Hülsing auxiliary-submitters: diff --git a/crypto_sign/sphincs-sha256-192f-simple/clean/Makefile b/crypto_sign/sphincs-sha256-192f-simple/clean/Makefile index f847f77a..95d9a155 100644 --- a/crypto_sign/sphincs-sha256-192f-simple/clean/Makefile +++ b/crypto_sign/sphincs-sha256-192f-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-192f-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_simple.o sha256.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-192f-simple/clean/hash_sha256.c b/crypto_sign/sphincs-sha256-192f-simple/clean/hash_sha256.c index 6944d0ff..2bc9f610 100644 --- a/crypto_sign/sphincs-sha256-192f-simple/clean/hash_sha256.c +++ b/crypto_sign/sphincs-sha256-192f-simple/clean/hash_sha256.c @@ -45,7 +45,7 @@ void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_gen_message_random( const unsigned char *sk_prf, const unsigned char *optrand, const unsigned char *m, size_t mlen) { unsigned char buf[SPX_SHA256_BLOCK_BYTES + SPX_SHA256_OUTPUT_BYTES]; - uint8_t state[40]; + sha256ctx state; int i; /* This implements HMAC-SHA256 */ @@ -54,25 +54,25 @@ void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_gen_message_random( } memset(buf + SPX_N, 0x36, SPX_SHA256_BLOCK_BYTES - SPX_N); - sha256_inc_init(state); - sha256_inc_blocks(state, buf, 1); + sha256_inc_init(&state); + sha256_inc_blocks(&state, buf, 1); memcpy(buf, optrand, SPX_N); /* If optrand + message cannot fill up an entire block */ if (SPX_N + mlen < SPX_SHA256_BLOCK_BYTES) { memcpy(buf + SPX_N, m, mlen); - sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, state, + sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, &state, buf, mlen + SPX_N); } /* Otherwise first fill a block, so that finalize only uses the message */ else { memcpy(buf + SPX_N, m, SPX_SHA256_BLOCK_BYTES - SPX_N); - sha256_inc_blocks(state, buf, 1); + sha256_inc_blocks(&state, buf, 1); m += SPX_SHA256_BLOCK_BYTES - SPX_N; mlen -= SPX_SHA256_BLOCK_BYTES - SPX_N; - sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, state, m, mlen); + sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, &state, m, mlen); } for (i = 0; i < SPX_N; i++) { @@ -108,9 +108,9 @@ void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_hash_message( unsigned char buf[SPX_DGST_BYTES]; unsigned char *bufp = buf; - uint8_t state[40]; + sha256ctx state; - sha256_inc_init(state); + sha256_inc_init(&state); memcpy(inbuf, R, SPX_N); memcpy(inbuf + SPX_N, pk, SPX_PK_BYTES); @@ -118,17 +118,17 @@ void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_hash_message( /* If R + pk + message cannot fill up an entire block */ if (SPX_N + SPX_PK_BYTES + mlen < SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES) { memcpy(inbuf + SPX_N + SPX_PK_BYTES, m, mlen); - sha256_inc_finalize(seed, state, inbuf, SPX_N + SPX_PK_BYTES + mlen); + sha256_inc_finalize(seed, &state, inbuf, SPX_N + SPX_PK_BYTES + mlen); } /* Otherwise first fill a block, so that finalize only uses the message */ else { memcpy(inbuf + SPX_N + SPX_PK_BYTES, m, SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES); - sha256_inc_blocks(state, inbuf, SPX_INBLOCKS); + sha256_inc_blocks(&state, inbuf, SPX_INBLOCKS); m += SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES; mlen -= SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES; - sha256_inc_finalize(seed, state, m, mlen); + sha256_inc_finalize(seed, &state, m, mlen); } /* By doing this in two steps, we prevent hashing the message twice; diff --git a/crypto_sign/sphincs-sha256-192f-simple/clean/sha256.c b/crypto_sign/sphincs-sha256-192f-simple/clean/sha256.c index 425fd631..4de4b235 100644 --- a/crypto_sign/sphincs-sha256-192f-simple/clean/sha256.c +++ b/crypto_sign/sphincs-sha256-192f-simple/clean/sha256.c @@ -50,7 +50,7 @@ void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_mgf1( } } -uint8_t PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_state_seeded[40]; +sha256ctx PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_state_seeded; /** * Absorb the constant pub_seed using one round of the compression function @@ -67,6 +67,6 @@ void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_seed_state(const unsigned char *pub_s block[i] = 0; } - sha256_inc_init(PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_state_seeded); - sha256_inc_blocks(PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_state_seeded, block, 1); + sha256_inc_init(&PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_state_seeded); + sha256_inc_blocks(&PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_state_seeded, block, 1); } diff --git a/crypto_sign/sphincs-sha256-192f-simple/clean/sha256.h b/crypto_sign/sphincs-sha256-192f-simple/clean/sha256.h index 02e0536f..c4f74403 100644 --- a/crypto_sign/sphincs-sha256-192f-simple/clean/sha256.h +++ b/crypto_sign/sphincs-sha256-192f-simple/clean/sha256.h @@ -8,13 +8,15 @@ #include #include +#include "sha2.h" + void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_compress_address(unsigned char *out, const uint32_t addr[8]); void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_mgf1( unsigned char *out, unsigned long outlen, unsigned char *input_plus_four_bytes, unsigned long inlen); -extern uint8_t PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_state_seeded[40]; +extern sha256ctx PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_state_seeded; void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_seed_state(const unsigned char *pub_seed); diff --git a/crypto_sign/sphincs-sha256-192f-simple/clean/thash_sha256_simple.c b/crypto_sign/sphincs-sha256-192f-simple/clean/thash_sha256_simple.c index 0f843507..966d33db 100644 --- a/crypto_sign/sphincs-sha256-192f-simple/clean/thash_sha256_simple.c +++ b/crypto_sign/sphincs-sha256-192f-simple/clean/thash_sha256_simple.c @@ -17,17 +17,17 @@ static void PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_thash( const unsigned char *pub_seed, uint32_t addr[8]) { unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; - uint8_t sha2_state[40]; + sha256ctx sha2_state; (void)pub_seed; /* Suppress an 'unused parameter' warning. */ /* Retrieve precomputed state containing pub_seed */ - memcpy(sha2_state, PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_state_seeded, 40 * sizeof(uint8_t)); + memcpy(&sha2_state, &PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_state_seeded, sizeof(sha256ctx)); PQCLEAN_SPHINCSSHA256192FSIMPLE_CLEAN_compress_address(buf, addr); memcpy(buf + SPX_SHA256_ADDR_BYTES, in, inblocks * SPX_N); - sha256_inc_finalize(outbuf, sha2_state, buf, SPX_SHA256_ADDR_BYTES + inblocks * SPX_N); + sha256_inc_finalize(outbuf, &sha2_state, buf, SPX_SHA256_ADDR_BYTES + inblocks * SPX_N); memcpy(out, outbuf, SPX_N); } diff --git a/crypto_sign/sphincs-sha256-192s-robust/META.yml b/crypto_sign/sphincs-sha256-192s-robust/META.yml index 72efa7d9..8c25156d 100644 --- a/crypto_sign/sphincs-sha256-192s-robust/META.yml +++ b/crypto_sign/sphincs-sha256-192s-robust/META.yml @@ -4,6 +4,7 @@ claimed-nist-level: 3 length-public-key: 48 length-secret-key: 96 length-signature: 17064 +nistkat-sha256: 23374b2ece45c8ec7272473d70eb424894324702616b8456343dbd79f109b675 testvectors-sha256: 1be5c30de6d0b856b1b51f0ff50a2acf9c3a359ee2178004e153bdfc50a68832 principal-submitter: Andreas Hülsing auxiliary-submitters: diff --git a/crypto_sign/sphincs-sha256-192s-robust/clean/Makefile b/crypto_sign/sphincs-sha256-192s-robust/clean/Makefile index 2f134259..bc213ecc 100644 --- a/crypto_sign/sphincs-sha256-192s-robust/clean/Makefile +++ b/crypto_sign/sphincs-sha256-192s-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-192s-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_robust.o sha256.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-192s-robust/clean/hash_sha256.c b/crypto_sign/sphincs-sha256-192s-robust/clean/hash_sha256.c index 99850139..59659720 100644 --- a/crypto_sign/sphincs-sha256-192s-robust/clean/hash_sha256.c +++ b/crypto_sign/sphincs-sha256-192s-robust/clean/hash_sha256.c @@ -45,7 +45,7 @@ void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_gen_message_random( const unsigned char *sk_prf, const unsigned char *optrand, const unsigned char *m, size_t mlen) { unsigned char buf[SPX_SHA256_BLOCK_BYTES + SPX_SHA256_OUTPUT_BYTES]; - uint8_t state[40]; + sha256ctx state; int i; /* This implements HMAC-SHA256 */ @@ -54,25 +54,25 @@ void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_gen_message_random( } memset(buf + SPX_N, 0x36, SPX_SHA256_BLOCK_BYTES - SPX_N); - sha256_inc_init(state); - sha256_inc_blocks(state, buf, 1); + sha256_inc_init(&state); + sha256_inc_blocks(&state, buf, 1); memcpy(buf, optrand, SPX_N); /* If optrand + message cannot fill up an entire block */ if (SPX_N + mlen < SPX_SHA256_BLOCK_BYTES) { memcpy(buf + SPX_N, m, mlen); - sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, state, + sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, &state, buf, mlen + SPX_N); } /* Otherwise first fill a block, so that finalize only uses the message */ else { memcpy(buf + SPX_N, m, SPX_SHA256_BLOCK_BYTES - SPX_N); - sha256_inc_blocks(state, buf, 1); + sha256_inc_blocks(&state, buf, 1); m += SPX_SHA256_BLOCK_BYTES - SPX_N; mlen -= SPX_SHA256_BLOCK_BYTES - SPX_N; - sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, state, m, mlen); + sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, &state, m, mlen); } for (i = 0; i < SPX_N; i++) { @@ -108,9 +108,9 @@ void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_hash_message( unsigned char buf[SPX_DGST_BYTES]; unsigned char *bufp = buf; - uint8_t state[40]; + sha256ctx state; - sha256_inc_init(state); + sha256_inc_init(&state); memcpy(inbuf, R, SPX_N); memcpy(inbuf + SPX_N, pk, SPX_PK_BYTES); @@ -118,17 +118,17 @@ void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_hash_message( /* If R + pk + message cannot fill up an entire block */ if (SPX_N + SPX_PK_BYTES + mlen < SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES) { memcpy(inbuf + SPX_N + SPX_PK_BYTES, m, mlen); - sha256_inc_finalize(seed, state, inbuf, SPX_N + SPX_PK_BYTES + mlen); + sha256_inc_finalize(seed, &state, inbuf, SPX_N + SPX_PK_BYTES + mlen); } /* Otherwise first fill a block, so that finalize only uses the message */ else { memcpy(inbuf + SPX_N + SPX_PK_BYTES, m, SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES); - sha256_inc_blocks(state, inbuf, SPX_INBLOCKS); + sha256_inc_blocks(&state, inbuf, SPX_INBLOCKS); m += SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES; mlen -= SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES; - sha256_inc_finalize(seed, state, m, mlen); + sha256_inc_finalize(seed, &state, m, mlen); } /* By doing this in two steps, we prevent hashing the message twice; diff --git a/crypto_sign/sphincs-sha256-192s-robust/clean/sha256.c b/crypto_sign/sphincs-sha256-192s-robust/clean/sha256.c index 2d94d069..2666f1d3 100644 --- a/crypto_sign/sphincs-sha256-192s-robust/clean/sha256.c +++ b/crypto_sign/sphincs-sha256-192s-robust/clean/sha256.c @@ -50,7 +50,7 @@ void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_mgf1( } } -uint8_t PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_state_seeded[40]; +sha256ctx PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_state_seeded; /** * Absorb the constant pub_seed using one round of the compression function @@ -67,6 +67,6 @@ void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_seed_state(const unsigned char *pub_s block[i] = 0; } - sha256_inc_init(PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_state_seeded); - sha256_inc_blocks(PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_state_seeded, block, 1); + sha256_inc_init(&PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_state_seeded); + sha256_inc_blocks(&PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_state_seeded, block, 1); } diff --git a/crypto_sign/sphincs-sha256-192s-robust/clean/sha256.h b/crypto_sign/sphincs-sha256-192s-robust/clean/sha256.h index 63f173d0..a391bc85 100644 --- a/crypto_sign/sphincs-sha256-192s-robust/clean/sha256.h +++ b/crypto_sign/sphincs-sha256-192s-robust/clean/sha256.h @@ -8,13 +8,15 @@ #include #include +#include "sha2.h" + void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_compress_address(unsigned char *out, const uint32_t addr[8]); void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_mgf1( unsigned char *out, unsigned long outlen, unsigned char *input_plus_four_bytes, unsigned long inlen); -extern uint8_t PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_state_seeded[40]; +extern sha256ctx PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_state_seeded; void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_seed_state(const unsigned char *pub_seed); diff --git a/crypto_sign/sphincs-sha256-192s-robust/clean/thash_sha256_robust.c b/crypto_sign/sphincs-sha256-192s-robust/clean/thash_sha256_robust.c index c2c09379..ee3ce784 100644 --- a/crypto_sign/sphincs-sha256-192s-robust/clean/thash_sha256_robust.c +++ b/crypto_sign/sphincs-sha256-192s-robust/clean/thash_sha256_robust.c @@ -18,7 +18,7 @@ static void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_thash( unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; unsigned char *bitmask = buf + SPX_N + SPX_SHA256_ADDR_BYTES + 4; - uint8_t sha2_state[40]; + sha256ctx sha2_state; unsigned int i; memcpy(buf, pub_seed, SPX_N); @@ -27,13 +27,13 @@ static void PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_thash( PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_mgf1(bitmask, inblocks * SPX_N, buf, SPX_N + SPX_SHA256_ADDR_BYTES); /* Retrieve precomputed state containing pub_seed */ - memcpy(sha2_state, PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_state_seeded, 40 * sizeof(uint8_t)); + memcpy(&sha2_state, &PQCLEAN_SPHINCSSHA256192SROBUST_CLEAN_state_seeded, sizeof(sha256ctx)); for (i = 0; i < inblocks * SPX_N; i++) { buf[SPX_N + SPX_SHA256_ADDR_BYTES + i] = in[i] ^ bitmask[i]; } - sha256_inc_finalize(outbuf, sha2_state, buf + SPX_N, + sha256_inc_finalize(outbuf, &sha2_state, buf + SPX_N, SPX_SHA256_ADDR_BYTES + inblocks * SPX_N); memcpy(out, outbuf, SPX_N); } diff --git a/crypto_sign/sphincs-sha256-192s-simple/META.yml b/crypto_sign/sphincs-sha256-192s-simple/META.yml index 53a29b4f..ebd07554 100644 --- a/crypto_sign/sphincs-sha256-192s-simple/META.yml +++ b/crypto_sign/sphincs-sha256-192s-simple/META.yml @@ -4,6 +4,7 @@ claimed-nist-level: 3 length-public-key: 48 length-secret-key: 96 length-signature: 17064 +nistkat-sha256: 02b192ff93bc8977a80e9efc8fa6814ae85c2ad939f7185a959b428c1eb77150 testvectors-sha256: ee413e410a29274a9647b9440d6a554670e0f9587efaaddedf82e4923f68f80e principal-submitter: Andreas Hülsing auxiliary-submitters: diff --git a/crypto_sign/sphincs-sha256-192s-simple/clean/Makefile b/crypto_sign/sphincs-sha256-192s-simple/clean/Makefile index 087324db..329667ce 100644 --- a/crypto_sign/sphincs-sha256-192s-simple/clean/Makefile +++ b/crypto_sign/sphincs-sha256-192s-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-192s-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_simple.o sha256.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-192s-simple/clean/hash_sha256.c b/crypto_sign/sphincs-sha256-192s-simple/clean/hash_sha256.c index 230ad7de..027a2825 100644 --- a/crypto_sign/sphincs-sha256-192s-simple/clean/hash_sha256.c +++ b/crypto_sign/sphincs-sha256-192s-simple/clean/hash_sha256.c @@ -45,7 +45,7 @@ void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_gen_message_random( const unsigned char *sk_prf, const unsigned char *optrand, const unsigned char *m, size_t mlen) { unsigned char buf[SPX_SHA256_BLOCK_BYTES + SPX_SHA256_OUTPUT_BYTES]; - uint8_t state[40]; + sha256ctx state; int i; /* This implements HMAC-SHA256 */ @@ -54,25 +54,25 @@ void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_gen_message_random( } memset(buf + SPX_N, 0x36, SPX_SHA256_BLOCK_BYTES - SPX_N); - sha256_inc_init(state); - sha256_inc_blocks(state, buf, 1); + sha256_inc_init(&state); + sha256_inc_blocks(&state, buf, 1); memcpy(buf, optrand, SPX_N); /* If optrand + message cannot fill up an entire block */ if (SPX_N + mlen < SPX_SHA256_BLOCK_BYTES) { memcpy(buf + SPX_N, m, mlen); - sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, state, + sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, &state, buf, mlen + SPX_N); } /* Otherwise first fill a block, so that finalize only uses the message */ else { memcpy(buf + SPX_N, m, SPX_SHA256_BLOCK_BYTES - SPX_N); - sha256_inc_blocks(state, buf, 1); + sha256_inc_blocks(&state, buf, 1); m += SPX_SHA256_BLOCK_BYTES - SPX_N; mlen -= SPX_SHA256_BLOCK_BYTES - SPX_N; - sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, state, m, mlen); + sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, &state, m, mlen); } for (i = 0; i < SPX_N; i++) { @@ -108,9 +108,9 @@ void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_hash_message( unsigned char buf[SPX_DGST_BYTES]; unsigned char *bufp = buf; - uint8_t state[40]; + sha256ctx state; - sha256_inc_init(state); + sha256_inc_init(&state); memcpy(inbuf, R, SPX_N); memcpy(inbuf + SPX_N, pk, SPX_PK_BYTES); @@ -118,17 +118,17 @@ void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_hash_message( /* If R + pk + message cannot fill up an entire block */ if (SPX_N + SPX_PK_BYTES + mlen < SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES) { memcpy(inbuf + SPX_N + SPX_PK_BYTES, m, mlen); - sha256_inc_finalize(seed, state, inbuf, SPX_N + SPX_PK_BYTES + mlen); + sha256_inc_finalize(seed, &state, inbuf, SPX_N + SPX_PK_BYTES + mlen); } /* Otherwise first fill a block, so that finalize only uses the message */ else { memcpy(inbuf + SPX_N + SPX_PK_BYTES, m, SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES); - sha256_inc_blocks(state, inbuf, SPX_INBLOCKS); + sha256_inc_blocks(&state, inbuf, SPX_INBLOCKS); m += SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES; mlen -= SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES; - sha256_inc_finalize(seed, state, m, mlen); + sha256_inc_finalize(seed, &state, m, mlen); } /* By doing this in two steps, we prevent hashing the message twice; diff --git a/crypto_sign/sphincs-sha256-192s-simple/clean/sha256.c b/crypto_sign/sphincs-sha256-192s-simple/clean/sha256.c index d6fe5626..7db3b07f 100644 --- a/crypto_sign/sphincs-sha256-192s-simple/clean/sha256.c +++ b/crypto_sign/sphincs-sha256-192s-simple/clean/sha256.c @@ -50,7 +50,7 @@ void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_mgf1( } } -uint8_t PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_state_seeded[40]; +sha256ctx PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_state_seeded; /** * Absorb the constant pub_seed using one round of the compression function @@ -67,6 +67,6 @@ void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_seed_state(const unsigned char *pub_s block[i] = 0; } - sha256_inc_init(PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_state_seeded); - sha256_inc_blocks(PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_state_seeded, block, 1); + sha256_inc_init(&PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_state_seeded); + sha256_inc_blocks(&PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_state_seeded, block, 1); } diff --git a/crypto_sign/sphincs-sha256-192s-simple/clean/sha256.h b/crypto_sign/sphincs-sha256-192s-simple/clean/sha256.h index c5c68a72..e9208f3a 100644 --- a/crypto_sign/sphincs-sha256-192s-simple/clean/sha256.h +++ b/crypto_sign/sphincs-sha256-192s-simple/clean/sha256.h @@ -8,13 +8,15 @@ #include #include +#include "sha2.h" + void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_compress_address(unsigned char *out, const uint32_t addr[8]); void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_mgf1( unsigned char *out, unsigned long outlen, unsigned char *input_plus_four_bytes, unsigned long inlen); -extern uint8_t PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_state_seeded[40]; +extern sha256ctx PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_state_seeded; void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_seed_state(const unsigned char *pub_seed); diff --git a/crypto_sign/sphincs-sha256-192s-simple/clean/thash_sha256_simple.c b/crypto_sign/sphincs-sha256-192s-simple/clean/thash_sha256_simple.c index 64745d6d..f03f06b0 100644 --- a/crypto_sign/sphincs-sha256-192s-simple/clean/thash_sha256_simple.c +++ b/crypto_sign/sphincs-sha256-192s-simple/clean/thash_sha256_simple.c @@ -17,17 +17,17 @@ static void PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_thash( const unsigned char *pub_seed, uint32_t addr[8]) { unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; - uint8_t sha2_state[40]; + sha256ctx sha2_state; (void)pub_seed; /* Suppress an 'unused parameter' warning. */ /* Retrieve precomputed state containing pub_seed */ - memcpy(sha2_state, PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_state_seeded, 40 * sizeof(uint8_t)); + memcpy(&sha2_state, &PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_state_seeded, sizeof(sha256ctx)); PQCLEAN_SPHINCSSHA256192SSIMPLE_CLEAN_compress_address(buf, addr); memcpy(buf + SPX_SHA256_ADDR_BYTES, in, inblocks * SPX_N); - sha256_inc_finalize(outbuf, sha2_state, buf, SPX_SHA256_ADDR_BYTES + inblocks * SPX_N); + sha256_inc_finalize(outbuf, &sha2_state, buf, SPX_SHA256_ADDR_BYTES + inblocks * SPX_N); memcpy(out, outbuf, SPX_N); } diff --git a/crypto_sign/sphincs-sha256-256f-robust/META.yml b/crypto_sign/sphincs-sha256-256f-robust/META.yml index 996632a5..ca697970 100644 --- a/crypto_sign/sphincs-sha256-256f-robust/META.yml +++ b/crypto_sign/sphincs-sha256-256f-robust/META.yml @@ -4,6 +4,7 @@ claimed-nist-level: 5 length-public-key: 64 length-secret-key: 128 length-signature: 49216 +nistkat-sha256: e6fafb97dc3575d5dcd79183a4d7faad4f2c986745c63e61ddae3648559664f7 testvectors-sha256: 14dd19ba3ff75bad890949050289ab0f178d7baa6dcb8ff6bcd6a873692a5686 principal-submitter: Andreas Hülsing auxiliary-submitters: diff --git a/crypto_sign/sphincs-sha256-256f-robust/clean/Makefile b/crypto_sign/sphincs-sha256-256f-robust/clean/Makefile index cae42e69..c312b90e 100644 --- a/crypto_sign/sphincs-sha256-256f-robust/clean/Makefile +++ b/crypto_sign/sphincs-sha256-256f-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-256f-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_robust.o sha256.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-256f-robust/clean/hash_sha256.c b/crypto_sign/sphincs-sha256-256f-robust/clean/hash_sha256.c index 699f52e1..02d07d37 100644 --- a/crypto_sign/sphincs-sha256-256f-robust/clean/hash_sha256.c +++ b/crypto_sign/sphincs-sha256-256f-robust/clean/hash_sha256.c @@ -45,7 +45,7 @@ void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_gen_message_random( const unsigned char *sk_prf, const unsigned char *optrand, const unsigned char *m, size_t mlen) { unsigned char buf[SPX_SHA256_BLOCK_BYTES + SPX_SHA256_OUTPUT_BYTES]; - uint8_t state[40]; + sha256ctx state; int i; /* This implements HMAC-SHA256 */ @@ -54,25 +54,25 @@ void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_gen_message_random( } memset(buf + SPX_N, 0x36, SPX_SHA256_BLOCK_BYTES - SPX_N); - sha256_inc_init(state); - sha256_inc_blocks(state, buf, 1); + sha256_inc_init(&state); + sha256_inc_blocks(&state, buf, 1); memcpy(buf, optrand, SPX_N); /* If optrand + message cannot fill up an entire block */ if (SPX_N + mlen < SPX_SHA256_BLOCK_BYTES) { memcpy(buf + SPX_N, m, mlen); - sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, state, + sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, &state, buf, mlen + SPX_N); } /* Otherwise first fill a block, so that finalize only uses the message */ else { memcpy(buf + SPX_N, m, SPX_SHA256_BLOCK_BYTES - SPX_N); - sha256_inc_blocks(state, buf, 1); + sha256_inc_blocks(&state, buf, 1); m += SPX_SHA256_BLOCK_BYTES - SPX_N; mlen -= SPX_SHA256_BLOCK_BYTES - SPX_N; - sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, state, m, mlen); + sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, &state, m, mlen); } for (i = 0; i < SPX_N; i++) { @@ -108,9 +108,9 @@ void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_hash_message( unsigned char buf[SPX_DGST_BYTES]; unsigned char *bufp = buf; - uint8_t state[40]; + sha256ctx state; - sha256_inc_init(state); + sha256_inc_init(&state); memcpy(inbuf, R, SPX_N); memcpy(inbuf + SPX_N, pk, SPX_PK_BYTES); @@ -118,17 +118,17 @@ void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_hash_message( /* If R + pk + message cannot fill up an entire block */ if (SPX_N + SPX_PK_BYTES + mlen < SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES) { memcpy(inbuf + SPX_N + SPX_PK_BYTES, m, mlen); - sha256_inc_finalize(seed, state, inbuf, SPX_N + SPX_PK_BYTES + mlen); + sha256_inc_finalize(seed, &state, inbuf, SPX_N + SPX_PK_BYTES + mlen); } /* Otherwise first fill a block, so that finalize only uses the message */ else { memcpy(inbuf + SPX_N + SPX_PK_BYTES, m, SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES); - sha256_inc_blocks(state, inbuf, SPX_INBLOCKS); + sha256_inc_blocks(&state, inbuf, SPX_INBLOCKS); m += SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES; mlen -= SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES; - sha256_inc_finalize(seed, state, m, mlen); + sha256_inc_finalize(seed, &state, m, mlen); } /* By doing this in two steps, we prevent hashing the message twice; diff --git a/crypto_sign/sphincs-sha256-256f-robust/clean/sha256.c b/crypto_sign/sphincs-sha256-256f-robust/clean/sha256.c index 294b0de6..85500774 100644 --- a/crypto_sign/sphincs-sha256-256f-robust/clean/sha256.c +++ b/crypto_sign/sphincs-sha256-256f-robust/clean/sha256.c @@ -50,7 +50,7 @@ void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_mgf1( } } -uint8_t PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_state_seeded[40]; +sha256ctx PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_state_seeded; /** * Absorb the constant pub_seed using one round of the compression function @@ -67,6 +67,6 @@ void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_seed_state(const unsigned char *pub_s block[i] = 0; } - sha256_inc_init(PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_state_seeded); - sha256_inc_blocks(PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_state_seeded, block, 1); + sha256_inc_init(&PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_state_seeded); + sha256_inc_blocks(&PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_state_seeded, block, 1); } diff --git a/crypto_sign/sphincs-sha256-256f-robust/clean/sha256.h b/crypto_sign/sphincs-sha256-256f-robust/clean/sha256.h index c16a7819..3e605ea5 100644 --- a/crypto_sign/sphincs-sha256-256f-robust/clean/sha256.h +++ b/crypto_sign/sphincs-sha256-256f-robust/clean/sha256.h @@ -8,13 +8,15 @@ #include #include +#include "sha2.h" + void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_compress_address(unsigned char *out, const uint32_t addr[8]); void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_mgf1( unsigned char *out, unsigned long outlen, unsigned char *input_plus_four_bytes, unsigned long inlen); -extern uint8_t PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_state_seeded[40]; +extern sha256ctx PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_state_seeded; void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_seed_state(const unsigned char *pub_seed); diff --git a/crypto_sign/sphincs-sha256-256f-robust/clean/thash_sha256_robust.c b/crypto_sign/sphincs-sha256-256f-robust/clean/thash_sha256_robust.c index 37f81ded..db986771 100644 --- a/crypto_sign/sphincs-sha256-256f-robust/clean/thash_sha256_robust.c +++ b/crypto_sign/sphincs-sha256-256f-robust/clean/thash_sha256_robust.c @@ -18,7 +18,7 @@ static void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_thash( unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; unsigned char *bitmask = buf + SPX_N + SPX_SHA256_ADDR_BYTES + 4; - uint8_t sha2_state[40]; + sha256ctx sha2_state; unsigned int i; memcpy(buf, pub_seed, SPX_N); @@ -27,13 +27,13 @@ static void PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_thash( PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_mgf1(bitmask, inblocks * SPX_N, buf, SPX_N + SPX_SHA256_ADDR_BYTES); /* Retrieve precomputed state containing pub_seed */ - memcpy(sha2_state, PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_state_seeded, 40 * sizeof(uint8_t)); + memcpy(&sha2_state, &PQCLEAN_SPHINCSSHA256256FROBUST_CLEAN_state_seeded, sizeof(sha256ctx)); for (i = 0; i < inblocks * SPX_N; i++) { buf[SPX_N + SPX_SHA256_ADDR_BYTES + i] = in[i] ^ bitmask[i]; } - sha256_inc_finalize(outbuf, sha2_state, buf + SPX_N, + sha256_inc_finalize(outbuf, &sha2_state, buf + SPX_N, SPX_SHA256_ADDR_BYTES + inblocks * SPX_N); memcpy(out, outbuf, SPX_N); } diff --git a/crypto_sign/sphincs-sha256-256f-simple/META.yml b/crypto_sign/sphincs-sha256-256f-simple/META.yml index 0a52e059..af6c695f 100644 --- a/crypto_sign/sphincs-sha256-256f-simple/META.yml +++ b/crypto_sign/sphincs-sha256-256f-simple/META.yml @@ -4,6 +4,7 @@ claimed-nist-level: 5 length-public-key: 64 length-secret-key: 128 length-signature: 49216 +nistkat-sha256: 88fa150041ce9c305a971cef8ec444881afc14c4590637fa4b91c1deb15bb215 testvectors-sha256: b4755edf8351c51225921af38a724d2bd9ff9f3afe4ae2abbc3a59763ecc897d principal-submitter: Andreas Hülsing auxiliary-submitters: diff --git a/crypto_sign/sphincs-sha256-256f-simple/clean/Makefile b/crypto_sign/sphincs-sha256-256f-simple/clean/Makefile index df2ed05c..852496ea 100644 --- a/crypto_sign/sphincs-sha256-256f-simple/clean/Makefile +++ b/crypto_sign/sphincs-sha256-256f-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-256f-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_simple.o sha256.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-256f-simple/clean/hash_sha256.c b/crypto_sign/sphincs-sha256-256f-simple/clean/hash_sha256.c index f8c840fb..be9cae55 100644 --- a/crypto_sign/sphincs-sha256-256f-simple/clean/hash_sha256.c +++ b/crypto_sign/sphincs-sha256-256f-simple/clean/hash_sha256.c @@ -45,7 +45,7 @@ void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_gen_message_random( const unsigned char *sk_prf, const unsigned char *optrand, const unsigned char *m, size_t mlen) { unsigned char buf[SPX_SHA256_BLOCK_BYTES + SPX_SHA256_OUTPUT_BYTES]; - uint8_t state[40]; + sha256ctx state; int i; /* This implements HMAC-SHA256 */ @@ -54,25 +54,25 @@ void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_gen_message_random( } memset(buf + SPX_N, 0x36, SPX_SHA256_BLOCK_BYTES - SPX_N); - sha256_inc_init(state); - sha256_inc_blocks(state, buf, 1); + sha256_inc_init(&state); + sha256_inc_blocks(&state, buf, 1); memcpy(buf, optrand, SPX_N); /* If optrand + message cannot fill up an entire block */ if (SPX_N + mlen < SPX_SHA256_BLOCK_BYTES) { memcpy(buf + SPX_N, m, mlen); - sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, state, + sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, &state, buf, mlen + SPX_N); } /* Otherwise first fill a block, so that finalize only uses the message */ else { memcpy(buf + SPX_N, m, SPX_SHA256_BLOCK_BYTES - SPX_N); - sha256_inc_blocks(state, buf, 1); + sha256_inc_blocks(&state, buf, 1); m += SPX_SHA256_BLOCK_BYTES - SPX_N; mlen -= SPX_SHA256_BLOCK_BYTES - SPX_N; - sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, state, m, mlen); + sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, &state, m, mlen); } for (i = 0; i < SPX_N; i++) { @@ -108,9 +108,9 @@ void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_hash_message( unsigned char buf[SPX_DGST_BYTES]; unsigned char *bufp = buf; - uint8_t state[40]; + sha256ctx state; - sha256_inc_init(state); + sha256_inc_init(&state); memcpy(inbuf, R, SPX_N); memcpy(inbuf + SPX_N, pk, SPX_PK_BYTES); @@ -118,17 +118,17 @@ void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_hash_message( /* If R + pk + message cannot fill up an entire block */ if (SPX_N + SPX_PK_BYTES + mlen < SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES) { memcpy(inbuf + SPX_N + SPX_PK_BYTES, m, mlen); - sha256_inc_finalize(seed, state, inbuf, SPX_N + SPX_PK_BYTES + mlen); + sha256_inc_finalize(seed, &state, inbuf, SPX_N + SPX_PK_BYTES + mlen); } /* Otherwise first fill a block, so that finalize only uses the message */ else { memcpy(inbuf + SPX_N + SPX_PK_BYTES, m, SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES); - sha256_inc_blocks(state, inbuf, SPX_INBLOCKS); + sha256_inc_blocks(&state, inbuf, SPX_INBLOCKS); m += SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES; mlen -= SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES; - sha256_inc_finalize(seed, state, m, mlen); + sha256_inc_finalize(seed, &state, m, mlen); } /* By doing this in two steps, we prevent hashing the message twice; diff --git a/crypto_sign/sphincs-sha256-256f-simple/clean/sha256.c b/crypto_sign/sphincs-sha256-256f-simple/clean/sha256.c index 13d1aece..02ab0dc3 100644 --- a/crypto_sign/sphincs-sha256-256f-simple/clean/sha256.c +++ b/crypto_sign/sphincs-sha256-256f-simple/clean/sha256.c @@ -50,7 +50,7 @@ void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_mgf1( } } -uint8_t PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_state_seeded[40]; +sha256ctx PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_state_seeded; /** * Absorb the constant pub_seed using one round of the compression function @@ -67,6 +67,6 @@ void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_seed_state(const unsigned char *pub_s block[i] = 0; } - sha256_inc_init(PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_state_seeded); - sha256_inc_blocks(PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_state_seeded, block, 1); + sha256_inc_init(&PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_state_seeded); + sha256_inc_blocks(&PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_state_seeded, block, 1); } diff --git a/crypto_sign/sphincs-sha256-256f-simple/clean/sha256.h b/crypto_sign/sphincs-sha256-256f-simple/clean/sha256.h index 7dad0c93..e77db8ec 100644 --- a/crypto_sign/sphincs-sha256-256f-simple/clean/sha256.h +++ b/crypto_sign/sphincs-sha256-256f-simple/clean/sha256.h @@ -8,13 +8,15 @@ #include #include +#include "sha2.h" + void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_compress_address(unsigned char *out, const uint32_t addr[8]); void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_mgf1( unsigned char *out, unsigned long outlen, unsigned char *input_plus_four_bytes, unsigned long inlen); -extern uint8_t PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_state_seeded[40]; +extern sha256ctx PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_state_seeded; void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_seed_state(const unsigned char *pub_seed); diff --git a/crypto_sign/sphincs-sha256-256f-simple/clean/thash_sha256_simple.c b/crypto_sign/sphincs-sha256-256f-simple/clean/thash_sha256_simple.c index ab8c6af8..466ca969 100644 --- a/crypto_sign/sphincs-sha256-256f-simple/clean/thash_sha256_simple.c +++ b/crypto_sign/sphincs-sha256-256f-simple/clean/thash_sha256_simple.c @@ -17,17 +17,17 @@ static void PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_thash( const unsigned char *pub_seed, uint32_t addr[8]) { unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; - uint8_t sha2_state[40]; + sha256ctx sha2_state; (void)pub_seed; /* Suppress an 'unused parameter' warning. */ /* Retrieve precomputed state containing pub_seed */ - memcpy(sha2_state, PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_state_seeded, 40 * sizeof(uint8_t)); + memcpy(&sha2_state, &PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_state_seeded, sizeof(sha256ctx)); PQCLEAN_SPHINCSSHA256256FSIMPLE_CLEAN_compress_address(buf, addr); memcpy(buf + SPX_SHA256_ADDR_BYTES, in, inblocks * SPX_N); - sha256_inc_finalize(outbuf, sha2_state, buf, SPX_SHA256_ADDR_BYTES + inblocks * SPX_N); + sha256_inc_finalize(outbuf, &sha2_state, buf, SPX_SHA256_ADDR_BYTES + inblocks * SPX_N); memcpy(out, outbuf, SPX_N); } diff --git a/crypto_sign/sphincs-sha256-256s-robust/META.yml b/crypto_sign/sphincs-sha256-256s-robust/META.yml index f4ab2c23..68d01b3a 100644 --- a/crypto_sign/sphincs-sha256-256s-robust/META.yml +++ b/crypto_sign/sphincs-sha256-256s-robust/META.yml @@ -4,6 +4,7 @@ claimed-nist-level: 5 length-public-key: 64 length-secret-key: 128 length-signature: 29792 +nistkat-sha256: da28ff350ac552f100b35b01ecb494dc02f9dcf542fa2d88439cd427985e9581 testvectors-sha256: 6a85ec1f64d017fc2ffd88aa7d679de7e0554e00bdea62c7fea5c4c403e3eafa principal-submitter: Andreas Hülsing auxiliary-submitters: diff --git a/crypto_sign/sphincs-sha256-256s-robust/clean/Makefile b/crypto_sign/sphincs-sha256-256s-robust/clean/Makefile index e06192c4..efa210e8 100644 --- a/crypto_sign/sphincs-sha256-256s-robust/clean/Makefile +++ b/crypto_sign/sphincs-sha256-256s-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-256s-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_robust.o sha256.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-256s-robust/clean/hash_sha256.c b/crypto_sign/sphincs-sha256-256s-robust/clean/hash_sha256.c index da4e2519..6e7d10cf 100644 --- a/crypto_sign/sphincs-sha256-256s-robust/clean/hash_sha256.c +++ b/crypto_sign/sphincs-sha256-256s-robust/clean/hash_sha256.c @@ -45,7 +45,7 @@ void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_gen_message_random( const unsigned char *sk_prf, const unsigned char *optrand, const unsigned char *m, size_t mlen) { unsigned char buf[SPX_SHA256_BLOCK_BYTES + SPX_SHA256_OUTPUT_BYTES]; - uint8_t state[40]; + sha256ctx state; int i; /* This implements HMAC-SHA256 */ @@ -54,25 +54,25 @@ void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_gen_message_random( } memset(buf + SPX_N, 0x36, SPX_SHA256_BLOCK_BYTES - SPX_N); - sha256_inc_init(state); - sha256_inc_blocks(state, buf, 1); + sha256_inc_init(&state); + sha256_inc_blocks(&state, buf, 1); memcpy(buf, optrand, SPX_N); /* If optrand + message cannot fill up an entire block */ if (SPX_N + mlen < SPX_SHA256_BLOCK_BYTES) { memcpy(buf + SPX_N, m, mlen); - sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, state, + sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, &state, buf, mlen + SPX_N); } /* Otherwise first fill a block, so that finalize only uses the message */ else { memcpy(buf + SPX_N, m, SPX_SHA256_BLOCK_BYTES - SPX_N); - sha256_inc_blocks(state, buf, 1); + sha256_inc_blocks(&state, buf, 1); m += SPX_SHA256_BLOCK_BYTES - SPX_N; mlen -= SPX_SHA256_BLOCK_BYTES - SPX_N; - sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, state, m, mlen); + sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, &state, m, mlen); } for (i = 0; i < SPX_N; i++) { @@ -108,9 +108,9 @@ void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_hash_message( unsigned char buf[SPX_DGST_BYTES]; unsigned char *bufp = buf; - uint8_t state[40]; + sha256ctx state; - sha256_inc_init(state); + sha256_inc_init(&state); memcpy(inbuf, R, SPX_N); memcpy(inbuf + SPX_N, pk, SPX_PK_BYTES); @@ -118,17 +118,17 @@ void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_hash_message( /* If R + pk + message cannot fill up an entire block */ if (SPX_N + SPX_PK_BYTES + mlen < SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES) { memcpy(inbuf + SPX_N + SPX_PK_BYTES, m, mlen); - sha256_inc_finalize(seed, state, inbuf, SPX_N + SPX_PK_BYTES + mlen); + sha256_inc_finalize(seed, &state, inbuf, SPX_N + SPX_PK_BYTES + mlen); } /* Otherwise first fill a block, so that finalize only uses the message */ else { memcpy(inbuf + SPX_N + SPX_PK_BYTES, m, SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES); - sha256_inc_blocks(state, inbuf, SPX_INBLOCKS); + sha256_inc_blocks(&state, inbuf, SPX_INBLOCKS); m += SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES; mlen -= SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES; - sha256_inc_finalize(seed, state, m, mlen); + sha256_inc_finalize(seed, &state, m, mlen); } /* By doing this in two steps, we prevent hashing the message twice; diff --git a/crypto_sign/sphincs-sha256-256s-robust/clean/sha256.c b/crypto_sign/sphincs-sha256-256s-robust/clean/sha256.c index 181009b8..fa002464 100644 --- a/crypto_sign/sphincs-sha256-256s-robust/clean/sha256.c +++ b/crypto_sign/sphincs-sha256-256s-robust/clean/sha256.c @@ -50,7 +50,7 @@ void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_mgf1( } } -uint8_t PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_state_seeded[40]; +sha256ctx PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_state_seeded; /** * Absorb the constant pub_seed using one round of the compression function @@ -67,6 +67,6 @@ void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_seed_state(const unsigned char *pub_s block[i] = 0; } - sha256_inc_init(PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_state_seeded); - sha256_inc_blocks(PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_state_seeded, block, 1); + sha256_inc_init(&PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_state_seeded); + sha256_inc_blocks(&PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_state_seeded, block, 1); } diff --git a/crypto_sign/sphincs-sha256-256s-robust/clean/sha256.h b/crypto_sign/sphincs-sha256-256s-robust/clean/sha256.h index 80106cc7..fe94f592 100644 --- a/crypto_sign/sphincs-sha256-256s-robust/clean/sha256.h +++ b/crypto_sign/sphincs-sha256-256s-robust/clean/sha256.h @@ -8,13 +8,15 @@ #include #include +#include "sha2.h" + void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_compress_address(unsigned char *out, const uint32_t addr[8]); void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_mgf1( unsigned char *out, unsigned long outlen, unsigned char *input_plus_four_bytes, unsigned long inlen); -extern uint8_t PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_state_seeded[40]; +extern sha256ctx PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_state_seeded; void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_seed_state(const unsigned char *pub_seed); diff --git a/crypto_sign/sphincs-sha256-256s-robust/clean/thash_sha256_robust.c b/crypto_sign/sphincs-sha256-256s-robust/clean/thash_sha256_robust.c index d7498c60..37e4b2b2 100644 --- a/crypto_sign/sphincs-sha256-256s-robust/clean/thash_sha256_robust.c +++ b/crypto_sign/sphincs-sha256-256s-robust/clean/thash_sha256_robust.c @@ -18,7 +18,7 @@ static void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_thash( unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; unsigned char *bitmask = buf + SPX_N + SPX_SHA256_ADDR_BYTES + 4; - uint8_t sha2_state[40]; + sha256ctx sha2_state; unsigned int i; memcpy(buf, pub_seed, SPX_N); @@ -27,13 +27,13 @@ static void PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_thash( PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_mgf1(bitmask, inblocks * SPX_N, buf, SPX_N + SPX_SHA256_ADDR_BYTES); /* Retrieve precomputed state containing pub_seed */ - memcpy(sha2_state, PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_state_seeded, 40 * sizeof(uint8_t)); + memcpy(&sha2_state, &PQCLEAN_SPHINCSSHA256256SROBUST_CLEAN_state_seeded, sizeof(sha256ctx)); for (i = 0; i < inblocks * SPX_N; i++) { buf[SPX_N + SPX_SHA256_ADDR_BYTES + i] = in[i] ^ bitmask[i]; } - sha256_inc_finalize(outbuf, sha2_state, buf + SPX_N, + sha256_inc_finalize(outbuf, &sha2_state, buf + SPX_N, SPX_SHA256_ADDR_BYTES + inblocks * SPX_N); memcpy(out, outbuf, SPX_N); } diff --git a/crypto_sign/sphincs-sha256-256s-simple/META.yml b/crypto_sign/sphincs-sha256-256s-simple/META.yml index 231b96dc..8d3bd747 100644 --- a/crypto_sign/sphincs-sha256-256s-simple/META.yml +++ b/crypto_sign/sphincs-sha256-256s-simple/META.yml @@ -4,6 +4,7 @@ claimed-nist-level: 5 length-public-key: 64 length-secret-key: 128 length-signature: 29792 +nistkat-sha256: 768d61c537b3abacca3ab468623edafb33d28a33dc5a9859f803679a3020b639 testvectors-sha256: 796b5101fa5170c92f0186b347716dc0662eac35002a8c4d80ac9283cbef5a02 principal-submitter: Andreas Hülsing auxiliary-submitters: diff --git a/crypto_sign/sphincs-sha256-256s-simple/clean/Makefile b/crypto_sign/sphincs-sha256-256s-simple/clean/Makefile index ce925c1b..cc527069 100644 --- a/crypto_sign/sphincs-sha256-256s-simple/clean/Makefile +++ b/crypto_sign/sphincs-sha256-256s-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-sha256-256s-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h sha256.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_sha256.o thash_sha256_simple.o sha256.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-sha256-256s-simple/clean/hash_sha256.c b/crypto_sign/sphincs-sha256-256s-simple/clean/hash_sha256.c index 73cb17d0..0fa93668 100644 --- a/crypto_sign/sphincs-sha256-256s-simple/clean/hash_sha256.c +++ b/crypto_sign/sphincs-sha256-256s-simple/clean/hash_sha256.c @@ -45,7 +45,7 @@ void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_gen_message_random( const unsigned char *sk_prf, const unsigned char *optrand, const unsigned char *m, size_t mlen) { unsigned char buf[SPX_SHA256_BLOCK_BYTES + SPX_SHA256_OUTPUT_BYTES]; - uint8_t state[40]; + sha256ctx state; int i; /* This implements HMAC-SHA256 */ @@ -54,25 +54,25 @@ void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_gen_message_random( } memset(buf + SPX_N, 0x36, SPX_SHA256_BLOCK_BYTES - SPX_N); - sha256_inc_init(state); - sha256_inc_blocks(state, buf, 1); + sha256_inc_init(&state); + sha256_inc_blocks(&state, buf, 1); memcpy(buf, optrand, SPX_N); /* If optrand + message cannot fill up an entire block */ if (SPX_N + mlen < SPX_SHA256_BLOCK_BYTES) { memcpy(buf + SPX_N, m, mlen); - sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, state, + sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, &state, buf, mlen + SPX_N); } /* Otherwise first fill a block, so that finalize only uses the message */ else { memcpy(buf + SPX_N, m, SPX_SHA256_BLOCK_BYTES - SPX_N); - sha256_inc_blocks(state, buf, 1); + sha256_inc_blocks(&state, buf, 1); m += SPX_SHA256_BLOCK_BYTES - SPX_N; mlen -= SPX_SHA256_BLOCK_BYTES - SPX_N; - sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, state, m, mlen); + sha256_inc_finalize(buf + SPX_SHA256_BLOCK_BYTES, &state, m, mlen); } for (i = 0; i < SPX_N; i++) { @@ -108,9 +108,9 @@ void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_hash_message( unsigned char buf[SPX_DGST_BYTES]; unsigned char *bufp = buf; - uint8_t state[40]; + sha256ctx state; - sha256_inc_init(state); + sha256_inc_init(&state); memcpy(inbuf, R, SPX_N); memcpy(inbuf + SPX_N, pk, SPX_PK_BYTES); @@ -118,17 +118,17 @@ void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_hash_message( /* If R + pk + message cannot fill up an entire block */ if (SPX_N + SPX_PK_BYTES + mlen < SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES) { memcpy(inbuf + SPX_N + SPX_PK_BYTES, m, mlen); - sha256_inc_finalize(seed, state, inbuf, SPX_N + SPX_PK_BYTES + mlen); + sha256_inc_finalize(seed, &state, inbuf, SPX_N + SPX_PK_BYTES + mlen); } /* Otherwise first fill a block, so that finalize only uses the message */ else { memcpy(inbuf + SPX_N + SPX_PK_BYTES, m, SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES); - sha256_inc_blocks(state, inbuf, SPX_INBLOCKS); + sha256_inc_blocks(&state, inbuf, SPX_INBLOCKS); m += SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES; mlen -= SPX_INBLOCKS * SPX_SHA256_BLOCK_BYTES - SPX_N - SPX_PK_BYTES; - sha256_inc_finalize(seed, state, m, mlen); + sha256_inc_finalize(seed, &state, m, mlen); } /* By doing this in two steps, we prevent hashing the message twice; diff --git a/crypto_sign/sphincs-sha256-256s-simple/clean/sha256.c b/crypto_sign/sphincs-sha256-256s-simple/clean/sha256.c index acaa08e0..4c46b19d 100644 --- a/crypto_sign/sphincs-sha256-256s-simple/clean/sha256.c +++ b/crypto_sign/sphincs-sha256-256s-simple/clean/sha256.c @@ -50,7 +50,7 @@ void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_mgf1( } } -uint8_t PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_state_seeded[40]; +sha256ctx PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_state_seeded; /** * Absorb the constant pub_seed using one round of the compression function @@ -67,6 +67,6 @@ void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_seed_state(const unsigned char *pub_s block[i] = 0; } - sha256_inc_init(PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_state_seeded); - sha256_inc_blocks(PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_state_seeded, block, 1); + sha256_inc_init(&PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_state_seeded); + sha256_inc_blocks(&PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_state_seeded, block, 1); } diff --git a/crypto_sign/sphincs-sha256-256s-simple/clean/sha256.h b/crypto_sign/sphincs-sha256-256s-simple/clean/sha256.h index a7a557a0..c6dda301 100644 --- a/crypto_sign/sphincs-sha256-256s-simple/clean/sha256.h +++ b/crypto_sign/sphincs-sha256-256s-simple/clean/sha256.h @@ -8,13 +8,15 @@ #include #include +#include "sha2.h" + void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_compress_address(unsigned char *out, const uint32_t addr[8]); void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_mgf1( unsigned char *out, unsigned long outlen, unsigned char *input_plus_four_bytes, unsigned long inlen); -extern uint8_t PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_state_seeded[40]; +extern sha256ctx PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_state_seeded; void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_seed_state(const unsigned char *pub_seed); diff --git a/crypto_sign/sphincs-sha256-256s-simple/clean/thash_sha256_simple.c b/crypto_sign/sphincs-sha256-256s-simple/clean/thash_sha256_simple.c index 67d008c6..d3a31872 100644 --- a/crypto_sign/sphincs-sha256-256s-simple/clean/thash_sha256_simple.c +++ b/crypto_sign/sphincs-sha256-256s-simple/clean/thash_sha256_simple.c @@ -17,17 +17,17 @@ static void PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_thash( const unsigned char *pub_seed, uint32_t addr[8]) { unsigned char outbuf[SPX_SHA256_OUTPUT_BYTES]; - uint8_t sha2_state[40]; + sha256ctx sha2_state; (void)pub_seed; /* Suppress an 'unused parameter' warning. */ /* Retrieve precomputed state containing pub_seed */ - memcpy(sha2_state, PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_state_seeded, 40 * sizeof(uint8_t)); + memcpy(&sha2_state, &PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_state_seeded, sizeof(sha256ctx)); PQCLEAN_SPHINCSSHA256256SSIMPLE_CLEAN_compress_address(buf, addr); memcpy(buf + SPX_SHA256_ADDR_BYTES, in, inblocks * SPX_N); - sha256_inc_finalize(outbuf, sha2_state, buf, SPX_SHA256_ADDR_BYTES + inblocks * SPX_N); + sha256_inc_finalize(outbuf, &sha2_state, buf, SPX_SHA256_ADDR_BYTES + inblocks * SPX_N); memcpy(out, outbuf, SPX_N); } diff --git a/crypto_sign/sphincs-shake256-128f-robust/META.yml b/crypto_sign/sphincs-shake256-128f-robust/META.yml index 9b2474f3..6c85ad7b 100644 --- a/crypto_sign/sphincs-shake256-128f-robust/META.yml +++ b/crypto_sign/sphincs-shake256-128f-robust/META.yml @@ -4,6 +4,7 @@ claimed-nist-level: 1 length-public-key: 32 length-secret-key: 64 length-signature: 16976 +nistkat-sha256: e7789df37278d1e147996bd9bf4cda55d5ec5cbe921e64b0766927af4b02decd testvectors-sha256: eea7f59958e732c15110d0d06e3c23005d73df2b15a1e7b4ebc0ca2dcf162bb5 principal-submitter: Andreas Hülsing auxiliary-submitters: diff --git a/crypto_sign/sphincs-shake256-128f-robust/clean/Makefile b/crypto_sign/sphincs-shake256-128f-robust/clean/Makefile index 86825431..df59f00d 100644 --- a/crypto_sign/sphincs-shake256-128f-robust/clean/Makefile +++ b/crypto_sign/sphincs-shake256-128f-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-128f-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_robust.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-128f-robust/clean/hash_shake256.c b/crypto_sign/sphincs-shake256-128f-robust/clean/hash_shake256.c index 9603b8c8..d3b7ac7d 100644 --- a/crypto_sign/sphincs-shake256-128f-robust/clean/hash_shake256.c +++ b/crypto_sign/sphincs-shake256-128f-robust/clean/hash_shake256.c @@ -37,14 +37,14 @@ void PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_gen_message_random( unsigned char *R, const unsigned char *sk_prf, const unsigned char *optrand, const unsigned char *m, size_t mlen) { - uint64_t s_inc[26]; + shake256incctx state; - shake256_inc_init(s_inc); - shake256_inc_absorb(s_inc, sk_prf, SPX_N); - shake256_inc_absorb(s_inc, optrand, SPX_N); - shake256_inc_absorb(s_inc, m, mlen); - shake256_inc_finalize(s_inc); - shake256_inc_squeeze(R, SPX_N, s_inc); + shake256_inc_init(&state); + shake256_inc_absorb(&state, sk_prf, SPX_N); + shake256_inc_absorb(&state, optrand, SPX_N); + shake256_inc_absorb(&state, m, mlen); + shake256_inc_finalize(&state); + shake256_inc_squeeze(R, SPX_N, &state); } /** @@ -64,14 +64,14 @@ void PQCLEAN_SPHINCSSHAKE256128FROBUST_CLEAN_hash_message( unsigned char buf[SPX_DGST_BYTES]; unsigned char *bufp = buf; - uint64_t s_inc[26]; + shake256incctx state; - shake256_inc_init(s_inc); - shake256_inc_absorb(s_inc, R, SPX_N); - shake256_inc_absorb(s_inc, pk, SPX_PK_BYTES); - shake256_inc_absorb(s_inc, m, mlen); - shake256_inc_finalize(s_inc); - shake256_inc_squeeze(buf, SPX_DGST_BYTES, s_inc); + shake256_inc_init(&state); + shake256_inc_absorb(&state, R, SPX_N); + shake256_inc_absorb(&state, pk, SPX_PK_BYTES); + shake256_inc_absorb(&state, m, mlen); + shake256_inc_finalize(&state); + shake256_inc_squeeze(buf, SPX_DGST_BYTES, &state); memcpy(digest, bufp, SPX_FORS_MSG_BYTES); bufp += SPX_FORS_MSG_BYTES; diff --git a/crypto_sign/sphincs-shake256-128f-simple/META.yml b/crypto_sign/sphincs-shake256-128f-simple/META.yml index 5814eaa1..e53da837 100644 --- a/crypto_sign/sphincs-shake256-128f-simple/META.yml +++ b/crypto_sign/sphincs-shake256-128f-simple/META.yml @@ -4,6 +4,7 @@ claimed-nist-level: 1 length-public-key: 32 length-secret-key: 64 length-signature: 16976 +nistkat-sha256: c99700873ca6914944fcef3b649270c86c056dcd11ce6e8f22580b193a136e6f testvectors-sha256: a14cb8e4f149493fc5979e465e09ce943e8d669186ff5c7c3d11239fa869def6 principal-submitter: Andreas Hülsing auxiliary-submitters: diff --git a/crypto_sign/sphincs-shake256-128f-simple/clean/Makefile b/crypto_sign/sphincs-shake256-128f-simple/clean/Makefile index 1e5260b5..0d64090f 100644 --- a/crypto_sign/sphincs-shake256-128f-simple/clean/Makefile +++ b/crypto_sign/sphincs-shake256-128f-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-128f-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_simple.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-128f-simple/clean/hash_shake256.c b/crypto_sign/sphincs-shake256-128f-simple/clean/hash_shake256.c index 68103a41..bd6894ca 100644 --- a/crypto_sign/sphincs-shake256-128f-simple/clean/hash_shake256.c +++ b/crypto_sign/sphincs-shake256-128f-simple/clean/hash_shake256.c @@ -37,14 +37,14 @@ void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_gen_message_random( unsigned char *R, const unsigned char *sk_prf, const unsigned char *optrand, const unsigned char *m, size_t mlen) { - uint64_t s_inc[26]; + shake256incctx state; - shake256_inc_init(s_inc); - shake256_inc_absorb(s_inc, sk_prf, SPX_N); - shake256_inc_absorb(s_inc, optrand, SPX_N); - shake256_inc_absorb(s_inc, m, mlen); - shake256_inc_finalize(s_inc); - shake256_inc_squeeze(R, SPX_N, s_inc); + shake256_inc_init(&state); + shake256_inc_absorb(&state, sk_prf, SPX_N); + shake256_inc_absorb(&state, optrand, SPX_N); + shake256_inc_absorb(&state, m, mlen); + shake256_inc_finalize(&state); + shake256_inc_squeeze(R, SPX_N, &state); } /** @@ -64,14 +64,14 @@ void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_hash_message( unsigned char buf[SPX_DGST_BYTES]; unsigned char *bufp = buf; - uint64_t s_inc[26]; + shake256incctx state; - shake256_inc_init(s_inc); - shake256_inc_absorb(s_inc, R, SPX_N); - shake256_inc_absorb(s_inc, pk, SPX_PK_BYTES); - shake256_inc_absorb(s_inc, m, mlen); - shake256_inc_finalize(s_inc); - shake256_inc_squeeze(buf, SPX_DGST_BYTES, s_inc); + shake256_inc_init(&state); + shake256_inc_absorb(&state, R, SPX_N); + shake256_inc_absorb(&state, pk, SPX_PK_BYTES); + shake256_inc_absorb(&state, m, mlen); + shake256_inc_finalize(&state); + shake256_inc_squeeze(buf, SPX_DGST_BYTES, &state); memcpy(digest, bufp, SPX_FORS_MSG_BYTES); bufp += SPX_FORS_MSG_BYTES; diff --git a/crypto_sign/sphincs-shake256-128s-robust/META.yml b/crypto_sign/sphincs-shake256-128s-robust/META.yml index 6302c5c7..824c4d4e 100644 --- a/crypto_sign/sphincs-shake256-128s-robust/META.yml +++ b/crypto_sign/sphincs-shake256-128s-robust/META.yml @@ -4,6 +4,7 @@ claimed-nist-level: 1 length-public-key: 32 length-secret-key: 64 length-signature: 8080 +nistkat-sha256: e9c31937277677d1cb387ce76408c76b0128938f3af047f60fb5d073a3c788b3 testvectors-sha256: f3f56ddff38a75ee07b44c023b9c9133ffe9538bb4b64f8ec8742b21fcaa6a50 principal-submitter: Andreas Hülsing auxiliary-submitters: diff --git a/crypto_sign/sphincs-shake256-128s-robust/clean/Makefile b/crypto_sign/sphincs-shake256-128s-robust/clean/Makefile index dcb37067..5a9b6997 100644 --- a/crypto_sign/sphincs-shake256-128s-robust/clean/Makefile +++ b/crypto_sign/sphincs-shake256-128s-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-128s-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_robust.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-128s-robust/clean/hash_shake256.c b/crypto_sign/sphincs-shake256-128s-robust/clean/hash_shake256.c index f636a41f..a897adf6 100644 --- a/crypto_sign/sphincs-shake256-128s-robust/clean/hash_shake256.c +++ b/crypto_sign/sphincs-shake256-128s-robust/clean/hash_shake256.c @@ -37,14 +37,14 @@ void PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_gen_message_random( unsigned char *R, const unsigned char *sk_prf, const unsigned char *optrand, const unsigned char *m, size_t mlen) { - uint64_t s_inc[26]; + shake256incctx state; - shake256_inc_init(s_inc); - shake256_inc_absorb(s_inc, sk_prf, SPX_N); - shake256_inc_absorb(s_inc, optrand, SPX_N); - shake256_inc_absorb(s_inc, m, mlen); - shake256_inc_finalize(s_inc); - shake256_inc_squeeze(R, SPX_N, s_inc); + shake256_inc_init(&state); + shake256_inc_absorb(&state, sk_prf, SPX_N); + shake256_inc_absorb(&state, optrand, SPX_N); + shake256_inc_absorb(&state, m, mlen); + shake256_inc_finalize(&state); + shake256_inc_squeeze(R, SPX_N, &state); } /** @@ -64,14 +64,14 @@ void PQCLEAN_SPHINCSSHAKE256128SROBUST_CLEAN_hash_message( unsigned char buf[SPX_DGST_BYTES]; unsigned char *bufp = buf; - uint64_t s_inc[26]; + shake256incctx state; - shake256_inc_init(s_inc); - shake256_inc_absorb(s_inc, R, SPX_N); - shake256_inc_absorb(s_inc, pk, SPX_PK_BYTES); - shake256_inc_absorb(s_inc, m, mlen); - shake256_inc_finalize(s_inc); - shake256_inc_squeeze(buf, SPX_DGST_BYTES, s_inc); + shake256_inc_init(&state); + shake256_inc_absorb(&state, R, SPX_N); + shake256_inc_absorb(&state, pk, SPX_PK_BYTES); + shake256_inc_absorb(&state, m, mlen); + shake256_inc_finalize(&state); + shake256_inc_squeeze(buf, SPX_DGST_BYTES, &state); memcpy(digest, bufp, SPX_FORS_MSG_BYTES); bufp += SPX_FORS_MSG_BYTES; diff --git a/crypto_sign/sphincs-shake256-128s-simple/META.yml b/crypto_sign/sphincs-shake256-128s-simple/META.yml index 41237bc4..24cf2b38 100644 --- a/crypto_sign/sphincs-shake256-128s-simple/META.yml +++ b/crypto_sign/sphincs-shake256-128s-simple/META.yml @@ -4,6 +4,7 @@ claimed-nist-level: 1 length-public-key: 32 length-secret-key: 64 length-signature: 8080 +nistkat-sha256: 5d23c9f334e9bd99d5294cf40c6b2c096ee668076e809b44b928ca146d2c5e3a testvectors-sha256: ee2af38333f6ba705102ab66689c262b07c1fd9ce1d46180796bcb263bf1a654 principal-submitter: Andreas Hülsing auxiliary-submitters: diff --git a/crypto_sign/sphincs-shake256-128s-simple/clean/Makefile b/crypto_sign/sphincs-shake256-128s-simple/clean/Makefile index c3c9de0b..9c01dfa1 100644 --- a/crypto_sign/sphincs-shake256-128s-simple/clean/Makefile +++ b/crypto_sign/sphincs-shake256-128s-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-128s-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_simple.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-128s-simple/clean/hash_shake256.c b/crypto_sign/sphincs-shake256-128s-simple/clean/hash_shake256.c index 2408a3e0..74d4ffeb 100644 --- a/crypto_sign/sphincs-shake256-128s-simple/clean/hash_shake256.c +++ b/crypto_sign/sphincs-shake256-128s-simple/clean/hash_shake256.c @@ -37,14 +37,14 @@ void PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_gen_message_random( unsigned char *R, const unsigned char *sk_prf, const unsigned char *optrand, const unsigned char *m, size_t mlen) { - uint64_t s_inc[26]; + shake256incctx state; - shake256_inc_init(s_inc); - shake256_inc_absorb(s_inc, sk_prf, SPX_N); - shake256_inc_absorb(s_inc, optrand, SPX_N); - shake256_inc_absorb(s_inc, m, mlen); - shake256_inc_finalize(s_inc); - shake256_inc_squeeze(R, SPX_N, s_inc); + shake256_inc_init(&state); + shake256_inc_absorb(&state, sk_prf, SPX_N); + shake256_inc_absorb(&state, optrand, SPX_N); + shake256_inc_absorb(&state, m, mlen); + shake256_inc_finalize(&state); + shake256_inc_squeeze(R, SPX_N, &state); } /** @@ -64,14 +64,14 @@ void PQCLEAN_SPHINCSSHAKE256128SSIMPLE_CLEAN_hash_message( unsigned char buf[SPX_DGST_BYTES]; unsigned char *bufp = buf; - uint64_t s_inc[26]; + shake256incctx state; - shake256_inc_init(s_inc); - shake256_inc_absorb(s_inc, R, SPX_N); - shake256_inc_absorb(s_inc, pk, SPX_PK_BYTES); - shake256_inc_absorb(s_inc, m, mlen); - shake256_inc_finalize(s_inc); - shake256_inc_squeeze(buf, SPX_DGST_BYTES, s_inc); + shake256_inc_init(&state); + shake256_inc_absorb(&state, R, SPX_N); + shake256_inc_absorb(&state, pk, SPX_PK_BYTES); + shake256_inc_absorb(&state, m, mlen); + shake256_inc_finalize(&state); + shake256_inc_squeeze(buf, SPX_DGST_BYTES, &state); memcpy(digest, bufp, SPX_FORS_MSG_BYTES); bufp += SPX_FORS_MSG_BYTES; diff --git a/crypto_sign/sphincs-shake256-192f-robust/META.yml b/crypto_sign/sphincs-shake256-192f-robust/META.yml index 95be6a3a..0fba24a0 100644 --- a/crypto_sign/sphincs-shake256-192f-robust/META.yml +++ b/crypto_sign/sphincs-shake256-192f-robust/META.yml @@ -4,6 +4,7 @@ claimed-nist-level: 3 length-public-key: 48 length-secret-key: 96 length-signature: 35664 +nistkat-sha256: 5cfcf998ad0bedf8e6b961c8891048f456d6422d3b4a26fcb095a913c9efd03e testvectors-sha256: de65b2a7b6d5e819f58b6e1a08ec4ef3308a9c36b7c962450105f82263e35e98 principal-submitter: Andreas Hülsing auxiliary-submitters: diff --git a/crypto_sign/sphincs-shake256-192f-robust/clean/Makefile b/crypto_sign/sphincs-shake256-192f-robust/clean/Makefile index 1173c5ef..812a7645 100644 --- a/crypto_sign/sphincs-shake256-192f-robust/clean/Makefile +++ b/crypto_sign/sphincs-shake256-192f-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-192f-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_robust.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-192f-robust/clean/hash_shake256.c b/crypto_sign/sphincs-shake256-192f-robust/clean/hash_shake256.c index 6e5b7b07..49c8ae7b 100644 --- a/crypto_sign/sphincs-shake256-192f-robust/clean/hash_shake256.c +++ b/crypto_sign/sphincs-shake256-192f-robust/clean/hash_shake256.c @@ -37,14 +37,14 @@ void PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_gen_message_random( unsigned char *R, const unsigned char *sk_prf, const unsigned char *optrand, const unsigned char *m, size_t mlen) { - uint64_t s_inc[26]; + shake256incctx state; - shake256_inc_init(s_inc); - shake256_inc_absorb(s_inc, sk_prf, SPX_N); - shake256_inc_absorb(s_inc, optrand, SPX_N); - shake256_inc_absorb(s_inc, m, mlen); - shake256_inc_finalize(s_inc); - shake256_inc_squeeze(R, SPX_N, s_inc); + shake256_inc_init(&state); + shake256_inc_absorb(&state, sk_prf, SPX_N); + shake256_inc_absorb(&state, optrand, SPX_N); + shake256_inc_absorb(&state, m, mlen); + shake256_inc_finalize(&state); + shake256_inc_squeeze(R, SPX_N, &state); } /** @@ -64,14 +64,14 @@ void PQCLEAN_SPHINCSSHAKE256192FROBUST_CLEAN_hash_message( unsigned char buf[SPX_DGST_BYTES]; unsigned char *bufp = buf; - uint64_t s_inc[26]; + shake256incctx state; - shake256_inc_init(s_inc); - shake256_inc_absorb(s_inc, R, SPX_N); - shake256_inc_absorb(s_inc, pk, SPX_PK_BYTES); - shake256_inc_absorb(s_inc, m, mlen); - shake256_inc_finalize(s_inc); - shake256_inc_squeeze(buf, SPX_DGST_BYTES, s_inc); + shake256_inc_init(&state); + shake256_inc_absorb(&state, R, SPX_N); + shake256_inc_absorb(&state, pk, SPX_PK_BYTES); + shake256_inc_absorb(&state, m, mlen); + shake256_inc_finalize(&state); + shake256_inc_squeeze(buf, SPX_DGST_BYTES, &state); memcpy(digest, bufp, SPX_FORS_MSG_BYTES); bufp += SPX_FORS_MSG_BYTES; diff --git a/crypto_sign/sphincs-shake256-192f-simple/META.yml b/crypto_sign/sphincs-shake256-192f-simple/META.yml index 4e9fe612..5759e456 100644 --- a/crypto_sign/sphincs-shake256-192f-simple/META.yml +++ b/crypto_sign/sphincs-shake256-192f-simple/META.yml @@ -4,6 +4,7 @@ claimed-nist-level: 3 length-public-key: 48 length-secret-key: 96 length-signature: 35664 +nistkat-sha256: 28528adef75a728d013bb493d85e358a75344c72000792419f1f539c16f24f10 testvectors-sha256: 14f60a3099cfddf30c46491a98a5f3508739df108425b2eaa5c19383f0ca4b22 principal-submitter: Andreas Hülsing auxiliary-submitters: diff --git a/crypto_sign/sphincs-shake256-192f-simple/clean/Makefile b/crypto_sign/sphincs-shake256-192f-simple/clean/Makefile index 895dd95b..917bc6c6 100644 --- a/crypto_sign/sphincs-shake256-192f-simple/clean/Makefile +++ b/crypto_sign/sphincs-shake256-192f-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-192f-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_simple.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-192f-simple/clean/hash_shake256.c b/crypto_sign/sphincs-shake256-192f-simple/clean/hash_shake256.c index d970155e..82e4430e 100644 --- a/crypto_sign/sphincs-shake256-192f-simple/clean/hash_shake256.c +++ b/crypto_sign/sphincs-shake256-192f-simple/clean/hash_shake256.c @@ -37,14 +37,14 @@ void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_gen_message_random( unsigned char *R, const unsigned char *sk_prf, const unsigned char *optrand, const unsigned char *m, size_t mlen) { - uint64_t s_inc[26]; + shake256incctx state; - shake256_inc_init(s_inc); - shake256_inc_absorb(s_inc, sk_prf, SPX_N); - shake256_inc_absorb(s_inc, optrand, SPX_N); - shake256_inc_absorb(s_inc, m, mlen); - shake256_inc_finalize(s_inc); - shake256_inc_squeeze(R, SPX_N, s_inc); + shake256_inc_init(&state); + shake256_inc_absorb(&state, sk_prf, SPX_N); + shake256_inc_absorb(&state, optrand, SPX_N); + shake256_inc_absorb(&state, m, mlen); + shake256_inc_finalize(&state); + shake256_inc_squeeze(R, SPX_N, &state); } /** @@ -64,14 +64,14 @@ void PQCLEAN_SPHINCSSHAKE256192FSIMPLE_CLEAN_hash_message( unsigned char buf[SPX_DGST_BYTES]; unsigned char *bufp = buf; - uint64_t s_inc[26]; + shake256incctx state; - shake256_inc_init(s_inc); - shake256_inc_absorb(s_inc, R, SPX_N); - shake256_inc_absorb(s_inc, pk, SPX_PK_BYTES); - shake256_inc_absorb(s_inc, m, mlen); - shake256_inc_finalize(s_inc); - shake256_inc_squeeze(buf, SPX_DGST_BYTES, s_inc); + shake256_inc_init(&state); + shake256_inc_absorb(&state, R, SPX_N); + shake256_inc_absorb(&state, pk, SPX_PK_BYTES); + shake256_inc_absorb(&state, m, mlen); + shake256_inc_finalize(&state); + shake256_inc_squeeze(buf, SPX_DGST_BYTES, &state); memcpy(digest, bufp, SPX_FORS_MSG_BYTES); bufp += SPX_FORS_MSG_BYTES; diff --git a/crypto_sign/sphincs-shake256-192s-robust/META.yml b/crypto_sign/sphincs-shake256-192s-robust/META.yml index ccc5bc5c..860fc704 100644 --- a/crypto_sign/sphincs-shake256-192s-robust/META.yml +++ b/crypto_sign/sphincs-shake256-192s-robust/META.yml @@ -4,6 +4,7 @@ claimed-nist-level: 3 length-public-key: 48 length-secret-key: 96 length-signature: 17064 +nistkat-sha256: 619ce596575f52ed8fd3e5b0501db21985e505c95f0f595faa4d6a6f0a2fd81c testvectors-sha256: 4f80c9cf98c017293c7543f96170f18655e6ef65675300aa302de42562b21f5a principal-submitter: Andreas Hülsing auxiliary-submitters: diff --git a/crypto_sign/sphincs-shake256-192s-robust/clean/Makefile b/crypto_sign/sphincs-shake256-192s-robust/clean/Makefile index 3a777491..506d6ae4 100644 --- a/crypto_sign/sphincs-shake256-192s-robust/clean/Makefile +++ b/crypto_sign/sphincs-shake256-192s-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-192s-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_robust.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-192s-robust/clean/hash_shake256.c b/crypto_sign/sphincs-shake256-192s-robust/clean/hash_shake256.c index 6b4e0656..0181d11e 100644 --- a/crypto_sign/sphincs-shake256-192s-robust/clean/hash_shake256.c +++ b/crypto_sign/sphincs-shake256-192s-robust/clean/hash_shake256.c @@ -37,14 +37,14 @@ void PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_gen_message_random( unsigned char *R, const unsigned char *sk_prf, const unsigned char *optrand, const unsigned char *m, size_t mlen) { - uint64_t s_inc[26]; + shake256incctx state; - shake256_inc_init(s_inc); - shake256_inc_absorb(s_inc, sk_prf, SPX_N); - shake256_inc_absorb(s_inc, optrand, SPX_N); - shake256_inc_absorb(s_inc, m, mlen); - shake256_inc_finalize(s_inc); - shake256_inc_squeeze(R, SPX_N, s_inc); + shake256_inc_init(&state); + shake256_inc_absorb(&state, sk_prf, SPX_N); + shake256_inc_absorb(&state, optrand, SPX_N); + shake256_inc_absorb(&state, m, mlen); + shake256_inc_finalize(&state); + shake256_inc_squeeze(R, SPX_N, &state); } /** @@ -64,14 +64,14 @@ void PQCLEAN_SPHINCSSHAKE256192SROBUST_CLEAN_hash_message( unsigned char buf[SPX_DGST_BYTES]; unsigned char *bufp = buf; - uint64_t s_inc[26]; + shake256incctx state; - shake256_inc_init(s_inc); - shake256_inc_absorb(s_inc, R, SPX_N); - shake256_inc_absorb(s_inc, pk, SPX_PK_BYTES); - shake256_inc_absorb(s_inc, m, mlen); - shake256_inc_finalize(s_inc); - shake256_inc_squeeze(buf, SPX_DGST_BYTES, s_inc); + shake256_inc_init(&state); + shake256_inc_absorb(&state, R, SPX_N); + shake256_inc_absorb(&state, pk, SPX_PK_BYTES); + shake256_inc_absorb(&state, m, mlen); + shake256_inc_finalize(&state); + shake256_inc_squeeze(buf, SPX_DGST_BYTES, &state); memcpy(digest, bufp, SPX_FORS_MSG_BYTES); bufp += SPX_FORS_MSG_BYTES; diff --git a/crypto_sign/sphincs-shake256-192s-simple/META.yml b/crypto_sign/sphincs-shake256-192s-simple/META.yml index 3bf7fa16..695619d5 100644 --- a/crypto_sign/sphincs-shake256-192s-simple/META.yml +++ b/crypto_sign/sphincs-shake256-192s-simple/META.yml @@ -4,6 +4,7 @@ claimed-nist-level: 3 length-public-key: 48 length-secret-key: 96 length-signature: 17064 +nistkat-sha256: 31b341c25230f8524e123db8a5dc29e8dd952cd11a63a821ac488b97d5106597 testvectors-sha256: ea1c38dafdeec8bd6b5a844955b1edffbb1d16f392a647fdae8e6dd148c6396c principal-submitter: Andreas Hülsing auxiliary-submitters: diff --git a/crypto_sign/sphincs-shake256-192s-simple/clean/Makefile b/crypto_sign/sphincs-shake256-192s-simple/clean/Makefile index 49763008..4758a68f 100644 --- a/crypto_sign/sphincs-shake256-192s-simple/clean/Makefile +++ b/crypto_sign/sphincs-shake256-192s-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-192s-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_simple.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-192s-simple/clean/hash_shake256.c b/crypto_sign/sphincs-shake256-192s-simple/clean/hash_shake256.c index 5c79d478..7129db40 100644 --- a/crypto_sign/sphincs-shake256-192s-simple/clean/hash_shake256.c +++ b/crypto_sign/sphincs-shake256-192s-simple/clean/hash_shake256.c @@ -37,14 +37,14 @@ void PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_gen_message_random( unsigned char *R, const unsigned char *sk_prf, const unsigned char *optrand, const unsigned char *m, size_t mlen) { - uint64_t s_inc[26]; + shake256incctx state; - shake256_inc_init(s_inc); - shake256_inc_absorb(s_inc, sk_prf, SPX_N); - shake256_inc_absorb(s_inc, optrand, SPX_N); - shake256_inc_absorb(s_inc, m, mlen); - shake256_inc_finalize(s_inc); - shake256_inc_squeeze(R, SPX_N, s_inc); + shake256_inc_init(&state); + shake256_inc_absorb(&state, sk_prf, SPX_N); + shake256_inc_absorb(&state, optrand, SPX_N); + shake256_inc_absorb(&state, m, mlen); + shake256_inc_finalize(&state); + shake256_inc_squeeze(R, SPX_N, &state); } /** @@ -64,14 +64,14 @@ void PQCLEAN_SPHINCSSHAKE256192SSIMPLE_CLEAN_hash_message( unsigned char buf[SPX_DGST_BYTES]; unsigned char *bufp = buf; - uint64_t s_inc[26]; + shake256incctx state; - shake256_inc_init(s_inc); - shake256_inc_absorb(s_inc, R, SPX_N); - shake256_inc_absorb(s_inc, pk, SPX_PK_BYTES); - shake256_inc_absorb(s_inc, m, mlen); - shake256_inc_finalize(s_inc); - shake256_inc_squeeze(buf, SPX_DGST_BYTES, s_inc); + shake256_inc_init(&state); + shake256_inc_absorb(&state, R, SPX_N); + shake256_inc_absorb(&state, pk, SPX_PK_BYTES); + shake256_inc_absorb(&state, m, mlen); + shake256_inc_finalize(&state); + shake256_inc_squeeze(buf, SPX_DGST_BYTES, &state); memcpy(digest, bufp, SPX_FORS_MSG_BYTES); bufp += SPX_FORS_MSG_BYTES; diff --git a/crypto_sign/sphincs-shake256-256f-robust/META.yml b/crypto_sign/sphincs-shake256-256f-robust/META.yml index 67eb8355..b949d913 100644 --- a/crypto_sign/sphincs-shake256-256f-robust/META.yml +++ b/crypto_sign/sphincs-shake256-256f-robust/META.yml @@ -4,6 +4,7 @@ claimed-nist-level: 5 length-public-key: 64 length-secret-key: 128 length-signature: 49216 +nistkat-sha256: d5410edbaa120cf24f0bcf8cb834fdb08b4b5652809ee17c026d37212f4a4934 testvectors-sha256: 4757a2ce7aec6daac4ab894336586949f7919c63d55200ec6325eb395efcf1ef principal-submitter: Andreas Hülsing auxiliary-submitters: diff --git a/crypto_sign/sphincs-shake256-256f-robust/clean/Makefile b/crypto_sign/sphincs-shake256-256f-robust/clean/Makefile index 7a30f008..4944a906 100644 --- a/crypto_sign/sphincs-shake256-256f-robust/clean/Makefile +++ b/crypto_sign/sphincs-shake256-256f-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-256f-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_robust.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-256f-robust/clean/hash_shake256.c b/crypto_sign/sphincs-shake256-256f-robust/clean/hash_shake256.c index 308338b4..8fbf5cbf 100644 --- a/crypto_sign/sphincs-shake256-256f-robust/clean/hash_shake256.c +++ b/crypto_sign/sphincs-shake256-256f-robust/clean/hash_shake256.c @@ -37,14 +37,14 @@ void PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_gen_message_random( unsigned char *R, const unsigned char *sk_prf, const unsigned char *optrand, const unsigned char *m, size_t mlen) { - uint64_t s_inc[26]; + shake256incctx state; - shake256_inc_init(s_inc); - shake256_inc_absorb(s_inc, sk_prf, SPX_N); - shake256_inc_absorb(s_inc, optrand, SPX_N); - shake256_inc_absorb(s_inc, m, mlen); - shake256_inc_finalize(s_inc); - shake256_inc_squeeze(R, SPX_N, s_inc); + shake256_inc_init(&state); + shake256_inc_absorb(&state, sk_prf, SPX_N); + shake256_inc_absorb(&state, optrand, SPX_N); + shake256_inc_absorb(&state, m, mlen); + shake256_inc_finalize(&state); + shake256_inc_squeeze(R, SPX_N, &state); } /** @@ -64,14 +64,14 @@ void PQCLEAN_SPHINCSSHAKE256256FROBUST_CLEAN_hash_message( unsigned char buf[SPX_DGST_BYTES]; unsigned char *bufp = buf; - uint64_t s_inc[26]; + shake256incctx state; - shake256_inc_init(s_inc); - shake256_inc_absorb(s_inc, R, SPX_N); - shake256_inc_absorb(s_inc, pk, SPX_PK_BYTES); - shake256_inc_absorb(s_inc, m, mlen); - shake256_inc_finalize(s_inc); - shake256_inc_squeeze(buf, SPX_DGST_BYTES, s_inc); + shake256_inc_init(&state); + shake256_inc_absorb(&state, R, SPX_N); + shake256_inc_absorb(&state, pk, SPX_PK_BYTES); + shake256_inc_absorb(&state, m, mlen); + shake256_inc_finalize(&state); + shake256_inc_squeeze(buf, SPX_DGST_BYTES, &state); memcpy(digest, bufp, SPX_FORS_MSG_BYTES); bufp += SPX_FORS_MSG_BYTES; diff --git a/crypto_sign/sphincs-shake256-256f-simple/META.yml b/crypto_sign/sphincs-shake256-256f-simple/META.yml index 37d2134b..7978a30b 100644 --- a/crypto_sign/sphincs-shake256-256f-simple/META.yml +++ b/crypto_sign/sphincs-shake256-256f-simple/META.yml @@ -4,6 +4,7 @@ claimed-nist-level: 5 length-public-key: 64 length-secret-key: 128 length-signature: 49216 +nistkat-sha256: 5a8959fc0436a66d6d69cc8adb2f24936b763ae324bc97ed139ae92f9f7e03c3 testvectors-sha256: 1b261fc7394dc847349c07bde922ac028aad94c534f51341f8202670558ed27a principal-submitter: Andreas Hülsing auxiliary-submitters: diff --git a/crypto_sign/sphincs-shake256-256f-simple/clean/Makefile b/crypto_sign/sphincs-shake256-256f-simple/clean/Makefile index 2d90b6a9..2e09eaae 100644 --- a/crypto_sign/sphincs-shake256-256f-simple/clean/Makefile +++ b/crypto_sign/sphincs-shake256-256f-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-256f-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_simple.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-256f-simple/clean/hash_shake256.c b/crypto_sign/sphincs-shake256-256f-simple/clean/hash_shake256.c index db8875d7..9a1306e9 100644 --- a/crypto_sign/sphincs-shake256-256f-simple/clean/hash_shake256.c +++ b/crypto_sign/sphincs-shake256-256f-simple/clean/hash_shake256.c @@ -37,14 +37,14 @@ void PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_gen_message_random( unsigned char *R, const unsigned char *sk_prf, const unsigned char *optrand, const unsigned char *m, size_t mlen) { - uint64_t s_inc[26]; + shake256incctx state; - shake256_inc_init(s_inc); - shake256_inc_absorb(s_inc, sk_prf, SPX_N); - shake256_inc_absorb(s_inc, optrand, SPX_N); - shake256_inc_absorb(s_inc, m, mlen); - shake256_inc_finalize(s_inc); - shake256_inc_squeeze(R, SPX_N, s_inc); + shake256_inc_init(&state); + shake256_inc_absorb(&state, sk_prf, SPX_N); + shake256_inc_absorb(&state, optrand, SPX_N); + shake256_inc_absorb(&state, m, mlen); + shake256_inc_finalize(&state); + shake256_inc_squeeze(R, SPX_N, &state); } /** @@ -64,14 +64,14 @@ void PQCLEAN_SPHINCSSHAKE256256FSIMPLE_CLEAN_hash_message( unsigned char buf[SPX_DGST_BYTES]; unsigned char *bufp = buf; - uint64_t s_inc[26]; + shake256incctx state; - shake256_inc_init(s_inc); - shake256_inc_absorb(s_inc, R, SPX_N); - shake256_inc_absorb(s_inc, pk, SPX_PK_BYTES); - shake256_inc_absorb(s_inc, m, mlen); - shake256_inc_finalize(s_inc); - shake256_inc_squeeze(buf, SPX_DGST_BYTES, s_inc); + shake256_inc_init(&state); + shake256_inc_absorb(&state, R, SPX_N); + shake256_inc_absorb(&state, pk, SPX_PK_BYTES); + shake256_inc_absorb(&state, m, mlen); + shake256_inc_finalize(&state); + shake256_inc_squeeze(buf, SPX_DGST_BYTES, &state); memcpy(digest, bufp, SPX_FORS_MSG_BYTES); bufp += SPX_FORS_MSG_BYTES; diff --git a/crypto_sign/sphincs-shake256-256s-robust/META.yml b/crypto_sign/sphincs-shake256-256s-robust/META.yml index a04440fd..bf7b1bf1 100644 --- a/crypto_sign/sphincs-shake256-256s-robust/META.yml +++ b/crypto_sign/sphincs-shake256-256s-robust/META.yml @@ -4,6 +4,7 @@ claimed-nist-level: 5 length-public-key: 64 length-secret-key: 128 length-signature: 29792 +nistkat-sha256: 09004dba03b2a190a327b5404a4d75c663f025703253b78946d0a99ca1492d6f testvectors-sha256: eea62308d71394a888e05128f078c4663dc83e128c34e0300bb16cb839d8698b principal-submitter: Andreas Hülsing auxiliary-submitters: diff --git a/crypto_sign/sphincs-shake256-256s-robust/clean/Makefile b/crypto_sign/sphincs-shake256-256s-robust/clean/Makefile index 66d22b40..c767c4ac 100644 --- a/crypto_sign/sphincs-shake256-256s-robust/clean/Makefile +++ b/crypto_sign/sphincs-shake256-256s-robust/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-256s-robust_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_robust.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-256s-robust/clean/hash_shake256.c b/crypto_sign/sphincs-shake256-256s-robust/clean/hash_shake256.c index 41146c98..5aeb3db4 100644 --- a/crypto_sign/sphincs-shake256-256s-robust/clean/hash_shake256.c +++ b/crypto_sign/sphincs-shake256-256s-robust/clean/hash_shake256.c @@ -37,14 +37,14 @@ void PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_gen_message_random( unsigned char *R, const unsigned char *sk_prf, const unsigned char *optrand, const unsigned char *m, size_t mlen) { - uint64_t s_inc[26]; + shake256incctx state; - shake256_inc_init(s_inc); - shake256_inc_absorb(s_inc, sk_prf, SPX_N); - shake256_inc_absorb(s_inc, optrand, SPX_N); - shake256_inc_absorb(s_inc, m, mlen); - shake256_inc_finalize(s_inc); - shake256_inc_squeeze(R, SPX_N, s_inc); + shake256_inc_init(&state); + shake256_inc_absorb(&state, sk_prf, SPX_N); + shake256_inc_absorb(&state, optrand, SPX_N); + shake256_inc_absorb(&state, m, mlen); + shake256_inc_finalize(&state); + shake256_inc_squeeze(R, SPX_N, &state); } /** @@ -64,14 +64,14 @@ void PQCLEAN_SPHINCSSHAKE256256SROBUST_CLEAN_hash_message( unsigned char buf[SPX_DGST_BYTES]; unsigned char *bufp = buf; - uint64_t s_inc[26]; + shake256incctx state; - shake256_inc_init(s_inc); - shake256_inc_absorb(s_inc, R, SPX_N); - shake256_inc_absorb(s_inc, pk, SPX_PK_BYTES); - shake256_inc_absorb(s_inc, m, mlen); - shake256_inc_finalize(s_inc); - shake256_inc_squeeze(buf, SPX_DGST_BYTES, s_inc); + shake256_inc_init(&state); + shake256_inc_absorb(&state, R, SPX_N); + shake256_inc_absorb(&state, pk, SPX_PK_BYTES); + shake256_inc_absorb(&state, m, mlen); + shake256_inc_finalize(&state); + shake256_inc_squeeze(buf, SPX_DGST_BYTES, &state); memcpy(digest, bufp, SPX_FORS_MSG_BYTES); bufp += SPX_FORS_MSG_BYTES; diff --git a/crypto_sign/sphincs-shake256-256s-simple/META.yml b/crypto_sign/sphincs-shake256-256s-simple/META.yml index 33732662..482dc1e4 100644 --- a/crypto_sign/sphincs-shake256-256s-simple/META.yml +++ b/crypto_sign/sphincs-shake256-256s-simple/META.yml @@ -4,6 +4,7 @@ claimed-nist-level: 5 length-public-key: 64 length-secret-key: 128 length-signature: 29792 +nistkat-sha256: f704deaf990987c306082bb28258cfb8c6f03b49940c06df582ef3fb86958e8a testvectors-sha256: fc518be7778d0363f17a30c50efbe28841f5a795e7375e94d206f115967f30df principal-submitter: Andreas Hülsing auxiliary-submitters: diff --git a/crypto_sign/sphincs-shake256-256s-simple/clean/Makefile b/crypto_sign/sphincs-shake256-256s-simple/clean/Makefile index f764bc17..e871e956 100644 --- a/crypto_sign/sphincs-shake256-256s-simple/clean/Makefile +++ b/crypto_sign/sphincs-shake256-256s-simple/clean/Makefile @@ -5,7 +5,7 @@ LIB=libsphincs-shake256-256s-simple_clean.a HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_simple.o -CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) +CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) all: $(LIB) diff --git a/crypto_sign/sphincs-shake256-256s-simple/clean/hash_shake256.c b/crypto_sign/sphincs-shake256-256s-simple/clean/hash_shake256.c index a0982585..acc211fb 100644 --- a/crypto_sign/sphincs-shake256-256s-simple/clean/hash_shake256.c +++ b/crypto_sign/sphincs-shake256-256s-simple/clean/hash_shake256.c @@ -37,14 +37,14 @@ void PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_gen_message_random( unsigned char *R, const unsigned char *sk_prf, const unsigned char *optrand, const unsigned char *m, size_t mlen) { - uint64_t s_inc[26]; + shake256incctx state; - shake256_inc_init(s_inc); - shake256_inc_absorb(s_inc, sk_prf, SPX_N); - shake256_inc_absorb(s_inc, optrand, SPX_N); - shake256_inc_absorb(s_inc, m, mlen); - shake256_inc_finalize(s_inc); - shake256_inc_squeeze(R, SPX_N, s_inc); + shake256_inc_init(&state); + shake256_inc_absorb(&state, sk_prf, SPX_N); + shake256_inc_absorb(&state, optrand, SPX_N); + shake256_inc_absorb(&state, m, mlen); + shake256_inc_finalize(&state); + shake256_inc_squeeze(R, SPX_N, &state); } /** @@ -64,14 +64,14 @@ void PQCLEAN_SPHINCSSHAKE256256SSIMPLE_CLEAN_hash_message( unsigned char buf[SPX_DGST_BYTES]; unsigned char *bufp = buf; - uint64_t s_inc[26]; + shake256incctx state; - shake256_inc_init(s_inc); - shake256_inc_absorb(s_inc, R, SPX_N); - shake256_inc_absorb(s_inc, pk, SPX_PK_BYTES); - shake256_inc_absorb(s_inc, m, mlen); - shake256_inc_finalize(s_inc); - shake256_inc_squeeze(buf, SPX_DGST_BYTES, s_inc); + shake256_inc_init(&state); + shake256_inc_absorb(&state, R, SPX_N); + shake256_inc_absorb(&state, pk, SPX_PK_BYTES); + shake256_inc_absorb(&state, m, mlen); + shake256_inc_finalize(&state); + shake256_inc_squeeze(buf, SPX_DGST_BYTES, &state); memcpy(digest, bufp, SPX_FORS_MSG_BYTES); bufp += SPX_FORS_MSG_BYTES; diff --git a/test/Makefile b/test/Makefile index 10fae81f..3963d9bd 100644 --- a/test/Makefile +++ b/test/Makefile @@ -10,7 +10,7 @@ SCHEME_UPPERCASE=$(shell echo $(SCHEME) | tr a-z A-Z | sed 's/-//g') IMPLEMENTATION_UPPERCASE=$(shell echo $(IMPLEMENTATION) | tr a-z A-Z | sed 's/-//g') COMMON_DIR=../common -COMMON_FILES=$(COMMON_DIR)/aes.c $(COMMON_DIR)/sha2.c $(COMMON_DIR)/fips202.c +COMMON_FILES=$(COMMON_DIR)/aes.c $(COMMON_DIR)/sha2.c $(COMMON_DIR)/fips202.c $(COMMON_DIR)/sp800-185.c COMMON_HEADERS=$(COMMON_DIR)/*.h DEST_DIR=../bin @@ -47,7 +47,16 @@ printparams: $(DEST_DIR)/printparams_$(SCHEME)_$(IMPLEMENTATION) .PHONY: nistkat nistkat: $(DEST_DIR)/nistkat_$(SCHEME)_$(IMPLEMENTATION) -$(DEST_DIR)/test_common_%: common/%.c $(COMMON_FILES) +$(DEST_DIR)/test_common_aes: common/aes.c $(COMMON_FILES) + mkdir -p $(DEST_DIR) + $(CC) $(CFLAGS) $< $(COMMON_FILES) -o $@ +$(DEST_DIR)/test_common_fips202: common/fips202.c $(COMMON_FILES) + mkdir -p $(DEST_DIR) + $(CC) $(CFLAGS) $< $(COMMON_FILES) -o $@ +$(DEST_DIR)/test_common_sha2: common/sha2.c $(COMMON_FILES) + mkdir -p $(DEST_DIR) + $(CC) $(CFLAGS) $< $(COMMON_FILES) -o $@ +$(DEST_DIR)/test_common_sp800-185: common/sp800-185.c $(COMMON_FILES) mkdir -p $(DEST_DIR) $(CC) $(CFLAGS) $< $(COMMON_FILES) -o $@ @@ -76,6 +85,7 @@ clean: $(RM) $(DEST_DIR)/test_aes $(RM) $(DEST_DIR)/test_fips202 $(RM) $(DEST_DIR)/test_sha2 + $(RM) $(DEST_DIR)/test_sp800-185 .PHONY: distclean distclean: diff --git a/test/Makefile.Microsoft_nmake b/test/Makefile.Microsoft_nmake index d0bb5abc..3bd9f0df 100644 --- a/test/Makefile.Microsoft_nmake +++ b/test/Makefile.Microsoft_nmake @@ -12,8 +12,8 @@ IMPLEMENTATION_UPPERCASE=CLEAN SCHEME_DIR=..\crypto_$(TYPE)\$(SCHEME)\$(IMPLEMENTATION) COMMON_DIR=..\common -COMMON_OBJECTS=$(COMMON_DIR)\aes.obj $(COMMON_DIR)\fips202.obj $(COMMON_DIR)\sha2.obj -COMMON_OBJECTS_NOPATH=aes.obj fips202.obj sha2.obj +COMMON_OBJECTS=$(COMMON_DIR)\aes.obj $(COMMON_DIR)\fips202.obj $(COMMON_DIR)\sha2.obj $(COMMON_DIR)\sp800-185.obj +COMMON_OBJECTS_NOPATH=aes.obj fips202.obj sha2.obj sp800-185.obj DEST_DIR=..\bin diff --git a/test/common/fips202.c b/test/common/fips202.c index e7d017d8..9cd09f85 100644 --- a/test/common/fips202.c +++ b/test/common/fips202.c @@ -56,7 +56,7 @@ static int test_sha3_256_incremental(void) { unsigned char input[512]; unsigned char check[32]; unsigned char output[32]; - uint64_t s_inc[26]; + sha3_256incctx state; int i; int absorbed; int returncode = 0; @@ -67,18 +67,18 @@ static int test_sha3_256_incremental(void) { sha3_256(check, input, 512); - sha3_256_inc_init(s_inc); + sha3_256_inc_init(&state); absorbed = 0; for (i = 0; i < 512 && absorbed + i <= 512; i++) { - sha3_256_inc_absorb(s_inc, input + absorbed, i); + sha3_256_inc_absorb(&state, input + absorbed, i); absorbed += i; } - sha3_256_inc_absorb(s_inc, input + absorbed, 512 - absorbed); + sha3_256_inc_absorb(&state, input + absorbed, 512 - absorbed); - sha3_256_inc_finalize(output, s_inc); + sha3_256_inc_finalize(output, &state); - if (memcmp(check, output, 32)) { + if (memcmp(check, output, 32) != 0) { printf("ERROR sha3_256 incremental did not match sha3_256.\n"); printf(" Expected: "); for (i = 0; i < 32; i++) { @@ -100,11 +100,11 @@ static int test_shake128_incremental(void) { unsigned char input[512]; unsigned char check[512]; unsigned char output[512]; - uint64_t s_inc_absorb[26]; - uint64_t s_inc_squeeze[26]; - uint64_t s_inc_squeeze_all[26]; - uint64_t s_inc_both[26]; - uint64_t s_combined[25]; + shake128incctx state_absorb; + shake128incctx state_squeeze; + shake128incctx state_squeeze_all; + shake128incctx state_both; + shake128ctx state_combined; int i; int absorbed; int squeezed; @@ -116,47 +116,27 @@ static int test_shake128_incremental(void) { shake128(check, 512, input, 512); - shake128_inc_init(s_inc_absorb); + shake128_inc_init(&state_absorb); absorbed = 0; for (i = 0; i < 512 && absorbed + i <= 512; i++) { - shake128_inc_absorb(s_inc_absorb, input + absorbed, i); + shake128_inc_absorb(&state_absorb, input + absorbed, i); absorbed += i; } - shake128_inc_absorb(s_inc_absorb, input + absorbed, 512 - absorbed); + shake128_inc_absorb(&state_absorb, input + absorbed, 512 - absorbed); - shake128_inc_finalize(s_inc_absorb); + shake128_inc_finalize(&state_absorb); - shake128_absorb(s_combined, input, 512); + shake128_absorb(&state_combined, input, 512); - if (memcmp(s_inc_absorb, s_combined, 25 * sizeof(uint64_t))) { + if (memcmp(&state_absorb, &state_combined, sizeof(shake128ctx)) != 0) { printf("ERROR shake128 state after incremental absorb did not match all-at-once absorb.\n"); - printf(" Expected: "); - for (i = 0; i < 25; i++) { - printf("%016" PRIx64, s_combined[i]); - } - printf("\n"); - printf(" State: "); - for (i = 0; i < 25; i++) { - printf("%016" PRIx64, s_inc_absorb[i]); - } - printf("\n"); - for (i = 0; i < 8 * 25; i++) { - if (((s_combined[i >> 3] >> (8*(i & 0x7))) & 0xFF) != - ((s_inc_absorb[i >> 3] >> (8*(i & 0x7))) & 0xFF)) { - printf(" First occurred in int %d, byte %d (%02X should be %02X)\n", - i >> 3, i & 0x7, - (uint8_t)((s_inc_absorb[i >> 3] >> (8*(i & 0x7))) & 0xFF), - (uint8_t)((s_combined[i >> 3] >> (8*(i & 0x7))) & 0xFF)); - break; - } - } returncode = 1; } - memcpy(s_inc_both, s_inc_absorb, 26 * sizeof(uint64_t)); + memcpy(&state_both, &state_absorb, sizeof(shake128incctx)); - shake128_squeezeblocks(output, 3, s_inc_absorb); + shake128_squeezeblocks(output, 3, (shake128ctx*)&state_absorb); if (memcmp(check, output, 3*SHAKE128_RATE)) { printf("ERROR shake128 incremental absorb did not match shake128.\n"); @@ -173,14 +153,14 @@ static int test_shake128_incremental(void) { returncode = 1; } - shake128_absorb(s_inc_squeeze, input, 512); - s_inc_squeeze[25] = 0; + shake128_absorb((shake128ctx*)&state_squeeze, input, 512); + state_squeeze.ctx[25] = 0; - memcpy(s_inc_squeeze_all, s_inc_squeeze, 26 * sizeof(uint64_t)); + memcpy(&state_squeeze_all, &state_squeeze, sizeof(shake128incctx)); - shake128_inc_squeeze(output, 512, s_inc_squeeze_all); + shake128_inc_squeeze(output, 512, &state_squeeze_all); - if (memcmp(check, output, 512)) { + if (memcmp(check, output, 512) != 0) { printf("ERROR shake128 incremental squeeze-all did not match shake128.\n"); printf(" Expected: "); for (i = 0; i < 512; i++) { @@ -198,12 +178,12 @@ static int test_shake128_incremental(void) { squeezed = 0; memset(output, 0, 512); for (i = 0; i < 512 && squeezed + i <= 512; i++) { - shake128_inc_squeeze(output + squeezed, i, s_inc_squeeze); + shake128_inc_squeeze(output + squeezed, i, &state_squeeze); squeezed += i; } - shake128_inc_squeeze(output + squeezed, 512 - squeezed, s_inc_squeeze); + shake128_inc_squeeze(output + squeezed, 512 - squeezed, &state_squeeze); - if (memcmp(check, output, 512)) { + if (memcmp(check, output, 512) != 0) { printf("ERROR shake128 incremental squeeze did not match shake128.\n"); printf(" Expected: "); for (i = 0; i < 512; i++) { @@ -221,12 +201,12 @@ static int test_shake128_incremental(void) { squeezed = 0; memset(output, 0, 512); for (i = 0; i < 512 && squeezed + i <= 512; i++) { - shake128_inc_squeeze(output + squeezed, i, s_inc_both); + shake128_inc_squeeze(output + squeezed, i, &state_both); squeezed += i; } - shake128_inc_squeeze(output + squeezed, 512 - squeezed, s_inc_both); + shake128_inc_squeeze(output + squeezed, 512 - squeezed, &state_both); - if (memcmp(check, output, 512)) { + if (memcmp(check, output, 512) != 0) { printf("ERROR shake128 incremental absorb + squeeze did not match shake128.\n"); printf(" Expected: "); for (i = 0; i < 512; i++) { @@ -250,7 +230,7 @@ static int test_shake128(void) { shake128(output, 32, plaintext, 43); - if (memcmp(expected, output, 32)) { + if (memcmp(expected, output, 32) != 0) { printf("ERROR shake128 output did not match test vector.\n"); printf("Expected: "); for (i = 0; i < 32; i++) { diff --git a/test/common/sha2.c b/test/common/sha2.c index f08eb06b..b04f59a2 100644 --- a/test/common/sha2.c +++ b/test/common/sha2.c @@ -37,14 +37,14 @@ const unsigned char expected_512[64] = { static int test_sha256_incremental(void) { unsigned char output[32]; - uint8_t state[40]; + sha256ctx state; int i = 0; - sha256_inc_init(state); - sha256_inc_blocks(state, plaintext, 1); - sha256_inc_finalize(output, state, plaintext + 64, 112 - 64); + sha256_inc_init(&state); + sha256_inc_blocks(&state, plaintext, 1); + sha256_inc_finalize(output, &state, plaintext + 64, 112 - 64); - if (memcmp(expected_256, output, 32)) { + if (memcmp(expected_256, output, 32) != 0) { printf("ERROR sha256 incremental did not match sha256.\n"); printf(" Expected: "); for (i = 0; i < 32; i++) { @@ -68,7 +68,7 @@ static int test_sha224(void) { sha224(output, plaintext, 112); - if (memcmp(expected_224, output, 28)) { + if (memcmp(expected_224, output, 28) != 0) { printf("ERROR sha224 output did not match test vector.\n"); printf("Expected: "); for (i = 0; i < 28; i++) { @@ -92,7 +92,7 @@ static int test_sha256(void) { sha256(output, plaintext, 112); - if (memcmp(expected_256, output, 32)) { + if (memcmp(expected_256, output, 32) != 0) { printf("ERROR sha256 output did not match test vector.\n"); printf("Expected: "); for (i = 0; i < 32; i++) { @@ -116,7 +116,7 @@ static int test_sha384(void) { sha384(output, plaintext, 112); - if (memcmp(expected_384, output, 48)) { + if (memcmp(expected_384, output, 48) != 0) { printf("ERROR sha384 output did not match test vector.\n"); printf("Expected: "); for (i = 0; i < 48; i++) { @@ -140,7 +140,7 @@ static int test_sha512(void) { sha512(output, plaintext, 112); - if (memcmp(expected_512, output, 64)) { + if (memcmp(expected_512, output, 64) != 0) { printf("ERROR sha512 output did not match test vector.\n"); printf("Expected: "); for (i = 0; i < 64; i++) { diff --git a/test/common/sp800-185.c b/test/common/sp800-185.c new file mode 100644 index 00000000..f77d3fb4 --- /dev/null +++ b/test/common/sp800-185.c @@ -0,0 +1,146 @@ +#include +#include +#include + +#include "sp800-185.h" + +const unsigned char name[] = ""; +const unsigned char customization[] = "Email Signature"; + +const unsigned char output1[32] = { + 0xC1, 0xC3, 0x69, 0x25, 0xB6, 0x40, 0x9A, 0x04, 0xF1, 0xB5, 0x04, 0xFC, 0xBC, 0xA9, 0xD8, 0x2B, + 0x40, 0x17, 0x27, 0x7C, 0xB5, 0xED, 0x2B, 0x20, 0x65, 0xFC, 0x1D, 0x38, 0x14, 0xD5, 0xAA, 0xF5 +}; +const unsigned char output2[32] = { + 0xC5, 0x22, 0x1D, 0x50, 0xE4, 0xF8, 0x22, 0xD9, 0x6A, 0x2E, 0x88, 0x81, 0xA9, 0x61, 0x42, 0x0F, + 0x29, 0x4B, 0x7B, 0x24, 0xFE, 0x3D, 0x20, 0x94, 0xBA, 0xED, 0x2C, 0x65, 0x24, 0xCC, 0x16, 0x6B +}; +const unsigned char output3[64] = { + 0xD0, 0x08, 0x82, 0x8E, 0x2B, 0x80, 0xAC, 0x9D, 0x22, 0x18, 0xFF, 0xEE, 0x1D, 0x07, 0x0C, 0x48, + 0xB8, 0xE4, 0xC8, 0x7B, 0xFF, 0x32, 0xC9, 0x69, 0x9D, 0x5B, 0x68, 0x96, 0xEE, 0xE0, 0xED, 0xD1, + 0x64, 0x02, 0x0E, 0x2B, 0xE0, 0x56, 0x08, 0x58, 0xD9, 0xC0, 0x0C, 0x03, 0x7E, 0x34, 0xA9, 0x69, + 0x37, 0xC5, 0x61, 0xA7, 0x4C, 0x41, 0x2B, 0xB4, 0xC7, 0x46, 0x46, 0x95, 0x27, 0x28, 0x1C, 0x8C +}; +const unsigned char output4[64] = { + 0x07, 0xDC, 0x27, 0xB1, 0x1E, 0x51, 0xFB, 0xAC, 0x75, 0xBC, 0x7B, 0x3C, 0x1D, 0x98, 0x3E, 0x8B, + 0x4B, 0x85, 0xFB, 0x1D, 0xEF, 0xAF, 0x21, 0x89, 0x12, 0xAC, 0x86, 0x43, 0x02, 0x73, 0x09, 0x17, + 0x27, 0xF4, 0x2B, 0x17, 0xED, 0x1D, 0xF6, 0x3E, 0x8E, 0xC1, 0x18, 0xF0, 0x4B, 0x23, 0x63, 0x3C, + 0x1D, 0xFB, 0x15, 0x74, 0xC8, 0xFB, 0x55, 0xCB, 0x45, 0xDA, 0x8E, 0x25, 0xAF, 0xB0, 0x92, 0xBB +}; + +static int test_cshake128(void) { + unsigned char input[200]; + unsigned char output[32]; + int i; + int returncode = 0; + size_t namelen = strlen((const char *)name); + size_t cstmlen = strlen((const char *)customization); + + for (i = 0; i < 4; i++) { + input[i] = i; + } + + cshake128(output, 32, name, namelen, customization, cstmlen, input, 4); + + if (memcmp(output1, output, 32) != 0) { + puts("ERROR shake128 did not match test vector 1."); + printf(" Expected: "); + for (i = 0; i < 32; i++) { + printf("%02X", output1[i]); + } + puts(""); + printf(" Received: "); + for (i = 0; i < 32; i++) { + printf("%02X", output[i]); + } + puts(""); + returncode = 1; + } + + for (i = 0; i < 200; i++) { + input[i] = i; + } + + cshake128(output, 32, name, namelen, customization, cstmlen, input, 200); + + if (memcmp(output2, output, 32) != 0) { + puts("ERROR shake128 did not match test vector 2."); + printf(" Expected: "); + for (i = 0; i < 32; i++) { + printf("%02X", output2[i]); + } + puts(""); + printf(" Received: "); + for (i = 0; i < 32; i++) { + printf("%02X", output[i]); + } + puts(""); + returncode = 1; + } + + return returncode; +} + +static int test_cshake256(void) { + unsigned char input[200]; + unsigned char output[64]; + int i; + int returncode = 0; + size_t namelen = strlen((const char *)name); + size_t cstmlen = strlen((const char *)customization); + + for (i = 0; i < 4; i++) { + input[i] = i; + } + + cshake256(output, 64, name, namelen, customization, cstmlen, input, 4); + + if (memcmp(output3, output, 64) != 0) { + puts("ERROR shake256 did not match test vector 3."); + printf(" Expected: "); + for (i = 0; i < 64; i++) { + printf("%02X", output3[i]); + } + puts(""); + printf(" Received: "); + for (i = 0; i < 64; i++) { + printf("%02X", output[i]); + } + puts(""); + returncode = 1; + } + + for (i = 0; i < 200; i++) { + input[i] = i; + } + + cshake256(output, 64, name, namelen, customization, cstmlen, input, 200); + + if (memcmp(output4, output, 64) != 0) { + puts("ERROR shake256 did not match test vector 4."); + printf(" Expected: "); + for (i = 0; i < 64; i++) { + printf("%02X", output4[i]); + } + puts(""); + printf(" Received: "); + for (i = 0; i < 64; i++) { + printf("%02X", output[i]); + } + puts(""); + returncode = 1; + } + + return returncode; +} + +int main(void) { + int result = 0; + result += test_cshake128(); + result += test_cshake256(); + + if (result != 0) { + puts("Errors occurred"); + } + return result; +} diff --git a/test/crypto_sign/nistkat.c b/test/crypto_sign/nistkat.c new file mode 100644 index 00000000..267b072f --- /dev/null +++ b/test/crypto_sign/nistkat.c @@ -0,0 +1,102 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "api.h" +#include "randombytes.h" + +// https://stackoverflow.com/a/1489985/1711232 +#define PASTER(x, y) x##_##y +#define EVALUATOR(x, y) PASTER(x, y) +#define NAMESPACE(fun) EVALUATOR(PQCLEAN_NAMESPACE, fun) + +#define CRYPTO_PUBLICKEYBYTES NAMESPACE(CRYPTO_PUBLICKEYBYTES) +#define CRYPTO_SECRETKEYBYTES NAMESPACE(CRYPTO_SECRETKEYBYTES) +#define CRYPTO_BYTES NAMESPACE(CRYPTO_BYTES) +#define CRYPTO_ALGNAME NAMESPACE(CRYPTO_ALGNAME) + +#define crypto_sign_keypair NAMESPACE(crypto_sign_keypair) +#define crypto_sign NAMESPACE(crypto_sign) +#define crypto_sign_open NAMESPACE(crypto_sign_open) + +void nist_kat_init(unsigned char *entropy_input, unsigned char *personalization_string, int security_strength); + +static void fprintBstr(FILE *fp, const char *S, const uint8_t *A, size_t L) { + size_t i; + fprintf(fp, "%s", S); + for (i = 0; i < L; i++) { + fprintf(fp, "%02X", A[i]); + } + if (L == 0) { + fprintf(fp, "00"); + } + fprintf(fp, "\n"); +} + +int main() { + + uint8_t entropy_input[48]; + uint8_t seed[48]; + FILE *fh = stdout; + uint8_t public_key[CRYPTO_PUBLICKEYBYTES]; + uint8_t secret_key[CRYPTO_SECRETKEYBYTES]; + size_t mlen = 33; + size_t smlen, mlen1; + uint8_t m[33]; + uint8_t sm[33 + CRYPTO_BYTES]; + int rc; + + for (uint8_t i = 0; i < 48; i++) { + entropy_input[i] = i; + } + + nist_kat_init(entropy_input, NULL, 256); + + fprintf(fh, "count = 0\n"); + randombytes(seed, 48); + fprintBstr(fh, "seed = ", seed, 48); + + fprintf(fh, "mlen = 33\n"); + + randombytes(m, mlen); + fprintBstr(fh, "msg = ", m, mlen); + + nist_kat_init(seed, NULL, 256); + + rc = crypto_sign_keypair(public_key, secret_key); + if (rc != 0) { + fprintf(stderr, "[kat_kem] %s ERROR: crypto_kem_keypair failed!\n", CRYPTO_ALGNAME); + return -1; + } + fprintBstr(fh, "pk = ", public_key, CRYPTO_PUBLICKEYBYTES); + fprintBstr(fh, "sk = ", secret_key, CRYPTO_SECRETKEYBYTES); + + rc = crypto_sign(sm, &smlen, m, mlen, secret_key); + if (rc != 0) { + fprintf(stderr, "[kat_kem] %s ERROR: crypto_sign failed!\n", CRYPTO_ALGNAME); + return -2; + } + fprintf(fh, "smlen = %zu\n", smlen); + fprintBstr(fh, "sm = ", sm, smlen); + + rc = crypto_sign_open(sm, &mlen1, sm, smlen, public_key); + if (rc != 0) { + fprintf(stderr, "[kat_kem] %s ERROR: crypto_sign_open failed!\n", CRYPTO_ALGNAME); + return -3; + } + + if ( mlen != mlen1 ) { + printf("crypto_sign_open returned bad 'mlen': got <%zu>, expected <%zu>\n", mlen1, mlen); + return -4; + } + if (memcmp(m, sm, mlen)) { + printf("crypto_sign_open returned bad 'm' value\n"); + return -5; + } + return 0; + +} diff --git a/test/duplicate_consistency/frodokem1344aes_opt.yml b/test/duplicate_consistency/frodokem1344aes_opt.yml new file mode 100644 index 00000000..9d81ab98 --- /dev/null +++ b/test/duplicate_consistency/frodokem1344aes_opt.yml @@ -0,0 +1,16 @@ +consistency_checks: +- source: + scheme: frodokem1344aes + implementation: clean + files: + - api.h + - common.h + - params.h + - kem.c + - noise.c + - util.c +- source: + scheme: frodokem640aes + implementation: opt + files: + - matrix_aes.c diff --git a/test/duplicate_consistency/frodokem1344shake_opt.yml b/test/duplicate_consistency/frodokem1344shake_opt.yml new file mode 100644 index 00000000..f0bd1883 --- /dev/null +++ b/test/duplicate_consistency/frodokem1344shake_opt.yml @@ -0,0 +1,16 @@ +consistency_checks: +- source: + scheme: frodokem1344shake + implementation: clean + files: + - api.h + - common.h + - params.h + - kem.c + - noise.c + - util.c +- source: + scheme: frodokem640shake + implementation: opt + files: + - matrix_shake.c diff --git a/test/duplicate_consistency/frodokem640aes_opt.yml b/test/duplicate_consistency/frodokem640aes_opt.yml new file mode 100644 index 00000000..6f2a554f --- /dev/null +++ b/test/duplicate_consistency/frodokem640aes_opt.yml @@ -0,0 +1,11 @@ +consistency_checks: +- source: + scheme: frodokem640aes + implementation: clean + files: + - api.h + - common.h + - params.h + - kem.c + - noise.c + - util.c diff --git a/test/duplicate_consistency/frodokem640shake_opt.yml b/test/duplicate_consistency/frodokem640shake_opt.yml new file mode 100644 index 00000000..a3aa6115 --- /dev/null +++ b/test/duplicate_consistency/frodokem640shake_opt.yml @@ -0,0 +1,11 @@ +consistency_checks: +- source: + scheme: frodokem640shake + implementation: clean + files: + - api.h + - common.h + - params.h + - kem.c + - noise.c + - util.c diff --git a/test/duplicate_consistency/frodokem976aes_opt.yml b/test/duplicate_consistency/frodokem976aes_opt.yml new file mode 100644 index 00000000..a460521d --- /dev/null +++ b/test/duplicate_consistency/frodokem976aes_opt.yml @@ -0,0 +1,16 @@ +consistency_checks: +- source: + scheme: frodokem976aes + implementation: clean + files: + - api.h + - common.h + - params.h + - kem.c + - noise.c + - util.c +- source: + scheme: frodokem640aes + implementation: opt + files: + - matrix_aes.c diff --git a/test/duplicate_consistency/frodokem976shake_opt.yml b/test/duplicate_consistency/frodokem976shake_opt.yml new file mode 100644 index 00000000..afce9c53 --- /dev/null +++ b/test/duplicate_consistency/frodokem976shake_opt.yml @@ -0,0 +1,16 @@ +consistency_checks: +- source: + scheme: frodokem976shake + implementation: clean + files: + - api.h + - common.h + - params.h + - kem.c + - noise.c + - util.c +- source: + scheme: frodokem640shake + implementation: opt + files: + - matrix_shake.c diff --git a/test/duplicate_consistency/newhope1024cca_clean.yml b/test/duplicate_consistency/newhope1024cca_clean.yml new file mode 100644 index 00000000..21764ea3 --- /dev/null +++ b/test/duplicate_consistency/newhope1024cca_clean.yml @@ -0,0 +1,43 @@ +consistency_checks: +- source: + scheme: newhope1024cpa + implementation: clean + files: + - ntt.c + - poly.c + - precomp.c + - cpapke.c + - reduce.c + - verify.c + - params.h + - cpapke.h + - ntt.h + - poly.h + - reduce.h + - verify.h +- source: + scheme: newhope512cca + implementation: clean + files: + - kem.c + - cpapke.c + - reduce.c + - verify.c + - cpapke.h + - ntt.h + - poly.h + - reduce.h + - verify.h +- source: + scheme: newhope512cpa + implementation: clean + files: + - cpapke.c + - reduce.c + - verify.c + - cpapke.h + - ntt.h + - poly.h + - reduce.h + - verify.h + diff --git a/test/duplicate_consistency/newhope1024cpa_clean.yml b/test/duplicate_consistency/newhope1024cpa_clean.yml new file mode 100644 index 00000000..ecf8b874 --- /dev/null +++ b/test/duplicate_consistency/newhope1024cpa_clean.yml @@ -0,0 +1,42 @@ +consistency_checks: +- source: + scheme: newhope1024cca + implementation: clean + files: + - ntt.c + - poly.c + - precomp.c + - cpapke.c + - reduce.c + - verify.c + - params.h + - cpapke.h + - ntt.h + - poly.h + - reduce.h + - verify.h +- source: + scheme: newhope512cca + implementation: clean + files: + - cpapke.c + - reduce.c + - verify.c + - cpapke.h + - ntt.h + - poly.h + - reduce.h + - verify.h +- source: + scheme: newhope512cpa + implementation: clean + files: + - kem.c + - cpapke.c + - reduce.c + - verify.c + - cpapke.h + - ntt.h + - poly.h + - reduce.h + - verify.h diff --git a/test/duplicate_consistency/newhope512cca_clean.yml b/test/duplicate_consistency/newhope512cca_clean.yml new file mode 100644 index 00000000..ff0c6036 --- /dev/null +++ b/test/duplicate_consistency/newhope512cca_clean.yml @@ -0,0 +1,44 @@ +consistency_checks: +- source: + scheme: newhope1024cpa + implementation: clean + files: + - cpapke.c + - reduce.c + - verify.c + - cpapke.h + - ntt.h + - poly.h + - reduce.h + - verify.h +- source: + scheme: newhope1024cca + implementation: clean + files: + - kem.c + - cpapke.c + - reduce.c + - verify.c + - cpapke.h + - ntt.h + - poly.h + - reduce.h + - verify.h +- source: + scheme: newhope512cpa + implementation: clean + files: + - ntt.c + - poly.c + - precomp.c + - cpapke.c + - reduce.c + - verify.c + - params.h + - cpapke.h + - ntt.h + - poly.h + - reduce.h + - verify.h + + diff --git a/test/duplicate_consistency/newhope512cpa_clean.yml b/test/duplicate_consistency/newhope512cpa_clean.yml new file mode 100644 index 00000000..e18fab3b --- /dev/null +++ b/test/duplicate_consistency/newhope512cpa_clean.yml @@ -0,0 +1,42 @@ +consistency_checks: +- source: + scheme: newhope1024cpa + implementation: clean + files: + - kem.c + - cpapke.c + - reduce.c + - verify.c + - cpapke.h + - ntt.h + - poly.h + - reduce.h + - verify.h +- source: + scheme: newhope1024cca + implementation: clean + files: + - cpapke.c + - reduce.c + - verify.c + - cpapke.h + - ntt.h + - poly.h + - reduce.h + - verify.h +- source: + scheme: newhope512cca + implementation: clean + files: + - ntt.c + - poly.c + - precomp.c + - cpapke.c + - reduce.c + - verify.c + - params.h + - cpapke.h + - ntt.h + - poly.h + - reduce.h + - verify.h diff --git a/test/test_metadata.py b/test/test_metadata.py index 472b92b8..284c2678 100644 --- a/test/test_metadata.py +++ b/test/test_metadata.py @@ -47,6 +47,7 @@ EXPECTED_FIELDS = { 'claimed-nist-level': {'type': int, 'min': 1, 'max': 5}, 'length-public-key': {'type': int, 'min': 1}, 'length-secret-key': {'type': int, 'min': 1}, + 'nistkat-sha256': {'type': str, 'length': 64}, 'principal-submitter': {'type': str}, 'auxiliary-submitters': {'type': list, 'elements': {'type': str}}, 'implementations': { @@ -65,7 +66,6 @@ KEM_FIELDS = { 'claimed-security' : {'type' : str, 'values' : ['IND-CPA', 'IND-CCA2'] }, 'length-ciphertext': {'type': int, 'min': 1}, 'length-shared-secret': {'type': int, 'min': 1}, - 'nistkat-sha256': {'type': str, 'length': 64}, } SIGNATURE_FIELDS = { diff --git a/test/test_nistkat.py b/test/test_nistkat.py index daebca49..6aac1318 100644 --- a/test/test_nistkat.py +++ b/test/test_nistkat.py @@ -17,8 +17,6 @@ import unittest def test_nistkat(): for scheme in pqclean.Scheme.all_schemes(): - if scheme.type != 'kem': - continue for implementation in scheme.implementations: yield check_nistkat, implementation