diff --git a/Cargo.toml b/Cargo.toml index c242119c..378dd4f5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,8 +34,10 @@ name = "plonk" harness = false [dependencies] +bitvec = "0.18" subtle = "2.2.1" crossbeam-utils = "0.7" +ff = "0.8" metrics = "=0.13.0-alpha.11" num_cpus = "1.13" rand = "0.7" diff --git a/benches/arithmetic.rs b/benches/arithmetic.rs index a4fe17f8..5939c262 100644 --- a/benches/arithmetic.rs +++ b/benches/arithmetic.rs @@ -2,7 +2,7 @@ extern crate criterion; extern crate halo2; -use crate::arithmetic::{small_multiexp, Field}; +use crate::arithmetic::{small_multiexp, FieldExt}; use crate::poly::commitment::Params; use crate::transcript::DummyHash; use crate::tweedle::{EqAffine, Fp, Fq}; @@ -18,8 +18,8 @@ fn criterion_benchmark(c: &mut Criterion) { let len = g.len() / 2; let (g_lo, g_hi) = g.split_at_mut(len); - let coeff_1 = Fp::random(); - let coeff_2 = Fp::random(); + let coeff_1 = Fp::rand(); + let coeff_2 = Fp::rand(); c.bench_function("double-and-add", |b| { b.iter(|| { diff --git a/benches/plonk.rs b/benches/plonk.rs index b92e398d..13334160 100644 --- a/benches/plonk.rs +++ b/benches/plonk.rs @@ -2,7 +2,7 @@ extern crate criterion; extern crate halo2; -use halo2::arithmetic::Field; +use halo2::arithmetic::FieldExt; use halo2::plonk::*; use halo2::poly::commitment::Params; use halo2::transcript::DummyHash; @@ -33,7 +33,7 @@ fn bench_with_k(name: &str, k: u32, c: &mut Criterion) { perm: usize, } - trait StandardCS { + trait StandardCS { fn raw_multiply(&mut self, f: F) -> Result<(Variable, Variable, Variable), Error> where F: FnOnce() -> Result<(FF, FF, FF), Error>; @@ -43,19 +43,19 @@ fn bench_with_k(name: &str, k: u32, c: &mut Criterion) { fn copy(&mut self, a: Variable, b: Variable) -> Result<(), Error>; } - struct MyCircuit { + struct MyCircuit { a: Option, k: u32, } - struct StandardPLONK<'a, F: Field, CS: Assignment + 'a> { + struct StandardPLONK<'a, F: FieldExt, CS: Assignment + 'a> { cs: &'a mut CS, config: PLONKConfig, current_gate: usize, _marker: PhantomData, } - impl<'a, FF: Field, CS: Assignment> StandardPLONK<'a, FF, CS> { + impl<'a, FF: FieldExt, CS: Assignment> StandardPLONK<'a, FF, CS> { fn new(cs: &'a mut CS, config: PLONKConfig) -> Self { StandardPLONK { cs, @@ -66,7 +66,7 @@ fn bench_with_k(name: &str, k: u32, c: &mut Criterion) { } } - impl<'a, FF: Field, CS: Assignment> StandardCS for StandardPLONK<'a, FF, CS> { + impl<'a, FF: FieldExt, CS: Assignment> StandardCS for StandardPLONK<'a, FF, CS> { fn raw_multiply(&mut self, f: F) -> Result<(Variable, Variable, Variable), Error> where F: FnOnce() -> Result<(FF, FF, FF), Error>, @@ -150,7 +150,7 @@ fn bench_with_k(name: &str, k: u32, c: &mut Criterion) { } } - impl Circuit for MyCircuit { + impl Circuit for MyCircuit { type Config = PLONKConfig; fn configure(meta: &mut ConstraintSystem) -> PLONKConfig { @@ -234,7 +234,7 @@ fn bench_with_k(name: &str, k: u32, c: &mut Criterion) { c.bench_function(&prover_name, |b| { b.iter(|| { let circuit: MyCircuit = MyCircuit { - a: Some(Fp::random()), + a: Some(Fp::rand()), k, }; @@ -245,7 +245,7 @@ fn bench_with_k(name: &str, k: u32, c: &mut Criterion) { }); let circuit: MyCircuit = MyCircuit { - a: Some(Fp::random()), + a: Some(Fp::rand()), k, }; diff --git a/examples/performance_model.rs b/examples/performance_model.rs index 9da022e5..796dbc10 100644 --- a/examples/performance_model.rs +++ b/examples/performance_model.rs @@ -1,5 +1,5 @@ use halo2::{ - arithmetic::{Curve, Field}, + arithmetic::{Curve, FieldExt}, model::ModelRecorder, plonk::*, poly::commitment::{Blind, Params}, @@ -27,7 +27,7 @@ struct PLONKConfig { perm: usize, } -trait StandardCS { +trait StandardCS { fn raw_multiply(&mut self, f: F) -> Result<(Variable, Variable, Variable), Error> where F: FnOnce() -> Result<(FF, FF, FF), Error>; @@ -40,19 +40,19 @@ trait StandardCS { F: FnOnce() -> Result; } -struct MyCircuit { +struct MyCircuit { a: Option, k: u32, } -struct StandardPLONK<'a, F: Field, CS: Assignment + 'a> { +struct StandardPLONK<'a, F: FieldExt, CS: Assignment + 'a> { cs: &'a mut CS, config: PLONKConfig, current_gate: usize, _marker: PhantomData, } -impl<'a, FF: Field, CS: Assignment> StandardPLONK<'a, FF, CS> { +impl<'a, FF: FieldExt, CS: Assignment> StandardPLONK<'a, FF, CS> { fn new(cs: &'a mut CS, config: PLONKConfig) -> Self { StandardPLONK { cs, @@ -63,7 +63,7 @@ impl<'a, FF: Field, CS: Assignment> StandardPLONK<'a, FF, CS> { } } -impl<'a, FF: Field, CS: Assignment> StandardCS for StandardPLONK<'a, FF, CS> { +impl<'a, FF: FieldExt, CS: Assignment> StandardCS for StandardPLONK<'a, FF, CS> { fn raw_multiply(&mut self, f: F) -> Result<(Variable, Variable, Variable), Error> where F: FnOnce() -> Result<(FF, FF, FF), Error>, @@ -159,7 +159,7 @@ impl<'a, FF: Field, CS: Assignment> StandardCS for StandardPLONK<'a, FF, } } -impl Circuit for MyCircuit { +impl Circuit for MyCircuit { type Config = PLONKConfig; fn configure(meta: &mut ConstraintSystem) -> PLONKConfig { @@ -268,7 +268,7 @@ fn main() { recorder.clear(); let circuit: MyCircuit = MyCircuit { - a: Some(Fp::random()), + a: Some(Fp::rand()), k, }; diff --git a/src/arithmetic.rs b/src/arithmetic.rs index cab568ef..5ad4ebbb 100644 --- a/src/arithmetic.rs +++ b/src/arithmetic.rs @@ -2,6 +2,7 @@ //! field and polynomial arithmetic. use crossbeam_utils::thread; +use ff::Field; mod curves; mod fields; @@ -15,7 +16,7 @@ pub use fields::*; pub trait Group: Copy + Clone + Send + Sync + 'static { /// The group is assumed to be of prime order $p$. `Scalar` is the /// associated scalar field of size $p$. - type Scalar: Field; + type Scalar: FieldExt; /// Returns the additive identity of the group. fn group_zero() -> Self; @@ -40,7 +41,7 @@ pub trait BatchInvert { impl<'a, F, I> BatchInvert for I where - F: Field, + F: FieldExt, I: IntoIterator, { fn batch_invert(self) -> F { @@ -50,13 +51,13 @@ where for p in iter { let q = *p; tmp.push((acc, p)); - acc = F::conditional_select(&(acc * q), &acc, q.is_zero()); + acc = F::conditional_select(&(acc * q), &acc, q.ct_is_zero()); } acc = acc.invert().unwrap(); let allinv = acc; for (tmp, p) in tmp.into_iter().rev() { - let skip = p.is_zero(); + let skip = p.ct_is_zero(); let tmp = tmp * acc; acc = F::conditional_select(&(acc * *p), &acc, skip); @@ -73,7 +74,7 @@ pub struct Challenge(pub(crate) u128); /// This algorithm applies the mapping of Algorithm 1 from the /// [Halo](https://eprint.iacr.org/2019/1021) paper. -pub fn get_challenge_scalar(challenge: Challenge) -> F { +pub fn get_challenge_scalar(challenge: Challenge) -> F { let mut acc = (F::ZETA + F::one()).double(); for i in (0..64).rev() { @@ -432,7 +433,7 @@ fn log2_floor(num: usize) -> u32 { /// Returns coefficients of an n - 1 degree polynomial given a set of n points /// and their evaluations. This function will panic if two values in `points` /// are the same. -pub fn lagrange_interpolate(points: &[F], evals: &[F]) -> Vec { +pub fn lagrange_interpolate(points: &[F], evals: &[F]) -> Vec { assert_eq!(points.len(), evals.len()); if points.len() == 1 { // Constant polynomial @@ -492,8 +493,8 @@ use crate::tweedle::Fp; #[test] fn test_lagrange_interpolate() { - let points = (0..5).map(|_| Fp::random()).collect::>(); - let evals = (0..5).map(|_| Fp::random()).collect::>(); + let points = (0..5).map(|_| Fp::rand()).collect::>(); + let evals = (0..5).map(|_| Fp::rand()).collect::>(); for coeffs in 0..5 { let points = &points[0..coeffs]; diff --git a/src/arithmetic/curves.rs b/src/arithmetic/curves.rs index 184c7bc8..3d6befb8 100644 --- a/src/arithmetic/curves.rs +++ b/src/arithmetic/curves.rs @@ -6,7 +6,7 @@ use core::fmt::Debug; use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; -use super::{Field, Group}; +use super::{FieldExt, Group}; /// This trait is a common interface for dealing with elements of an elliptic /// curve group in the "projective" form, where that arithmetic is usually more @@ -51,9 +51,9 @@ pub trait Curve: + Neg::Affine> + From; /// The scalar field of this elliptic curve. - type Scalar: Field; + type Scalar: FieldExt; /// The base field over which this elliptic curve is constructed. - type Base: Field; + type Base: FieldExt; /// Obtains the additive identity. fn zero() -> Self; @@ -118,9 +118,9 @@ pub trait CurveAffine: + SubAssign + From; /// The scalar field of this elliptic curve. - type Scalar: Field; + type Scalar: FieldExt; /// The base field over which this elliptic curve is constructed. - type Base: Field; + type Base: FieldExt; /// Obtains the additive identity. fn zero() -> Self; diff --git a/src/arithmetic/fields.rs b/src/arithmetic/fields.rs index d0fff80f..5c209f03 100644 --- a/src/arithmetic/fields.rs +++ b/src/arithmetic/fields.rs @@ -1,55 +1,15 @@ //! This module contains the `Field` abstraction that allows us to write //! code that generalizes over a pair of fields. -use std::fmt::Debug; -use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; -use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; +use subtle::{Choice, ConstantTimeEq, CtOption}; use super::Group; /// This trait is a common interface for dealing with elements of a finite /// field. -pub trait Field: - Sized - + Default - + Copy - + Clone - + Send - + Sync - + 'static - + Debug - + From - + From - + Add - + Sub - + Mul - + Neg - + for<'a> Add<&'a Self, Output = Self> - + for<'a> Mul<&'a Self, Output = Self> - + for<'a> Sub<&'a Self, Output = Self> - + MulAssign - + AddAssign - + SubAssign - + for<'a> MulAssign<&'a Self> - + for<'a> AddAssign<&'a Self> - + for<'a> SubAssign<&'a Self> - + PartialEq - + Eq - + PartialOrd - + Ord - + ConditionallySelectable - + ConstantTimeEq - + Group +pub trait FieldExt: + ff::PrimeField + From + Ord + ConstantTimeEq + Group { - /// How many bits needed to express the modulus $p$? - const NUM_BITS: u32; - - /// How many bits of information can be stored reliably? - const CAPACITY: u32; - - /// Represents $S$ where $p - 1 = 2^S \cdot t$ with $t$ odd. - const S: u32; - /// Generator of the $2^S$ multiplicative subgroup const ROOT_OF_UNITY: Self; @@ -82,20 +42,12 @@ pub trait Field: const ZETA: Self; /// This computes a random element of the field using system randomness. - fn random() -> Self { - use rand::{thread_rng, RngCore}; - - let mut random_bytes = [0; 64]; - thread_rng().fill_bytes(&mut random_bytes[..]); - - Self::from_bytes_wide(&random_bytes) + fn rand() -> Self { + Self::random(rand::rngs::OsRng) } /// Returns whether or not this element is zero. - fn is_zero(&self) -> Choice; - - /// Doubles this element in the field. - fn double(&self) -> Self; + fn ct_is_zero(&self) -> Choice; /// Obtains a field element congruent to the integer `v`. fn from_u64(v: u64) -> Self; @@ -103,21 +55,6 @@ pub trait Field: /// Obtains a field element congruent to the integer `v`. fn from_u128(v: u128) -> Self; - /// Attempts to obtain the square root of this field element. - fn sqrt(&self) -> CtOption; - - /// Attempts to find the multiplicative inverse of this field element. - fn invert(&self) -> CtOption; - - /// Returns zero, the additive identity. - fn zero() -> Self; - - /// Returns one, the multiplicative identity. - fn one() -> Self; - - /// Squares this element in the field. - fn square(&self) -> Self; - /// Converts this field element to its normalized, little endian byte /// representation. fn to_bytes(&self) -> [u8; 32]; @@ -152,7 +89,7 @@ pub trait Field: /// integer `s` such that `self` is the square of $a \cdot \omega^{s}$ if /// indeed `self` is a square. fn extract_radix2_vartime(&self) -> Option<(Self, u64)> { - if bool::from(self.is_zero()) { + if bool::from(self.ct_is_zero()) { return None; } @@ -207,29 +144,6 @@ pub trait Field: res } - /// Exponentiates `self` by `by`, where `by` is a little-endian order - /// integer exponent. - /// - /// **This operation is variable time with respect to the exponent.** If the - /// exponent is fixed, this operation is effectively constant time. - fn pow_vartime(&self, by: &[u64; 4]) -> Self { - let mut res = Self::one(); - let mut found_one = false; - for e in by.iter().rev() { - for i in (0..64).rev() { - if found_one { - res = res.square(); - } - - if ((*e >> i) & 1) == 1 { - found_one = true; - res.mul_assign(self); - } - } - } - res - } - /// Gets the lower 128 bits of this field element when expressed /// canonically. fn get_lower_128(&self) -> u128; @@ -242,14 +156,14 @@ pub trait Field: let mut acc = Self::one(); for p in v.iter() { tmp.push(acc); - acc = Self::conditional_select(&(acc * p), &acc, p.is_zero()); + acc = Self::conditional_select(&(acc * p), &acc, p.ct_is_zero()); } acc = acc.invert().unwrap(); let allinv = acc; for (p, tmp) in v.iter_mut().rev().zip(tmp.into_iter().rev()) { - let skip = p.is_zero(); + let skip = p.ct_is_zero(); let tmp = tmp * acc; acc = Self::conditional_select(&(acc * *p), &acc, skip); diff --git a/src/plonk.rs b/src/plonk.rs index 5595bcd8..7953cba0 100644 --- a/src/plonk.rs +++ b/src/plonk.rs @@ -97,7 +97,7 @@ impl VerifyingKey { #[test] fn test_proving() { - use crate::arithmetic::{Curve, Field}; + use crate::arithmetic::{Curve, FieldExt}; use crate::poly::commitment::{Blind, Params}; use crate::transcript::DummyHash; use crate::tweedle::{EqAffine, Fp, Fq}; @@ -129,7 +129,7 @@ fn test_proving() { perm2: usize, } - trait StandardCS { + trait StandardCS { fn raw_multiply(&mut self, f: F) -> Result<(Variable, Variable, Variable), Error> where F: FnOnce() -> Result<(FF, FF, FF), Error>; @@ -142,18 +142,18 @@ fn test_proving() { F: FnOnce() -> Result; } - struct MyCircuit { + struct MyCircuit { a: Option, } - struct StandardPLONK<'a, F: Field, CS: Assignment + 'a> { + struct StandardPLONK<'a, F: FieldExt, CS: Assignment + 'a> { cs: &'a mut CS, config: PLONKConfig, current_gate: usize, _marker: PhantomData, } - impl<'a, FF: Field, CS: Assignment> StandardPLONK<'a, FF, CS> { + impl<'a, FF: FieldExt, CS: Assignment> StandardPLONK<'a, FF, CS> { fn new(cs: &'a mut CS, config: PLONKConfig) -> Self { StandardPLONK { cs, @@ -164,7 +164,7 @@ fn test_proving() { } } - impl<'a, FF: Field, CS: Assignment> StandardCS for StandardPLONK<'a, FF, CS> { + impl<'a, FF: FieldExt, CS: Assignment> StandardCS for StandardPLONK<'a, FF, CS> { fn raw_multiply(&mut self, f: F) -> Result<(Variable, Variable, Variable), Error> where F: FnOnce() -> Result<(FF, FF, FF), Error>, @@ -279,7 +279,7 @@ fn test_proving() { } } - impl Circuit for MyCircuit { + impl Circuit for MyCircuit { type Config = PLONKConfig; fn configure(meta: &mut ConstraintSystem) -> PLONKConfig { @@ -376,7 +376,7 @@ fn test_proving() { } let circuit: MyCircuit = MyCircuit { - a: Some(Fp::random()), + a: Some(Fp::rand()), }; let empty_circuit: MyCircuit = MyCircuit { a: None }; diff --git a/src/plonk/circuit.rs b/src/plonk/circuit.rs index b5d7f4ed..c5447c52 100644 --- a/src/plonk/circuit.rs +++ b/src/plonk/circuit.rs @@ -1,10 +1,10 @@ use core::cmp::max; use core::ops::{Add, Mul}; +use ff::Field; use std::collections::BTreeMap; use std::convert::TryFrom; use super::Error; -use crate::arithmetic::Field; use crate::poly::Rotation; /// A column type diff --git a/src/plonk/keygen.rs b/src/plonk/keygen.rs index 76240737..5b7af796 100644 --- a/src/plonk/keygen.rs +++ b/src/plonk/keygen.rs @@ -1,8 +1,10 @@ +use ff::Field; + use super::{ circuit::{Advice, Assignment, Circuit, Column, ConstraintSystem, Fixed}, Error, ProvingKey, VerifyingKey, }; -use crate::arithmetic::{Curve, CurveAffine, Field}; +use crate::arithmetic::{Curve, CurveAffine, FieldExt}; use crate::poly::{ commitment::{Blind, Params}, EvaluationDomain, LagrangeCoeff, Polynomial, Rotation, diff --git a/src/plonk/prover.rs b/src/plonk/prover.rs index e769c509..8d75168c 100644 --- a/src/plonk/prover.rs +++ b/src/plonk/prover.rs @@ -1,3 +1,4 @@ +use ff::Field; use std::iter; use super::{ @@ -6,7 +7,7 @@ use super::{ }; use crate::arithmetic::{ eval_polynomial, get_challenge_scalar, parallelize, BatchInvert, Challenge, Curve, CurveAffine, - Field, + FieldExt, }; use crate::poly::{ commitment::{Blind, Params}, @@ -134,7 +135,7 @@ impl Proof { let advice_blinds: Vec<_> = witness .advice .iter() - .map(|_| Blind(C::Scalar::random())) + .map(|_| Blind(C::Scalar::rand())) .collect(); let advice_commitments_projective: Vec<_> = witness .advice @@ -273,7 +274,7 @@ impl Proof { } let z = domain.lagrange_from_vec(z); - let blind = Blind(C::Scalar::random()); + let blind = Blind(C::Scalar::rand()); permutation_product_commitments_projective.push(params.commit_lagrange(&z, blind)); permutation_product_blinds.push(blind); @@ -380,10 +381,7 @@ impl Proof { .map(|v| domain.coeff_from_vec(v.to_vec())) .collect::>(); drop(h_poly); - let h_blinds: Vec<_> = h_pieces - .iter() - .map(|_| Blind(C::Scalar::random())) - .collect(); + let h_blinds: Vec<_> = h_pieces.iter().map(|_| Blind(C::Scalar::rand())).collect(); // Compute commitments to each h(X) piece let h_commitments_projective: Vec<_> = h_pieces diff --git a/src/plonk/verifier.rs b/src/plonk/verifier.rs index 4745c349..ce5eb3c9 100644 --- a/src/plonk/verifier.rs +++ b/src/plonk/verifier.rs @@ -1,7 +1,8 @@ +use ff::Field; use std::iter; use super::{Error, Proof, VerifyingKey}; -use crate::arithmetic::{get_challenge_scalar, Challenge, CurveAffine, Field}; +use crate::arithmetic::{get_challenge_scalar, Challenge, CurveAffine, FieldExt}; use crate::poly::{ commitment::{Guard, Params, MSM}, multiopen::VerifierQuery, diff --git a/src/poly.rs b/src/poly.rs index c78b5e35..923d58ea 100644 --- a/src/poly.rs +++ b/src/poly.rs @@ -2,8 +2,9 @@ //! various forms, including computing commitments to them and provably opening //! the committed polynomials at arbitrary points. -use crate::arithmetic::{parallelize, Field}; +use crate::arithmetic::parallelize; +use ff::Field; use std::fmt::Debug; use std::marker::PhantomData; use std::ops::{Add, Deref, DerefMut, Index, IndexMut, Mul, RangeFrom, RangeFull, Sub}; diff --git a/src/poly/commitment.rs b/src/poly/commitment.rs index 0016c829..8faa3baf 100644 --- a/src/poly/commitment.rs +++ b/src/poly/commitment.rs @@ -4,8 +4,10 @@ //! [halo]: https://eprint.iacr.org/2019/1021 use super::{Coeff, LagrangeCoeff, Polynomial}; -use crate::arithmetic::{best_fft, best_multiexp, parallelize, Curve, CurveAffine, Field}; +use crate::arithmetic::{best_fft, best_multiexp, parallelize, Curve, CurveAffine, FieldExt}; use crate::transcript::Hasher; + +use ff::{Field, PrimeField}; use std::ops::{Add, AddAssign, Mul, MulAssign}; mod msm; @@ -237,7 +239,7 @@ fn test_commit_lagrange() { let b = domain.lagrange_to_coeff(a.clone()); - let alpha = Blind(Fq::random()); + let alpha = Blind(Fq::rand()); assert_eq!(params.commit(&b, alpha), params.commit_lagrange(&a, alpha)); } @@ -246,12 +248,14 @@ fn test_commit_lagrange() { fn test_opening_proof() { const K: u32 = 6; + use ff::Field; + use super::{ commitment::{Blind, Params}, EvaluationDomain, }; use crate::arithmetic::{ - eval_polynomial, get_challenge_scalar, Challenge, Curve, CurveAffine, Field, + eval_polynomial, get_challenge_scalar, Challenge, Curve, CurveAffine, FieldExt, }; use crate::transcript::{DummyHash, Hasher, Transcript}; use crate::tweedle::{EpAffine, Fp, Fq}; @@ -265,7 +269,7 @@ fn test_opening_proof() { *a = Fq::from(i as u64); } - let blind = Blind(Fq::random()); + let blind = Blind(Fq::rand()); let p = params.commit(&px, blind).to_affine(); diff --git a/src/poly/commitment/prover.rs b/src/poly/commitment/prover.rs index 52847b98..5c9def6d 100644 --- a/src/poly/commitment/prover.rs +++ b/src/poly/commitment/prover.rs @@ -1,8 +1,10 @@ +use ff::Field; + use super::super::{Coeff, Error, Polynomial}; use super::{Blind, Params, Proof}; use crate::arithmetic::{ best_multiexp, compute_inner_product, get_challenge_scalar, parallelize, small_multiexp, - Challenge, Curve, CurveAffine, Field, + Challenge, Curve, CurveAffine, FieldExt, }; use crate::transcript::{Hasher, Transcript}; @@ -83,8 +85,8 @@ impl Proof { let r = best_multiexp(&a[half..], &g[0..half]); let value_l = compute_inner_product(&a[0..half], &b[half..]); let value_r = compute_inner_product(&a[half..], &b[0..half]); - let mut l_randomness = C::Scalar::random(); - let r_randomness = C::Scalar::random(); + let mut l_randomness = C::Scalar::rand(); + let r_randomness = C::Scalar::rand(); metrics::counter!("multiexp", 2, "val" => "l/r", "size" => "2"); let l = l + &best_multiexp(&[value_l, l_randomness], &[u, params.h]); let r = r + &best_multiexp(&[value_r, r_randomness], &[u, params.h]); @@ -172,8 +174,8 @@ impl Proof { let g = g[0]; // Random nonces for the zero-knowledge opening - let d = C::Scalar::random(); - let s = C::Scalar::random(); + let d = C::Scalar::rand(); + let s = C::Scalar::rand(); metrics::increment!("multiexp", "val" => "delta", "size" => "3"); let delta = best_multiexp(&[d, d * &b, s], &[g, u, params.h]).to_affine(); diff --git a/src/poly/commitment/verifier.rs b/src/poly/commitment/verifier.rs index d786c74c..f92dc433 100644 --- a/src/poly/commitment/verifier.rs +++ b/src/poly/commitment/verifier.rs @@ -1,9 +1,11 @@ +use ff::Field; + use super::super::Error; use super::{Params, Proof, MSM}; use crate::transcript::{Hasher, Transcript}; use crate::arithmetic::{ - best_multiexp, get_challenge_scalar, Challenge, Curve, CurveAffine, Field, + best_multiexp, get_challenge_scalar, Challenge, Curve, CurveAffine, FieldExt, }; /// A guard returned by the verifier diff --git a/src/poly/domain.rs b/src/poly/domain.rs index d336818d..09a2cd8b 100644 --- a/src/poly/domain.rs +++ b/src/poly/domain.rs @@ -1,9 +1,11 @@ //! Contains utilities for performing polynomial arithmetic over an evaluation //! domain that is of a suitable size for the application. -use crate::arithmetic::{best_fft, parallelize, BatchInvert, Field, Group}; +use crate::arithmetic::{best_fft, parallelize, BatchInvert, FieldExt, Group}; use super::{Coeff, ExtendedLagrangeCoeff, LagrangeCoeff, Polynomial}; + +use ff::{Field, PrimeField}; use std::marker::PhantomData; /// Describes a relative location in the evaluation domain; applying a rotation diff --git a/src/poly/multiopen.rs b/src/poly/multiopen.rs index e10a240a..da3f58d1 100644 --- a/src/poly/multiopen.rs +++ b/src/poly/multiopen.rs @@ -3,10 +3,11 @@ //! //! [halo]: https://eprint.iacr.org/2019/1021 +use ff::Field; use std::collections::{BTreeMap, BTreeSet}; use super::*; -use crate::arithmetic::CurveAffine; +use crate::arithmetic::{CurveAffine, FieldExt}; mod prover; mod verifier; @@ -74,7 +75,7 @@ trait Query: Sized { fn get_commitment(&self) -> Self::Commitment; } -fn construct_intermediate_sets>( +fn construct_intermediate_sets>( queries: I, ) -> (Vec>, Vec>) where @@ -191,7 +192,7 @@ where #[cfg(test)] mod tests { use super::{construct_intermediate_sets, Query}; - use crate::arithmetic::Field; + use crate::arithmetic::FieldExt; use crate::tweedle::Fp; #[derive(Clone)] @@ -217,65 +218,59 @@ mod tests { #[test] fn test_coherence() { - let points = &[ - Fp::random(), - Fp::random(), - Fp::random(), - Fp::random(), - Fp::random(), - ]; + let points = &[Fp::rand(), Fp::rand(), Fp::rand(), Fp::rand(), Fp::rand()]; let build_queries = || { vec![ MyQuery { commitment: 0, point: points[0], - eval: Fp::random(), + eval: Fp::rand(), }, MyQuery { commitment: 0, point: points[1], - eval: Fp::random(), + eval: Fp::rand(), }, MyQuery { commitment: 1, point: points[0], - eval: Fp::random(), + eval: Fp::rand(), }, MyQuery { commitment: 1, point: points[1], - eval: Fp::random(), + eval: Fp::rand(), }, MyQuery { commitment: 2, point: points[0], - eval: Fp::random(), + eval: Fp::rand(), }, MyQuery { commitment: 2, point: points[1], - eval: Fp::random(), + eval: Fp::rand(), }, MyQuery { commitment: 2, point: points[2], - eval: Fp::random(), + eval: Fp::rand(), }, MyQuery { commitment: 3, point: points[0], - eval: Fp::random(), + eval: Fp::rand(), }, MyQuery { commitment: 3, point: points[3], - eval: Fp::random(), + eval: Fp::rand(), }, MyQuery { commitment: 4, point: points[4], - eval: Fp::random(), + eval: Fp::rand(), }, ] }; diff --git a/src/poly/multiopen/prover.rs b/src/poly/multiopen/prover.rs index c0e49a56..f512a740 100644 --- a/src/poly/multiopen/prover.rs +++ b/src/poly/multiopen/prover.rs @@ -6,9 +6,11 @@ use super::{construct_intermediate_sets, Proof, ProverQuery, Query}; use crate::arithmetic::{ eval_polynomial, get_challenge_scalar, kate_division, lagrange_interpolate, Challenge, Curve, - CurveAffine, Field, + CurveAffine, FieldExt, }; use crate::transcript::{Hasher, Transcript}; + +use ff::Field; use std::marker::PhantomData; #[derive(Debug, Clone)] @@ -103,7 +105,7 @@ impl Proof { }) .unwrap(); - let mut f_blind = Blind(C::Scalar::random()); + let mut f_blind = Blind(C::Scalar::rand()); let mut f_commitment = params.commit(&f_poly, f_blind).to_affine(); let (opening, q_evals) = loop { diff --git a/src/poly/multiopen/verifier.rs b/src/poly/multiopen/verifier.rs index 6bd8a6ae..48dfb59a 100644 --- a/src/poly/multiopen/verifier.rs +++ b/src/poly/multiopen/verifier.rs @@ -1,10 +1,12 @@ +use ff::Field; + use super::super::{ commitment::{Guard, Params, MSM}, Error, }; use super::{construct_intermediate_sets, Proof, Query, VerifierQuery}; use crate::arithmetic::{ - eval_polynomial, get_challenge_scalar, lagrange_interpolate, Challenge, CurveAffine, Field, + eval_polynomial, get_challenge_scalar, lagrange_interpolate, Challenge, CurveAffine, FieldExt, }; use crate::transcript::{Hasher, Transcript}; @@ -30,7 +32,7 @@ impl Proof { // Scale the MSM by a random factor to ensure that if the existing MSM // has is_zero() == false then this argument won't be able to interfere // with it to make it true, with high probability. - msm.scale(C::Scalar::random()); + msm.scale(C::Scalar::rand()); // Sample x_4 for compressing openings at the same point sets together let x_4: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128())); diff --git a/src/transcript.rs b/src/transcript.rs index 5fc54885..254bf323 100644 --- a/src/transcript.rs +++ b/src/transcript.rs @@ -1,12 +1,14 @@ //! This module contains utilities and traits for dealing with Fiat-Shamir //! transcripts. -use crate::arithmetic::{CurveAffine, Field}; +use ff::Field; use std::marker::PhantomData; +use crate::arithmetic::{CurveAffine, FieldExt}; + /// This is a generic interface for a sponge function that can be used for /// Fiat-Shamir transformations. -pub trait Hasher: Clone + Send + Sync + 'static { +pub trait Hasher: Clone + Send + Sync + 'static { /// Initialize the sponge with some key. fn init(key: F) -> Self; /// Absorb a field element into the sponge. @@ -18,12 +20,12 @@ pub trait Hasher: Clone + Send + Sync + 'static { /// This is just a simple (and completely broken) hash function, standing in for /// some algebraic hash function that we'll switch to later. #[derive(Debug, Clone)] -pub struct DummyHash { +pub struct DummyHash { power: F, state: F, } -impl Hasher for DummyHash { +impl Hasher for DummyHash { fn init(key: F) -> Self { DummyHash { power: F::ZETA + F::one() + key, diff --git a/src/tweedle/curves.rs b/src/tweedle/curves.rs index 646bd1fd..cfc7df67 100644 --- a/src/tweedle/curves.rs +++ b/src/tweedle/curves.rs @@ -4,10 +4,11 @@ use core::cmp; use core::fmt::Debug; use core::ops::{Add, Mul, Neg, Sub}; +use ff::Field; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; use super::{Fp, Fq}; -use crate::arithmetic::{Curve, CurveAffine, Field, Group}; +use crate::arithmetic::{Curve, CurveAffine, FieldExt, Group}; macro_rules! new_curve_impl { ($name:ident, $name_affine:ident, $base:ident, $scalar:ident) => { @@ -62,7 +63,7 @@ macro_rules! new_curve_impl { } fn is_zero(&self) -> Choice { - self.z.is_zero() + self.z.ct_is_zero() } fn to_affine(&self) -> Self::Affine { @@ -78,7 +79,7 @@ macro_rules! new_curve_impl { infinity: Choice::from(0u8), }; - $name_affine::conditional_select(&tmp, &$name_affine::zero(), zinv.is_zero()) + $name_affine::conditional_select(&tmp, &$name_affine::zero(), zinv.ct_is_zero()) } fn double(&self) -> Self { @@ -131,7 +132,7 @@ macro_rules! new_curve_impl { (self.y.square() - (self.x.square() * self.x)) .ct_eq(&((self.z.square() * self.z).square() * $name::curve_constant_b())) - | self.z.is_zero() + | self.z.ct_is_zero() } fn batch_to_affine(p: &[Self], q: &mut [Self::Affine]) { @@ -552,7 +553,7 @@ macro_rules! new_curve_impl { tmp[31] &= 0b0111_1111; $base::from_bytes(&tmp).and_then(|x| { - CtOption::new(Self::zero(), x.is_zero() & (!ysign)).or_else(|| { + CtOption::new(Self::zero(), x.ct_is_zero() & (!ysign)).or_else(|| { let x3 = x.square() * x; (x3 + $name::curve_constant_b()).sqrt().and_then(|y| { let sign = Choice::from(y.to_bytes()[0] & 1); @@ -593,7 +594,7 @@ macro_rules! new_curve_impl { $base::from_bytes(&xbytes).and_then(|x| { $base::from_bytes(&ybytes).and_then(|y| { - CtOption::new(Self::zero(), x.is_zero() & y.is_zero()).or_else(|| { + CtOption::new(Self::zero(), x.ct_is_zero() & y.ct_is_zero()).or_else(|| { let on_curve = (x * x.square() + $name::curve_constant_b()).ct_eq(&y.square()); diff --git a/src/tweedle/fields.rs b/src/tweedle/fields.rs index 03f15b39..e9f4972f 100644 --- a/src/tweedle/fields.rs +++ b/src/tweedle/fields.rs @@ -8,11 +8,14 @@ pub use fp::*; pub use fq::*; #[cfg(test)] -use crate::arithmetic::Field; +use ff::{Field, PrimeField}; + +#[cfg(test)] +use crate::arithmetic::FieldExt; #[test] fn test_extract() { - let a = Fq::random(); + let a = Fq::rand(); let a = a.square(); let (t, s) = a.extract_radix2_vartime().unwrap(); assert_eq!( diff --git a/src/tweedle/fields/fp.rs b/src/tweedle/fields/fp.rs index 89d8bfbb..2b969a31 100644 --- a/src/tweedle/fields/fp.rs +++ b/src/tweedle/fields/fp.rs @@ -1,10 +1,11 @@ +use bitvec::{array::BitArray, order::Lsb0}; use core::convert::TryInto; use core::fmt; use core::ops::{Add, Mul, Neg, Sub}; - +use rand::RngCore; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; -use crate::arithmetic::{adc, mac, sbb, Field, Group}; +use crate::arithmetic::{adc, mac, sbb, FieldExt, Group}; /// This represents an element of $\mathbb{F}_p$ where /// @@ -101,6 +102,19 @@ const MODULUS: Fp = Fp([ 0x4000000000000000, ]); +/// The modulus as u32 limbs. +#[cfg(not(target_pointer_width = "64"))] +const MODULUS_LIMBS_32: [u32; 8] = [ + 0x0000_0001, + 0xa140_64e2, + 0x6c3f_59b9, + 0x038a_a127, + 0x0000_0000, + 0x0000_0000, + 0x0000_0000, + 0x4000_0000, +]; + impl<'a> Neg for &'a Fp { type Output = Fp; @@ -176,6 +190,15 @@ const R3: Fp = Fp([ 0x217cb214ebb8fc72, ]); +/// `GENERATOR = 5 mod p` is a generator of the `p - 1` order multiplicative subgroup, and +/// is also a quadratic non-residue. +const GENERATOR: Fp = Fp::from_raw([ + 0x0000_0000_0000_0005, + 0x0000_0000_0000_0000, + 0x0000_0000_0000_0000, + 0x0000_0000_0000_0000, +]); + const S: u32 = 33; /// GENERATOR^t where t * 2^s + 1 = p @@ -416,6 +439,12 @@ impl Fp { } } +impl From for [u8; 32] { + fn from(value: Fp) -> [u8; 32] { + value.to_bytes() + } +} + impl<'a> From<&'a Fp> for [u8; 32] { fn from(value: &'a Fp) -> [u8; 32] { value.to_bytes() @@ -439,53 +468,12 @@ impl Group for Fp { } } -impl Field for Fp { - const NUM_BITS: u32 = 255; - const CAPACITY: u32 = 254; - const S: u32 = S; - const ROOT_OF_UNITY: Self = ROOT_OF_UNITY; - const ROOT_OF_UNITY_INV: Self = Fp::from_raw([ - 0x9246674078fa45bb, - 0xd822ebd60888c5ea, - 0x56d579133a11731f, - 0x1c88fa9e942120bb, - ]); - const UNROLL_T_EXPONENT: [u64; 4] = [ - 0x3b3a6633d1897d83, - 0x0000000000c93d5b, - 0xf000000000000000, - 0xe34ab16, - ]; - const T_EXPONENT: [u64; 4] = [ - 0xb61facdcd0a03271, - 0x0000000001c55093, - 0x0000000000000000, - 0x20000000, - ]; - const DELTA: Self = DELTA; - const UNROLL_S_EXPONENT: u64 = 0x11cb54e91; - const TWO_INV: Self = Fp::from_raw([ - 0xd0a0327100000001, - 0x01c55093b61facdc, - 0x0000000000000000, - 0x2000000000000000, - ]); - const RESCUE_ALPHA: u64 = 5; - const RESCUE_INVALPHA: [u64; 4] = [ - 0x810050b4cccccccd, - 0x360880ec56991494, - 0x3333333333333333, - 0x3333333333333333, - ]; - const ZETA: Self = Fp::from_raw([ - 0x8598abb3a410c9c8, - 0x7881fb239ba41a26, - 0x9bebc9146ef83d9a, - 0x1508415ab5e97c94, - ]); +impl ff::Field for Fp { + fn random(mut rng: impl RngCore) -> Self { + let mut random_bytes = [0; 64]; + rng.fill_bytes(&mut random_bytes[..]); - fn is_zero(&self) -> Choice { - self.ct_eq(&Self::zero()) + Self::from_bytes_wide(&random_bytes) } fn zero() -> Self { @@ -496,12 +484,8 @@ impl Field for Fp { Self::one() } - fn from_u64(v: u64) -> Self { - Fp::from_raw([v as u64, 0, 0, 0]) - } - - fn from_u128(v: u128) -> Self { - Fp::from_raw([v as u64, (v >> 64) as u64, 0, 0]) + fn is_zero(&self) -> bool { + self.ct_is_zero().into() } fn double(&self) -> Self { @@ -569,6 +553,150 @@ impl Field for Fp { CtOption::new(tmp, !self.ct_eq(&Self::zero())) } + fn pow_vartime>(&self, exp: S) -> Self { + let mut res = Self::one(); + let mut found_one = false; + for e in exp.as_ref().iter().rev() { + for i in (0..64).rev() { + if found_one { + res = res.square(); + } + + if ((*e >> i) & 1) == 1 { + found_one = true; + res *= self; + } + } + } + res + } +} + +#[cfg(not(target_pointer_width = "64"))] +type ReprBits = [u32; 8]; + +#[cfg(target_pointer_width = "64")] +type ReprBits = [u64; 4]; + +impl ff::PrimeField for Fp { + type Repr = [u8; 32]; + type ReprBits = ReprBits; + + const NUM_BITS: u32 = 255; + const CAPACITY: u32 = 254; + const S: u32 = S; + + fn from_repr(repr: Self::Repr) -> Option { + Self::from_bytes(&repr).into() + } + + fn to_repr(&self) -> Self::Repr { + self.to_bytes() + } + + fn to_le_bits(&self) -> BitArray { + let bytes = self.to_bytes(); + + #[cfg(not(target_pointer_width = "64"))] + let limbs = [ + u32::from_le_bytes(bytes[0..4].try_into().unwrap()), + u32::from_le_bytes(bytes[4..8].try_into().unwrap()), + u32::from_le_bytes(bytes[8..12].try_into().unwrap()), + u32::from_le_bytes(bytes[12..16].try_into().unwrap()), + u32::from_le_bytes(bytes[16..20].try_into().unwrap()), + u32::from_le_bytes(bytes[20..24].try_into().unwrap()), + u32::from_le_bytes(bytes[24..28].try_into().unwrap()), + u32::from_le_bytes(bytes[28..32].try_into().unwrap()), + ]; + + #[cfg(target_pointer_width = "64")] + let limbs = [ + u64::from_le_bytes(bytes[0..8].try_into().unwrap()), + u64::from_le_bytes(bytes[8..16].try_into().unwrap()), + u64::from_le_bytes(bytes[16..24].try_into().unwrap()), + u64::from_le_bytes(bytes[24..32].try_into().unwrap()), + ]; + + BitArray::new(limbs) + } + + fn is_odd(&self) -> bool { + self.to_bytes()[0] & 1 == 1 + } + + fn char_le_bits() -> BitArray { + #[cfg(not(target_pointer_width = "64"))] + { + BitArray::new(MODULUS_LIMBS_32) + } + + #[cfg(target_pointer_width = "64")] + BitArray::new(MODULUS.0) + } + + fn multiplicative_generator() -> Self { + GENERATOR + } + + fn root_of_unity() -> Self { + Self::ROOT_OF_UNITY + } +} + +impl FieldExt for Fp { + const ROOT_OF_UNITY: Self = ROOT_OF_UNITY; + const ROOT_OF_UNITY_INV: Self = Fp::from_raw([ + 0x9246674078fa45bb, + 0xd822ebd60888c5ea, + 0x56d579133a11731f, + 0x1c88fa9e942120bb, + ]); + const UNROLL_T_EXPONENT: [u64; 4] = [ + 0x3b3a6633d1897d83, + 0x0000000000c93d5b, + 0xf000000000000000, + 0xe34ab16, + ]; + const T_EXPONENT: [u64; 4] = [ + 0xb61facdcd0a03271, + 0x0000000001c55093, + 0x0000000000000000, + 0x20000000, + ]; + const DELTA: Self = DELTA; + const UNROLL_S_EXPONENT: u64 = 0x11cb54e91; + const TWO_INV: Self = Fp::from_raw([ + 0xd0a0327100000001, + 0x01c55093b61facdc, + 0x0000000000000000, + 0x2000000000000000, + ]); + const RESCUE_ALPHA: u64 = 5; + const RESCUE_INVALPHA: [u64; 4] = [ + 0x810050b4cccccccd, + 0x360880ec56991494, + 0x3333333333333333, + 0x3333333333333333, + ]; + const ZETA: Self = Fp::from_raw([ + 0x8598abb3a410c9c8, + 0x7881fb239ba41a26, + 0x9bebc9146ef83d9a, + 0x1508415ab5e97c94, + ]); + + fn ct_is_zero(&self) -> Choice { + self.ct_eq(&Self::zero()) + } + + fn from_u64(v: u64) -> Self { + Fp::from_raw([v as u64, 0, 0, 0]) + } + + fn from_u128(v: u128) -> Self { + Fp::from_raw([v as u64, (v >> 64) as u64, 0, 0]) + } + /// Attempts to convert a little-endian byte representation of /// a scalar into a `Fp`, failing if the input is not canonical. fn from_bytes(bytes: &[u8; 32]) -> CtOption { @@ -635,6 +763,9 @@ impl Field for Fp { } } +#[cfg(test)] +use ff::{Field, PrimeField}; + #[test] fn test_inv() { // Compute -(r^{-1} mod 2^64) mod 2^64 by exponentiating diff --git a/src/tweedle/fields/fq.rs b/src/tweedle/fields/fq.rs index 1bc93e26..7462922a 100644 --- a/src/tweedle/fields/fq.rs +++ b/src/tweedle/fields/fq.rs @@ -1,10 +1,11 @@ +use bitvec::{array::BitArray, order::Lsb0}; use core::convert::TryInto; use core::fmt; use core::ops::{Add, Mul, Neg, Sub}; - +use rand::RngCore; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; -use crate::arithmetic::{adc, mac, sbb, Field, Group}; +use crate::arithmetic::{adc, mac, sbb, FieldExt, Group}; /// This represents an element of $\mathbb{F}_q$ where /// @@ -101,6 +102,19 @@ const MODULUS: Fq = Fq([ 0x4000000000000000, ]); +/// The modulus as u32 limbs. +#[cfg(not(target_pointer_width = "64"))] +const MODULUS_LIMBS_32: [u32; 8] = [ + 0x0000_0001, + 0x842c_afd4, + 0x6962_86c9, + 0x038a_a127, + 0x0000_0000, + 0x0000_0000, + 0x0000_0000, + 0x4000_0000, +]; + impl<'a> Neg for &'a Fq { type Output = Fq; @@ -176,6 +190,15 @@ const R3: Fq = Fq([ 0xa42cdf95f959577, ]); +/// `GENERATOR = 5 mod q` is a generator of the `q - 1` order multiplicative subgroup, and +/// is also a quadratic non-residue. +const GENERATOR: Fq = Fq::from_raw([ + 0x0000_0000_0000_0005, + 0x0000_0000_0000_0000, + 0x0000_0000_0000_0000, + 0x0000_0000_0000_0000, +]); + const S: u32 = 34; /// GENERATOR^t where t * 2^s + 1 = q @@ -431,6 +454,12 @@ impl Fq { } } +impl From for [u8; 32] { + fn from(value: Fq) -> [u8; 32] { + value.to_bytes() + } +} + impl<'a> From<&'a Fq> for [u8; 32] { fn from(value: &'a Fq) -> [u8; 32] { value.to_bytes() @@ -454,53 +483,12 @@ impl Group for Fq { } } -impl Field for Fq { - const NUM_BITS: u32 = 255; - const CAPACITY: u32 = 254; - const S: u32 = S; - const ROOT_OF_UNITY: Self = ROOT_OF_UNITY; - const ROOT_OF_UNITY_INV: Self = Fq::from_raw([ - 0x824860d3eb30de02, - 0xad9f0afd0ea63acc, - 0xd250318c11a16fe1, - 0x12a9f5e1dd62dabc, - ]); - const UNROLL_T_EXPONENT: [u64; 4] = [ - 0x9b71de17e6d2d5a0, - 0x0000000000296ee0, - 0x8c00000000000000, - 0x2ecc05e, - ]; - const T_EXPONENT: [u64; 4] = [ - 0xda58a1b2610b2bf5, - 0x0000000000e2a849, - 0x0000000000000000, - 0x10000000, - ]; - const DELTA: Self = DELTA; - const UNROLL_S_EXPONENT: u64 = 0x344cfe85d; - const TWO_INV: Self = Fq::from_raw([ - 0xc21657ea00000001, - 0x01c55093b4b14364, - 0x0000000000000000, - 0x2000000000000000, - ]); - const RESCUE_ALPHA: u64 = 5; - const RESCUE_INVALPHA: [u64; 4] = [ - 0xd023bfdccccccccd, - 0x360880ec544ed23a, - 0x3333333333333333, - 0x3333333333333333, - ]; - const ZETA: Self = Fq::from_raw([ - 0x4394c2bd148fa4fd, - 0x69cf8de720e52ec1, - 0x87ad8b5ff9731ffe, - 0x36c66d3a1e049a58, - ]); +impl ff::Field for Fq { + fn random(mut rng: impl RngCore) -> Self { + let mut random_bytes = [0; 64]; + rng.fill_bytes(&mut random_bytes[..]); - fn is_zero(&self) -> Choice { - self.ct_eq(&Self::zero()) + Self::from_bytes_wide(&random_bytes) } fn zero() -> Self { @@ -511,12 +499,8 @@ impl Field for Fq { Self::one() } - fn from_u64(v: u64) -> Self { - Fq::from_raw([v as u64, 0, 0, 0]) - } - - fn from_u128(v: u128) -> Self { - Fq::from_raw([v as u64, (v >> 64) as u64, 0, 0]) + fn is_zero(&self) -> bool { + self.ct_is_zero().into() } fn double(&self) -> Self { @@ -584,6 +568,150 @@ impl Field for Fq { CtOption::new(tmp, !self.ct_eq(&Self::zero())) } + fn pow_vartime>(&self, exp: S) -> Self { + let mut res = Self::one(); + let mut found_one = false; + for e in exp.as_ref().iter().rev() { + for i in (0..64).rev() { + if found_one { + res = res.square(); + } + + if ((*e >> i) & 1) == 1 { + found_one = true; + res *= self; + } + } + } + res + } +} + +#[cfg(not(target_pointer_width = "64"))] +type ReprBits = [u32; 8]; + +#[cfg(target_pointer_width = "64")] +type ReprBits = [u64; 4]; + +impl ff::PrimeField for Fq { + type Repr = [u8; 32]; + type ReprBits = ReprBits; + + const NUM_BITS: u32 = 255; + const CAPACITY: u32 = 254; + const S: u32 = S; + + fn from_repr(repr: Self::Repr) -> Option { + Self::from_bytes(&repr).into() + } + + fn to_repr(&self) -> Self::Repr { + self.to_bytes() + } + + fn to_le_bits(&self) -> BitArray { + let bytes = self.to_bytes(); + + #[cfg(not(target_pointer_width = "64"))] + let limbs = [ + u32::from_le_bytes(bytes[0..4].try_into().unwrap()), + u32::from_le_bytes(bytes[4..8].try_into().unwrap()), + u32::from_le_bytes(bytes[8..12].try_into().unwrap()), + u32::from_le_bytes(bytes[12..16].try_into().unwrap()), + u32::from_le_bytes(bytes[16..20].try_into().unwrap()), + u32::from_le_bytes(bytes[20..24].try_into().unwrap()), + u32::from_le_bytes(bytes[24..28].try_into().unwrap()), + u32::from_le_bytes(bytes[28..32].try_into().unwrap()), + ]; + + #[cfg(target_pointer_width = "64")] + let limbs = [ + u64::from_le_bytes(bytes[0..8].try_into().unwrap()), + u64::from_le_bytes(bytes[8..16].try_into().unwrap()), + u64::from_le_bytes(bytes[16..24].try_into().unwrap()), + u64::from_le_bytes(bytes[24..32].try_into().unwrap()), + ]; + + BitArray::new(limbs) + } + + fn is_odd(&self) -> bool { + self.to_bytes()[0] & 1 == 1 + } + + fn char_le_bits() -> BitArray { + #[cfg(not(target_pointer_width = "64"))] + { + BitArray::new(MODULUS_LIMBS_32) + } + + #[cfg(target_pointer_width = "64")] + BitArray::new(MODULUS.0) + } + + fn multiplicative_generator() -> Self { + GENERATOR + } + + fn root_of_unity() -> Self { + Self::ROOT_OF_UNITY + } +} + +impl FieldExt for Fq { + const ROOT_OF_UNITY: Self = ROOT_OF_UNITY; + const ROOT_OF_UNITY_INV: Self = Fq::from_raw([ + 0x824860d3eb30de02, + 0xad9f0afd0ea63acc, + 0xd250318c11a16fe1, + 0x12a9f5e1dd62dabc, + ]); + const UNROLL_T_EXPONENT: [u64; 4] = [ + 0x9b71de17e6d2d5a0, + 0x0000000000296ee0, + 0x8c00000000000000, + 0x2ecc05e, + ]; + const T_EXPONENT: [u64; 4] = [ + 0xda58a1b2610b2bf5, + 0x0000000000e2a849, + 0x0000000000000000, + 0x10000000, + ]; + const DELTA: Self = DELTA; + const UNROLL_S_EXPONENT: u64 = 0x344cfe85d; + const TWO_INV: Self = Fq::from_raw([ + 0xc21657ea00000001, + 0x01c55093b4b14364, + 0x0000000000000000, + 0x2000000000000000, + ]); + const RESCUE_ALPHA: u64 = 5; + const RESCUE_INVALPHA: [u64; 4] = [ + 0xd023bfdccccccccd, + 0x360880ec544ed23a, + 0x3333333333333333, + 0x3333333333333333, + ]; + const ZETA: Self = Fq::from_raw([ + 0x4394c2bd148fa4fd, + 0x69cf8de720e52ec1, + 0x87ad8b5ff9731ffe, + 0x36c66d3a1e049a58, + ]); + + fn ct_is_zero(&self) -> Choice { + self.ct_eq(&Self::zero()) + } + + fn from_u64(v: u64) -> Self { + Fq::from_raw([v as u64, 0, 0, 0]) + } + + fn from_u128(v: u128) -> Self { + Fq::from_raw([v as u64, (v >> 64) as u64, 0, 0]) + } + /// Attempts to convert a little-endian byte representation of /// a scalar into a `Fq`, failing if the input is not canonical. fn from_bytes(bytes: &[u8; 32]) -> CtOption { @@ -650,6 +778,9 @@ impl Field for Fq { } } +#[cfg(test)] +use ff::{Field, PrimeField}; + #[test] fn test_inv() { // Compute -(r^{-1} mod 2^64) mod 2^64 by exponentiating