diff --git a/into_fr.rs b/into_fr.rs new file mode 100644 index 0000000..ad09d79 --- /dev/null +++ b/into_fr.rs @@ -0,0 +1,55 @@ +use pairing::bls12_381::Fr; +use pairing::{Field, PrimeField}; + +/// A conversion into an element of the field `Fr`. +pub trait IntoFr: Copy { + fn into_fr(self) -> Fr; +} + +impl IntoFr for Fr { + fn into_fr(self) -> Fr { + self + } +} + +impl IntoFr for u64 { + fn into_fr(self) -> Fr { + Fr::from_repr(self.into()).expect("modulus is greater than u64::MAX") + } +} + +impl IntoFr for usize { + fn into_fr(self) -> Fr { + (self as u64).into_fr() + } +} + +impl IntoFr for i32 { + fn into_fr(self) -> Fr { + if self >= 0 { + (self as u64).into_fr() + } else { + let mut result = ((-self) as u64).into_fr(); + result.negate(); + result + } + } +} + +impl IntoFr for i64 { + fn into_fr(self) -> Fr { + if self >= 0 { + (self as u64).into_fr() + } else { + let mut result = ((-self) as u64).into_fr(); + result.negate(); + result + } + } +} + +impl<'a, T: IntoFr> IntoFr for &'a T { + fn into_fr(self) -> Fr { + (*self).into_fr() + } +} diff --git a/mod.rs b/mod.rs index 4a06c3f..0eebc9a 100644 --- a/mod.rs +++ b/mod.rs @@ -3,6 +3,7 @@ #![cfg_attr(feature = "cargo-clippy", allow(derive_hash_xor_eq))] pub mod error; +mod into_fr; pub mod poly; #[cfg(feature = "serialization-protobuf")] pub mod protobuf_impl; @@ -14,12 +15,13 @@ use std::ptr::write_volatile; use byteorder::{BigEndian, ByteOrder}; use init_with::InitWith; -use pairing::bls12_381::{Bls12, Fr, FrRepr, G1, G1Affine, G2, G2Affine}; -use pairing::{CurveAffine, CurveProjective, Engine, Field, PrimeField}; +use pairing::bls12_381::{Bls12, Fr, G1, G1Affine, G2, G2Affine}; +use pairing::{CurveAffine, CurveProjective, Engine, Field}; use rand::{ChaChaRng, OsRng, Rng, SeedableRng}; use ring::digest; use self::error::{ErrorKind, Result}; +use self::into_fr::IntoFr; use self::poly::{Commitment, Poly}; use fmt::HexBytes; @@ -325,26 +327,26 @@ impl PublicKeySet { } /// Returns the `i`-th public key share. - pub fn public_key_share>(&self, i: T) -> PublicKeyShare { - let value = self.commit.evaluate(from_repr_plus_1::(i.into())); + pub fn public_key_share(&self, i: T) -> PublicKeyShare { + let value = self.commit.evaluate(into_fr_plus_1(i)); PublicKeyShare(PublicKey(value)) } /// Combines the shares into a signature that can be verified with the main public key. - pub fn combine_signatures<'a, ITR, IND>(&self, shares: ITR) -> Result + pub fn combine_signatures<'a, T, I>(&self, shares: I) -> Result where - ITR: IntoIterator, - IND: Into + Clone + 'a, + I: IntoIterator, + T: IntoFr, { let samples = shares.into_iter().map(|(i, share)| (i, &(share.0).0)); Ok(Signature(interpolate(self.commit.degree() + 1, samples)?)) } /// Combines the shares to decrypt the ciphertext. - pub fn decrypt<'a, ITR, IND>(&self, shares: ITR, ct: &Ciphertext) -> Result> + pub fn decrypt<'a, T, I>(&self, shares: I, ct: &Ciphertext) -> Result> where - ITR: IntoIterator, - IND: Into + Clone + 'a, + I: IntoIterator, + T: IntoFr, { let samples = shares.into_iter().map(|(i, share)| (i, &share.0)); let g = interpolate(self.commit.degree() + 1, samples)?; @@ -381,8 +383,8 @@ impl SecretKeySet { } /// Returns the `i`-th secret key share. - pub fn secret_key_share>(&self, i: T) -> SecretKeyShare { - let value = self.poly.evaluate(from_repr_plus_1::(i.into())); + pub fn secret_key_share(&self, i: T) -> SecretKeyShare { + let value = self.poly.evaluate(into_fr_plus_1(i)); SecretKeyShare(SecretKey(value)) } @@ -441,15 +443,15 @@ fn xor_vec(x: &[u8], y: &[u8]) -> Vec { /// Given a list of `t` samples `(i - 1, f(i) * g)` for a polynomial `f` of degree `t - 1`, and a /// group generator `g`, returns `f(0) * g`. -fn interpolate<'a, C, ITR, IND>(t: usize, items: ITR) -> Result +fn interpolate<'a, C, T, I>(t: usize, items: I) -> Result where - C: CurveProjective, - ITR: IntoIterator, - IND: Into<::Repr> + Clone + 'a, + C: CurveProjective, + I: IntoIterator, + T: IntoFr, { let samples: Vec<_> = items .into_iter() - .map(|(i, sample)| (from_repr_plus_1::(i.clone().into()), sample)) + .map(|(i, sample)| (into_fr_plus_1(i), sample)) .collect(); if samples.len() < t { return Err(ErrorKind::NotEnoughShares.into()); @@ -475,10 +477,10 @@ where Ok(result) } -fn from_repr_plus_1(repr: F::Repr) -> F { - let mut x = F::one(); - x.add_assign(&F::from_repr(repr).expect("invalid index")); - x +fn into_fr_plus_1(x: I) -> Fr { + let mut result = Fr::one(); + result.add_assign(&x.into_fr()); + result } #[cfg(test)] diff --git a/poly.rs b/poly.rs index c019ab8..af4fb72 100644 --- a/poly.rs +++ b/poly.rs @@ -21,10 +21,12 @@ use std::hash::{Hash, Hasher}; use std::ptr::write_volatile; use std::{cmp, iter, ops}; -use pairing::bls12_381::{Fr, FrRepr, G1, G1Affine}; -use pairing::{CurveAffine, CurveProjective, Field, PrimeField}; +use pairing::bls12_381::{Fr, G1, G1Affine}; +use pairing::{CurveAffine, CurveProjective, Field}; use rand::Rng; +use super::IntoFr; + /// A univariate polynomial in the prime field. #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] pub struct Poly { @@ -176,15 +178,13 @@ impl Poly { /// Returns the unique polynomial `f` of degree `samples.len() - 1` with the given values /// `(x, f(x))`. - pub fn interpolate<'a, T, I>(samples_repr: I) -> Self + pub fn interpolate(samples_repr: I) -> Self where - I: IntoIterator, - T: Into + Clone + 'a, + I: IntoIterator, + T: IntoFr, + U: IntoFr, { - let convert = |(x_repr, y): (&T, &Fr)| { - let x = Fr::from_repr(x_repr.clone().into()).expect("invalid index"); - (x, *y) - }; + let convert = |(x, y): (T, U)| (x.into_fr(), y.into_fr()); let samples: Vec<(Fr, Fr)> = samples_repr.into_iter().map(convert).collect(); Self::compute_interpolation(&samples) } @@ -195,12 +195,12 @@ impl Poly { } /// Returns the value at the point `i`. - pub fn evaluate>(&self, i: T) -> Fr { + pub fn evaluate(&self, i: T) -> Fr { let mut result = match self.coeff.last() { None => return Fr::zero(), Some(c) => *c, }; - let x = Fr::from_repr(i.into()).expect("invalid index"); + let x = i.into_fr(); for c in self.coeff.iter().rev().skip(1) { result.mul_assign(&x); result.add_assign(c); @@ -306,12 +306,12 @@ impl Commitment { } /// Returns the `i`-th public key share. - pub fn evaluate>(&self, i: T) -> G1 { + pub fn evaluate(&self, i: T) -> G1 { let mut result = match self.coeff.last() { None => return G1::zero(), Some(c) => *c, }; - let x = Fr::from_repr(i.into()).expect("invalid index"); + let x = i.into_fr(); for c in self.coeff.iter().rev().skip(1) { result.mul_assign(x); result.add_assign(c); @@ -367,7 +367,7 @@ impl BivarPoly { } /// Returns the polynomial's value at the point `(x, y)`. - pub fn evaluate>(&self, x: T, y: T) -> Fr { + pub fn evaluate(&self, x: T, y: T) -> Fr { let x_pow = self.powers(x); let y_pow = self.powers(y); // TODO: Can we save a few multiplication steps here due to the symmetry? @@ -384,7 +384,7 @@ impl BivarPoly { } /// Returns the `x`-th row, as a univariate polynomial. - pub fn row>(&self, x: T) -> Poly { + pub fn row(&self, x: T) -> Poly { let x_pow = self.powers(x); let coeff: Vec = (0..=self.degree) .map(|i| { @@ -410,8 +410,8 @@ impl BivarPoly { } /// Returns the `0`-th to `degree`-th power of `x`. - fn powers>(&self, x_repr: T) -> Vec { - powers(x_repr, self.degree) + fn powers(&self, x: T) -> Vec { + powers(x, self.degree) } } @@ -441,7 +441,7 @@ impl BivarCommitment { } /// Returns the commitment's value at the point `(x, y)`. - pub fn evaluate>(&self, x: T, y: T) -> G1 { + pub fn evaluate(&self, x: T, y: T) -> G1 { let x_pow = self.powers(x); let y_pow = self.powers(y); // TODO: Can we save a few multiplication steps here due to the symmetry? @@ -458,7 +458,7 @@ impl BivarCommitment { } /// Returns the `x`-th row, as a commitment to a univariate polynomial. - pub fn row>(&self, x: T) -> Commitment { + pub fn row(&self, x: T) -> Commitment { let x_pow = self.powers(x); let coeff: Vec = (0..=self.degree) .map(|i| { @@ -475,18 +475,18 @@ impl BivarCommitment { } /// Returns the `0`-th to `degree`-th power of `x`. - fn powers>(&self, x_repr: T) -> Vec { - powers(x_repr, self.degree) + fn powers(&self, x: T) -> Vec { + powers(x, self.degree) } } /// Returns the `0`-th to `degree`-th power of `x`. -fn powers>(x_repr: T, degree: usize) -> Vec

{ - let x = &P::from_repr(x_repr.into()).expect("invalid index"); - let mut x_pow_i = P::one(); +fn powers(into_x: T, degree: usize) -> Vec { + let x = into_x.into_fr(); + let mut x_pow_i = Fr::one(); iter::once(x_pow_i) .chain((0..degree).map(|_| { - x_pow_i.mul_assign(x); + x_pow_i.mul_assign(&x); x_pow_i })) .collect() @@ -507,18 +507,14 @@ fn coeff_pos(i: usize, j: usize) -> usize { mod tests { use std::collections::BTreeMap; - use super::{coeff_pos, BivarPoly, Poly}; + use super::{coeff_pos, BivarPoly, IntoFr, Poly}; use pairing::bls12_381::{Fr, G1Affine}; - use pairing::{CurveAffine, Field, PrimeField}; + use pairing::{CurveAffine, Field}; use rand; fn fr(x: i64) -> Fr { - let mut result = Fr::from_repr((x.abs() as u64).into()).unwrap(); - if x < 0 { - result.negate(); - } - result + x.into_fr() } #[test] @@ -552,8 +548,7 @@ mod tests { for &(x, y) in &samples { assert_eq!(y, poly.evaluate(x)); } - let sample_iter = samples.iter().map(|&(ref x, ref y)| (x, y)); - assert_eq!(Poly::interpolate(sample_iter), poly); + assert_eq!(Poly::interpolate(samples), poly); } #[test] @@ -579,16 +574,16 @@ mod tests { for (bi_poly, bi_commit) in bi_polys.iter().zip(&pub_bi_commits) { for m in 1..=node_num { // Node `m` receives its row and verifies it. - let row_poly = bi_poly.row(m as u64); - let row_commit = bi_commit.row(m as u64); + let row_poly = bi_poly.row(m); + let row_commit = bi_commit.row(m); assert_eq!(row_poly.commitment(), row_commit); // Node `s` receives the `s`-th value and verifies it. for s in 1..=node_num { - let val = row_poly.evaluate(s as u64); + let val = row_poly.evaluate(s); let val_g1 = G1Affine::one().mul(val); - assert_eq!(bi_commit.evaluate(m as u64, s as u64), val_g1); + assert_eq!(bi_commit.evaluate(m, s), val_g1); // The node can't verify this directly, but it should have the correct value: - assert_eq!(bi_poly.evaluate(m as u64, s as u64), val); + assert_eq!(bi_poly.evaluate(m, s), val); } // A cheating dealer who modified the polynomial would be detected. @@ -604,10 +599,10 @@ mod tests { // `m` received three correct entries from that row: let received: BTreeMap<_, _> = [1, 2, 4] .iter() - .map(|&i| (i, bi_poly.evaluate(m as u64, i as u64))) + .map(|&i| (i, bi_poly.evaluate(m, i))) .collect(); - let my_row = Poly::interpolate(&received); - assert_eq!(bi_poly.evaluate(m as u64, 0), my_row.evaluate(0)); + let my_row = Poly::interpolate(received); + assert_eq!(bi_poly.evaluate(m, 0), my_row.evaluate(0)); assert_eq!(row_poly, my_row); // The node sums up all values number `0` it received from the different dealer. No @@ -626,7 +621,7 @@ mod tests { sec_key_set += bi_poly.row(0); } for m in 1..=node_num { - assert_eq!(sec_key_set.evaluate(m as u64), sec_keys[m - 1]); + assert_eq!(sec_key_set.evaluate(m), sec_keys[m - 1]); } // The sum of the first rows of the public commitments is the commitment to the secret key