1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
/********************************************************************************************
* Supersingular Isogeny Key Encapsulation Library
*
* Abstract: supersingular isogeny key encapsulation (SIKE) protocol
*********************************************************************************************/
#include <string.h>
#include "P503_internal_r1.h"
#include "fips202_r1.h"
#include "pq-crypto/s2n_pq_random.h"
#include "utils/s2n_safety.h"
#include "tls/s2n_kem.h"
int SIKE_P503_r1_crypto_kem_keypair(unsigned char *pk, unsigned char *sk)
{ // SIKE's key generation
// Outputs: secret key sk (SIKE_P503_R1_SECRET_KEY_BYTES = MSG_BYTES + SECRETKEY_B_BYTES + SIKE_P503_R1_PUBLIC_KEY_BYTES bytes)
// public key pk (SIKE_P503_R1_PUBLIC_KEY_BYTES bytes)
digit_t _sk[SECRETKEY_B_BYTES/sizeof(digit_t)];
// Generate lower portion of secret key sk <- s||SK
GUARD_AS_POSIX(s2n_get_random_bytes(sk, MSG_BYTES));
GUARD(random_mod_order_B((unsigned char*)_sk));
// Generate public key pk
EphemeralKeyGeneration_B(_sk, pk);
memcpy(sk + MSG_BYTES, _sk, SECRETKEY_B_BYTES);
// Append public key pk to secret key sk
memcpy(&sk[MSG_BYTES + SECRETKEY_B_BYTES], pk, SIKE_P503_R1_PUBLIC_KEY_BYTES);
return 0;
}
int SIKE_P503_r1_crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk)
{ // SIKE's encapsulation
// Input: public key pk (SIKE_P503_R1_PUBLIC_KEY_BYTES bytes)
// Outputs: shared secret ss (SIKE_P503_R1_SHARED_SECRET_BYTES bytes)
// ciphertext message ct (SIKE_P503_R1_CIPHERTEXT_BYTES = SIKE_P503_R1_PUBLIC_KEY_BYTES + MSG_BYTES bytes)
const uint16_t G = 0;
const uint16_t H = 1;
const uint16_t P = 2;
union {
unsigned char b[SECRETKEY_A_BYTES];
digit_t d[SECRETKEY_A_BYTES/sizeof(digit_t)];
} ephemeralsk;
unsigned char jinvariant[FP2_ENCODED_BYTES];
unsigned char h[MSG_BYTES];
unsigned char temp[SIKE_P503_R1_CIPHERTEXT_BYTES+MSG_BYTES];
unsigned int i;
// Generate ephemeralsk <- G(m||pk) mod oA
GUARD_AS_POSIX(s2n_get_random_bytes(temp, MSG_BYTES));
memcpy(&temp[MSG_BYTES], pk, SIKE_P503_R1_PUBLIC_KEY_BYTES);
cshake256_simple(ephemeralsk.b, SECRETKEY_A_BYTES, G, temp, SIKE_P503_R1_PUBLIC_KEY_BYTES+MSG_BYTES);
/* ephemeralsk is a union; the memory set here through .b will get accessed through the .d member later */
/* cppcheck-suppress unreadVariable */
ephemeralsk.b[SECRETKEY_A_BYTES - 1] &= MASK_ALICE;
// Encrypt
EphemeralKeyGeneration_A(ephemeralsk.d, ct);
EphemeralSecretAgreement_A(ephemeralsk.d, pk, jinvariant);
cshake256_simple(h, MSG_BYTES, P, jinvariant, FP2_ENCODED_BYTES);
for (i = 0; i < MSG_BYTES; i++) ct[i + SIKE_P503_R1_PUBLIC_KEY_BYTES] = temp[i] ^ h[i];
// Generate shared secret ss <- H(m||ct)
memcpy(&temp[MSG_BYTES], ct, SIKE_P503_R1_CIPHERTEXT_BYTES);
cshake256_simple(ss, SIKE_P503_R1_SHARED_SECRET_BYTES, H, temp, SIKE_P503_R1_CIPHERTEXT_BYTES+MSG_BYTES);
return 0;
}
int SIKE_P503_r1_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk)
{ // SIKE's decapsulation
// Input: secret key sk (SIKE_P503_R1_SECRET_KEY_BYTES = MSG_BYTES + SECRETKEY_B_BYTES + SIKE_P503_R1_PUBLIC_KEY_BYTES bytes)
// ciphertext message ct (SIKE_P503_R1_CIPHERTEXT_BYTES = SIKE_P503_R1_PUBLIC_KEY_BYTES + MSG_BYTES bytes)
// Outputs: shared secret ss (SIKE_P503_R1_SHARED_SECRET_BYTES bytes)
const uint16_t G = 0;
const uint16_t H = 1;
const uint16_t P = 2;
union {
unsigned char b[SECRETKEY_A_BYTES];
digit_t d[SECRETKEY_A_BYTES/sizeof(digit_t)];
} ephemeralsk_;
unsigned char jinvariant_[FP2_ENCODED_BYTES];
unsigned char h_[MSG_BYTES];
unsigned char c0_[SIKE_P503_R1_PUBLIC_KEY_BYTES];
unsigned char temp[SIKE_P503_R1_CIPHERTEXT_BYTES+MSG_BYTES];
unsigned int i;
digit_t _sk[SECRETKEY_B_BYTES/sizeof(digit_t)];
memcpy(_sk, sk + MSG_BYTES, SECRETKEY_B_BYTES);
// Decrypt
EphemeralSecretAgreement_B(_sk, ct, jinvariant_);
cshake256_simple(h_, MSG_BYTES, P, jinvariant_, FP2_ENCODED_BYTES);
for (i = 0; i < MSG_BYTES; i++) temp[i] = ct[i + SIKE_P503_R1_PUBLIC_KEY_BYTES] ^ h_[i];
// Generate ephemeralsk_ <- G(m||pk) mod oA
memcpy(&temp[MSG_BYTES], &sk[MSG_BYTES + SECRETKEY_B_BYTES], SIKE_P503_R1_PUBLIC_KEY_BYTES);
cshake256_simple(ephemeralsk_.b, SECRETKEY_A_BYTES, G, temp, SIKE_P503_R1_PUBLIC_KEY_BYTES+MSG_BYTES);
/* ephemeralsk_ is a union; the memory set here through .b will get accessed through the .d member later */
/* cppcheck-suppress unreadVariable */
/* cppcheck-suppress uninitvar */
ephemeralsk_.b[SECRETKEY_A_BYTES - 1] &= MASK_ALICE;
// Generate shared secret ss <- H(m||ct) or output ss <- H(s||ct)
EphemeralKeyGeneration_A(ephemeralsk_.d, c0_);
if (memcmp(c0_, ct, SIKE_P503_R1_PUBLIC_KEY_BYTES) != 0) {
memcpy(temp, sk, MSG_BYTES);
}
memcpy(&temp[MSG_BYTES], ct, SIKE_P503_R1_CIPHERTEXT_BYTES);
cshake256_simple(ss, SIKE_P503_R1_SHARED_SECRET_BYTES, H, temp, SIKE_P503_R1_CIPHERTEXT_BYTES+MSG_BYTES);
return 0;
}
|