packages feed

KpqC-0.1.0: cbits/third_party/AIMer/aim3.c

// SPDX-License-Identifier: MIT

#include "aim3.h"
#include "field.h"
#include "hash.h"
#include "params.h"
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>

static void squeeze_invertible_matrix(hash_instance *ctx,
                                      gf mat[AIM3_NUM_BITS_FIELD])
{
  uint8_t buf[AIM3_NUM_BYTES_FIELD];
  uint64_t ormask, lmask, umask;

  gf matrix_L[AIM3_NUM_BITS_FIELD];
  gf matrix_U[AIM3_NUM_BITS_FIELD];
  gf temp = {0,};

  for (size_t row = 0; row < AIM3_NUM_BITS_FIELD; row++)
  {
    hash_squeeze(ctx, buf, AIM3_NUM_BYTES_FIELD);
    gf_from_bytes(temp, buf);

    ormask = ((uint64_t)1) << (row % 64);
    lmask = ((uint64_t)-1) << (row % 64);
    umask = ~lmask;

    size_t inter = row / 64;
    size_t col_word;
    for (col_word = 0; col_word < inter; col_word++)
    {
      // L is zero, U is full
      matrix_L[row][col_word] = 0;
      matrix_U[row][col_word] = temp[col_word];
    }
    matrix_L[row][inter] = (temp[inter] & lmask) | ormask;
    matrix_U[row][inter] = (temp[inter] & umask) | ormask;
    for (col_word = inter + 1; col_word < AIM3_NUM_WORDS_FIELD; col_word++)
    {
      // L is full, U is zero
      matrix_L[row][col_word] = temp[col_word];
      matrix_U[row][col_word] = 0;
    }
  }

  for (size_t i = 0; i < AIM3_NUM_BITS_FIELD; i++)
  {
    gf_mat_vec_mul(mat[i], matrix_U[i], (const gf *)matrix_L);
  }
}

void aim3_generate_linear(aim_lin_t *lin, const uint8_t iv[AIM3_IV_SIZE])
{
  hash_instance ctx;

  hash_init(&ctx);
  hash_update(&ctx, iv, AIM3_IV_SIZE);
  hash_final(&ctx);

  for (size_t ell = 0; ell < 2 * AIM3_NUM_INPUT_SBOX; ell++)
  {
    squeeze_invertible_matrix(&ctx, lin->mat_A[ell]);
  }

  for (size_t ell = 0; ell < AIM3_NUM_INPUT_SBOX + 1; ell++)
  {
    hash_squeeze(&ctx, (uint8_t *)lin->vec_b[ell], AIM3_NUM_BYTES_FIELD);
  }
  hash_ctx_release(&ctx);
}

int aim3_nozeroinpsb(uint8_t ct[AIM3_NUM_BYTES_FIELD],
                     const uint8_t pt[AIM3_NUM_BYTES_FIELD],
                     const uint8_t iv[AIM3_IV_SIZE])
{
  aim_lin_t *lin = (aim_lin_t *)malloc(sizeof(aim_lin_t));
  if (lin == NULL)
  {
    // allocation failure
    return -2;
  }

  gf state[AIM3_NUM_INPUT_SBOX];
  gf pt_gf = {0,}, ct_gf = {0,}, tmp = {0,};
  gf_from_bytes(pt_gf, pt);

  // generate random matrix
  aim3_generate_linear(lin, iv);

  for (size_t i = 0; i < AIM3_NUM_INPUT_SBOX; i++)
  {
    // linear component: affine layer
    gf_mat_vec_mul(state[i], pt_gf, lin->mat_A[i]);
    gf_add(state[i], state[i], lin->vec_b[i]);

    // non-linear component: y = x^{2^e-1} + x^{-1} = x^{-1} * (x^2^e + 1)
    if (gf_is0(state[i]))
    {
      free(lin);
      return -1;
    }
    gf_inv(tmp, state[i]);
    for (size_t e = 0; e < aim3_exponents[i]; e++)
    {
      gf_sqr(state[i], state[i]);
    }
    state[i][0] ^= 1;
    gf_mul(state[i], state[i], tmp);

    // linear component: affine layer
    gf_mat_vec_mul(state[i], state[i],
                   (const gf *)lin->mat_A[i + AIM3_NUM_INPUT_SBOX]);
  }

  for (size_t i = 1; i < AIM3_NUM_INPUT_SBOX; i++)
  {
    gf_add(state[0], state[0], state[i]);
  }
  gf_add(state[0], state[0], lin->vec_b[AIM3_NUM_INPUT_SBOX]);

  // non-linear component: y = x^{2^e-1} + x^{-1} = x^{-1} * (x^2^e + 1)
  if (gf_is0(state[0]))
  {
    free(lin);
    return -1;
  }
  gf_inv(tmp, state[0]);
  for (size_t e = 0; e < aim3_exponents[AIM3_NUM_INPUT_SBOX]; e++)
  {
    gf_sqr(state[0], state[0]);
  }
  state[0][0] ^= 1;
  gf_mul(state[0], state[0], tmp);

  // linear component: feed-forward
  gf_add(ct_gf, pt_gf, state[0]);

  gf_to_bytes(ct, ct_gf);

  free(lin);
  return 0;
}

void aim3_sbox_outputs(gf sbox_outputs[AIM3_NUM_INPUT_SBOX+1],
                       const aim_lin_t* lin,
                       const gf pt, const gf ct)
{
  gf tmp = {0,};
  for (size_t i = 0; i < AIM3_NUM_INPUT_SBOX; i ++)
  {
    // linear component: affine layer
    gf_mat_vec_mul(sbox_outputs[i], pt, lin->mat_A[i]);
    gf_add(sbox_outputs[i], sbox_outputs[i], lin->vec_b[i]);

    // non-linear component: y = x^{2^e-1} + x^{-1} = x^{-1} * (x^2^e + 1)
    gf_inv(tmp, sbox_outputs[i]);
    for (size_t e = 0; e < aim3_exponents[i]; e++)
    {
      gf_sqr(sbox_outputs[i], sbox_outputs[i]);
    }
    sbox_outputs[i][0] ^= 1;
    gf_mul(sbox_outputs[i], sbox_outputs[i], tmp);
  }
  gf_add(sbox_outputs[AIMER_L], pt, ct);
}

void aim3_mpc(mult_chk_t *mult_chk, const aim_lin_t *lin,
              const tape_t *tape, const gf ct_gf,
              size_t party)
{
  for (size_t i = 0; i < AIMER_L + 1; i++)
  {
    gf_copy(mult_chk->a_shares[i], tape->a_shares[i]);
  }

  // b_shares[i] = share of sbox outputs
  for (size_t i = 0; i < AIMER_L; i++)
  {
    gf_copy(mult_chk->b_shares[i], tape->y_shares[i]);
  }
  gf_copy(mult_chk->b_shares[AIMER_L], tape->pt_share);
  if (party == AIMER_N - 1)
  {
    gf_add(mult_chk->b_shares[AIMER_L], mult_chk->b_shares[AIMER_L], ct_gf);
  }

  gf_copy(mult_chk->c_share, tape->c_share);

  // Set x_shares (= share of sbox inputs)
  for (size_t i = 0; i < AIMER_L; i++)
  {
    gf_mat_vec_mul(mult_chk->x_shares[i], tape->pt_share, lin->mat_A[i]);
    if (party == AIMER_N - 1)
    {
      gf_add(mult_chk->x_shares[i], mult_chk->x_shares[i], lin->vec_b[i]);
    }
  }

  gf_set0(mult_chk->x_shares[AIMER_L]);
  for (size_t ell = 0; ell < AIMER_L; ell++)
  {
    gf_mat_vec_mul_add(mult_chk->x_shares[AIMER_L], tape->y_shares[ell],
                       lin->mat_A[ell+AIMER_L]);
  }
  if (party == AIMER_N - 1)
  {
    gf_add(mult_chk->x_shares[AIMER_L], mult_chk->x_shares[AIMER_L],
           lin->vec_b[AIMER_L]);
  }

  // Set z_shares: z[i] = x[i]^{2^e} + 1
  // y = x^{-1} + x^{2^e-1} -> xy = x^{2^e} + 1
  for (size_t ell = 0; ell < AIMER_L + 1; ell++)
  {
    gf_sqr(mult_chk->z_shares[ell], mult_chk->x_shares[ell]);
    for (size_t i = 1; i < aim3_exponents[ell]; i++)
    {
      gf_sqr(mult_chk->z_shares[ell], mult_chk->z_shares[ell]);
    }
    if (party == AIMER_N - 1)
    {
      mult_chk->z_shares[ell][0] ^= 1;
    }
  }
}