Merge pull request #61 from zcash/ff-traits

Migrate to ff traits
This commit is contained in:
ebfull 2020-12-01 13:59:06 -07:00 committed by GitHub
commit 3bcfe7825f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 498 additions and 302 deletions

View File

@ -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"

View File

@ -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(|| {

View File

@ -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<FF: Field> {
trait StandardCS<FF: FieldExt> {
fn raw_multiply<F>(&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<F: Field> {
struct MyCircuit<F: FieldExt> {
a: Option<F>,
k: u32,
}
struct StandardPLONK<'a, F: Field, CS: Assignment<F> + 'a> {
struct StandardPLONK<'a, F: FieldExt, CS: Assignment<F> + 'a> {
cs: &'a mut CS,
config: PLONKConfig,
current_gate: usize,
_marker: PhantomData<F>,
}
impl<'a, FF: Field, CS: Assignment<FF>> StandardPLONK<'a, FF, CS> {
impl<'a, FF: FieldExt, CS: Assignment<FF>> 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<FF>> StandardCS<FF> for StandardPLONK<'a, FF, CS> {
impl<'a, FF: FieldExt, CS: Assignment<FF>> StandardCS<FF> for StandardPLONK<'a, FF, CS> {
fn raw_multiply<F>(&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<F: Field> Circuit<F> for MyCircuit<F> {
impl<F: FieldExt> Circuit<F> for MyCircuit<F> {
type Config = PLONKConfig;
fn configure(meta: &mut ConstraintSystem<F>) -> 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<Fp> = 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<Fp> = MyCircuit {
a: Some(Fp::random()),
a: Some(Fp::rand()),
k,
};

View File

@ -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<FF: Field> {
trait StandardCS<FF: FieldExt> {
fn raw_multiply<F>(&mut self, f: F) -> Result<(Variable, Variable, Variable), Error>
where
F: FnOnce() -> Result<(FF, FF, FF), Error>;
@ -40,19 +40,19 @@ trait StandardCS<FF: Field> {
F: FnOnce() -> Result<FF, Error>;
}
struct MyCircuit<F: Field> {
struct MyCircuit<F: FieldExt> {
a: Option<F>,
k: u32,
}
struct StandardPLONK<'a, F: Field, CS: Assignment<F> + 'a> {
struct StandardPLONK<'a, F: FieldExt, CS: Assignment<F> + 'a> {
cs: &'a mut CS,
config: PLONKConfig,
current_gate: usize,
_marker: PhantomData<F>,
}
impl<'a, FF: Field, CS: Assignment<FF>> StandardPLONK<'a, FF, CS> {
impl<'a, FF: FieldExt, CS: Assignment<FF>> 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<FF>> StandardPLONK<'a, FF, CS> {
}
}
impl<'a, FF: Field, CS: Assignment<FF>> StandardCS<FF> for StandardPLONK<'a, FF, CS> {
impl<'a, FF: FieldExt, CS: Assignment<FF>> StandardCS<FF> for StandardPLONK<'a, FF, CS> {
fn raw_multiply<F>(&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<FF>> StandardCS<FF> for StandardPLONK<'a, FF,
}
}
impl<F: Field> Circuit<F> for MyCircuit<F> {
impl<F: FieldExt> Circuit<F> for MyCircuit<F> {
type Config = PLONKConfig;
fn configure(meta: &mut ConstraintSystem<F>) -> PLONKConfig {
@ -268,7 +268,7 @@ fn main() {
recorder.clear();
let circuit: MyCircuit<Fp> = MyCircuit {
a: Some(Fp::random()),
a: Some(Fp::rand()),
k,
};

View File

@ -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<F: Field> {
impl<'a, F, I> BatchInvert<F> for I
where
F: Field,
F: FieldExt,
I: IntoIterator<Item = &'a mut F>,
{
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<F: Field>(challenge: Challenge) -> F {
pub fn get_challenge_scalar<F: FieldExt>(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<F: Field>(points: &[F], evals: &[F]) -> Vec<F> {
pub fn lagrange_interpolate<F: FieldExt>(points: &[F], evals: &[F]) -> Vec<F> {
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::<Vec<_>>();
let evals = (0..5).map(|_| Fp::random()).collect::<Vec<_>>();
let points = (0..5).map(|_| Fp::rand()).collect::<Vec<_>>();
let evals = (0..5).map(|_| Fp::rand()).collect::<Vec<_>>();
for coeffs in 0..5 {
let points = &points[0..coeffs];

View File

@ -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<Output = <Self as Curve>::Affine>
+ From<Self>;
/// 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<Self>
+ From<Self>;
/// 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;

View File

@ -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<bool>
+ From<u64>
+ Add<Output = Self>
+ Sub<Output = Self>
+ Mul<Output = Self>
+ Neg<Output = Self>
+ 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<Scalar = Self>
pub trait FieldExt:
ff::PrimeField + From<bool> + Ord + ConstantTimeEq + Group<Scalar = Self>
{
/// 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<Self>;
/// Attempts to find the multiplicative inverse of this field element.
fn invert(&self) -> CtOption<Self>;
/// 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);

View File

@ -97,7 +97,7 @@ impl<C: CurveAffine> VerifyingKey<C> {
#[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<FF: Field> {
trait StandardCS<FF: FieldExt> {
fn raw_multiply<F>(&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<FF, Error>;
}
struct MyCircuit<F: Field> {
struct MyCircuit<F: FieldExt> {
a: Option<F>,
}
struct StandardPLONK<'a, F: Field, CS: Assignment<F> + 'a> {
struct StandardPLONK<'a, F: FieldExt, CS: Assignment<F> + 'a> {
cs: &'a mut CS,
config: PLONKConfig,
current_gate: usize,
_marker: PhantomData<F>,
}
impl<'a, FF: Field, CS: Assignment<FF>> StandardPLONK<'a, FF, CS> {
impl<'a, FF: FieldExt, CS: Assignment<FF>> 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<FF>> StandardCS<FF> for StandardPLONK<'a, FF, CS> {
impl<'a, FF: FieldExt, CS: Assignment<FF>> StandardCS<FF> for StandardPLONK<'a, FF, CS> {
fn raw_multiply<F>(&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<F: Field> Circuit<F> for MyCircuit<F> {
impl<F: FieldExt> Circuit<F> for MyCircuit<F> {
type Config = PLONKConfig;
fn configure(meta: &mut ConstraintSystem<F>) -> PLONKConfig {
@ -376,7 +376,7 @@ fn test_proving() {
}
let circuit: MyCircuit<Fp> = MyCircuit {
a: Some(Fp::random()),
a: Some(Fp::rand()),
};
let empty_circuit: MyCircuit<Fp> = MyCircuit { a: None };

View File

@ -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

View File

@ -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,

View File

@ -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<C: CurveAffine> Proof<C> {
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<C: CurveAffine> Proof<C> {
}
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<C: CurveAffine> Proof<C> {
.map(|v| domain.coeff_from_vec(v.to_vec()))
.collect::<Vec<_>>();
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

View File

@ -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,

View File

@ -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};

View File

@ -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();

View File

@ -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<C: CurveAffine> Proof<C> {
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<C: CurveAffine> Proof<C> {
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();

View File

@ -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

View File

@ -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

View File

@ -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<F>: Sized {
fn get_commitment(&self) -> Self::Commitment;
}
fn construct_intermediate_sets<F: Field, I, Q: Query<F>>(
fn construct_intermediate_sets<F: FieldExt, I, Q: Query<F>>(
queries: I,
) -> (Vec<CommitmentData<F, Q::Commitment>>, Vec<Vec<F>>)
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(),
},
]
};

View File

@ -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<C: CurveAffine> Proof<C> {
})
.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 {

View File

@ -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<C: CurveAffine> Proof<C> {
// 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()));

View File

@ -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<F: Field>: Clone + Send + Sync + 'static {
pub trait Hasher<F: FieldExt>: 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<F: Field>: 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<F: Field> {
pub struct DummyHash<F: FieldExt> {
power: F,
state: F,
}
impl<F: Field> Hasher<F> for DummyHash<F> {
impl<F: FieldExt> Hasher<F> for DummyHash<F> {
fn init(key: F) -> Self {
DummyHash {
power: F::ZETA + F::one() + key,

View File

@ -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());

View File

@ -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!(

View File

@ -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<Fp> 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<S: AsRef<[u64]>>(&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> {
Self::from_bytes(&repr).into()
}
fn to_repr(&self) -> Self::Repr {
self.to_bytes()
}
fn to_le_bits(&self) -> BitArray<Lsb0, Self::ReprBits> {
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<Lsb0, Self::ReprBits> {
#[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<Fp> {
@ -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

View File

@ -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<Fq> 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<S: AsRef<[u64]>>(&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> {
Self::from_bytes(&repr).into()
}
fn to_repr(&self) -> Self::Repr {
self.to_bytes()
}
fn to_le_bits(&self) -> BitArray<Lsb0, Self::ReprBits> {
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<Lsb0, Self::ReprBits> {
#[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<Fq> {
@ -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