mirror of https://github.com/zcash/halo2.git
commit
3bcfe7825f
|
@ -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"
|
||||
|
|
|
@ -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(|| {
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
16
src/plonk.rs
16
src/plonk.rs
|
@ -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 };
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(),
|
||||
},
|
||||
]
|
||||
};
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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()));
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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!(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue