Revision 5b2fbf3c4989a9b0587a00578f69f3041df3f957 authored by Jonathan Protzenko on 08 April 2020, 18:59:46 UTC, committed by Jonathan Protzenko on 08 April 2020, 18:59:46 UTC
1 parent d4ca892
Raw File
Hacl_Frodo_KEM.c
/* MIT License
 *
 * Copyright (c) 2016-2020 INRIA, CMU and Microsoft Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */


#include "Hacl_Frodo_KEM.h"

static inline void matrix_add(uint32_t n1, uint32_t n2, uint16_t *a, uint16_t *b)
{
  for (uint32_t i0 = (uint32_t)0U; i0 < n1; i0++)
  {
    for (uint32_t i = (uint32_t)0U; i < n2; i++)
    {
      a[i0 * n2 + i] = a[i0 * n2 + i] + b[i0 * n2 + i];
    }
  }
}

static inline void matrix_sub(uint32_t n1, uint32_t n2, uint16_t *a, uint16_t *b)
{
  for (uint32_t i0 = (uint32_t)0U; i0 < n1; i0++)
  {
    for (uint32_t i = (uint32_t)0U; i < n2; i++)
    {
      b[i0 * n2 + i] = a[i0 * n2 + i] - b[i0 * n2 + i];
    }
  }
}

static inline void
matrix_mul(uint32_t n1, uint32_t n2, uint32_t n3, uint16_t *a, uint16_t *b, uint16_t *c)
{
  for (uint32_t i0 = (uint32_t)0U; i0 < n1; i0++)
  {
    for (uint32_t i1 = (uint32_t)0U; i1 < n3; i1++)
    {
      uint16_t res = (uint16_t)0U;
      for (uint32_t i = (uint32_t)0U; i < n2; i++)
      {
        uint16_t aij = a[i0 * n2 + i];
        uint16_t bjk = b[i * n3 + i1];
        uint16_t res0 = res;
        res = res0 + aij * bjk;
      }
      c[i0 * n3 + i1] = res;
    }
  }
}

static inline void
matrix_mul_s(uint32_t n1, uint32_t n2, uint32_t n3, uint16_t *a, uint16_t *b, uint16_t *c)
{
  for (uint32_t i0 = (uint32_t)0U; i0 < n1; i0++)
  {
    for (uint32_t i1 = (uint32_t)0U; i1 < n3; i1++)
    {
      uint16_t res = (uint16_t)0U;
      for (uint32_t i = (uint32_t)0U; i < n2; i++)
      {
        uint16_t aij = a[i0 * n2 + i];
        uint16_t bjk = b[i1 * n2 + i];
        uint16_t res0 = res;
        res = res0 + aij * bjk;
      }
      c[i0 * n3 + i1] = res;
    }
  }
}

static inline bool matrix_eq(uint32_t n1, uint32_t n2, uint32_t m, uint16_t *a, uint16_t *b)
{
  bool res = true;
  uint32_t n3 = n1 * n2;
  for (uint32_t i = (uint32_t)0U; i < n3; i++)
  {
    uint16_t ai = a[i];
    uint16_t bi = b[i];
    bool a1 = res;
    res =
      a1
      &&
        ((uint32_t)ai & (((uint32_t)1U << m) - (uint32_t)1U))
        == ((uint32_t)bi & (((uint32_t)1U << m) - (uint32_t)1U));
  }
  return res;
}

static inline void matrix_to_lbytes(uint32_t n1, uint32_t n2, uint16_t *m, uint8_t *res)
{
  uint32_t n3 = n1 * n2;
  for (uint32_t i = (uint32_t)0U; i < n3; i++)
  {
    uint8_t *tmp = res + (uint32_t)2U * i;
    store16_le(tmp, m[i]);
  }
}

static inline void matrix_from_lbytes(uint32_t n1, uint32_t n2, uint8_t *b, uint16_t *res)
{
  uint32_t n3 = n1 * n2;
  for (uint32_t i = (uint32_t)0U; i < n3; i++)
  {
    uint16_t u = load16_le(b + (uint32_t)2U * i);
    res[i] = u;
  }
}

static inline void
frodo_gen_matrix_cshake(uint32_t n1, uint32_t seed_len, uint8_t *seed, uint16_t *res)
{
  KRML_CHECK_SIZE(sizeof (uint8_t), (uint32_t)2U * n1);
  uint8_t r[(uint32_t)2U * n1];
  memset(r, 0U, (uint32_t)2U * n1 * sizeof (r[0U]));
  memset(res, 0U, n1 * n1 * sizeof (res[0U]));
  for (uint32_t i = (uint32_t)0U; i < n1; i++)
  {
    uint32_t ctr = (uint32_t)256U + i;
    uint64_t s[25U] = { 0U };
    s[0U] = (uint64_t)0x10010001a801U | (uint64_t)(uint16_t)ctr << (uint32_t)48U;
    Hacl_Impl_SHA3_state_permute(s);
    Hacl_Impl_SHA3_absorb(s, (uint32_t)168U, seed_len, seed, (uint8_t)0x04U);
    Hacl_Impl_SHA3_squeeze(s, (uint32_t)168U, (uint32_t)2U * n1, r);
    for (uint32_t i0 = (uint32_t)0U; i0 < n1; i0++)
    {
      uint8_t *resij = r + (uint32_t)2U * i0;
      uint16_t u = load16_le(resij);
      res[i * n1 + i0] = u;
    }
  }
}

static const
uint16_t
cdf_table[12U] =
  {
    (uint16_t)4727U, (uint16_t)13584U, (uint16_t)20864U, (uint16_t)26113U, (uint16_t)29434U,
    (uint16_t)31278U, (uint16_t)32176U, (uint16_t)32560U, (uint16_t)32704U, (uint16_t)32751U,
    (uint16_t)32764U, (uint16_t)32767U
  };

static inline uint16_t frodo_sample(uint16_t r)
{
  uint16_t prnd = r >> (uint32_t)1U;
  uint16_t sign = r & (uint16_t)1U;
  uint16_t sample = (uint16_t)0U;
  uint32_t bound = (uint32_t)11U;
  for (uint32_t i = (uint32_t)0U; i < bound; i++)
  {
    uint16_t sample0 = sample;
    uint16_t ti = cdf_table[i];
    uint16_t samplei = (uint16_t)(uint32_t)(ti - prnd) >> (uint32_t)15U;
    sample = samplei + sample0;
  }
  uint16_t sample0 = sample;
  return ((~sign + (uint16_t)1U) ^ sample0) + sign;
}

static inline void
frodo_sample_matrix(
  uint32_t n1,
  uint32_t n2,
  uint32_t seed_len,
  uint8_t *seed,
  uint16_t ctr,
  uint16_t *res
)
{
  KRML_CHECK_SIZE(sizeof (uint8_t), (uint32_t)2U * n1 * n2);
  uint8_t r[(uint32_t)2U * n1 * n2];
  memset(r, 0U, (uint32_t)2U * n1 * n2 * sizeof (r[0U]));
  uint64_t s[25U] = { 0U };
  s[0U] = (uint64_t)0x10010001a801U | (uint64_t)ctr << (uint32_t)48U;
  Hacl_Impl_SHA3_state_permute(s);
  Hacl_Impl_SHA3_absorb(s, (uint32_t)168U, seed_len, seed, (uint8_t)0x04U);
  Hacl_Impl_SHA3_squeeze(s, (uint32_t)168U, (uint32_t)2U * n1 * n2, r);
  memset(res, 0U, n1 * n2 * sizeof (res[0U]));
  for (uint32_t i0 = (uint32_t)0U; i0 < n1; i0++)
  {
    for (uint32_t i = (uint32_t)0U; i < n2; i++)
    {
      uint8_t *resij = r + (uint32_t)2U * (n2 * i0 + i);
      uint16_t u = load16_le(resij);
      res[i0 * n2 + i] = frodo_sample(u);
    }
  }
}

static inline void frodo_pack(uint32_t n1, uint32_t n2, uint32_t d, uint16_t *a, uint8_t *res)
{
  uint32_t n3 = n1 * n2 / (uint32_t)8U;
  for (uint32_t i = (uint32_t)0U; i < n3; i++)
  {
    uint16_t *a1 = a + (uint32_t)8U * i;
    uint8_t *r = res + d * i;
    uint16_t maskd = (uint16_t)((uint32_t)1U << d) - (uint16_t)1U;
    uint8_t v16[16U] = { 0U };
    uint16_t a0 = a1[0U] & maskd;
    uint16_t a11 = a1[1U] & maskd;
    uint16_t a2 = a1[2U] & maskd;
    uint16_t a3 = a1[3U] & maskd;
    uint16_t a4 = a1[4U] & maskd;
    uint16_t a5 = a1[5U] & maskd;
    uint16_t a6 = a1[6U] & maskd;
    uint16_t a7 = a1[7U] & maskd;
    uint128_t
    templong =
      (((((((uint128_t)(uint64_t)a0
      << (uint32_t)7U * d
      | (uint128_t)(uint64_t)a11 << (uint32_t)6U * d)
      | (uint128_t)(uint64_t)a2 << (uint32_t)5U * d)
      | (uint128_t)(uint64_t)a3 << (uint32_t)4U * d)
      | (uint128_t)(uint64_t)a4 << (uint32_t)3U * d)
      | (uint128_t)(uint64_t)a5 << (uint32_t)2U * d)
      | (uint128_t)(uint64_t)a6 << (uint32_t)1U * d)
      | (uint128_t)(uint64_t)a7 << (uint32_t)0U * d;
    store128_be(v16, templong);
    uint8_t *src = v16 + (uint32_t)16U - d;
    memcpy(r, src, d * sizeof (src[0U]));
  }
}

static inline void
frodo_unpack(uint32_t n1, uint32_t n2, uint32_t d, uint8_t *b, uint16_t *res)
{
  uint32_t n3 = n1 * n2 / (uint32_t)8U;
  for (uint32_t i = (uint32_t)0U; i < n3; i++)
  {
    uint8_t *b1 = b + d * i;
    uint16_t *r = res + (uint32_t)8U * i;
    uint16_t maskd = (uint16_t)((uint32_t)1U << d) - (uint16_t)1U;
    uint8_t src[16U] = { 0U };
    memcpy(src + (uint32_t)16U - d, b1, d * sizeof (b1[0U]));
    uint128_t u = load128_be(src);
    uint128_t templong = u;
    r[0U] = (uint16_t)(uint64_t)(templong >> (uint32_t)7U * d) & maskd;
    r[1U] = (uint16_t)(uint64_t)(templong >> (uint32_t)6U * d) & maskd;
    r[2U] = (uint16_t)(uint64_t)(templong >> (uint32_t)5U * d) & maskd;
    r[3U] = (uint16_t)(uint64_t)(templong >> (uint32_t)4U * d) & maskd;
    r[4U] = (uint16_t)(uint64_t)(templong >> (uint32_t)3U * d) & maskd;
    r[5U] = (uint16_t)(uint64_t)(templong >> (uint32_t)2U * d) & maskd;
    r[6U] = (uint16_t)(uint64_t)(templong >> (uint32_t)1U * d) & maskd;
    r[7U] = (uint16_t)(uint64_t)(templong >> (uint32_t)0U * d) & maskd;
  }
}

static void randombytes_(uint32_t len, uint8_t *res)
{
  bool b = Lib_RandomBuffer_System_randombytes(res, len);
}

static uint32_t bytes_mu = (uint32_t)16U;

static uint32_t crypto_publickeybytes = (uint32_t)976U;

static uint32_t crypto_ciphertextbytes = (uint32_t)1096U;

static inline void
frodo_mul_add_as_plus_e_pack(uint8_t *seed_a, uint8_t *seed_e, uint8_t *b, uint8_t *s)
{
  uint16_t s_matrix[512U] = { 0U };
  frodo_sample_matrix((uint32_t)64U,
    (uint32_t)8U,
    (uint32_t)16U,
    seed_e,
    (uint16_t)1U,
    s_matrix);
  matrix_to_lbytes((uint32_t)64U, (uint32_t)8U, s_matrix, s);
  uint16_t b_matrix[512U] = { 0U };
  uint16_t a_matrix[4096U] = { 0U };
  uint16_t e_matrix[512U] = { 0U };
  frodo_gen_matrix_cshake((uint32_t)64U, (uint32_t)16U, seed_a, a_matrix);
  frodo_sample_matrix((uint32_t)64U,
    (uint32_t)8U,
    (uint32_t)16U,
    seed_e,
    (uint16_t)2U,
    e_matrix);
  matrix_mul_s((uint32_t)64U, (uint32_t)64U, (uint32_t)8U, a_matrix, s_matrix, b_matrix);
  matrix_add((uint32_t)64U, (uint32_t)8U, b_matrix, e_matrix);
  Lib_Memzero_clear_words_u16((uint32_t)512U, e_matrix);
  frodo_pack((uint32_t)64U, (uint32_t)8U, (uint32_t)15U, b_matrix, b);
  Lib_Memzero_clear_words_u16((uint32_t)512U, s_matrix);
}

static inline void frodo_key_encode(uint32_t b, uint8_t *a, uint16_t *res)
{
  for (uint32_t i0 = (uint32_t)0U; i0 < (uint32_t)8U; i0++)
  {
    uint8_t v8[8U] = { 0U };
    uint8_t *chunk = a + i0 * b;
    memcpy(v8, chunk, b * sizeof (chunk[0U]));
    uint64_t u = load64_le(v8);
    uint64_t x = u;
    uint64_t x0 = x;
    for (uint32_t i = (uint32_t)0U; i < (uint32_t)8U; i++)
    {
      uint64_t rk = x0 >> b * i & (((uint64_t)1U << b) - (uint64_t)1U);
      res[i0 * (uint32_t)8U + i] = (uint16_t)rk << ((uint32_t)15U - b);
    }
  }
}

static inline void frodo_key_decode(uint32_t b, uint16_t *a, uint8_t *res)
{
  for (uint32_t i0 = (uint32_t)0U; i0 < (uint32_t)8U; i0++)
  {
    uint64_t templong = (uint64_t)0U;
    for (uint32_t i = (uint32_t)0U; i < (uint32_t)8U; i++)
    {
      uint16_t aik = a[i0 * (uint32_t)8U + i];
      uint16_t
      res1 = (aik + ((uint16_t)1U << ((uint32_t)15U - b - (uint32_t)1U))) >> ((uint32_t)15U - b);
      templong = templong | (uint64_t)(res1 & (((uint16_t)1U << b) - (uint16_t)1U)) << b * i;
    }
    uint64_t templong0 = templong;
    uint8_t v8[8U] = { 0U };
    store64_le(v8, templong0);
    uint8_t *tmp = v8;
    memcpy(res + i0 * b, tmp, b * sizeof (tmp[0U]));
  }
}

static inline void
frodo_mul_add_sb_plus_e_plus_mu(
  uint8_t *b,
  uint8_t *seed_e,
  uint8_t *coins,
  uint16_t *sp_matrix,
  uint16_t *v_matrix
)
{
  uint16_t b_matrix[512U] = { 0U };
  uint16_t epp_matrix[64U] = { 0U };
  frodo_unpack((uint32_t)64U, (uint32_t)8U, (uint32_t)15U, b, b_matrix);
  frodo_sample_matrix((uint32_t)8U,
    (uint32_t)8U,
    (uint32_t)16U,
    seed_e,
    (uint16_t)6U,
    epp_matrix);
  matrix_mul((uint32_t)8U, (uint32_t)64U, (uint32_t)8U, sp_matrix, b_matrix, v_matrix);
  matrix_add((uint32_t)8U, (uint32_t)8U, v_matrix, epp_matrix);
  Lib_Memzero_clear_words_u16((uint32_t)64U, epp_matrix);
  uint16_t mu_encode[64U] = { 0U };
  frodo_key_encode((uint32_t)2U, coins, mu_encode);
  matrix_add((uint32_t)8U, (uint32_t)8U, v_matrix, mu_encode);
}

static inline void crypto_kem_enc_ct(uint8_t *pk, uint8_t *g, uint8_t *coins, uint8_t *ct)
{
  uint8_t *seed_a = pk;
  uint8_t *b = pk + (uint32_t)16U;
  uint8_t *seed_e = g;
  uint8_t *d = g + (uint32_t)32U;
  uint16_t sp_matrix[512U] = { 0U };
  frodo_sample_matrix((uint32_t)8U,
    (uint32_t)64U,
    (uint32_t)16U,
    seed_e,
    (uint16_t)4U,
    sp_matrix);
  uint32_t c1Len = (uint32_t)960U;
  uint32_t c2Len = (uint32_t)120U;
  uint32_t c12Len = c1Len + c2Len;
  uint8_t *c1 = ct;
  uint16_t bp_matrix[512U] = { 0U };
  uint16_t a_matrix[4096U] = { 0U };
  uint16_t ep_matrix[512U] = { 0U };
  frodo_gen_matrix_cshake((uint32_t)64U, (uint32_t)16U, seed_a, a_matrix);
  frodo_sample_matrix((uint32_t)8U,
    (uint32_t)64U,
    (uint32_t)16U,
    seed_e,
    (uint16_t)5U,
    ep_matrix);
  matrix_mul((uint32_t)8U, (uint32_t)64U, (uint32_t)64U, sp_matrix, a_matrix, bp_matrix);
  matrix_add((uint32_t)8U, (uint32_t)64U, bp_matrix, ep_matrix);
  Lib_Memzero_clear_words_u16((uint32_t)512U, ep_matrix);
  frodo_pack((uint32_t)8U, (uint32_t)64U, (uint32_t)15U, bp_matrix, c1);
  uint8_t *c2 = ct + c1Len;
  uint16_t v_matrix[64U] = { 0U };
  frodo_mul_add_sb_plus_e_plus_mu(b, seed_e, coins, sp_matrix, v_matrix);
  frodo_pack((uint32_t)8U, (uint32_t)8U, (uint32_t)15U, v_matrix, c2);
  Lib_Memzero_clear_words_u16((uint32_t)64U, v_matrix);
  memcpy(ct + c12Len, d, (uint32_t)16U * sizeof (d[0U]));
  Lib_Memzero_clear_words_u16((uint32_t)512U, sp_matrix);
}

static inline void crypto_kem_enc_ss(uint8_t *g, uint8_t *ct, uint8_t *ss)
{
  uint32_t ss_init_len = crypto_ciphertextbytes + (uint32_t)16U;
  KRML_CHECK_SIZE(sizeof (uint8_t), ss_init_len);
  uint8_t ss_init[ss_init_len];
  memset(ss_init, 0U, ss_init_len * sizeof (ss_init[0U]));
  uint8_t *c12 = ct;
  uint8_t *kd = g + (uint32_t)16U;
  memcpy(ss_init, c12, (crypto_ciphertextbytes - (uint32_t)16U) * sizeof (c12[0U]));
  memcpy(ss_init + crypto_ciphertextbytes - (uint32_t)16U, kd, (uint32_t)32U * sizeof (kd[0U]));
  uint64_t s[25U] = { 0U };
  s[0U] = (uint64_t)0x10010001a801U | (uint64_t)(uint16_t)7U << (uint32_t)48U;
  Hacl_Impl_SHA3_state_permute(s);
  Hacl_Impl_SHA3_absorb(s, (uint32_t)168U, ss_init_len, ss_init, (uint8_t)0x04U);
  Hacl_Impl_SHA3_squeeze(s, (uint32_t)168U, (uint32_t)16U, ss);
}

uint32_t Hacl_Frodo_KEM_crypto_kem_keypair(uint8_t *pk, uint8_t *sk)
{
  uint8_t coins[48U] = { 0U };
  randombytes_((uint32_t)48U, coins);
  uint8_t *s = coins;
  uint8_t *seed_e = coins + (uint32_t)16U;
  uint8_t *z = coins + (uint32_t)32U;
  uint8_t *seed_a = pk;
  uint64_t s1[25U] = { 0U };
  s1[0U] = (uint64_t)0x10010001a801U | (uint64_t)(uint16_t)0U << (uint32_t)48U;
  Hacl_Impl_SHA3_state_permute(s1);
  Hacl_Impl_SHA3_absorb(s1, (uint32_t)168U, (uint32_t)16U, z, (uint8_t)0x04U);
  Hacl_Impl_SHA3_squeeze(s1, (uint32_t)168U, (uint32_t)16U, seed_a);
  uint8_t *b = pk + (uint32_t)16U;
  uint8_t *s_bytes = sk + (uint32_t)16U + crypto_publickeybytes;
  frodo_mul_add_as_plus_e_pack(seed_a, seed_e, b, s_bytes);
  memcpy(sk, s, (uint32_t)16U * sizeof (s[0U]));
  memcpy(sk + (uint32_t)16U, pk, crypto_publickeybytes * sizeof (pk[0U]));
  return (uint32_t)0U;
}

uint32_t Hacl_Frodo_KEM_crypto_kem_enc(uint8_t *ct, uint8_t *ss, uint8_t *pk)
{
  uint8_t coins[16U] = { 0U };
  randombytes_(bytes_mu, coins);
  uint8_t g[48U] = { 0U };
  uint8_t pk_coins[992U] = { 0U };
  memcpy(pk_coins, pk, crypto_publickeybytes * sizeof (pk[0U]));
  memcpy(pk_coins + crypto_publickeybytes, coins, bytes_mu * sizeof (coins[0U]));
  uint64_t s[25U] = { 0U };
  s[0U] = (uint64_t)0x10010001a801U | (uint64_t)(uint16_t)3U << (uint32_t)48U;
  Hacl_Impl_SHA3_state_permute(s);
  Hacl_Impl_SHA3_absorb(s,
    (uint32_t)168U,
    crypto_publickeybytes + bytes_mu,
    pk_coins,
    (uint8_t)0x04U);
  Hacl_Impl_SHA3_squeeze(s, (uint32_t)168U, (uint32_t)48U, g);
  crypto_kem_enc_ct(pk, g, coins, ct);
  crypto_kem_enc_ss(g, ct, ss);
  Lib_Memzero_clear_words_u8((uint32_t)32U, g);
  return (uint32_t)0U;
}

uint32_t Hacl_Frodo_KEM_crypto_kem_dec(uint8_t *ss, uint8_t *ct, uint8_t *sk)
{
  uint16_t bp_matrix[512U] = { 0U };
  uint16_t c_matrix[64U] = { 0U };
  uint8_t mu_decode[16U] = { 0U };
  uint32_t c1Len = (uint32_t)960U;
  uint8_t *c1 = ct;
  uint8_t *c2 = ct + c1Len;
  frodo_unpack((uint32_t)8U, (uint32_t)64U, (uint32_t)15U, c1, bp_matrix);
  frodo_unpack((uint32_t)8U, (uint32_t)8U, (uint32_t)15U, c2, c_matrix);
  uint8_t *s_bytes = sk + (uint32_t)16U + crypto_publickeybytes;
  uint8_t mu_decode1[16U] = { 0U };
  uint16_t s_matrix[512U] = { 0U };
  uint16_t m_matrix[64U] = { 0U };
  matrix_from_lbytes((uint32_t)64U, (uint32_t)8U, s_bytes, s_matrix);
  matrix_mul_s((uint32_t)8U, (uint32_t)64U, (uint32_t)8U, bp_matrix, s_matrix, m_matrix);
  matrix_sub((uint32_t)8U, (uint32_t)8U, c_matrix, m_matrix);
  frodo_key_decode((uint32_t)2U, m_matrix, mu_decode1);
  uint8_t g[48U] = { 0U };
  uint32_t pk_mu_decode_len = crypto_publickeybytes + bytes_mu;
  KRML_CHECK_SIZE(sizeof (uint8_t), pk_mu_decode_len);
  uint8_t pk_mu_decode[pk_mu_decode_len];
  memset(pk_mu_decode, 0U, pk_mu_decode_len * sizeof (pk_mu_decode[0U]));
  uint8_t *pk0 = sk + (uint32_t)16U;
  memcpy(pk_mu_decode, pk0, crypto_publickeybytes * sizeof (pk0[0U]));
  memcpy(pk_mu_decode + crypto_publickeybytes, mu_decode1, bytes_mu * sizeof (mu_decode1[0U]));
  uint64_t s0[25U] = { 0U };
  s0[0U] = (uint64_t)0x10010001a801U | (uint64_t)(uint16_t)3U << (uint32_t)48U;
  Hacl_Impl_SHA3_state_permute(s0);
  Hacl_Impl_SHA3_absorb(s0, (uint32_t)168U, pk_mu_decode_len, pk_mu_decode, (uint8_t)0x04U);
  Hacl_Impl_SHA3_squeeze(s0, (uint32_t)168U, (uint32_t)48U, g);
  uint8_t *dp = g + (uint32_t)32U;
  uint8_t *d0 = ct + crypto_ciphertextbytes - (uint32_t)16U;
  uint16_t bpp_matrix[512U] = { 0U };
  uint16_t cp_matrix[64U] = { 0U };
  uint8_t *pk = sk + (uint32_t)16U;
  uint8_t *seed_a = pk;
  uint8_t *b = pk + (uint32_t)16U;
  uint8_t *seed_ep = g;
  uint16_t sp_matrix[512U] = { 0U };
  frodo_sample_matrix((uint32_t)8U,
    (uint32_t)64U,
    (uint32_t)16U,
    seed_ep,
    (uint16_t)4U,
    sp_matrix);
  uint16_t a_matrix[4096U] = { 0U };
  uint16_t ep_matrix[512U] = { 0U };
  frodo_gen_matrix_cshake((uint32_t)64U, (uint32_t)16U, seed_a, a_matrix);
  frodo_sample_matrix((uint32_t)8U,
    (uint32_t)64U,
    (uint32_t)16U,
    seed_ep,
    (uint16_t)5U,
    ep_matrix);
  matrix_mul((uint32_t)8U, (uint32_t)64U, (uint32_t)64U, sp_matrix, a_matrix, bpp_matrix);
  matrix_add((uint32_t)8U, (uint32_t)64U, bpp_matrix, ep_matrix);
  Lib_Memzero_clear_words_u16((uint32_t)512U, ep_matrix);
  frodo_mul_add_sb_plus_e_plus_mu(b, seed_ep, mu_decode1, sp_matrix, cp_matrix);
  Lib_Memzero_clear_words_u16((uint32_t)512U, sp_matrix);
  uint8_t res = (uint8_t)255U;
  for (uint32_t i = (uint32_t)0U; i < (uint32_t)16U; i++)
  {
    uint8_t uu____0 = FStar_UInt8_eq_mask(d0[i], dp[i]);
    res = uu____0 & res;
  }
  uint8_t z = res;
  bool b1 = z == (uint8_t)255U;
  bool b2 = matrix_eq((uint32_t)8U, (uint32_t)64U, (uint32_t)15U, bp_matrix, bpp_matrix);
  bool b3 = matrix_eq((uint32_t)8U, (uint32_t)8U, (uint32_t)15U, c_matrix, cp_matrix);
  bool b0 = b1 && b2 && b3;
  bool b4 = b0;
  uint8_t *kp = g + (uint32_t)16U;
  uint8_t *s = sk;
  uint8_t *kp_s;
  if (b4)
  {
    kp_s = kp;
  }
  else
  {
    kp_s = s;
  }
  uint8_t *c12 = ct;
  uint8_t *d = ct + crypto_ciphertextbytes - (uint32_t)16U;
  uint32_t ss_init_len = crypto_ciphertextbytes + (uint32_t)16U;
  KRML_CHECK_SIZE(sizeof (uint8_t), ss_init_len);
  uint8_t ss_init[ss_init_len];
  memset(ss_init, 0U, ss_init_len * sizeof (ss_init[0U]));
  memcpy(ss_init, c12, (crypto_ciphertextbytes - (uint32_t)16U) * sizeof (c12[0U]));
  memcpy(ss_init + crypto_ciphertextbytes - (uint32_t)16U,
    kp_s,
    (uint32_t)16U * sizeof (kp_s[0U]));
  memcpy(ss_init + crypto_ciphertextbytes - (uint32_t)16U + (uint32_t)16U,
    d,
    (uint32_t)16U * sizeof (d[0U]));
  uint64_t s1[25U] = { 0U };
  s1[0U] = (uint64_t)0x10010001a801U | (uint64_t)(uint16_t)7U << (uint32_t)48U;
  Hacl_Impl_SHA3_state_permute(s1);
  Hacl_Impl_SHA3_absorb(s1, (uint32_t)168U, ss_init_len, ss_init, (uint8_t)0x04U);
  Hacl_Impl_SHA3_squeeze(s1, (uint32_t)168U, (uint32_t)16U, ss);
  Lib_Memzero_clear_words_u8((uint32_t)32U, g);
  return (uint32_t)0U;
}

back to top