in python3/frodokem.py [0:0]
def kem_keygen(self):
"""Generate a public key / secret key pair (FrodoKEM specification,
Algorithm 12)"""
# 1. Choose uniformly random seeds s || seedSE || z
s_seedSE_z = self.randombytes(self.len_s_bytes + self.len_seedSE_bytes + self.len_z_bytes)
self.__print_intermediate_value("randomness", s_seedSE_z)
s = bytes(s_seedSE_z[0:self.len_s_bytes])
seedSE = bytes(s_seedSE_z[self.len_s_bytes : self.len_s_bytes + self.len_seedSE_bytes])
z = bytes(s_seedSE_z[self.len_s_bytes + self.len_seedSE_bytes : self.len_s_bytes + self.len_seedSE_bytes + self.len_z_bytes])
# 2. Generate pseudorandom seed seedA = SHAKE(z, len_seedA) (length in bits)
seedA = self.shake(z, self.len_seedA_bytes)
self.__print_intermediate_value("seedA", seedA)
# 3. A = Frodo.Gen(seedA)
A = self.gen(seedA)
# self.__print_intermediate_value("A", A)
# 4. r = SHAKE(0x5F || seedSE, 2*n*nbar*len_chi) (length in bits), parsed as 2*n*nbar len_chi-bit integers in little-endian byte order
rbytes = self.shake(bytes(b'\x5f') + seedSE, 2 * self.n * self.nbar * self.len_chi_bytes)
r = [struct.unpack_from('<H', rbytes, 2*i)[0] for i in range(2 * self.n * self.nbar)]
self.__print_intermediate_value("r", r)
# 5. S^T = Frodo.SampleMatrix(r[0 .. n*nbar-1], nbar, n)
Stransposed = self.sample_matrix(r[0 : self.n * self.nbar], self.nbar, self.n)
self.__print_intermediate_value("S^T", Stransposed)
S = self.__matrix_transpose(Stransposed)
# 6. E = Frodo.SampleMatrix(r[n*nbar .. 2*n*nbar-1], n, nbar)
E = self.sample_matrix(r[self.n * self.nbar : 2 * self.n * self.nbar], self.n, self.nbar)
# self.__print_intermediate_value("E", E)
# 7. B = A S + E
B = self.__matrix_add(self.__matrix_mul(A, S), E)
self.__print_intermediate_value("B", B)
# 8. b = Pack(B)
b = self.pack(B)
self.__print_intermediate_value("b", b)
# 9. pkh = SHAKE(seedA || b, len_pkh) (length in bits)
pkh = self.shake(seedA + b, self.len_pkh_bytes)
self.__print_intermediate_value("pkh", pkh)
# 10. pk = seedA || b, sk = (s || seedA || b, S^T, pkh)
pk = seedA + b
assert len(pk) == self.len_pk_bytes
sk = bitstring.BitArray()
sk.append(s + seedA + b)
for i in range(self.nbar):
for j in range(self.n):
sk.append(bitstring.BitArray(intle = Stransposed[i][j], length = 16))
sk.append(pkh)
sk = sk.bytes
assert len(sk) == self.len_sk_bytes
return (pk, sk)