def kem_encaps()

in python3/frodokem.py [0:0]


    def kem_encaps(self, pk):
        """Encapsulate against a public key to create a ciphertext and shared secret 
        (FrodoKEM specification, Algorithm 13)"""
        # Parse pk = seedA || b
        assert len(pk) == self.len_seedA_bytes + self.D * self.n * self.nbar / 8, "Incorrect public key length"
        seedA = pk[0 : self.len_seedA_bytes]
        b = pk[self.len_seedA_bytes:]
        # 1. Choose a uniformly random key mu in {0,1}^len_mu (length in bits)
        mu = self.randombytes(self.len_mu_bytes)
        self.__print_intermediate_value("mu", mu)
        # 2. pkh = SHAKE(pk, len_pkh)
        pkh = self.shake(pk, self.len_pkh_bytes)
        self.__print_intermediate_value("pkh", pkh)
        # 3. seedSE || k = SHAKE(pkh || mu, len_seedSE + len_k) (length in bits)
        seedSE_k = self.shake(pkh + mu, self.len_seedSE_bytes + self.len_k_bytes)
        seedSE = seedSE_k[0:self.len_seedSE_bytes]
        self.__print_intermediate_value("seedSE", seedSE)
        k = seedSE_k[self.len_seedSE_bytes:self.len_seedSE_bytes + self.len_k_bytes]
        self.__print_intermediate_value("k", k)
        # 4. r = SHAKE(0x96 || seedSE, 2*mbar*n + mbar*nbar*len_chi) (length in bits)
        rbytes = self.shake(bytes(b'\x96') + seedSE, (2 * self.mbar * self.n + self.mbar * self.mbar) * self.len_chi_bytes)
        r = [struct.unpack_from('<H', rbytes, 2*i)[0] for i in range(2 * self.mbar * self.n + self.mbar * self.nbar)]
        self.__print_intermediate_value("r", r)
        # 5. S' = Frodo.SampleMatrix(r[0 .. mbar*n-1], mbar, n)
        Sprime = self.sample_matrix(r[0 : self.mbar * self.n], self.mbar, self.n)
        self.__print_intermediate_value("S'", Sprime)
        # 6. E' = Frodo.SampleMatrix(r[mbar*n .. 2*mbar*n-1], mbar, n)
        Eprime = self.sample_matrix(r[self.mbar * self.n : 2 * self.mbar * self.n], self.mbar, self.n)
        self.__print_intermediate_value("E'", Eprime)
        # 7. A = Frodo.Gen(seedA)
        A = self.gen(seedA)
        # 8. B' = S' A + E'
        Bprime = self.__matrix_add(self.__matrix_mul(Sprime, A), Eprime)
        self.__print_intermediate_value("B'", Bprime)
        # 9. c1 = Frodo.Pack(B')
        c1 = self.pack(Bprime)
        self.__print_intermediate_value("c1", c1)
        # 10. E'' = Frodo.SampleMatrix(r[2*mbar*n .. 2*mbar*n + mbar*nbar-1], mbar, n)
        Eprimeprime = self.sample_matrix(r[2 * self.mbar * self.n : 2 * self.mbar * self.n + self.mbar * self.nbar], self.mbar, self.nbar)
        self.__print_intermediate_value("E''", Eprimeprime)
        # 11. B = Frodo.Unpack(b, n, nbar)
        B = self.unpack(b, self.n, self.nbar)
        self.__print_intermediate_value("B", B)
        # 12. V = S' B + E''
        V = self.__matrix_add(self.__matrix_mul(Sprime, B), Eprimeprime)
        self.__print_intermediate_value("V", V)
        # 13. C = V + Frodo.Encode(mu)
        self.__print_intermediate_value("mu_encoded", self.encode(mu))
        C = self.__matrix_add(V, self.encode(mu))
        self.__print_intermediate_value("C", C)
        # 14. c2 = Frodo.Pack(C)
        c2 = self.pack(C)
        self.__print_intermediate_value("c2", c2)
        # 15. ss = SHAKE(c1 || c2 || k, len_ss)
        ss = self.shake(c1 + c2 + k, self.len_ss_bytes)
        ct = c1 + c2
        assert len(ct) == self.len_ct_bytes
        assert len(ss) == self.len_ss_bytes
        return (ct, ss)