Merge branch 'master' into fix-sphincs-windows
This commit is contained in:
commit
a80abd64ff
@ -24,6 +24,9 @@ Use at your own risk.
|
||||
### 2019-XX-XX
|
||||
-->
|
||||
|
||||
### 2020-06-19
|
||||
* A potential timing leak was present in the FrodoKEM decapsulation routine, as identified by [Guo, Johansson, and Nilsson](https://eprint.iacr.org/2020/743). This was fixed in [PR #303](https://github.com/PQClean/PQClean/pull/303).
|
||||
|
||||
### 2019-09-24
|
||||
* All Falcon implementations before [PR #235][PR 235] got merged were insecure. See [EPRINT report 2019/893][2019/893].
|
||||
|
||||
|
@ -12,6 +12,8 @@ void PQCLEAN_FRODOKEM1344AES_CLEAN_key_encode(uint16_t *out, const uint16_t *in)
|
||||
void PQCLEAN_FRODOKEM1344AES_CLEAN_key_decode(uint16_t *out, const uint16_t *in);
|
||||
void PQCLEAN_FRODOKEM1344AES_CLEAN_pack(uint8_t *out, size_t outlen, const uint16_t *in, size_t inlen, uint8_t lsb);
|
||||
void PQCLEAN_FRODOKEM1344AES_CLEAN_unpack(uint16_t *out, size_t outlen, const uint8_t *in, size_t inlen, uint8_t lsb);
|
||||
int8_t PQCLEAN_FRODOKEM1344AES_CLEAN_ct_verify(const uint16_t *a, const uint16_t *b, size_t len);
|
||||
void PQCLEAN_FRODOKEM1344AES_CLEAN_ct_select(uint8_t *r, const uint8_t *a, const uint8_t *b, size_t len, int8_t selector);
|
||||
void PQCLEAN_FRODOKEM1344AES_CLEAN_clear_bytes(uint8_t *mem, size_t n);
|
||||
uint16_t PQCLEAN_FRODOKEM1344AES_CLEAN_LE_TO_UINT16(uint16_t n);
|
||||
uint16_t PQCLEAN_FRODOKEM1344AES_CLEAN_UINT16_TO_LE(uint16_t n);
|
||||
|
@ -214,14 +214,13 @@ int PQCLEAN_FRODOKEM1344AES_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct,
|
||||
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);
|
||||
}
|
||||
// If (Bp == BBp & C == CC) then ss = F(ct || k'), else ss = F(ct || s)
|
||||
// Needs to avoid branching on secret data as per:
|
||||
// Qian Guo, Thomas Johansson, Alexander Nilsson. A key-recovery timing attack on post-quantum
|
||||
// primitives using the Fujisaki-Okamoto transformation and its application on FrodoKEM. In CRYPTO 2020.
|
||||
int8_t selector = PQCLEAN_FRODOKEM1344AES_CLEAN_ct_verify(Bp, BBp, PARAMS_N * PARAMS_NBAR) | PQCLEAN_FRODOKEM1344AES_CLEAN_ct_verify(C, CC, PARAMS_NBAR * PARAMS_NBAR);
|
||||
// If (selector == 0) then load k' to do ss = F(ct || k'), else if (selector == -1) load s to do ss = F(ct || s)
|
||||
PQCLEAN_FRODOKEM1344AES_CLEAN_ct_select((uint8_t *)Fin_k, (uint8_t *)kprime, (uint8_t *)sk_s, CRYPTO_BYTES, selector);
|
||||
shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES);
|
||||
|
||||
// Cleanup:
|
||||
|
@ -224,6 +224,30 @@ void PQCLEAN_FRODOKEM1344AES_CLEAN_unpack(uint16_t *out, size_t outlen, const ui
|
||||
}
|
||||
|
||||
|
||||
int8_t PQCLEAN_FRODOKEM1344AES_CLEAN_ct_verify(const uint16_t *a, const uint16_t *b, size_t len) {
|
||||
// Compare two arrays in constant time.
|
||||
// Returns 0 if the byte arrays are equal, -1 otherwise.
|
||||
uint16_t r = 0;
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
r |= a[i] ^ b[i];
|
||||
}
|
||||
|
||||
r = (-(int16_t)r) >> (8 * sizeof(uint16_t) -1);
|
||||
return (int8_t)r;
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM1344AES_CLEAN_ct_select(uint8_t *r, const uint8_t *a, const uint8_t *b, size_t len, int8_t selector) {
|
||||
// Select one of the two input arrays to be moved to r
|
||||
// If (selector == 0) then load r with a, else if (selector == -1) load r with b
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
r[i] = (~selector & a[i]) | (selector & b[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM1344AES_CLEAN_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.
|
||||
|
@ -12,6 +12,8 @@ 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);
|
||||
int8_t PQCLEAN_FRODOKEM1344AES_OPT_ct_verify(const uint16_t *a, const uint16_t *b, size_t len);
|
||||
void PQCLEAN_FRODOKEM1344AES_OPT_ct_select(uint8_t *r, const uint8_t *a, const uint8_t *b, size_t len, int8_t selector);
|
||||
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);
|
||||
|
@ -214,14 +214,13 @@ int PQCLEAN_FRODOKEM1344AES_OPT_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, c
|
||||
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);
|
||||
}
|
||||
// If (Bp == BBp & C == CC) then ss = F(ct || k'), else ss = F(ct || s)
|
||||
// Needs to avoid branching on secret data as per:
|
||||
// Qian Guo, Thomas Johansson, Alexander Nilsson. A key-recovery timing attack on post-quantum
|
||||
// primitives using the Fujisaki-Okamoto transformation and its application on FrodoKEM. In CRYPTO 2020.
|
||||
int8_t selector = PQCLEAN_FRODOKEM1344AES_OPT_ct_verify(Bp, BBp, PARAMS_N * PARAMS_NBAR) | PQCLEAN_FRODOKEM1344AES_OPT_ct_verify(C, CC, PARAMS_NBAR * PARAMS_NBAR);
|
||||
// If (selector == 0) then load k' to do ss = F(ct || k'), else if (selector == -1) load s to do ss = F(ct || s)
|
||||
PQCLEAN_FRODOKEM1344AES_OPT_ct_select((uint8_t *)Fin_k, (uint8_t *)kprime, (uint8_t *)sk_s, CRYPTO_BYTES, selector);
|
||||
shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES);
|
||||
|
||||
// Cleanup:
|
||||
|
@ -224,6 +224,30 @@ void PQCLEAN_FRODOKEM1344AES_OPT_unpack(uint16_t *out, size_t outlen, const uint
|
||||
}
|
||||
|
||||
|
||||
int8_t PQCLEAN_FRODOKEM1344AES_OPT_ct_verify(const uint16_t *a, const uint16_t *b, size_t len) {
|
||||
// Compare two arrays in constant time.
|
||||
// Returns 0 if the byte arrays are equal, -1 otherwise.
|
||||
uint16_t r = 0;
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
r |= a[i] ^ b[i];
|
||||
}
|
||||
|
||||
r = (-(int16_t)r) >> (8 * sizeof(uint16_t) -1);
|
||||
return (int8_t)r;
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM1344AES_OPT_ct_select(uint8_t *r, const uint8_t *a, const uint8_t *b, size_t len, int8_t selector) {
|
||||
// Select one of the two input arrays to be moved to r
|
||||
// If (selector == 0) then load r with a, else if (selector == -1) load r with b
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
r[i] = (~selector & a[i]) | (selector & b[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.
|
||||
|
@ -12,6 +12,8 @@ void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_key_encode(uint16_t *out, const uint16_t *i
|
||||
void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_key_decode(uint16_t *out, const uint16_t *in);
|
||||
void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_pack(uint8_t *out, size_t outlen, const uint16_t *in, size_t inlen, uint8_t lsb);
|
||||
void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_unpack(uint16_t *out, size_t outlen, const uint8_t *in, size_t inlen, uint8_t lsb);
|
||||
int8_t PQCLEAN_FRODOKEM1344SHAKE_CLEAN_ct_verify(const uint16_t *a, const uint16_t *b, size_t len);
|
||||
void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_ct_select(uint8_t *r, const uint8_t *a, const uint8_t *b, size_t len, int8_t selector);
|
||||
void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes(uint8_t *mem, size_t n);
|
||||
uint16_t PQCLEAN_FRODOKEM1344SHAKE_CLEAN_LE_TO_UINT16(uint16_t n);
|
||||
uint16_t PQCLEAN_FRODOKEM1344SHAKE_CLEAN_UINT16_TO_LE(uint16_t n);
|
||||
|
@ -214,14 +214,13 @@ int PQCLEAN_FRODOKEM1344SHAKE_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *c
|
||||
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);
|
||||
}
|
||||
// If (Bp == BBp & C == CC) then ss = F(ct || k'), else ss = F(ct || s)
|
||||
// Needs to avoid branching on secret data as per:
|
||||
// Qian Guo, Thomas Johansson, Alexander Nilsson. A key-recovery timing attack on post-quantum
|
||||
// primitives using the Fujisaki-Okamoto transformation and its application on FrodoKEM. In CRYPTO 2020.
|
||||
int8_t selector = PQCLEAN_FRODOKEM1344SHAKE_CLEAN_ct_verify(Bp, BBp, PARAMS_N * PARAMS_NBAR) | PQCLEAN_FRODOKEM1344SHAKE_CLEAN_ct_verify(C, CC, PARAMS_NBAR * PARAMS_NBAR);
|
||||
// If (selector == 0) then load k' to do ss = F(ct || k'), else if (selector == -1) load s to do ss = F(ct || s)
|
||||
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_ct_select((uint8_t *)Fin_k, (uint8_t *)kprime, (uint8_t *)sk_s, CRYPTO_BYTES, selector);
|
||||
shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES);
|
||||
|
||||
// Cleanup:
|
||||
|
@ -224,6 +224,30 @@ void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_unpack(uint16_t *out, size_t outlen, const
|
||||
}
|
||||
|
||||
|
||||
int8_t PQCLEAN_FRODOKEM1344SHAKE_CLEAN_ct_verify(const uint16_t *a, const uint16_t *b, size_t len) {
|
||||
// Compare two arrays in constant time.
|
||||
// Returns 0 if the byte arrays are equal, -1 otherwise.
|
||||
uint16_t r = 0;
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
r |= a[i] ^ b[i];
|
||||
}
|
||||
|
||||
r = (-(int16_t)r) >> (8 * sizeof(uint16_t) -1);
|
||||
return (int8_t)r;
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_ct_select(uint8_t *r, const uint8_t *a, const uint8_t *b, size_t len, int8_t selector) {
|
||||
// Select one of the two input arrays to be moved to r
|
||||
// If (selector == 0) then load r with a, else if (selector == -1) load r with b
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
r[i] = (~selector & a[i]) | (selector & b[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_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.
|
||||
|
@ -12,6 +12,8 @@ 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);
|
||||
int8_t PQCLEAN_FRODOKEM1344SHAKE_OPT_ct_verify(const uint16_t *a, const uint16_t *b, size_t len);
|
||||
void PQCLEAN_FRODOKEM1344SHAKE_OPT_ct_select(uint8_t *r, const uint8_t *a, const uint8_t *b, size_t len, int8_t selector);
|
||||
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);
|
||||
|
@ -214,14 +214,13 @@ int PQCLEAN_FRODOKEM1344SHAKE_OPT_crypto_kem_dec(uint8_t *ss, const uint8_t *ct,
|
||||
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);
|
||||
}
|
||||
// If (Bp == BBp & C == CC) then ss = F(ct || k'), else ss = F(ct || s)
|
||||
// Needs to avoid branching on secret data as per:
|
||||
// Qian Guo, Thomas Johansson, Alexander Nilsson. A key-recovery timing attack on post-quantum
|
||||
// primitives using the Fujisaki-Okamoto transformation and its application on FrodoKEM. In CRYPTO 2020.
|
||||
int8_t selector = PQCLEAN_FRODOKEM1344SHAKE_OPT_ct_verify(Bp, BBp, PARAMS_N * PARAMS_NBAR) | PQCLEAN_FRODOKEM1344SHAKE_OPT_ct_verify(C, CC, PARAMS_NBAR * PARAMS_NBAR);
|
||||
// If (selector == 0) then load k' to do ss = F(ct || k'), else if (selector == -1) load s to do ss = F(ct || s)
|
||||
PQCLEAN_FRODOKEM1344SHAKE_OPT_ct_select((uint8_t *)Fin_k, (uint8_t *)kprime, (uint8_t *)sk_s, CRYPTO_BYTES, selector);
|
||||
shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES);
|
||||
|
||||
// Cleanup:
|
||||
|
@ -224,6 +224,30 @@ void PQCLEAN_FRODOKEM1344SHAKE_OPT_unpack(uint16_t *out, size_t outlen, const ui
|
||||
}
|
||||
|
||||
|
||||
int8_t PQCLEAN_FRODOKEM1344SHAKE_OPT_ct_verify(const uint16_t *a, const uint16_t *b, size_t len) {
|
||||
// Compare two arrays in constant time.
|
||||
// Returns 0 if the byte arrays are equal, -1 otherwise.
|
||||
uint16_t r = 0;
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
r |= a[i] ^ b[i];
|
||||
}
|
||||
|
||||
r = (-(int16_t)r) >> (8 * sizeof(uint16_t) -1);
|
||||
return (int8_t)r;
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM1344SHAKE_OPT_ct_select(uint8_t *r, const uint8_t *a, const uint8_t *b, size_t len, int8_t selector) {
|
||||
// Select one of the two input arrays to be moved to r
|
||||
// If (selector == 0) then load r with a, else if (selector == -1) load r with b
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
r[i] = (~selector & a[i]) | (selector & b[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.
|
||||
|
@ -12,6 +12,8 @@ void PQCLEAN_FRODOKEM640AES_CLEAN_key_encode(uint16_t *out, const uint16_t *in);
|
||||
void PQCLEAN_FRODOKEM640AES_CLEAN_key_decode(uint16_t *out, const uint16_t *in);
|
||||
void PQCLEAN_FRODOKEM640AES_CLEAN_pack(uint8_t *out, size_t outlen, const uint16_t *in, size_t inlen, uint8_t lsb);
|
||||
void PQCLEAN_FRODOKEM640AES_CLEAN_unpack(uint16_t *out, size_t outlen, const uint8_t *in, size_t inlen, uint8_t lsb);
|
||||
int8_t PQCLEAN_FRODOKEM640AES_CLEAN_ct_verify(const uint16_t *a, const uint16_t *b, size_t len);
|
||||
void PQCLEAN_FRODOKEM640AES_CLEAN_ct_select(uint8_t *r, const uint8_t *a, const uint8_t *b, size_t len, int8_t selector);
|
||||
void PQCLEAN_FRODOKEM640AES_CLEAN_clear_bytes(uint8_t *mem, size_t n);
|
||||
uint16_t PQCLEAN_FRODOKEM640AES_CLEAN_LE_TO_UINT16(uint16_t n);
|
||||
uint16_t PQCLEAN_FRODOKEM640AES_CLEAN_UINT16_TO_LE(uint16_t n);
|
||||
|
@ -214,14 +214,13 @@ int PQCLEAN_FRODOKEM640AES_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct,
|
||||
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);
|
||||
}
|
||||
// If (Bp == BBp & C == CC) then ss = F(ct || k'), else ss = F(ct || s)
|
||||
// Needs to avoid branching on secret data as per:
|
||||
// Qian Guo, Thomas Johansson, Alexander Nilsson. A key-recovery timing attack on post-quantum
|
||||
// primitives using the Fujisaki-Okamoto transformation and its application on FrodoKEM. In CRYPTO 2020.
|
||||
int8_t selector = PQCLEAN_FRODOKEM640AES_CLEAN_ct_verify(Bp, BBp, PARAMS_N * PARAMS_NBAR) | PQCLEAN_FRODOKEM640AES_CLEAN_ct_verify(C, CC, PARAMS_NBAR * PARAMS_NBAR);
|
||||
// If (selector == 0) then load k' to do ss = F(ct || k'), else if (selector == -1) load s to do ss = F(ct || s)
|
||||
PQCLEAN_FRODOKEM640AES_CLEAN_ct_select((uint8_t *)Fin_k, (uint8_t *)kprime, (uint8_t *)sk_s, CRYPTO_BYTES, selector);
|
||||
shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES);
|
||||
|
||||
// Cleanup:
|
||||
|
@ -224,6 +224,30 @@ void PQCLEAN_FRODOKEM640AES_CLEAN_unpack(uint16_t *out, size_t outlen, const uin
|
||||
}
|
||||
|
||||
|
||||
int8_t PQCLEAN_FRODOKEM640AES_CLEAN_ct_verify(const uint16_t *a, const uint16_t *b, size_t len) {
|
||||
// Compare two arrays in constant time.
|
||||
// Returns 0 if the byte arrays are equal, -1 otherwise.
|
||||
uint16_t r = 0;
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
r |= a[i] ^ b[i];
|
||||
}
|
||||
|
||||
r = (-(int16_t)r) >> (8 * sizeof(uint16_t) -1);
|
||||
return (int8_t)r;
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM640AES_CLEAN_ct_select(uint8_t *r, const uint8_t *a, const uint8_t *b, size_t len, int8_t selector) {
|
||||
// Select one of the two input arrays to be moved to r
|
||||
// If (selector == 0) then load r with a, else if (selector == -1) load r with b
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
r[i] = (~selector & a[i]) | (selector & b[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM640AES_CLEAN_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.
|
||||
|
@ -12,6 +12,8 @@ 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);
|
||||
int8_t PQCLEAN_FRODOKEM640AES_OPT_ct_verify(const uint16_t *a, const uint16_t *b, size_t len);
|
||||
void PQCLEAN_FRODOKEM640AES_OPT_ct_select(uint8_t *r, const uint8_t *a, const uint8_t *b, size_t len, int8_t selector);
|
||||
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);
|
||||
|
@ -214,14 +214,13 @@ int PQCLEAN_FRODOKEM640AES_OPT_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, co
|
||||
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);
|
||||
}
|
||||
// If (Bp == BBp & C == CC) then ss = F(ct || k'), else ss = F(ct || s)
|
||||
// Needs to avoid branching on secret data as per:
|
||||
// Qian Guo, Thomas Johansson, Alexander Nilsson. A key-recovery timing attack on post-quantum
|
||||
// primitives using the Fujisaki-Okamoto transformation and its application on FrodoKEM. In CRYPTO 2020.
|
||||
int8_t selector = PQCLEAN_FRODOKEM640AES_OPT_ct_verify(Bp, BBp, PARAMS_N * PARAMS_NBAR) | PQCLEAN_FRODOKEM640AES_OPT_ct_verify(C, CC, PARAMS_NBAR * PARAMS_NBAR);
|
||||
// If (selector == 0) then load k' to do ss = F(ct || k'), else if (selector == -1) load s to do ss = F(ct || s)
|
||||
PQCLEAN_FRODOKEM640AES_OPT_ct_select((uint8_t *)Fin_k, (uint8_t *)kprime, (uint8_t *)sk_s, CRYPTO_BYTES, selector);
|
||||
shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES);
|
||||
|
||||
// Cleanup:
|
||||
|
@ -224,6 +224,30 @@ void PQCLEAN_FRODOKEM640AES_OPT_unpack(uint16_t *out, size_t outlen, const uint8
|
||||
}
|
||||
|
||||
|
||||
int8_t PQCLEAN_FRODOKEM640AES_OPT_ct_verify(const uint16_t *a, const uint16_t *b, size_t len) {
|
||||
// Compare two arrays in constant time.
|
||||
// Returns 0 if the byte arrays are equal, -1 otherwise.
|
||||
uint16_t r = 0;
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
r |= a[i] ^ b[i];
|
||||
}
|
||||
|
||||
r = (-(int16_t)r) >> (8 * sizeof(uint16_t) -1);
|
||||
return (int8_t)r;
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM640AES_OPT_ct_select(uint8_t *r, const uint8_t *a, const uint8_t *b, size_t len, int8_t selector) {
|
||||
// Select one of the two input arrays to be moved to r
|
||||
// If (selector == 0) then load r with a, else if (selector == -1) load r with b
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
r[i] = (~selector & a[i]) | (selector & b[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.
|
||||
|
@ -12,6 +12,8 @@ void PQCLEAN_FRODOKEM640SHAKE_CLEAN_key_encode(uint16_t *out, const uint16_t *in
|
||||
void PQCLEAN_FRODOKEM640SHAKE_CLEAN_key_decode(uint16_t *out, const uint16_t *in);
|
||||
void PQCLEAN_FRODOKEM640SHAKE_CLEAN_pack(uint8_t *out, size_t outlen, const uint16_t *in, size_t inlen, uint8_t lsb);
|
||||
void PQCLEAN_FRODOKEM640SHAKE_CLEAN_unpack(uint16_t *out, size_t outlen, const uint8_t *in, size_t inlen, uint8_t lsb);
|
||||
int8_t PQCLEAN_FRODOKEM640SHAKE_CLEAN_ct_verify(const uint16_t *a, const uint16_t *b, size_t len);
|
||||
void PQCLEAN_FRODOKEM640SHAKE_CLEAN_ct_select(uint8_t *r, const uint8_t *a, const uint8_t *b, size_t len, int8_t selector);
|
||||
void PQCLEAN_FRODOKEM640SHAKE_CLEAN_clear_bytes(uint8_t *mem, size_t n);
|
||||
uint16_t PQCLEAN_FRODOKEM640SHAKE_CLEAN_LE_TO_UINT16(uint16_t n);
|
||||
uint16_t PQCLEAN_FRODOKEM640SHAKE_CLEAN_UINT16_TO_LE(uint16_t n);
|
||||
|
@ -214,14 +214,13 @@ int PQCLEAN_FRODOKEM640SHAKE_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct
|
||||
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);
|
||||
}
|
||||
// If (Bp == BBp & C == CC) then ss = F(ct || k'), else ss = F(ct || s)
|
||||
// Needs to avoid branching on secret data as per:
|
||||
// Qian Guo, Thomas Johansson, Alexander Nilsson. A key-recovery timing attack on post-quantum
|
||||
// primitives using the Fujisaki-Okamoto transformation and its application on FrodoKEM. In CRYPTO 2020.
|
||||
int8_t selector = PQCLEAN_FRODOKEM640SHAKE_CLEAN_ct_verify(Bp, BBp, PARAMS_N * PARAMS_NBAR) | PQCLEAN_FRODOKEM640SHAKE_CLEAN_ct_verify(C, CC, PARAMS_NBAR * PARAMS_NBAR);
|
||||
// If (selector == 0) then load k' to do ss = F(ct || k'), else if (selector == -1) load s to do ss = F(ct || s)
|
||||
PQCLEAN_FRODOKEM640SHAKE_CLEAN_ct_select((uint8_t *)Fin_k, (uint8_t *)kprime, (uint8_t *)sk_s, CRYPTO_BYTES, selector);
|
||||
shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES);
|
||||
|
||||
// Cleanup:
|
||||
|
@ -224,6 +224,30 @@ void PQCLEAN_FRODOKEM640SHAKE_CLEAN_unpack(uint16_t *out, size_t outlen, const u
|
||||
}
|
||||
|
||||
|
||||
int8_t PQCLEAN_FRODOKEM640SHAKE_CLEAN_ct_verify(const uint16_t *a, const uint16_t *b, size_t len) {
|
||||
// Compare two arrays in constant time.
|
||||
// Returns 0 if the byte arrays are equal, -1 otherwise.
|
||||
uint16_t r = 0;
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
r |= a[i] ^ b[i];
|
||||
}
|
||||
|
||||
r = (-(int16_t)r) >> (8 * sizeof(uint16_t) -1);
|
||||
return (int8_t)r;
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM640SHAKE_CLEAN_ct_select(uint8_t *r, const uint8_t *a, const uint8_t *b, size_t len, int8_t selector) {
|
||||
// Select one of the two input arrays to be moved to r
|
||||
// If (selector == 0) then load r with a, else if (selector == -1) load r with b
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
r[i] = (~selector & a[i]) | (selector & b[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM640SHAKE_CLEAN_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.
|
||||
|
@ -12,6 +12,8 @@ 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);
|
||||
int8_t PQCLEAN_FRODOKEM640SHAKE_OPT_ct_verify(const uint16_t *a, const uint16_t *b, size_t len);
|
||||
void PQCLEAN_FRODOKEM640SHAKE_OPT_ct_select(uint8_t *r, const uint8_t *a, const uint8_t *b, size_t len, int8_t selector);
|
||||
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);
|
||||
|
@ -214,14 +214,13 @@ int PQCLEAN_FRODOKEM640SHAKE_OPT_crypto_kem_dec(uint8_t *ss, const uint8_t *ct,
|
||||
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);
|
||||
}
|
||||
// If (Bp == BBp & C == CC) then ss = F(ct || k'), else ss = F(ct || s)
|
||||
// Needs to avoid branching on secret data as per:
|
||||
// Qian Guo, Thomas Johansson, Alexander Nilsson. A key-recovery timing attack on post-quantum
|
||||
// primitives using the Fujisaki-Okamoto transformation and its application on FrodoKEM. In CRYPTO 2020.
|
||||
int8_t selector = PQCLEAN_FRODOKEM640SHAKE_OPT_ct_verify(Bp, BBp, PARAMS_N * PARAMS_NBAR) | PQCLEAN_FRODOKEM640SHAKE_OPT_ct_verify(C, CC, PARAMS_NBAR * PARAMS_NBAR);
|
||||
// If (selector == 0) then load k' to do ss = F(ct || k'), else if (selector == -1) load s to do ss = F(ct || s)
|
||||
PQCLEAN_FRODOKEM640SHAKE_OPT_ct_select((uint8_t *)Fin_k, (uint8_t *)kprime, (uint8_t *)sk_s, CRYPTO_BYTES, selector);
|
||||
shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES);
|
||||
|
||||
// Cleanup:
|
||||
|
@ -224,6 +224,30 @@ void PQCLEAN_FRODOKEM640SHAKE_OPT_unpack(uint16_t *out, size_t outlen, const uin
|
||||
}
|
||||
|
||||
|
||||
int8_t PQCLEAN_FRODOKEM640SHAKE_OPT_ct_verify(const uint16_t *a, const uint16_t *b, size_t len) {
|
||||
// Compare two arrays in constant time.
|
||||
// Returns 0 if the byte arrays are equal, -1 otherwise.
|
||||
uint16_t r = 0;
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
r |= a[i] ^ b[i];
|
||||
}
|
||||
|
||||
r = (-(int16_t)r) >> (8 * sizeof(uint16_t) -1);
|
||||
return (int8_t)r;
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM640SHAKE_OPT_ct_select(uint8_t *r, const uint8_t *a, const uint8_t *b, size_t len, int8_t selector) {
|
||||
// Select one of the two input arrays to be moved to r
|
||||
// If (selector == 0) then load r with a, else if (selector == -1) load r with b
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
r[i] = (~selector & a[i]) | (selector & b[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.
|
||||
|
@ -12,6 +12,8 @@ void PQCLEAN_FRODOKEM976AES_CLEAN_key_encode(uint16_t *out, const uint16_t *in);
|
||||
void PQCLEAN_FRODOKEM976AES_CLEAN_key_decode(uint16_t *out, const uint16_t *in);
|
||||
void PQCLEAN_FRODOKEM976AES_CLEAN_pack(uint8_t *out, size_t outlen, const uint16_t *in, size_t inlen, uint8_t lsb);
|
||||
void PQCLEAN_FRODOKEM976AES_CLEAN_unpack(uint16_t *out, size_t outlen, const uint8_t *in, size_t inlen, uint8_t lsb);
|
||||
int8_t PQCLEAN_FRODOKEM976AES_CLEAN_ct_verify(const uint16_t *a, const uint16_t *b, size_t len);
|
||||
void PQCLEAN_FRODOKEM976AES_CLEAN_ct_select(uint8_t *r, const uint8_t *a, const uint8_t *b, size_t len, int8_t selector);
|
||||
void PQCLEAN_FRODOKEM976AES_CLEAN_clear_bytes(uint8_t *mem, size_t n);
|
||||
uint16_t PQCLEAN_FRODOKEM976AES_CLEAN_LE_TO_UINT16(uint16_t n);
|
||||
uint16_t PQCLEAN_FRODOKEM976AES_CLEAN_UINT16_TO_LE(uint16_t n);
|
||||
|
@ -214,14 +214,13 @@ int PQCLEAN_FRODOKEM976AES_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct,
|
||||
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);
|
||||
}
|
||||
// If (Bp == BBp & C == CC) then ss = F(ct || k'), else ss = F(ct || s)
|
||||
// Needs to avoid branching on secret data as per:
|
||||
// Qian Guo, Thomas Johansson, Alexander Nilsson. A key-recovery timing attack on post-quantum
|
||||
// primitives using the Fujisaki-Okamoto transformation and its application on FrodoKEM. In CRYPTO 2020.
|
||||
int8_t selector = PQCLEAN_FRODOKEM976AES_CLEAN_ct_verify(Bp, BBp, PARAMS_N * PARAMS_NBAR) | PQCLEAN_FRODOKEM976AES_CLEAN_ct_verify(C, CC, PARAMS_NBAR * PARAMS_NBAR);
|
||||
// If (selector == 0) then load k' to do ss = F(ct || k'), else if (selector == -1) load s to do ss = F(ct || s)
|
||||
PQCLEAN_FRODOKEM976AES_CLEAN_ct_select((uint8_t *)Fin_k, (uint8_t *)kprime, (uint8_t *)sk_s, CRYPTO_BYTES, selector);
|
||||
shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES);
|
||||
|
||||
// Cleanup:
|
||||
|
@ -224,6 +224,30 @@ void PQCLEAN_FRODOKEM976AES_CLEAN_unpack(uint16_t *out, size_t outlen, const uin
|
||||
}
|
||||
|
||||
|
||||
int8_t PQCLEAN_FRODOKEM976AES_CLEAN_ct_verify(const uint16_t *a, const uint16_t *b, size_t len) {
|
||||
// Compare two arrays in constant time.
|
||||
// Returns 0 if the byte arrays are equal, -1 otherwise.
|
||||
uint16_t r = 0;
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
r |= a[i] ^ b[i];
|
||||
}
|
||||
|
||||
r = (-(int16_t)r) >> (8 * sizeof(uint16_t) -1);
|
||||
return (int8_t)r;
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM976AES_CLEAN_ct_select(uint8_t *r, const uint8_t *a, const uint8_t *b, size_t len, int8_t selector) {
|
||||
// Select one of the two input arrays to be moved to r
|
||||
// If (selector == 0) then load r with a, else if (selector == -1) load r with b
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
r[i] = (~selector & a[i]) | (selector & b[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM976AES_CLEAN_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.
|
||||
|
@ -12,6 +12,8 @@ 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);
|
||||
int8_t PQCLEAN_FRODOKEM976AES_OPT_ct_verify(const uint16_t *a, const uint16_t *b, size_t len);
|
||||
void PQCLEAN_FRODOKEM976AES_OPT_ct_select(uint8_t *r, const uint8_t *a, const uint8_t *b, size_t len, int8_t selector);
|
||||
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);
|
||||
|
@ -214,14 +214,13 @@ int PQCLEAN_FRODOKEM976AES_OPT_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, co
|
||||
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);
|
||||
}
|
||||
// If (Bp == BBp & C == CC) then ss = F(ct || k'), else ss = F(ct || s)
|
||||
// Needs to avoid branching on secret data as per:
|
||||
// Qian Guo, Thomas Johansson, Alexander Nilsson. A key-recovery timing attack on post-quantum
|
||||
// primitives using the Fujisaki-Okamoto transformation and its application on FrodoKEM. In CRYPTO 2020.
|
||||
int8_t selector = PQCLEAN_FRODOKEM976AES_OPT_ct_verify(Bp, BBp, PARAMS_N * PARAMS_NBAR) | PQCLEAN_FRODOKEM976AES_OPT_ct_verify(C, CC, PARAMS_NBAR * PARAMS_NBAR);
|
||||
// If (selector == 0) then load k' to do ss = F(ct || k'), else if (selector == -1) load s to do ss = F(ct || s)
|
||||
PQCLEAN_FRODOKEM976AES_OPT_ct_select((uint8_t *)Fin_k, (uint8_t *)kprime, (uint8_t *)sk_s, CRYPTO_BYTES, selector);
|
||||
shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES);
|
||||
|
||||
// Cleanup:
|
||||
|
@ -224,6 +224,30 @@ void PQCLEAN_FRODOKEM976AES_OPT_unpack(uint16_t *out, size_t outlen, const uint8
|
||||
}
|
||||
|
||||
|
||||
int8_t PQCLEAN_FRODOKEM976AES_OPT_ct_verify(const uint16_t *a, const uint16_t *b, size_t len) {
|
||||
// Compare two arrays in constant time.
|
||||
// Returns 0 if the byte arrays are equal, -1 otherwise.
|
||||
uint16_t r = 0;
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
r |= a[i] ^ b[i];
|
||||
}
|
||||
|
||||
r = (-(int16_t)r) >> (8 * sizeof(uint16_t) -1);
|
||||
return (int8_t)r;
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM976AES_OPT_ct_select(uint8_t *r, const uint8_t *a, const uint8_t *b, size_t len, int8_t selector) {
|
||||
// Select one of the two input arrays to be moved to r
|
||||
// If (selector == 0) then load r with a, else if (selector == -1) load r with b
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
r[i] = (~selector & a[i]) | (selector & b[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.
|
||||
|
@ -12,6 +12,8 @@ void PQCLEAN_FRODOKEM976SHAKE_CLEAN_key_encode(uint16_t *out, const uint16_t *in
|
||||
void PQCLEAN_FRODOKEM976SHAKE_CLEAN_key_decode(uint16_t *out, const uint16_t *in);
|
||||
void PQCLEAN_FRODOKEM976SHAKE_CLEAN_pack(uint8_t *out, size_t outlen, const uint16_t *in, size_t inlen, uint8_t lsb);
|
||||
void PQCLEAN_FRODOKEM976SHAKE_CLEAN_unpack(uint16_t *out, size_t outlen, const uint8_t *in, size_t inlen, uint8_t lsb);
|
||||
int8_t PQCLEAN_FRODOKEM976SHAKE_CLEAN_ct_verify(const uint16_t *a, const uint16_t *b, size_t len);
|
||||
void PQCLEAN_FRODOKEM976SHAKE_CLEAN_ct_select(uint8_t *r, const uint8_t *a, const uint8_t *b, size_t len, int8_t selector);
|
||||
void PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes(uint8_t *mem, size_t n);
|
||||
uint16_t PQCLEAN_FRODOKEM976SHAKE_CLEAN_LE_TO_UINT16(uint16_t n);
|
||||
uint16_t PQCLEAN_FRODOKEM976SHAKE_CLEAN_UINT16_TO_LE(uint16_t n);
|
||||
|
@ -214,14 +214,13 @@ int PQCLEAN_FRODOKEM976SHAKE_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct
|
||||
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);
|
||||
}
|
||||
// If (Bp == BBp & C == CC) then ss = F(ct || k'), else ss = F(ct || s)
|
||||
// Needs to avoid branching on secret data as per:
|
||||
// Qian Guo, Thomas Johansson, Alexander Nilsson. A key-recovery timing attack on post-quantum
|
||||
// primitives using the Fujisaki-Okamoto transformation and its application on FrodoKEM. In CRYPTO 2020.
|
||||
int8_t selector = PQCLEAN_FRODOKEM976SHAKE_CLEAN_ct_verify(Bp, BBp, PARAMS_N * PARAMS_NBAR) | PQCLEAN_FRODOKEM976SHAKE_CLEAN_ct_verify(C, CC, PARAMS_NBAR * PARAMS_NBAR);
|
||||
// If (selector == 0) then load k' to do ss = F(ct || k'), else if (selector == -1) load s to do ss = F(ct || s)
|
||||
PQCLEAN_FRODOKEM976SHAKE_CLEAN_ct_select((uint8_t *)Fin_k, (uint8_t *)kprime, (uint8_t *)sk_s, CRYPTO_BYTES, selector);
|
||||
shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES);
|
||||
|
||||
// Cleanup:
|
||||
|
@ -224,6 +224,30 @@ void PQCLEAN_FRODOKEM976SHAKE_CLEAN_unpack(uint16_t *out, size_t outlen, const u
|
||||
}
|
||||
|
||||
|
||||
int8_t PQCLEAN_FRODOKEM976SHAKE_CLEAN_ct_verify(const uint16_t *a, const uint16_t *b, size_t len) {
|
||||
// Compare two arrays in constant time.
|
||||
// Returns 0 if the byte arrays are equal, -1 otherwise.
|
||||
uint16_t r = 0;
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
r |= a[i] ^ b[i];
|
||||
}
|
||||
|
||||
r = (-(int16_t)r) >> (8 * sizeof(uint16_t) -1);
|
||||
return (int8_t)r;
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM976SHAKE_CLEAN_ct_select(uint8_t *r, const uint8_t *a, const uint8_t *b, size_t len, int8_t selector) {
|
||||
// Select one of the two input arrays to be moved to r
|
||||
// If (selector == 0) then load r with a, else if (selector == -1) load r with b
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
r[i] = (~selector & a[i]) | (selector & b[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM976SHAKE_CLEAN_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.
|
||||
|
@ -12,6 +12,8 @@ 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);
|
||||
int8_t PQCLEAN_FRODOKEM976SHAKE_OPT_ct_verify(const uint16_t *a, const uint16_t *b, size_t len);
|
||||
void PQCLEAN_FRODOKEM976SHAKE_OPT_ct_select(uint8_t *r, const uint8_t *a, const uint8_t *b, size_t len, int8_t selector);
|
||||
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);
|
||||
|
@ -214,14 +214,13 @@ int PQCLEAN_FRODOKEM976SHAKE_OPT_crypto_kem_dec(uint8_t *ss, const uint8_t *ct,
|
||||
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);
|
||||
}
|
||||
// If (Bp == BBp & C == CC) then ss = F(ct || k'), else ss = F(ct || s)
|
||||
// Needs to avoid branching on secret data as per:
|
||||
// Qian Guo, Thomas Johansson, Alexander Nilsson. A key-recovery timing attack on post-quantum
|
||||
// primitives using the Fujisaki-Okamoto transformation and its application on FrodoKEM. In CRYPTO 2020.
|
||||
int8_t selector = PQCLEAN_FRODOKEM976SHAKE_OPT_ct_verify(Bp, BBp, PARAMS_N * PARAMS_NBAR) | PQCLEAN_FRODOKEM976SHAKE_OPT_ct_verify(C, CC, PARAMS_NBAR * PARAMS_NBAR);
|
||||
// If (selector == 0) then load k' to do ss = F(ct || k'), else if (selector == -1) load s to do ss = F(ct || s)
|
||||
PQCLEAN_FRODOKEM976SHAKE_OPT_ct_select((uint8_t *)Fin_k, (uint8_t *)kprime, (uint8_t *)sk_s, CRYPTO_BYTES, selector);
|
||||
shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES);
|
||||
|
||||
// Cleanup:
|
||||
|
@ -224,6 +224,30 @@ void PQCLEAN_FRODOKEM976SHAKE_OPT_unpack(uint16_t *out, size_t outlen, const uin
|
||||
}
|
||||
|
||||
|
||||
int8_t PQCLEAN_FRODOKEM976SHAKE_OPT_ct_verify(const uint16_t *a, const uint16_t *b, size_t len) {
|
||||
// Compare two arrays in constant time.
|
||||
// Returns 0 if the byte arrays are equal, -1 otherwise.
|
||||
uint16_t r = 0;
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
r |= a[i] ^ b[i];
|
||||
}
|
||||
|
||||
r = (-(int16_t)r) >> (8 * sizeof(uint16_t) -1);
|
||||
return (int8_t)r;
|
||||
}
|
||||
|
||||
|
||||
void PQCLEAN_FRODOKEM976SHAKE_OPT_ct_select(uint8_t *r, const uint8_t *a, const uint8_t *b, size_t len, int8_t selector) {
|
||||
// Select one of the two input arrays to be moved to r
|
||||
// If (selector == 0) then load r with a, else if (selector == -1) load r with b
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
r[i] = (~selector & a[i]) | (selector & b[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.
|
||||
|
@ -29,7 +29,6 @@ implementations:
|
||||
operating_systems:
|
||||
- Linux
|
||||
required_flags:
|
||||
- aes
|
||||
- avx2
|
||||
- bmi2
|
||||
- popcnt
|
||||
|
@ -29,7 +29,6 @@ implementations:
|
||||
operating_systems:
|
||||
- Linux
|
||||
required_flags:
|
||||
- aes
|
||||
- avx2
|
||||
- bmi2
|
||||
- popcnt
|
||||
|
@ -6,7 +6,7 @@ length-public-key: 1824
|
||||
length-secret-key: 3680
|
||||
length-ciphertext: 2208
|
||||
length-shared-secret: 32
|
||||
nistkat-sha256: 8500b88222b3a62e57a6ecaac57f79258f08af49211e0c3f2ca7eab8089c0ce0
|
||||
nistkat-sha256: 4a21f329bb5402a90d343af01ec1c8bc8ffffa8098cb0b89e1d2129f5157a073
|
||||
principal-submitters:
|
||||
- Thomas Pöppelmann
|
||||
auxiliary-submitters:
|
||||
|
@ -101,8 +101,9 @@ void PQCLEAN_NEWHOPE1024CCA_CLEAN_cpapke_keypair(unsigned char *pk,
|
||||
unsigned char *publicseed = z;
|
||||
unsigned char *noiseseed = z + NEWHOPE_SYMBYTES;
|
||||
|
||||
randombytes(z, NEWHOPE_SYMBYTES);
|
||||
shake256(z, 2 * NEWHOPE_SYMBYTES, z, NEWHOPE_SYMBYTES);
|
||||
z[0] = 0x01;
|
||||
randombytes(z + 1, NEWHOPE_SYMBYTES);
|
||||
shake256(z, 2 * NEWHOPE_SYMBYTES, z, NEWHOPE_SYMBYTES + 1);
|
||||
|
||||
gen_a(&ahat, publicseed);
|
||||
|
||||
|
@ -52,16 +52,18 @@ int PQCLEAN_NEWHOPE1024CCA_CLEAN_crypto_kem_keypair(unsigned char *pk, unsigned
|
||||
**************************************************/
|
||||
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];
|
||||
unsigned char buf[2 * NEWHOPE_SYMBYTES + 1];
|
||||
int i;
|
||||
|
||||
randombytes(buf, NEWHOPE_SYMBYTES);
|
||||
buf[0] = 0x04;
|
||||
randombytes(buf + 1, 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);
|
||||
shake256(buf + 1, NEWHOPE_SYMBYTES, buf, NEWHOPE_SYMBYTES + 1); /* Don't release system RNG output */
|
||||
shake256(buf + 1 + NEWHOPE_SYMBYTES, NEWHOPE_SYMBYTES, pk, NEWHOPE_CCAKEM_PUBLICKEYBYTES); /* Multitarget countermeasure for coins + contributory KEM */
|
||||
buf[0] = 0x08;
|
||||
shake256(k_coins_d, 3 * NEWHOPE_SYMBYTES, buf, 2 * NEWHOPE_SYMBYTES + 1);
|
||||
|
||||
PQCLEAN_NEWHOPE1024CCA_CLEAN_cpapke_enc(ct, buf, pk, k_coins_d + NEWHOPE_SYMBYTES); /* coins are in k_coins_d+NEWHOPE_SYMBYTES */
|
||||
PQCLEAN_NEWHOPE1024CCA_CLEAN_cpapke_enc(ct, buf + 1, 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 */
|
||||
@ -89,18 +91,19 @@ int PQCLEAN_NEWHOPE1024CCA_CLEAN_crypto_kem_enc(unsigned char *ct, unsigned char
|
||||
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 buf[2 * NEWHOPE_SYMBYTES + 1];
|
||||
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);
|
||||
buf[0] = 0x08;
|
||||
PQCLEAN_NEWHOPE1024CCA_CLEAN_cpapke_dec(buf + 1, 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];
|
||||
buf[1 + NEWHOPE_SYMBYTES + i] = sk[NEWHOPE_CCAKEM_SECRETKEYBYTES - 2 * NEWHOPE_SYMBYTES + i];
|
||||
}
|
||||
shake256(k_coins_d, 3 * NEWHOPE_SYMBYTES, buf, 2 * NEWHOPE_SYMBYTES);
|
||||
shake256(k_coins_d, 3 * NEWHOPE_SYMBYTES, buf, 2 * NEWHOPE_SYMBYTES + 1);
|
||||
|
||||
PQCLEAN_NEWHOPE1024CCA_CLEAN_cpapke_enc(ct_cmp, buf, pk, k_coins_d + NEWHOPE_SYMBYTES); /* coins are in k_coins_d+NEWHOPE_SYMBYTES */
|
||||
PQCLEAN_NEWHOPE1024CCA_CLEAN_cpapke_enc(ct_cmp, buf + 1, 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];
|
||||
|
@ -6,7 +6,7 @@ length-public-key: 1824
|
||||
length-secret-key: 1792
|
||||
length-ciphertext: 2176
|
||||
length-shared-secret: 32
|
||||
nistkat-sha256: f48b42b21a51d7f9325abc5fbda74872d62feaa8cbf818bee87f29bf96630a2f
|
||||
nistkat-sha256: 440e2afb40d212a44d1bb1dc9963d7c942fa6ceb16fed2b1ccf015fa75ab115b
|
||||
principal-submitters:
|
||||
- Thomas Pöppelmann
|
||||
auxiliary-submitters:
|
||||
|
@ -101,8 +101,9 @@ void PQCLEAN_NEWHOPE1024CPA_CLEAN_cpapke_keypair(unsigned char *pk,
|
||||
unsigned char *publicseed = z;
|
||||
unsigned char *noiseseed = z + NEWHOPE_SYMBYTES;
|
||||
|
||||
randombytes(z, NEWHOPE_SYMBYTES);
|
||||
shake256(z, 2 * NEWHOPE_SYMBYTES, z, NEWHOPE_SYMBYTES);
|
||||
z[0] = 0x01;
|
||||
randombytes(z + 1, NEWHOPE_SYMBYTES);
|
||||
shake256(z, 2 * NEWHOPE_SYMBYTES, z, NEWHOPE_SYMBYTES + 1);
|
||||
|
||||
gen_a(&ahat, publicseed);
|
||||
|
||||
|
@ -39,9 +39,10 @@ int PQCLEAN_NEWHOPE1024CPA_CLEAN_crypto_kem_keypair(unsigned char *pk, unsigned
|
||||
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);
|
||||
buf[0] = 0x02;
|
||||
randombytes(buf + 1, NEWHOPE_SYMBYTES);
|
||||
|
||||
shake256(buf, 2 * NEWHOPE_SYMBYTES, buf, NEWHOPE_SYMBYTES); /* Don't release system RNG output */
|
||||
shake256(buf, 2 * NEWHOPE_SYMBYTES, buf, NEWHOPE_SYMBYTES + 1); /* Don't release system RNG output */
|
||||
|
||||
PQCLEAN_NEWHOPE1024CPA_CLEAN_cpapke_enc(ct, buf, pk, buf + NEWHOPE_SYMBYTES); /* coins are in buf+NEWHOPE_SYMBYTES */
|
||||
|
||||
|
@ -6,7 +6,7 @@ length-public-key: 928
|
||||
length-secret-key: 1888
|
||||
length-ciphertext: 1120
|
||||
length-shared-secret: 32
|
||||
nistkat-sha256: 5b0389f8d9c30055ad0fb83da540ca36969dde041bebe6f1018c37768c5e1479
|
||||
nistkat-sha256: 4290da64305e70e65766be5d4e488dee2b4b238172876ceefc931934b6964a7d
|
||||
principal-submitters:
|
||||
- Thomas Pöppelmann
|
||||
auxiliary-submitters:
|
||||
|
@ -101,8 +101,9 @@ void PQCLEAN_NEWHOPE512CCA_CLEAN_cpapke_keypair(unsigned char *pk,
|
||||
unsigned char *publicseed = z;
|
||||
unsigned char *noiseseed = z + NEWHOPE_SYMBYTES;
|
||||
|
||||
randombytes(z, NEWHOPE_SYMBYTES);
|
||||
shake256(z, 2 * NEWHOPE_SYMBYTES, z, NEWHOPE_SYMBYTES);
|
||||
z[0] = 0x01;
|
||||
randombytes(z + 1, NEWHOPE_SYMBYTES);
|
||||
shake256(z, 2 * NEWHOPE_SYMBYTES, z, NEWHOPE_SYMBYTES + 1);
|
||||
|
||||
gen_a(&ahat, publicseed);
|
||||
|
||||
|
@ -52,16 +52,18 @@ int PQCLEAN_NEWHOPE512CCA_CLEAN_crypto_kem_keypair(unsigned char *pk, unsigned c
|
||||
**************************************************/
|
||||
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];
|
||||
unsigned char buf[2 * NEWHOPE_SYMBYTES + 1];
|
||||
int i;
|
||||
|
||||
randombytes(buf, NEWHOPE_SYMBYTES);
|
||||
buf[0] = 0x04;
|
||||
randombytes(buf + 1, 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);
|
||||
shake256(buf + 1, NEWHOPE_SYMBYTES, buf, NEWHOPE_SYMBYTES + 1); /* Don't release system RNG output */
|
||||
shake256(buf + 1 + NEWHOPE_SYMBYTES, NEWHOPE_SYMBYTES, pk, NEWHOPE_CCAKEM_PUBLICKEYBYTES); /* Multitarget countermeasure for coins + contributory KEM */
|
||||
buf[0] = 0x08;
|
||||
shake256(k_coins_d, 3 * NEWHOPE_SYMBYTES, buf, 2 * NEWHOPE_SYMBYTES + 1);
|
||||
|
||||
PQCLEAN_NEWHOPE512CCA_CLEAN_cpapke_enc(ct, buf, pk, k_coins_d + NEWHOPE_SYMBYTES); /* coins are in k_coins_d+NEWHOPE_SYMBYTES */
|
||||
PQCLEAN_NEWHOPE512CCA_CLEAN_cpapke_enc(ct, buf + 1, 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 */
|
||||
@ -89,18 +91,19 @@ int PQCLEAN_NEWHOPE512CCA_CLEAN_crypto_kem_enc(unsigned char *ct, unsigned char
|
||||
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 buf[2 * NEWHOPE_SYMBYTES + 1];
|
||||
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);
|
||||
buf[0] = 0x08;
|
||||
PQCLEAN_NEWHOPE512CCA_CLEAN_cpapke_dec(buf + 1, 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];
|
||||
buf[1 + NEWHOPE_SYMBYTES + i] = sk[NEWHOPE_CCAKEM_SECRETKEYBYTES - 2 * NEWHOPE_SYMBYTES + i];
|
||||
}
|
||||
shake256(k_coins_d, 3 * NEWHOPE_SYMBYTES, buf, 2 * NEWHOPE_SYMBYTES);
|
||||
shake256(k_coins_d, 3 * NEWHOPE_SYMBYTES, buf, 2 * NEWHOPE_SYMBYTES + 1);
|
||||
|
||||
PQCLEAN_NEWHOPE512CCA_CLEAN_cpapke_enc(ct_cmp, buf, pk, k_coins_d + NEWHOPE_SYMBYTES); /* coins are in k_coins_d+NEWHOPE_SYMBYTES */
|
||||
PQCLEAN_NEWHOPE512CCA_CLEAN_cpapke_enc(ct_cmp, buf + 1, 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];
|
||||
|
@ -6,7 +6,7 @@ length-public-key: 928
|
||||
length-secret-key: 896
|
||||
length-ciphertext: 1088
|
||||
length-shared-secret: 32
|
||||
nistkat-sha256: 42444446b96f45c9b7221c4fde8afd5dfc0b3c2ff05b9a88ff12ea3949fbb76c
|
||||
nistkat-sha256: 7df3eae4740483a61d13610f6bc2221f27e32c7849cf371e9770f986ce6fdb54
|
||||
principal-submitters:
|
||||
- Thomas Pöppelmann
|
||||
auxiliary-submitters:
|
||||
|
@ -101,8 +101,9 @@ void PQCLEAN_NEWHOPE512CPA_CLEAN_cpapke_keypair(unsigned char *pk,
|
||||
unsigned char *publicseed = z;
|
||||
unsigned char *noiseseed = z + NEWHOPE_SYMBYTES;
|
||||
|
||||
randombytes(z, NEWHOPE_SYMBYTES);
|
||||
shake256(z, 2 * NEWHOPE_SYMBYTES, z, NEWHOPE_SYMBYTES);
|
||||
z[0] = 0x01;
|
||||
randombytes(z + 1, NEWHOPE_SYMBYTES);
|
||||
shake256(z, 2 * NEWHOPE_SYMBYTES, z, NEWHOPE_SYMBYTES + 1);
|
||||
|
||||
gen_a(&ahat, publicseed);
|
||||
|
||||
|
@ -39,9 +39,10 @@ int PQCLEAN_NEWHOPE512CPA_CLEAN_crypto_kem_keypair(unsigned char *pk, unsigned c
|
||||
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);
|
||||
buf[0] = 0x02;
|
||||
randombytes(buf + 1, NEWHOPE_SYMBYTES);
|
||||
|
||||
shake256(buf, 2 * NEWHOPE_SYMBYTES, buf, NEWHOPE_SYMBYTES); /* Don't release system RNG output */
|
||||
shake256(buf, 2 * NEWHOPE_SYMBYTES, buf, NEWHOPE_SYMBYTES + 1); /* Don't release system RNG output */
|
||||
|
||||
PQCLEAN_NEWHOPE512CPA_CLEAN_cpapke_enc(ct, buf, pk, buf + NEWHOPE_SYMBYTES); /* coins are in buf+NEWHOPE_SYMBYTES */
|
||||
|
||||
|
@ -2,11 +2,13 @@ import atexit
|
||||
import functools
|
||||
import logging
|
||||
import os
|
||||
import secrets
|
||||
import shutil
|
||||
import string
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from functools import lru_cache
|
||||
|
||||
import pqclean
|
||||
|
||||
@ -22,6 +24,12 @@ def cleanup_testcases():
|
||||
|
||||
TEST_TEMPDIRS = []
|
||||
|
||||
ALPHABET = string.ascii_letters + string.digits + '_'
|
||||
def mktmpdir(parent, prefix):
|
||||
"""Returns a unique directory name"""
|
||||
uniq = ''.join(secrets.choice(ALPHABET) for i in range(8))
|
||||
return os.path.join(parent, "{}_{}".format(prefix, uniq))
|
||||
|
||||
|
||||
def isolate_test_files(impl_path, test_prefix,
|
||||
dir=os.path.join('..', 'testcases')):
|
||||
@ -34,24 +42,22 @@ def isolate_test_files(impl_path, test_prefix,
|
||||
os.mkdir(dir)
|
||||
except FileExistsError:
|
||||
pass
|
||||
test_dir = tempfile.mkdtemp(prefix=test_prefix, dir=dir)
|
||||
test_dir = mktmpdir(dir, test_prefix)
|
||||
test_dir = os.path.abspath(test_dir)
|
||||
TEST_TEMPDIRS.append(test_dir)
|
||||
|
||||
# the implementation will go here.
|
||||
scheme_dir = os.path.join(test_dir, 'crypto_bla', 'scheme')
|
||||
new_impl_dir = os.path.abspath(os.path.join(scheme_dir, 'impl'))
|
||||
|
||||
def initializer():
|
||||
"""Isolate the files to be tested"""
|
||||
# Create layers in folder structure
|
||||
nested_dir = os.path.join(test_dir, 'crypto_bla')
|
||||
os.mkdir(nested_dir)
|
||||
nested_dir = os.path.join(nested_dir, 'scheme')
|
||||
os.mkdir(nested_dir)
|
||||
os.makedirs(scheme_dir)
|
||||
|
||||
# Create test dependencies structure
|
||||
os.mkdir(os.path.join(test_dir, 'test'))
|
||||
|
||||
# the implementation will go here.
|
||||
new_impl_dir = os.path.abspath(os.path.join(nested_dir, 'impl'))
|
||||
|
||||
def initializer():
|
||||
"""Isolate the files to be tested"""
|
||||
# Copy common files (randombytes.c, aes.c, ...)
|
||||
shutil.copytree(
|
||||
os.path.join('..', 'common'), os.path.join(test_dir, 'common'))
|
||||
@ -160,6 +166,7 @@ def slow_test(f):
|
||||
return wrapper
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def ensure_available(executable):
|
||||
"""
|
||||
Checks if a command is available.
|
||||
@ -278,18 +285,16 @@ def filtered_test(func):
|
||||
return wrapper
|
||||
|
||||
|
||||
__CPUINFO = None
|
||||
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def get_cpu_info():
|
||||
global __CPUINFO
|
||||
while __CPUINFO is None or 'flags' not in __CPUINFO:
|
||||
the_info = None
|
||||
while the_info is None or 'flags' not in the_info:
|
||||
import cpuinfo
|
||||
__CPUINFO = cpuinfo.get_cpu_info()
|
||||
the_info = cpuinfo.get_cpu_info()
|
||||
|
||||
# CPUINFO is unreliable on Travis CI Macs
|
||||
if 'CI' in os.environ and sys.platform == 'darwin':
|
||||
__CPUINFO['flags'] = [
|
||||
the_info['flags'] = [
|
||||
'aes', 'apic', 'avx1.0', 'clfsh', 'cmov', 'cx16', 'cx8', 'de',
|
||||
'em64t', 'erms', 'f16c', 'fpu', 'fxsr', 'lahf', 'mca', 'mce',
|
||||
'mmx', 'mon', 'msr', 'mtrr', 'osxsave', 'pae', 'pat', 'pcid',
|
||||
@ -299,4 +304,4 @@ def get_cpu_info():
|
||||
'tsc_thread_offset', 'tsci', 'tsctmr', 'vme', 'vmm', 'x2apic',
|
||||
'xd', 'xsave']
|
||||
|
||||
return __CPUINFO
|
||||
return the_info
|
||||
|
@ -1,6 +1,7 @@
|
||||
import glob
|
||||
import os
|
||||
from typing import Optional
|
||||
from functools import lru_cache
|
||||
|
||||
import yaml
|
||||
import platform
|
||||
@ -20,6 +21,7 @@ class Scheme:
|
||||
return 'PQCLEAN_{}_'.format(self.name.upper()).replace('-', '')
|
||||
|
||||
@staticmethod
|
||||
@lru_cache(maxsize=None)
|
||||
def by_name(scheme_name):
|
||||
for scheme in Scheme.all_schemes():
|
||||
if scheme.name == scheme_name:
|
||||
@ -27,6 +29,7 @@ class Scheme:
|
||||
raise KeyError()
|
||||
|
||||
@staticmethod
|
||||
@lru_cache(maxsize=1)
|
||||
def all_schemes():
|
||||
schemes = []
|
||||
schemes.extend(Scheme.all_schemes_of_type('kem'))
|
||||
@ -34,6 +37,7 @@ class Scheme:
|
||||
return schemes
|
||||
|
||||
@staticmethod
|
||||
@lru_cache(maxsize=1)
|
||||
def all_implementations():
|
||||
implementations = []
|
||||
for scheme in Scheme.all_schemes():
|
||||
@ -41,11 +45,13 @@ class Scheme:
|
||||
return implementations
|
||||
|
||||
@staticmethod
|
||||
@lru_cache(maxsize=1)
|
||||
def all_supported_implementations():
|
||||
return [impl for impl in Scheme.all_implementations()
|
||||
if impl.supported_on_current_platform()]
|
||||
|
||||
@staticmethod
|
||||
@lru_cache(maxsize=32)
|
||||
def all_schemes_of_type(type: str) -> list:
|
||||
schemes = []
|
||||
p = os.path.join('..', 'crypto_' + type)
|
||||
@ -60,11 +66,12 @@ class Scheme:
|
||||
assert('Unknown type')
|
||||
return schemes
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def metadata(self):
|
||||
metafile = os.path.join(self.path(), 'META.yml')
|
||||
try:
|
||||
with open(metafile, encoding='utf-8') as f:
|
||||
metadata = yaml.safe_load(f.read())
|
||||
metadata = yaml.safe_load(f)
|
||||
return metadata
|
||||
except Exception as e:
|
||||
print("Can't open {}: {}".format(metafile, e))
|
||||
@ -80,6 +87,7 @@ class Implementation:
|
||||
self.scheme = scheme
|
||||
self.name = name
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def metadata(self):
|
||||
for i in self.scheme.metadata()['implementations']:
|
||||
if i['name'] == self.name:
|
||||
@ -104,6 +112,7 @@ class Implementation:
|
||||
'*.o' if os.name != 'nt' else '*.obj'))
|
||||
|
||||
@staticmethod
|
||||
@lru_cache(maxsize=None)
|
||||
def by_name(scheme_name, implementation_name):
|
||||
scheme = Scheme.by_name(scheme_name)
|
||||
for implementation in scheme.implementations:
|
||||
@ -112,6 +121,7 @@ class Implementation:
|
||||
raise KeyError()
|
||||
|
||||
@staticmethod
|
||||
@lru_cache(maxsize=None)
|
||||
def all_implementations(scheme: Scheme) -> list:
|
||||
implementations = []
|
||||
for d in os.listdir(scheme.path()):
|
||||
@ -143,6 +153,7 @@ class Implementation:
|
||||
|
||||
return True
|
||||
|
||||
@lru_cache(maxsize=10000)
|
||||
def supported_on_current_platform(self) -> bool:
|
||||
if 'supported_platforms' not in self.metadata():
|
||||
return True
|
||||
|
@ -2,3 +2,4 @@
|
||||
norecursedirs = .git *
|
||||
empty_parameter_set_mark = fail_at_collect
|
||||
junit_log_passing_tests = False
|
||||
junit_family=xunit2
|
||||
|
Loading…
Reference in New Issue
Block a user