Commit ac79afd5 authored by Robert Helmer's avatar Robert Helmer
Browse files

Bug 1539715 - update vendored libprio to 1.5 r=glandium

Differential Revision: https://phabricator.services.mozilla.com/D25192

--HG--
extra : moz-landing-system : lando
parent f648e66f
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
This directory contains the Prio source from the upstream repo:
https://github.com/mozilla/libprio

Current version: 1.4 [commit a95cfdd5eaf7104582709c54ef23395d24d7f7fd]
Current version: 1.5 [commit cfecb2cc84789b9c5b2119109c5212bb297f2724]

UPDATING:

+5 −45
Original line number Diff line number Diff line
@@ -15,42 +15,6 @@
#include "rand.h"
#include "util.h"

// The PrioConfig object stores "2^k-th roots of unity" modulo
// the prime modulus we use for all arithmetic. We use
// these roots to perform fast FFT-style polynomial
// interpolation and evaluation.
//
// In particular, we use a prime modulus p such that
//    p = (2^k)q + 1.
// The roots are integers such that r^{2^k} = 1 mod p.
static SECStatus
initialize_roots(MPArray arr, const char values[], bool inverted)
{
  // TODO: Read in only the number of roots of unity we need.
  // Right now we read in all 4096 roots whether or not we use
  // them all.
  MP_CHECK(mp_read_radix(&arr->data[0], &values[0], 16));
  unsigned int len = arr->len;
  unsigned int n_chars = len * RootWidth;

  if (n_chars != sizeof(Roots)) {
    return SECFailure;
  }

  if (inverted) {
    for (unsigned int i = n_chars - RootWidth, j = 1; i > 0;
         i -= RootWidth, j++) {
      MP_CHECK(mp_read_radix(&arr->data[j], &values[i], 16));
    }
  } else {
    for (unsigned int i = RootWidth, j = 1; i < n_chars; i += RootWidth, j++) {
      MP_CHECK(mp_read_radix(&arr->data[j], &values[i], 16));
    }
  }

  return SECSuccess;
}

int
PrioConfig_maxDataFields(void)
{
@@ -75,8 +39,7 @@ PrioConfig_new(int n_fields, PublicKey server_a, PublicKey server_b,
  cfg->n_roots = 1 << Generator2Order;
  MP_DIGITS(&cfg->modulus) = NULL;
  MP_DIGITS(&cfg->inv2) = NULL;
  cfg->roots = NULL;
  cfg->rootsInv = NULL;
  MP_DIGITS(&cfg->generator) = NULL;

  P_CHECKCB(cfg->n_roots > 1);
  P_CHECKCB(cfg->num_data_fields <= PrioConfig_maxDataFields());
@@ -87,16 +50,14 @@ PrioConfig_new(int n_fields, PublicKey server_a, PublicKey server_b,
  MP_CHECKC(mp_init(&cfg->modulus));
  MP_CHECKC(mp_read_radix(&cfg->modulus, Modulus, 16));

  MP_CHECKC(mp_init(&cfg->generator));
  MP_CHECKC(mp_read_radix(&cfg->generator, Generator, 16));

  // Compute  2^{-1} modulo M
  MP_CHECKC(mp_init(&cfg->inv2));
  mp_set(&cfg->inv2, 2);
  MP_CHECKC(mp_invmod(&cfg->inv2, &cfg->modulus, &cfg->inv2));

  P_CHECKA(cfg->roots = MPArray_new(cfg->n_roots));
  P_CHECKA(cfg->rootsInv = MPArray_new(cfg->n_roots));
  MP_CHECKC(initialize_roots(cfg->roots, Roots, /*inverted=*/false));
  MP_CHECKC(initialize_roots(cfg->rootsInv, Roots, /*inverted=*/true));

cleanup:
  if (rv != SECSuccess) {
    PrioConfig_clear(cfg);
@@ -119,10 +80,9 @@ PrioConfig_clear(PrioConfig cfg)
    return;
  if (cfg->batch_id)
    free(cfg->batch_id);
  MPArray_clear(cfg->roots);
  MPArray_clear(cfg->rootsInv);
  mp_clear(&cfg->modulus);
  mp_clear(&cfg->inv2);
  mp_clear(&cfg->generator);
  free(cfg);
}

+1 −2
Original line number Diff line number Diff line
@@ -26,8 +26,7 @@ struct prio_config
  mp_int inv2;

  int n_roots;
  MPArray roots;
  MPArray rootsInv;
  mp_int generator;
};

int PrioConfig_hPoints(const_PrioConfig cfg);
+2 −4112

File changed.

Preview size limit exceeded, changes collapsed.

+40 −18
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
 *
 * They present this algorithm as Algorithm 8.14.
 */

static SECStatus
fft_recurse(mp_int* out, const mp_int* mod, int n, const mp_int* roots,
            const mp_int* ys, mp_int* tmp, mp_int* ySub, mp_int* rootsSub)
@@ -60,7 +61,7 @@ fft_recurse(mp_int* out, const mp_int* mod, int n, const mp_int* roots,

static SECStatus
fft_interpolate_raw(mp_int* out, const mp_int* ys, int nPoints,
                    const mp_int* roots, const mp_int* mod, bool invert)
                    const_MPArray roots, const mp_int* mod, bool invert)
{
  SECStatus rv = SECSuccess;
  MPArray tmp = NULL;
@@ -74,8 +75,8 @@ fft_interpolate_raw(mp_int* out, const mp_int* ys, int nPoints,
  mp_int n_inverse;
  MP_DIGITS(&n_inverse) = NULL;

  MP_CHECKC(fft_recurse(out, mod, nPoints, roots, ys, tmp->data, ySub->data,
                        rootsSub->data));
  MP_CHECKC(fft_recurse(out, mod, nPoints, roots->data, ys, tmp->data,
                        ySub->data, rootsSub->data));

  if (invert) {
    MP_CHECKC(mp_init(&n_inverse));
@@ -103,16 +104,43 @@ cleanup:
 * of the n-th roots of unity.
 */
SECStatus
poly_fft_get_roots(mp_int* roots_out, int n_points, const_PrioConfig cfg,
poly_fft_get_roots(MPArray roots_out, int n_points, const_PrioConfig cfg,
                   bool invert)
{
  if (n_points > cfg->n_roots)
  if (n_points < 1) {
    return SECFailure;
  }

  if (n_points != roots_out->len) {
    return SECFailure;
  const mp_int* roots_in = invert ? cfg->rootsInv->data : cfg->roots->data;
  }

  if (n_points > cfg->n_roots) {
    return SECFailure;
  }

  mp_set(&roots_out->data[0], 1);
  if (n_points == 1) {
    return SECSuccess;
  }

  const int step_size = cfg->n_roots / n_points;
  mp_int* gen = &roots_out->data[1];

  MP_CHECK(mp_copy(&cfg->generator, gen));

  if (invert) {
    MP_CHECK(mp_invmod(gen, &cfg->modulus, gen));
  }

  // Compute g' = g^step_size
  // Now, g' generates a subgroup of order n_points.
  MP_CHECK(mp_exptmod_d(gen, step_size, &cfg->modulus, gen));

  for (int i = 0; i < n_points; i++) {
    roots_out[i] = roots_in[i * step_size];
  for (int i = 2; i < n_points; i++) {
    // Compute g^i for all i in {0,..., n-1}
    MP_CHECK(mp_mulmod(gen, &roots_out->data[i - 1], &cfg->modulus,
                       &roots_out->data[i]));
  }

  return SECSuccess;
@@ -124,7 +152,7 @@ poly_fft(MPArray points_out, const_MPArray points_in, const_PrioConfig cfg,
{
  SECStatus rv = SECSuccess;
  const int n_points = points_in->len;
  mp_int* scaled_roots = NULL;
  MPArray scaled_roots = NULL;

  if (points_out->len != points_in->len)
    return SECFailure;
@@ -133,15 +161,14 @@ poly_fft(MPArray points_out, const_MPArray points_in, const_PrioConfig cfg,
  if (cfg->n_roots % n_points != 0)
    return SECFailure;

  P_CHECKA(scaled_roots = calloc(n_points, sizeof(mp_int)));
  P_CHECKA(scaled_roots = MPArray_new(n_points));
  P_CHECKC(poly_fft_get_roots(scaled_roots, n_points, cfg, invert));

  P_CHECKC(fft_interpolate_raw(points_out->data, points_in->data, n_points,
                               scaled_roots, &cfg->modulus, invert));

cleanup:
  if (scaled_roots)
    free(scaled_roots);
  MPArray_clear(scaled_roots);

  return SECSuccess;
}
@@ -155,7 +182,7 @@ poly_eval(mp_int* value, const_MPArray coeffs, const mp_int* eval_at,

  // Use Horner's method to evaluate the polynomial at the point
  // `eval_at`
  mp_copy(&coeffs->data[n - 1], value);
  MP_CHECK(mp_copy(&coeffs->data[n - 1], value));
  for (int i = n - 2; i >= 0; i--) {
    MP_CHECK(mp_mulmod(value, eval_at, &cfg->modulus, value));
    MP_CHECK(mp_addmod(value, &coeffs->data[i], &cfg->modulus, value));
@@ -170,20 +197,15 @@ poly_interp_evaluate(mp_int* value, const_MPArray poly_points,
{
  SECStatus rv;
  MPArray coeffs = NULL;
  mp_int* roots = NULL;
  const int N = poly_points->len;

  P_CHECKA(roots = calloc(N, sizeof(mp_int)));
  P_CHECKA(coeffs = MPArray_new(N));
  P_CHECKC(poly_fft_get_roots(roots, N, cfg, false));

  // Interpolate polynomial through roots of unity
  P_CHECKC(poly_fft(coeffs, poly_points, cfg, true))
  P_CHECKC(poly_eval(value, coeffs, eval_at, cfg));

cleanup:
  if (roots)
    free(roots);
  MPArray_clear(coeffs);
  return rv;
}
Loading