https://gitlab.com/tezos/tezos
Raw File
Tip revision: 34bbc2e83b7e6eb55d920c825184cc654e259dc4 authored by Ding Xiang Fei on 13 March 2023, 14:13:18 UTC
scan zero tickets
Tip revision: 34bbc2e
bls12_381_polynomial_internal_polynomial.c
/* MIT License
 * Copyright (c) 2022 Nomadic Labs <contact@nomadic-labs.com>
 *
 * 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 "bls12_381_polynomial_internal_polynomial.h"
#include <caml/fail.h>

// IMPROVEME: can be improve it with lookups?
// FIXME: bitreverse is also exported by ocaml-bls12-381. Must be removed.
int bls12_381_polynomial_internal_polynomial_bitreverse_(int n, int l) {
  int r = 0;
  while (l-- > 0) {
    r = (r << 1) | (n & 1);
    n = n >> 1;
  }
  return r;
}

void bls12_381_polynomial_internal_polynomial_reorg_fr_array_coefficients(
    blst_fr *coefficients, int n, int logn) {
  blst_fr tmp;
  for (int i = 0; i < n; i++) {
    int reverse_i =
        bls12_381_polynomial_internal_polynomial_bitreverse_(i, logn);
    if (i < reverse_i) {
      memcpy(&tmp, coefficients + i, sizeof(blst_fr));
      memcpy(coefficients + i, coefficients + reverse_i, sizeof(blst_fr));
      memcpy(coefficients + reverse_i, &tmp, sizeof(blst_fr));
    }
  }
}

void bls12_381_polynomial_internal_polynomial_fft_inplace_aux(
    blst_fr *coefficients, blst_fr *domain, int log_domain_size, int log_diff,
    int inverse_domain) {
  int domain_size = 1 << log_domain_size;
  int m = 1 << log_diff;
  blst_fr tmp;
  int exponent;
  int k;
  int domain_idx;
  for (int i = 0; i < log_domain_size - log_diff; i++) {
    int exponent = domain_size / (2 * m);
    for (int k = 0; k < domain_size; k += (2 * m)) {
      for (int j = 0; j < m; j++) {
        if (inverse_domain == 0) {
          domain_idx = exponent * j;
        } else {
          domain_idx = domain_size - (exponent * j);
        };
        if (domain_idx == domain_size) {
          domain_idx = 0;
        };
        blst_fr_mul(&tmp, coefficients + (k + j + m), domain + domain_idx);
        blst_fr_sub(coefficients + (k + j + m), coefficients + (k + j), &tmp);
        blst_fr_add(coefficients + (k + j), coefficients + (k + j), &tmp);
      }
    }
    m = 2 * m;
  }
}

void bls12_381_polynomial_internal_polynomial_fft_inplace(blst_fr *coefficients,
                                                          blst_fr *domain,
                                                          int log_domain_size,
                                                          int degree,
                                                          int log_degree) {
  int domain_size = 1 << log_domain_size;
  int degree_next_pow_of_2 = 1 << log_degree;
  int log_diff;

  if (domain_size > degree) {
    bls12_381_polynomial_internal_polynomial_reorg_fr_array_coefficients(
        coefficients, degree_next_pow_of_2, log_degree);
    int ratio = domain_size / degree_next_pow_of_2;
    blst_fr *cp = malloc(sizeof(blst_fr) * degree_next_pow_of_2);
    if (cp == NULL) {
      caml_raise_out_of_memory();
    }
    memcpy(cp, coefficients, sizeof(blst_fr) * degree_next_pow_of_2);
    for (int i = 0; i < degree_next_pow_of_2; i++) {
      for (int j = 0; j < ratio; j++) {
        memcpy(coefficients + (i * ratio) + j, cp + i, sizeof(blst_fr));
      }
    }
    log_diff = log_domain_size - log_degree;
    free(cp);
  } else {
    bls12_381_polynomial_internal_polynomial_reorg_fr_array_coefficients(
        coefficients, domain_size, log_domain_size);
    log_diff = 0;
  }
  bls12_381_polynomial_internal_polynomial_fft_inplace_aux(
      coefficients, domain, log_domain_size, log_diff, 0);
}

void bls12_381_polynomial_internal_polynomial_ifft_inplace(
    blst_fr *coefficients, blst_fr *domain, int log_domain_size) {
  int domain_size = 1 << log_domain_size;
  uint64_t n[4] = {domain_size, 0, 0, 0};
  blst_fr inverse_n;

  bls12_381_polynomial_internal_polynomial_reorg_fr_array_coefficients(
      coefficients, domain_size, log_domain_size);
  bls12_381_polynomial_internal_polynomial_fft_inplace_aux(
      coefficients, domain, log_domain_size, 0, 1);

  blst_fr_from_uint64(&inverse_n, n);
  blst_fr_inverse(&inverse_n, &inverse_n);
  for (int i = 0; i < domain_size; i++) {
    blst_fr_mul(coefficients + i, coefficients + i, &inverse_n);
  }
}

void bls12_381_polynomial_internal_polynomial_dft_inplace(blst_fr *coefficients,
                                                          blst_fr *domain,
                                                          blst_fr *buffer,
                                                          int length,
                                                          int inverse) {
  // We copy the coefficients to the buffer to modify the coefficients
  // in-place
  memcpy(buffer, coefficients, length * sizeof(blst_fr));
  blst_fr tmp;
  for (int i = 0; i < length; i++) {
    blst_fr_set_to_zero(coefficients + i);
    for (int j = 0; j < length; j++) {
      int idx = ((i * j) % length);
      if (inverse && (idx != 0)) {
        idx = length - idx;
      }
      blst_fr_mul(&tmp, buffer + j, domain + (idx));
      blst_fr_add(coefficients + i, coefficients + i, &tmp);
    }
  }
  if (inverse) {
    blst_fr inv_n, n;
    blst_fr_from_uint64(&n, (uint64_t[4]){length, 0, 0, 0});
    blst_fr_inverse(&inv_n, &n);
    for (int i = 0; i < length; i++) {
      blst_fr_mul(coefficients + i, coefficients + i, &inv_n);
    }
  }
}

int bls12_381_polynomial_internal_polynomial_is_power_of_two(int n) {
  return (n & (n - 1)) == 0;
}

int bls12_381_polynomial_internal_polynomial_log2(int n) {
  int l = 0;
  while (n >>= 1) {
    ++l;
  }
  return l;
}

void bls12_381_polynomial_internal_polynomial_transpose(blst_fr *rows,
                                                        blst_fr *columns,
                                                        int n1, int n2) {
  for (int i = 0; i < n1; i++) {
    for (int j = 0; j < n2; j++) {
      rows[j * n1 + i] = columns[j + i * n2];
    }
  }
}

int bls12_381_polynomial_internal_polynomial_max(int a, int b) {
  return a >= b ? a : b;
}

void bls12_381_polynomial_internal_polynomial_fft_round(
    blst_fr *buffer, blst_fr *domain1, blst_fr *domain2, int length1,
    int length2, blst_fr *buffer_dft, int inverse) {
  if (bls12_381_polynomial_internal_polynomial_is_power_of_two(length2)) {
    int length2_log = bls12_381_polynomial_internal_polynomial_log2(length2);
    if (inverse) {
      for (int i = 0; i < length1; i++) {
        bls12_381_polynomial_internal_polynomial_ifft_inplace(
            buffer + (i * length2), domain2, length2_log);
      }

    } else {
      for (int i = 0; i < length1; i++) {
        bls12_381_polynomial_internal_polynomial_fft_inplace(
            buffer + (i * length2), domain2, length2_log, length2, length2_log);
      }
    }
  } else {
    for (int i = 0; i < length1; i++) {
      bls12_381_polynomial_internal_polynomial_dft_inplace(
          buffer + (i * length2), domain2, buffer_dft, length2, inverse);
    }
  }
}

// The buffer must have size at least 2 * |domain1| * |domain2|
void bls12_381_polynomial_internal_polynomial_prime_factor_algorithm_fft(
    blst_fr *coefficients, blst_fr *domain1, blst_fr *domain2, int length1,
    int length2, int inverse) {
  int dft_length =
      (!bls12_381_polynomial_internal_polynomial_is_power_of_two(length1) &&
       !bls12_381_polynomial_internal_polynomial_is_power_of_two(length2))
          ? bls12_381_polynomial_internal_polynomial_max(length1, length2)
          : (bls12_381_polynomial_internal_polynomial_is_power_of_two(length1)
                 ? length2
                 : length1);
  // We allocate buffer_dft on the stack because dft_length is <= 2^10 at most
  // in our use case
  blst_fr buffer_dft[dft_length];
  int length = length1 * length2;

  blst_fr *buffer = malloc(2 * length * sizeof(blst_fr));
  if (buffer == NULL) {
    caml_raise_out_of_memory();
  }

  for (int i = 0; i < length; i++) {
    buffer[(i % length1) * length2 + (i % length2)] = coefficients[i];
  }

  bls12_381_polynomial_internal_polynomial_fft_round(
      buffer, domain1, domain2, length1, length2, buffer_dft, inverse);

  blst_fr *new_buffer = buffer + length;

  bls12_381_polynomial_internal_polynomial_transpose(new_buffer, buffer,
                                                     length1, length2);

  bls12_381_polynomial_internal_polynomial_fft_round(
      new_buffer, domain2, domain1, length2, length1, buffer_dft, inverse);

  for (int i = 0; i < length1; i++) {
    for (int j = 0; j < length2; j++) {
      coefficients[(length1 * j + length2 * i) % length] =
          new_buffer[j * length1 + i];
    }
  }

  free(buffer);
}

void bls12_381_polynomial_internal_polynomial_add(blst_fr *res, blst_fr *poly_1,
                                                  blst_fr *poly_2,
                                                  const int size_1,
                                                  const int size_2) {
  if (size_1 >= size_2) {
    for (int i = 0; i < size_2; i++) {
      blst_fr_add(res + i, poly_1 + i, poly_2 + i);
    };
    for (int i = size_2; i < size_1; i++) {
      memcpy(res + i, poly_1 + i, sizeof(blst_fr));
    };
  } else {
    for (int i = 0; i < size_1; i++) {
      blst_fr_add(res + i, poly_1 + i, poly_2 + i);
    };
    for (int i = size_1; i < size_2; i++) {
      memcpy(res + i, poly_2 + i, sizeof(blst_fr));
    };
  }
}

void bls12_381_polynomial_internal_polynomial_sub(blst_fr *res, blst_fr *poly_1,
                                                  blst_fr *poly_2,
                                                  const int size_1,
                                                  const int size_2) {
  if (size_1 >= size_2) {
    for (int i = 0; i < size_2; i++) {
      blst_fr_sub(res + i, poly_1 + i, poly_2 + i);
    };
    for (int i = size_2; i < size_1; i++) {
      memcpy(res + i, poly_1 + i, sizeof(blst_fr));
    };
  } else {
    for (int i = 0; i < size_1; i++) {
      blst_fr_sub(res + i, poly_1 + i, poly_2 + i);
    };
    for (int i = size_1; i < size_2; i++) {
      blst_fr_cneg(res + i, poly_2 + i, 1);
    };
  }
}

void bls12_381_polynomial_internal_polynomial_mul(blst_fr *res,
                                                  const blst_fr *poly_1,
                                                  const blst_fr *poly_2,
                                                  const int size_1,
                                                  const int size_2) {
  blst_fr tmp;
  for (int i = 0; i < size_1; i++) {
    for (int j = 0; j < size_2; j++) {
      blst_fr_mul(&tmp, poly_1 + i, poly_2 + j);
      blst_fr_add(res + i + j, res + i + j, &tmp);
    }
  }
}

void bls12_381_polynomial_internal_polynomial_mul_by_scalar(blst_fr *res,
                                                            blst_fr *scalar,
                                                            blst_fr *arg,
                                                            int size) {
  for (int i = 0; i < size; i++) {
    blst_fr_mul(res + i, arg + i, scalar);
  };
}

// res is initialized with blst-fr zeros
void bls12_381_polynomial_internal_polynomial_linear(blst_fr *res,
                                                     blst_fr **polynomials,
                                                     int *polynomials_len,
                                                     blst_fr *linear_coeffs,
                                                     int nb_polys) {
  int poly_len_j;
  blst_fr tmp;

  poly_len_j = polynomials_len[0];
  for (int i = 0; i < poly_len_j; i++) {
    blst_fr_mul(res + i, polynomials[0] + i, linear_coeffs);
  }

  for (int j = 1; j < nb_polys; j++) {
    poly_len_j = polynomials_len[j];
    for (int i = 0; i < poly_len_j; i++) {
      blst_fr_mul(&tmp, polynomials[j] + i, linear_coeffs + j);
      blst_fr_add(res + i, res + i, &tmp);
    }
  }
}

// res is initialized with blst-fr zeros
// p_0 + s * p_1 + s^2 * p_2 + ... + s^n * p_n =
// (..((p_n * s) + p_{n-1}) * s + .. + p_1) * s + p_0
void bls12_381_polynomial_internal_polynomial_linear_with_powers_horner(
    blst_fr *res, blst_fr **polynomials, int *polynomials_len,
    blst_fr *linear_coeff, int nb_polys) {
  int poly_len_j;
  int max_len;
  blst_fr tmp;

  poly_len_j = polynomials_len[nb_polys - 1];
  max_len = poly_len_j;
  for (int i = 0; i < poly_len_j; i++) {
    memcpy(res + i, polynomials[nb_polys - 1] + i, sizeof(blst_fr));
  }

  for (int j = nb_polys - 2; j >= 0; j--) {
    for (int i = 0; i < max_len; i++) {
      blst_fr_mul(res + i, res + i, linear_coeff);
    }
    poly_len_j = polynomials_len[j];
    max_len = max_len < poly_len_j ? poly_len_j : max_len;
    for (int i = 0; i < poly_len_j; i++) {
      blst_fr_add(res + i, res + i, polynomials[j] + i);
    }
  }
}

// res is initialized with blst-fr zeros
// p_0 + s * p_1 + s^2 * p_2 + ... + s^n * p_n
void bls12_381_polynomial_internal_polynomial_linear_with_powers_naive(
    blst_fr *res, blst_fr **polynomials, int *polynomials_len,
    blst_fr *linear_coeff, int nb_polys) {
  int poly_len_j;
  blst_fr tmp;
  blst_fr coeff_j;

  poly_len_j = polynomials_len[0];
  for (int i = 0; i < poly_len_j; i++) {
    memcpy(res + i, polynomials[0] + i, sizeof(blst_fr));
  }

  memcpy(&coeff_j, linear_coeff, sizeof(blst_fr));
  for (int j = 1; j < nb_polys; j++) {
    poly_len_j = polynomials_len[j];
    for (int i = 0; i < poly_len_j; i++) {
      blst_fr_mul(&tmp, polynomials[j] + i, &coeff_j);
      blst_fr_add(res + i, res + i, &tmp);
    }
    blst_fr_mul(&coeff_j, &coeff_j, linear_coeff);
  }
}

void bls12_381_polynomial_internal_polynomial_linear_with_powers(
    blst_fr *res, blst_fr **polynomials, int *polynomials_len,
    blst_fr *linear_coeff, int nb_polys) {

  int poly_len_i = polynomials_len[0];
  int max_len = poly_len_i;
  int min_len = poly_len_i;

  for (int i = 1; i < nb_polys; i++) {
    poly_len_i = polynomials_len[i];
    max_len = max_len < poly_len_i ? poly_len_i : max_len;
    min_len = poly_len_i < min_len ? poly_len_i : min_len;
  }

  if (max_len != min_len) {
    bls12_381_polynomial_internal_polynomial_linear_with_powers_naive(
        res, polynomials, polynomials_len, linear_coeff, nb_polys);
  } else {
    bls12_381_polynomial_internal_polynomial_linear_with_powers_horner(
        res, polynomials, polynomials_len, linear_coeff, nb_polys);
  }
}

void bls12_381_polynomial_internal_polynomial_negate(blst_fr *res, blst_fr *arg,
                                                     int size) {
  for (int i = 0; i < size; i++) {
    blst_fr_cneg(res + i, arg + i, 1);
  };
}

void bls12_381_polynomial_internal_polynomial_evaluate(blst_fr *res,
                                                       const blst_fr *arg,
                                                       const int size,
                                                       const blst_fr *scalar) {
  *res = *(arg + size - 1);
  for (int i = size - 2; i >= 0; i--) {
    blst_fr_mul(res, res, scalar);
    blst_fr_add(res, res, arg + i);
  };
}

// poly / (X^n + 1), size > n
void bls12_381_polynomial_internal_polynomial_division_xn_one(
    blst_fr *res_q, blst_fr *res_r, const blst_fr *poly, const int size,
    const int n) {

  if (size >= 2 * n) {
    for (int i = size - 2 * n; i < size - n; i++) {
      memcpy(res_q + i, poly + i + n, sizeof(blst_fr));
    };

    for (int i = size - 2 * n - 1; i >= 0; i--) {
      blst_fr_sub(res_q + i, poly + i + n, res_q + i + n);
    };

    // remainder
    for (int i = 0; i < n; i++) {
      blst_fr_sub(res_r + i, poly + i, res_q + i);
    };
  } else {
    for (int i = 0; i < size - n; i++) {
      memcpy(res_q + i, poly + i + n, sizeof(blst_fr));
    };

    // remainder
    for (int i = 0; i < size - n; i++) {
      blst_fr_sub(res_r + i, poly + i, res_q + i);
    };

    for (int i = size - n; i < n; i++) {
      memcpy(res_r + i, poly + i, sizeof(blst_fr));
    };
  }
}

// poly / (X^n - 1), size > n
void bls12_381_polynomial_internal_polynomial_division_xn_minus_one(
    blst_fr *res_q, blst_fr *res_r, const blst_fr *poly, const int size,
    const int n) {

  if (size >= 2 * n) {
    for (int i = size - 2 * n; i < size - n; i++) {
      memcpy(res_q + i, poly + i + n, sizeof(blst_fr));
    };

    for (int i = size - 2 * n - 1; i >= 0; i--) {
      blst_fr_add(res_q + i, poly + i + n, res_q + i + n);
    };

    // remainder
    for (int i = 0; i < n; i++) {
      blst_fr_add(res_r + i, poly + i, res_q + i);
    };
  } else {
    for (int i = 0; i < size - n; i++) {
      memcpy(res_q + i, poly + i + n, sizeof(blst_fr));
    };

    // remainder
    for (int i = 0; i < size - n; i++) {
      blst_fr_add(res_r + i, poly + i, res_q + i);
    };

    for (int i = size - n; i < n; i++) {
      memcpy(res_r + i, poly + i, sizeof(blst_fr));
    };
  }
}

// poly / (X^n + scalar), size > n
void bls12_381_polynomial_internal_polynomial_division_xn(
    blst_fr *res_q, blst_fr *res_r, const blst_fr *poly, const int size,
    const int n, const blst_fr *scalar) {

  blst_fr minus_one;
  blst_fr_set_to_one(&minus_one);
  blst_fr_cneg(&minus_one, &minus_one, 1);

  if (blst_fr_is_equal(scalar, &minus_one)) {
    bls12_381_polynomial_internal_polynomial_division_xn_minus_one(
        res_q, res_r, poly, size, n);
    return;
  };

  if (blst_fr_is_one(scalar)) {
    bls12_381_polynomial_internal_polynomial_division_xn_one(res_q, res_r, poly,
                                                             size, n);
    return;
  };

  blst_fr tmp;
  if (size >= 2 * n) {
    for (int i = size - 2 * n; i < size - n; i++) {
      memcpy(res_q + i, poly + i + n, sizeof(blst_fr));
    };

    for (int i = size - 2 * n - 1; i >= 0; i--) {
      blst_fr_mul(&tmp, scalar, res_q + i + n);
      blst_fr_sub(res_q + i, poly + i + n, &tmp);
    };

    // remainder
    for (int i = 0; i < n; i++) {
      blst_fr_mul(&tmp, scalar, res_q + i);
      blst_fr_sub(res_r + i, poly + i, &tmp);
    };
  } else {
    for (int i = 0; i < size - n; i++) {
      memcpy(res_q + i, poly + i + n, sizeof(blst_fr));
    };

    // remainder
    for (int i = 0; i < size - n; i++) {
      blst_fr_mul(&tmp, scalar, res_q + i);
      blst_fr_sub(res_r + i, poly + i, &tmp);
    };

    for (int i = size - n; i < n; i++) {
      memcpy(res_r + i, poly + i, sizeof(blst_fr));
    };
  }
}

// poly * (X^n + 1)
// res is initialized with blst-fr zeros
void bls12_381_polynomial_internal_polynomial_mul_xn_one(blst_fr *res,
                                                         const blst_fr *poly,
                                                         const int size,
                                                         const int n) {

  if (size >= n) {
    for (int i = 0; i < n; i++) {
      memcpy(res + i, poly + i, sizeof(blst_fr));
    };

    for (int i = n; i < size; i++) {
      blst_fr_add(res + i, poly + i - n, poly + i);
    };

    for (int i = size; i < size + n; i++) {
      memcpy(res + i, poly + i - n, sizeof(blst_fr));
    };
  } else {
    for (int i = 0; i < size; i++) {
      memcpy(res + i, poly + i, sizeof(blst_fr));
    };
    // res[i] = 0 for i is in [size; n)
    for (int i = n; i < size + n; i++) {
      memcpy(res + i, poly + i - n, sizeof(blst_fr));
    };
  }
}

// poly * (X^n - 1)
// res is initialized with blst-fr zeros
void bls12_381_polynomial_internal_polynomial_mul_xn_minus_one(
    blst_fr *res, const blst_fr *poly, const int size, const int n) {

  if (size >= n) {
    for (int i = 0; i < n; i++) {
      blst_fr_cneg(res + i, poly + i, 1);
    };

    for (int i = n; i < size; i++) {
      blst_fr_sub(res + i, poly + i - n, poly + i);
    };

    for (int i = size; i < size + n; i++) {
      memcpy(res + i, poly + i - n, sizeof(blst_fr));
    };
  } else {
    for (int i = 0; i < size; i++) {
      blst_fr_cneg(res + i, poly + i, 1);
    };
    // res[i] = 0 for i is in [size; n)
    for (int i = n; i < size + n; i++) {
      memcpy(res + i, poly + i - n, sizeof(blst_fr));
    };
  }
}

// poly * (X^n + scalar)
// res is initialized with blst-fr zeros
void bls12_381_polynomial_internal_polynomial_mul_xn(blst_fr *res,
                                                     const blst_fr *poly,
                                                     const int size,
                                                     const int n,
                                                     const blst_fr *scalar) {

  blst_fr minus_one;
  blst_fr_set_to_one(&minus_one);
  blst_fr_cneg(&minus_one, &minus_one, 1);

  if (blst_fr_is_equal(scalar, &minus_one)) {
    bls12_381_polynomial_internal_polynomial_mul_xn_minus_one(res, poly, size,
                                                              n);
    return;
  };

  if (blst_fr_is_one(scalar)) {
    bls12_381_polynomial_internal_polynomial_mul_xn_one(res, poly, size, n);
    return;
  };

  blst_fr tmp;
  if (size >= n) {
    for (int i = 0; i < n; i++) {
      blst_fr_mul(res + i, scalar, poly + i);
    };

    for (int i = n; i < size; i++) {
      blst_fr_mul(&tmp, scalar, poly + i);
      blst_fr_add(res + i, poly + i - n, &tmp);
    };

    for (int i = size; i < size + n; i++) {
      memcpy(res + i, poly + i - n, sizeof(blst_fr));
    };
  } else {
    for (int i = 0; i < size; i++) {
      blst_fr_mul(res + i, scalar, poly + i);
    };
    // res[i] = 0 for i is in [size; n)
    for (int i = n; i < size + n; i++) {
      memcpy(res + i, poly + i - n, sizeof(blst_fr));
    };
  }
}

void bls12_381_polynomial_internal_polynomial_evaluations_add(
    blst_fr *res, blst_fr *eval_1, blst_fr *eval_2, int size_1, int size_2) {
  int size_res = size_2 >= size_1 ? size_1 : size_2;
  int step1 = size_1 / size_res;
  int step2 = size_2 / size_res;

  for (int i = 0; i < size_res; i++) {
    blst_fr_add(res + i, eval_1 + i * step1, eval_2 + i * step2);
  };
}

void bls12_381_polynomial_internal_polynomial_evaluations_rescale(
    blst_fr *res, blst_fr *eval, int size_res, int size_eval) {
  int step = size_eval / size_res;

  for (int i = 0; i < size_res; i++) {
    memcpy(res + i, eval + i * step, sizeof(blst_fr));
  };
}

void bls12_381_polynomial_internal_polynomial_evaluations_mul_arrays(
    blst_fr *res, blst_fr **evaluations, int *evaluations_len,
    int *composition_gx, byte **powers, int *powers_numbits, int size_res,
    int nb_evals) {
  int ind;
  int eval_len_j;
  int step_j;
  int composition_gx_j;
  int exp_pow_len_j;
  blst_fr tmp;

  eval_len_j = evaluations_len[0];
  step_j = eval_len_j / size_res;
  composition_gx_j = composition_gx[0];
  exp_pow_len_j = powers_numbits[0];

  for (int i = 0; i < size_res; i++) {
    ind = (i + composition_gx_j) * step_j % eval_len_j;
    blst_fr_pow(res + i, evaluations[0] + ind, powers[0], exp_pow_len_j);
  };

  for (int j = 1; j < nb_evals; j++) {
    eval_len_j = evaluations_len[j];
    step_j = eval_len_j / size_res;
    composition_gx_j = composition_gx[j];
    exp_pow_len_j = powers_numbits[j];

    for (int i = 0; i < size_res; i++) {
      ind = (i + composition_gx_j) * step_j % eval_len_j;
      blst_fr_pow(&tmp, evaluations[j] + ind, powers[j], exp_pow_len_j);
      blst_fr_mul(res + i, res + i, &tmp);
    }
  }
}

void bls12_381_polynomial_internal_polynomial_evaluations_linear_arrays(
    blst_fr *res, blst_fr **evaluations, int *evaluations_len,
    blst_fr *linear_coeffs, int *composition_gx, blst_fr *add_constant,
    int size_res, int nb_evals) {

  int ind;
  int eval_len_j;
  int step_j;
  int composition_gx_j;
  blst_fr tmp;

  blst_fr minus_one;
  blst_fr_set_to_one(&minus_one);
  blst_fr_cneg(&minus_one, &minus_one, 1);

  for (int i = 0; i < size_res; i++) {
    memcpy(res + i, add_constant, sizeof(blst_fr));
  };

  for (int j = 0; j < nb_evals; j++) {
    eval_len_j = evaluations_len[j];
    step_j = eval_len_j / size_res;
    composition_gx_j = composition_gx[j];

    if (blst_fr_is_one(linear_coeffs + j)) {
      for (int i = 0; i < size_res; i++) {
        ind = (i + composition_gx_j) * step_j % eval_len_j;
        blst_fr_add(res + i, res + i, evaluations[j] + ind);
      }
    } else {
      if (blst_fr_is_equal(linear_coeffs + j, &minus_one)) {
        for (int i = 0; i < size_res; i++) {
          ind = (i + composition_gx_j) * step_j % eval_len_j;
          blst_fr_sub(res + i, res + i, evaluations[j] + ind);
        }
      } else {
        for (int i = 0; i < size_res; i++) {
          ind = (i + composition_gx_j) * step_j % eval_len_j;
          blst_fr_mul(&tmp, linear_coeffs + j, evaluations[j] + ind);
          blst_fr_add(res + i, res + i, &tmp);
        }
      }
    }
  }
}

void bls12_381_polynomial_internal_polynomial_derivative(blst_fr *res,
                                                         blst_fr *poly,
                                                         const int size) {
  blst_fr scalar;
  uint64_t n[4] = {0};
  for (int i = 1; i < size; i++) {
    n[0] = i;
    blst_fr_from_uint64(&scalar, n);
    blst_fr_mul(res + (i - 1), &scalar, poly + i);
  };
}
back to top