def kem_keygen()

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)