Update `crypto-primitives` and their contraints.
jump to
@@ -49,10 +49,4 @@
[[bench]] name = "schnorr_sig" path = "benches/crypto_primitives/signature.rs" -harness = false - -[[bench]] -name = "gm17" -path = "benches/crypto_primitives/nizk.rs" -required-features = ["r1cs", "gm17"] -harness = false +harness = false
@@ -10,7 +10,7 @@
#[derive(Clone, PartialEq, Eq, Hash)] pub struct CommWindow; -impl PedersenWindow for CommWindow { +impl Window for CommWindow { const WINDOW_SIZE: usize = 250; const NUM_WINDOWS: usize = 8; }@@ -19,25 +19,21 @@ fn pedersen_comm_setup(c: &mut Criterion) {
c.bench_function("Pedersen Commitment Setup", move |b| { b.iter(|| { let mut rng = &mut rand::thread_rng(); - PedersenCommitment::<Edwards, CommWindow>::setup(&mut rng).unwrap() + Commitment::<Edwards, CommWindow>::setup(&mut rng).unwrap() }) }); } fn pedersen_comm_eval(c: &mut Criterion) { let mut rng = &mut rand::thread_rng(); - let parameters = PedersenCommitment::<Edwards, CommWindow>::setup(&mut rng).unwrap(); + let parameters = Commitment::<Edwards, CommWindow>::setup(&mut rng).unwrap(); let input = vec![5u8; 128]; c.bench_function("Pedersen Commitment Eval", move |b| { b.iter(|| { let rng = &mut rand::thread_rng(); - let commitment_randomness = PedersenRandomness::rand(rng); - PedersenCommitment::<Edwards, CommWindow>::commit( - ¶meters, - &input, - &commitment_randomness, - ) - .unwrap(); + let commitment_randomness = Randomness::rand(rng); + Commitment::<Edwards, CommWindow>::commit(¶meters, &input, &commitment_randomness) + .unwrap(); }) }); }
@@ -10,7 +10,7 @@
#[derive(Clone, PartialEq, Eq, Hash)] pub struct HashWindow; -impl PedersenWindow for HashWindow { +impl Window for HashWindow { const WINDOW_SIZE: usize = 250; const NUM_WINDOWS: usize = 8; }@@ -19,18 +19,18 @@ fn pedersen_crh_setup(c: &mut Criterion) {
c.bench_function("Pedersen CRH Setup", move |b| { b.iter(|| { let mut rng = &mut rand::thread_rng(); - PedersenCRH::<Edwards, HashWindow>::setup(&mut rng).unwrap() + CRH::<Edwards, HashWindow>::setup(&mut rng).unwrap() }) }); } fn pedersen_crh_eval(c: &mut Criterion) { let mut rng = &mut rand::thread_rng(); - let parameters = PedersenCRH::<Edwards, HashWindow>::setup(&mut rng).unwrap(); + let parameters = CRH::<Edwards, HashWindow>::setup(&mut rng).unwrap(); let input = vec![5u8; 128]; c.bench_function("Pedersen CRH Eval", move |b| { b.iter(|| { - PedersenCRH::<Edwards, HashWindow>::evaluate(¶meters, &input).unwrap(); + CRH::<Edwards, HashWindow>::evaluate(¶meters, &input).unwrap(); }) }); }
@@ -1,121 +0,0 @@
-#[macro_use] -extern crate criterion; - -use algebra::{curves::bls12_377::Bls12_377, fields::bls12_377::Fr, Field}; -use crypto_primitives::nizk::*; -use r1cs_core::{ConstraintSynthesizer, ConstraintSystem, SynthesisError}; - -use criterion::Criterion; -use rand::{thread_rng, Rng}; - -type TestProofSystem = Gm17<Bls12_377, Bench<Fr>, Fr>; - -struct Bench<F: Field> { - inputs: Vec<Option<F>>, - num_constraints: usize, -} - -impl<F: Field> ConstraintSynthesizer<F> for Bench<F> { - fn generate_constraints<CS: ConstraintSystem<F>>( - self, - cs: &mut CS, - ) -> Result<(), SynthesisError> { - assert!(self.inputs.len() >= 2); - assert!(self.num_constraints >= self.inputs.len()); - - let mut variables: Vec<_> = Vec::with_capacity(self.inputs.len()); - for (i, input) in self.inputs.into_iter().enumerate() { - let input_var = cs.alloc_input( - || format!("Input {}", i), - || input.ok_or(SynthesisError::AssignmentMissing), - )?; - variables.push((input, input_var)); - } - - for i in 0..self.num_constraints { - let new_entry = { - let (input_1_val, input_1_var) = variables[i]; - let (input_2_val, input_2_var) = variables[i + 1]; - let result_val = - input_1_val.and_then(|input_1| input_2_val.map(|input_2| input_1 * &input_2)); - let result_var = cs.alloc( - || format!("Result {}", i), - || result_val.ok_or(SynthesisError::AssignmentMissing), - )?; - cs.enforce( - || format!("Enforce constraint {}", i), - |lc| lc + input_1_var, - |lc| lc + input_2_var, - |lc| lc + result_var, - ); - (result_val, result_var) - }; - variables.push(new_entry); - } - Ok(()) - } -} - -fn gm17_setup(c: &mut Criterion) { - let num_inputs = 100; - let num_constraints = num_inputs; - let rng = &mut thread_rng(); - let mut inputs: Vec<Option<Fr>> = Vec::with_capacity(num_inputs); - for _ in 0..num_inputs { - inputs.push(Some(rng.gen())); - } - - c.bench_function("gm17_setup", move |b| { - b.iter(|| { - TestProofSystem::setup( - Bench::<Fr> { - inputs: vec![None; num_inputs], - num_constraints, - }, - rng, - ) - .unwrap() - }) - }); -} - -fn gm17_prove(c: &mut Criterion) { - let num_inputs = 100; - let num_constraints = num_inputs; - let rng = &mut thread_rng(); - let mut inputs: Vec<Option<Fr>> = Vec::with_capacity(num_inputs); - for _ in 0..num_inputs { - inputs.push(Some(rng.gen())); - } - - let params = TestProofSystem::setup( - Bench::<Fr> { - inputs: vec![None; num_inputs], - num_constraints, - }, - rng, - ) - .unwrap(); - - c.bench_function("gm17_prove", move |b| { - b.iter(|| { - TestProofSystem::prove( - ¶ms.0, - Bench { - inputs: inputs.clone(), - num_constraints, - }, - rng, - ) - .unwrap() - }) - }); -} - -criterion_group! { - name = nizk_eval; - config = Criterion::default().sample_size(10); - targets = gm17_setup, gm17_prove -} - -criterion_main!(nizk_eval);
@@ -1,180 +1,89 @@
#[macro_use] extern crate criterion; -mod affine { - use algebra::ed_on_bls12_377::EdwardsAffine as Edwards; - use blake2::Blake2s; - use criterion::Criterion; - use crypto_primitives::signature::{schnorr::*, SignatureScheme}; - use rand::{self, Rng}; +use algebra::ed_on_bls12_377::EdwardsProjective as Edwards; +use blake2::Blake2s; +use criterion::Criterion; +use crypto_primitives::signature::{schnorr::*, SignatureScheme}; +use rand::{self, Rng}; - type SchnorrEdwards = SchnorrSignature<Edwards, Blake2s>; - fn schnorr_signature_setup(c: &mut Criterion) { - c.bench_function("SchnorrEdwardsAffine: Setup", move |b| { - b.iter(|| { - let mut rng = &mut rand::thread_rng(); - SchnorrEdwards::setup(&mut rng).unwrap() - }) - }); - } +type SchnorrEdwards = Schnorr<Edwards, Blake2s>; +fn schnorr_signature_setup(c: &mut Criterion) { + c.bench_function("SchnorrEdwards: Setup", move |b| { + b.iter(|| { + let mut rng = &mut rand::thread_rng(); + SchnorrEdwards::setup(&mut rng).unwrap() + }) + }); +} - fn schnorr_signature_keygen(c: &mut Criterion) { - let mut rng = &mut rand::thread_rng(); - let parameters = SchnorrEdwards::setup(&mut rng).unwrap(); +fn schnorr_signature_keygen(c: &mut Criterion) { + let mut rng = &mut rand::thread_rng(); + let parameters = SchnorrEdwards::setup(&mut rng).unwrap(); - c.bench_function("SchnorrEdwardsAffine: KeyGen", move |b| { - b.iter(|| { - let mut rng = &mut rand::thread_rng(); - SchnorrEdwards::keygen(¶meters, &mut rng).unwrap() - }) - }); - } + c.bench_function("SchnorrEdwards: KeyGen", move |b| { + b.iter(|| { + let mut rng = &mut rand::thread_rng(); + SchnorrEdwards::keygen(¶meters, &mut rng).unwrap() + }) + }); +} - fn schnorr_signature_sign(c: &mut Criterion) { - let mut rng = &mut rand::thread_rng(); - let parameters = SchnorrEdwards::setup(&mut rng).unwrap(); - let (_, sk) = SchnorrEdwards::keygen(¶meters, &mut rng).unwrap(); - let message = [100u8; 128]; +fn schnorr_signature_sign(c: &mut Criterion) { + let mut rng = &mut rand::thread_rng(); + let parameters = SchnorrEdwards::setup(&mut rng).unwrap(); + let (_, sk) = SchnorrEdwards::keygen(¶meters, &mut rng).unwrap(); + let message = [100u8; 128]; - c.bench_function("SchnorrEdwardsAffine: Sign", move |b| { - b.iter(|| { - let mut rng = &mut rand::thread_rng(); - SchnorrEdwards::sign(¶meters, &sk, &message, &mut rng).unwrap() - }) - }); - } + c.bench_function("SchnorrEdwards: Sign", move |b| { + b.iter(|| { + let mut rng = &mut rand::thread_rng(); + SchnorrEdwards::sign(¶meters, &sk, &message, &mut rng).unwrap() + }) + }); +} - fn schnorr_signature_verify(c: &mut Criterion) { - let mut rng = &mut rand::thread_rng(); - let parameters = SchnorrEdwards::setup(&mut rng).unwrap(); - let (pk, sk) = SchnorrEdwards::keygen(¶meters, &mut rng).unwrap(); - let message = [100u8; 128]; - let signature = SchnorrEdwards::sign(¶meters, &sk, &message, &mut rng).unwrap(); +fn schnorr_signature_verify(c: &mut Criterion) { + let mut rng = &mut rand::thread_rng(); + let parameters = SchnorrEdwards::setup(&mut rng).unwrap(); + let (pk, sk) = SchnorrEdwards::keygen(¶meters, &mut rng).unwrap(); + let message = [100u8; 128]; + let signature = SchnorrEdwards::sign(¶meters, &sk, &message, &mut rng).unwrap(); - c.bench_function("SchnorrEdwardsAffine: Verify", move |b| { - b.iter(|| SchnorrEdwards::verify(¶meters, &pk, &message, &signature).unwrap()) - }); - } + c.bench_function("SchnorrEdwards: Verify", move |b| { + b.iter(|| SchnorrEdwards::verify(¶meters, &pk, &message, &signature).unwrap()) + }); +} - fn schnorr_signature_randomize_pk(c: &mut Criterion) { - let mut rng = &mut rand::thread_rng(); - let parameters = SchnorrEdwards::setup(&mut rng).unwrap(); - let (pk, _) = SchnorrEdwards::keygen(¶meters, &mut rng).unwrap(); - let randomness: [u8; 32] = rng.gen(); +fn schnorr_signature_randomize_pk(c: &mut Criterion) { + let mut rng = &mut rand::thread_rng(); + let parameters = SchnorrEdwards::setup(&mut rng).unwrap(); + let (pk, _) = SchnorrEdwards::keygen(¶meters, &mut rng).unwrap(); + let randomness: [u8; 32] = rng.gen(); - c.bench_function("SchnorrEdwardsAffine: Randomize PubKey", move |b| { - b.iter(|| SchnorrEdwards::randomize_public_key(¶meters, &pk, &randomness).unwrap()) - }); - } + c.bench_function("SchnorrEdwards: Randomize PubKey", move |b| { + b.iter(|| SchnorrEdwards::randomize_public_key(¶meters, &pk, &randomness).unwrap()) + }); +} - fn schnorr_signature_randomize_signature(c: &mut Criterion) { - let mut rng = &mut rand::thread_rng(); - let parameters = SchnorrEdwards::setup(&mut rng).unwrap(); - let (_, sk) = SchnorrEdwards::keygen(¶meters, &mut rng).unwrap(); - let randomness: [u8; 32] = rng.gen(); - let message = [100u8; 128]; - let signature = SchnorrEdwards::sign(¶meters, &sk, &message, &mut rng).unwrap(); +fn schnorr_signature_randomize_signature(c: &mut Criterion) { + let mut rng = &mut rand::thread_rng(); + let parameters = SchnorrEdwards::setup(&mut rng).unwrap(); + let (_, sk) = SchnorrEdwards::keygen(¶meters, &mut rng).unwrap(); + let randomness: [u8; 32] = rng.gen(); + let message = [100u8; 128]; + let signature = SchnorrEdwards::sign(¶meters, &sk, &message, &mut rng).unwrap(); - c.bench_function("SchnorrEdwardsAffine: Randomize Signature", move |b| { - b.iter(|| { - SchnorrEdwards::randomize_signature(¶meters, &signature, &randomness).unwrap() - }) - }); - } - criterion_group! { - name = schnorr_sig_affine; - config = Criterion::default().sample_size(20); - targets = schnorr_signature_setup, schnorr_signature_keygen, schnorr_signature_sign, - schnorr_signature_verify, schnorr_signature_randomize_pk, schnorr_signature_randomize_signature - } + c.bench_function("SchnorrEdwards: Randomize Signature", move |b| { + b.iter(|| { + SchnorrEdwards::randomize_signature(¶meters, &signature, &randomness).unwrap() + }) + }); } - -mod projective { - use algebra::ed_on_bls12_377::EdwardsProjective as Edwards; - use blake2::Blake2s; - use criterion::Criterion; - use crypto_primitives::signature::{schnorr::*, SignatureScheme}; - use rand::{self, Rng}; - - type SchnorrEdwards = SchnorrSignature<Edwards, Blake2s>; - fn schnorr_signature_setup(c: &mut Criterion) { - c.bench_function("SchnorrEdwardsProjective: Setup", move |b| { - b.iter(|| { - let mut rng = &mut rand::thread_rng(); - SchnorrEdwards::setup(&mut rng).unwrap() - }) - }); - } - - fn schnorr_signature_keygen(c: &mut Criterion) { - let mut rng = &mut rand::thread_rng(); - let parameters = SchnorrEdwards::setup(&mut rng).unwrap(); - - c.bench_function("SchnorrEdwardsProjective: KeyGen", move |b| { - b.iter(|| { - let mut rng = &mut rand::thread_rng(); - SchnorrEdwards::keygen(¶meters, &mut rng).unwrap() - }) - }); - } - - fn schnorr_signature_sign(c: &mut Criterion) { - let mut rng = &mut rand::thread_rng(); - let parameters = SchnorrEdwards::setup(&mut rng).unwrap(); - let (_, sk) = SchnorrEdwards::keygen(¶meters, &mut rng).unwrap(); - let message = [100u8; 128]; - - c.bench_function("SchnorrEdwardsProjective: Sign", move |b| { - b.iter(|| { - let mut rng = &mut rand::thread_rng(); - SchnorrEdwards::sign(¶meters, &sk, &message, &mut rng).unwrap() - }) - }); - } - - fn schnorr_signature_verify(c: &mut Criterion) { - let mut rng = &mut rand::thread_rng(); - let parameters = SchnorrEdwards::setup(&mut rng).unwrap(); - let (pk, sk) = SchnorrEdwards::keygen(¶meters, &mut rng).unwrap(); - let message = [100u8; 128]; - let signature = SchnorrEdwards::sign(¶meters, &sk, &message, &mut rng).unwrap(); - - c.bench_function("SchnorrEdwardsProjective: Verify", move |b| { - b.iter(|| SchnorrEdwards::verify(¶meters, &pk, &message, &signature).unwrap()) - }); - } - - fn schnorr_signature_randomize_pk(c: &mut Criterion) { - let mut rng = &mut rand::thread_rng(); - let parameters = SchnorrEdwards::setup(&mut rng).unwrap(); - let (pk, _) = SchnorrEdwards::keygen(¶meters, &mut rng).unwrap(); - let randomness: [u8; 32] = rng.gen(); - - c.bench_function("SchnorrEdwardsProjective: Randomize PubKey", move |b| { - b.iter(|| SchnorrEdwards::randomize_public_key(¶meters, &pk, &randomness).unwrap()) - }); - } - - fn schnorr_signature_randomize_signature(c: &mut Criterion) { - let mut rng = &mut rand::thread_rng(); - let parameters = SchnorrEdwards::setup(&mut rng).unwrap(); - let (_, sk) = SchnorrEdwards::keygen(¶meters, &mut rng).unwrap(); - let randomness: [u8; 32] = rng.gen(); - let message = [100u8; 128]; - let signature = SchnorrEdwards::sign(¶meters, &sk, &message, &mut rng).unwrap(); - - c.bench_function("SchnorrEdwardsProjective: Randomize Signature", move |b| { - b.iter(|| { - SchnorrEdwards::randomize_signature(¶meters, &signature, &randomness).unwrap() - }) - }); - } - criterion_group! { - name = schnorr_sig_projective; - config = Criterion::default().sample_size(20); - targets = schnorr_signature_setup, schnorr_signature_keygen, schnorr_signature_sign, - schnorr_signature_verify, schnorr_signature_randomize_pk, schnorr_signature_randomize_signature - } +criterion_group! { + name = schnorr_sig; + config = Criterion::default().sample_size(20); + targets = schnorr_signature_setup, schnorr_signature_keygen, schnorr_signature_sign, + schnorr_signature_verify, schnorr_signature_randomize_pk, schnorr_signature_randomize_signature } -use crate::{affine::schnorr_sig_affine, projective::schnorr_sig_projective}; -criterion_main!(schnorr_sig_affine, schnorr_sig_projective); +criterion_main!(schnorr_sig);
@@ -40,9 +40,9 @@ rayon = { version = "1.0", optional = true }
derivative = { version = "2.0", features = ["use_core"] } [features] -default = ["std"] +default = ["std", "r1cs"] r1cs = ["r1cs-core", "r1cs-std"] -std = ["r1cs", "algebra-core/std", "r1cs-core/std", "r1cs-std/std"] +std = [ "algebra-core/std", "r1cs-core/std", "r1cs-std/std"] parallel = ["std", "rayon", "gm17/parallel", "groth16/parallel", "ff-fft/parallel"] [dev-dependencies]
@@ -1,9 +1,10 @@
-use r1cs_core::{ConstraintSystem, SynthesisError}; +use r1cs_core::{Namespace, SynthesisError}; use crate::{ - commitment::blake2s::Blake2sCommitment, - prf::blake2s::constraints::{blake2s_gadget, Blake2sOutputGadget}, - CommitmentGadget, Vec, + commitment::blake2s, + commitment::CommitmentGadget, + prf::blake2s::constraints::{evaluate_blake2s, OutputVar}, + Vec, }; use algebra_core::{Field, PrimeField}; use r1cs_std::prelude::*;@@ -11,126 +12,58 @@
use core::borrow::Borrow; #[derive(Clone)] -pub struct Blake2sParametersGadget; +pub struct ParametersVar; #[derive(Clone)] -pub struct Blake2sRandomnessGadget(pub Vec<UInt8>); +pub struct RandomnessVar<F: Field>(pub Vec<UInt8<F>>); -pub struct Blake2sCommitmentGadget; +pub struct CommGadget; -impl<ConstraintF: PrimeField> CommitmentGadget<Blake2sCommitment, ConstraintF> - for Blake2sCommitmentGadget -{ - type OutputGadget = Blake2sOutputGadget; - type ParametersGadget = Blake2sParametersGadget; - type RandomnessGadget = Blake2sRandomnessGadget; +impl<F: PrimeField> CommitmentGadget<blake2s::Commitment, F> for CommGadget { + type OutputVar = OutputVar<F>; + type ParametersVar = ParametersVar; + type RandomnessVar = RandomnessVar<F>; - fn check_commitment_gadget<CS: ConstraintSystem<ConstraintF>>( - mut cs: CS, - _: &Self::ParametersGadget, - input: &[UInt8], - r: &Self::RandomnessGadget, - ) -> Result<Self::OutputGadget, SynthesisError> { + fn commit( + _: &Self::ParametersVar, + input: &[UInt8<F>], + r: &Self::RandomnessVar, + ) -> Result<Self::OutputVar, SynthesisError> { let mut input_bits = Vec::with_capacity(512); for byte in input.iter().chain(r.0.iter()) { input_bits.extend_from_slice(&byte.into_bits_le()); } let mut result = Vec::new(); - for (i, int) in blake2s_gadget(cs.ns(|| "Blake2s Eval"), &input_bits)? - .into_iter() - .enumerate() - { - let chunk = int.to_bytes(&mut cs.ns(|| format!("Result ToBytes {}", i)))?; + for int in evaluate_blake2s(&input_bits)?.into_iter() { + let chunk = int.to_bytes()?; result.extend_from_slice(&chunk); } - Ok(Blake2sOutputGadget(result)) + Ok(OutputVar(result)) } } -impl<ConstraintF: Field> AllocGadget<(), ConstraintF> for Blake2sParametersGadget { - fn alloc_constant<T, CS: ConstraintSystem<ConstraintF>>( - cs: CS, - val: T, - ) -> Result<Self, SynthesisError> - where - T: Borrow<()>, - { - Self::alloc(cs, || Ok(val)) - } - - fn alloc<F, T, CS: ConstraintSystem<ConstraintF>>(_: CS, _: F) -> Result<Self, SynthesisError> - where - F: FnOnce() -> Result<T, SynthesisError>, - T: Borrow<()>, - { - Ok(Blake2sParametersGadget) - } - - fn alloc_input<F, T, CS: ConstraintSystem<ConstraintF>>( - _: CS, - _: F, - ) -> Result<Self, SynthesisError> - where - F: FnOnce() -> Result<T, SynthesisError>, - T: Borrow<()>, - { - Ok(Blake2sParametersGadget) +impl<ConstraintF: Field> AllocVar<(), ConstraintF> for ParametersVar { + fn new_variable<T: Borrow<()>>( + _cs: impl Into<Namespace<ConstraintF>>, + _f: impl FnOnce() -> Result<T, SynthesisError>, + _mode: AllocationMode, + ) -> Result<Self, SynthesisError> { + Ok(ParametersVar) } } -impl<ConstraintF: PrimeField> AllocGadget<[u8; 32], ConstraintF> for Blake2sRandomnessGadget { - #[inline] - fn alloc_constant<T, CS: ConstraintSystem<ConstraintF>>( - mut cs: CS, - val: T, - ) -> Result<Self, SynthesisError> - where - T: Borrow<[u8; 32]>, - { - let mut bytes = vec![]; - for (i, b) in val.borrow().iter().enumerate() { - bytes.push(UInt8::alloc_constant(cs.ns(|| format!("value {}", i)), b)?) +impl<ConstraintF: PrimeField> AllocVar<[u8; 32], ConstraintF> for RandomnessVar<ConstraintF> { + fn new_variable<T: Borrow<[u8; 32]>>( + cs: impl Into<Namespace<ConstraintF>>, + f: impl FnOnce() -> Result<T, SynthesisError>, + mode: AllocationMode, + ) -> Result<Self, SynthesisError> { + let bytes = f().map(|b| *b.borrow()).unwrap_or([0u8; 32]); + match mode { + AllocationMode::Constant => Ok(Self(UInt8::constant_vec(&bytes))), + AllocationMode::Input => UInt8::new_input_vec(cs, &bytes).map(Self), + AllocationMode::Witness => UInt8::new_witness_vec(cs, &bytes).map(Self), } - - Ok(Blake2sRandomnessGadget(bytes)) - } - - #[inline] - fn alloc<F, T, CS: ConstraintSystem<ConstraintF>>( - cs: CS, - value_gen: F, - ) -> Result<Self, SynthesisError> - where - F: FnOnce() -> Result<T, SynthesisError>, - T: Borrow<[u8; 32]>, - { - let zeros = [0u8; 32]; - let value = match value_gen() { - Ok(val) => *(val.borrow()), - Err(_) => zeros, - }; - let bytes = <UInt8>::alloc_vec(cs, &value)?; - - Ok(Blake2sRandomnessGadget(bytes)) - } - - #[inline] - fn alloc_input<F, T, CS: ConstraintSystem<ConstraintF>>( - cs: CS, - value_gen: F, - ) -> Result<Self, SynthesisError> - where - F: FnOnce() -> Result<T, SynthesisError>, - T: Borrow<[u8; 32]>, - { - let zeros = [0u8; 32]; - let value = match value_gen() { - Ok(val) => *(val.borrow()), - Err(_) => zeros, - }; - let bytes = <UInt8>::alloc_input_vec(cs, &value)?; - - Ok(Blake2sRandomnessGadget(bytes)) } }@@ -138,64 +71,60 @@ #[cfg(test)]
mod test { use crate::{ commitment::blake2s::{ - constraints::{Blake2sCommitmentGadget, Blake2sRandomnessGadget}, - Blake2sCommitment, + constraints::{CommGadget, RandomnessVar}, + Commitment, }, - *, + commitment::{CommitmentGadget, CommitmentScheme}, }; use algebra::{ed_on_bls12_381::Fq as Fr, test_rng}; use r1cs_core::ConstraintSystem; - use r1cs_std::{prelude::*, test_constraint_system::TestConstraintSystem}; + use r1cs_std::prelude::*; use rand::Rng; #[test] fn commitment_gadget_test() { - let mut cs = TestConstraintSystem::<Fr>::new(); + let cs = ConstraintSystem::<Fr>::new_ref(); let input = [1u8; 32]; let rng = &mut test_rng(); - type TestCOMM = Blake2sCommitment; - type TestCOMMGadget = Blake2sCommitmentGadget; + type TestCOMM = Commitment; + type TestCOMMGadget = CommGadget; let mut randomness = [0u8; 32]; rng.fill(&mut randomness); let parameters = (); - let primitive_result = Blake2sCommitment::commit(¶meters, &input, &randomness).unwrap(); + let primitive_result = Commitment::commit(¶meters, &input, &randomness).unwrap(); - let mut input_bytes = vec![]; - for (byte_i, input_byte) in input.iter().enumerate() { - let cs = cs.ns(|| format!("input_byte_gadget_{}", byte_i)); - input_bytes.push(UInt8::alloc(cs, || Ok(*input_byte)).unwrap()); + let mut input_var = vec![]; + for byte in &input { + input_var.push(UInt8::new_witness(cs.clone(), || Ok(*byte)).unwrap()); } - let mut randomness_bytes = vec![]; - for (byte_i, random_byte) in randomness.iter().enumerate() { - let cs = cs.ns(|| format!("randomness_byte_gadget_{}", byte_i)); - randomness_bytes.push(UInt8::alloc(cs, || Ok(*random_byte)).unwrap()); + let mut randomness_var = vec![]; + for r_byte in randomness.iter() { + randomness_var.push(UInt8::new_witness(cs.clone(), || Ok(r_byte)).unwrap()); } - let randomness_bytes = Blake2sRandomnessGadget(randomness_bytes); + let randomness_var = RandomnessVar(randomness_var); - let gadget_parameters = - <TestCOMMGadget as CommitmentGadget<TestCOMM, Fr>>::ParametersGadget::alloc( - &mut cs.ns(|| "gadget_parameters"), + let parameters_var = + <TestCOMMGadget as CommitmentGadget<TestCOMM, Fr>>::ParametersVar::new_witness( + cs.ns("gadget_parameters"), || Ok(¶meters), ) .unwrap(); - let gadget_result = - <TestCOMMGadget as CommitmentGadget<TestCOMM, Fr>>::check_commitment_gadget( - &mut cs.ns(|| "gadget_evaluation"), - &gadget_parameters, - &input_bytes, - &randomness_bytes, - ) - .unwrap(); + let result_var = <TestCOMMGadget as CommitmentGadget<TestCOMM, Fr>>::commit( + ¶meters_var, + &input_var, + &randomness_var, + ) + .unwrap(); for i in 0..32 { - assert_eq!(primitive_result[i], gadget_result.0[i].get_value().unwrap()); + assert_eq!(primitive_result[i], result_var.0[i].value().unwrap()); } - assert!(cs.is_satisfied()); + assert!(cs.is_satisfied().unwrap()); } }
@@ -4,12 +4,12 @@ use blake2::Blake2s as b2s;
use digest::Digest; use rand::Rng; -pub struct Blake2sCommitment; +pub struct Commitment; #[cfg(feature = "r1cs")] pub mod constraints; -impl CommitmentScheme for Blake2sCommitment { +impl CommitmentScheme for Commitment { type Parameters = (); type Randomness = [u8; 32]; type Output = [u8; 32];@@ -21,11 +21,11 @@
fn commit( _: &Self::Parameters, input: &[u8], - randomness: &Self::Randomness, + r: &Self::Randomness, ) -> Result<Self::Output, Error> { let mut h = b2s::new(); h.input(input); - h.input(randomness.as_ref()); + h.input(r.as_ref()); let mut result = [0u8; 32]; result.copy_from_slice(&h.result()); Ok(result)
@@ -1,23 +1,23 @@
-use crate::CommitmentScheme; +use crate::commitment::CommitmentScheme; use algebra_core::Field; use core::fmt::Debug; -use r1cs_core::{ConstraintSystem, SynthesisError}; +use r1cs_core::SynthesisError; use r1cs_std::prelude::*; pub trait CommitmentGadget<C: CommitmentScheme, ConstraintF: Field> { - type OutputGadget: EqGadget<ConstraintF> + type OutputVar: EqGadget<ConstraintF> + ToBytesGadget<ConstraintF> - + AllocGadget<C::Output, ConstraintF> + + AllocVar<C::Output, ConstraintF> + + R1CSVar<ConstraintF> + Clone + Sized + Debug; - type ParametersGadget: AllocGadget<C::Parameters, ConstraintF> + Clone; - type RandomnessGadget: AllocGadget<C::Randomness, ConstraintF> + Clone; + type ParametersVar: AllocVar<C::Parameters, ConstraintF> + Clone; + type RandomnessVar: AllocVar<C::Randomness, ConstraintF> + Clone; - fn check_commitment_gadget<CS: ConstraintSystem<ConstraintF>>( - cs: CS, - parameters: &Self::ParametersGadget, - input: &[UInt8], - r: &Self::RandomnessGadget, - ) -> Result<Self::OutputGadget, SynthesisError>; + fn commit( + parameters: &Self::ParametersVar, + input: &[UInt8<ConstraintF>], + r: &Self::RandomnessVar, + ) -> Result<Self::OutputVar, SynthesisError>; }
@@ -1,62 +1,59 @@
-use algebra_core::{Field, PrimeField}; - use crate::commitment::{ injective_map::{InjectiveMap, PedersenCommCompressor}, pedersen::{ - constraints::{ - PedersenCommitmentGadget, PedersenCommitmentGadgetParameters, PedersenRandomnessGadget, - }, - PedersenWindow, + constraints::{CommGadget, ParametersVar, RandomnessVar}, + Window, }, - CommitmentGadget, }; pub use crate::crh::injective_map::constraints::InjectiveMapGadget; -use algebra_core::groups::Group; -use r1cs_core::{ConstraintSystem, SynthesisError}; -use r1cs_std::{groups::GroupGadget, uint8::UInt8}; +use algebra_core::{Field, PrimeField, ProjectiveCurve}; +use r1cs_core::SynthesisError; +use r1cs_std::{ + groups::{CurveVar, GroupOpsBounds}, + uint8::UInt8, +}; use core::marker::PhantomData; -pub struct PedersenCommitmentCompressorGadget<G, I, ConstraintF, GG, IG> +type ConstraintF<C> = <<C as ProjectiveCurve>::BaseField as Field>::BasePrimeField; + +pub struct CommitmentCompressorGadget<C, I, W, GG, IG> where - G: Group, - I: InjectiveMap<G>, - ConstraintF: Field, - GG: GroupGadget<G, ConstraintF>, - IG: InjectiveMapGadget<G, I, ConstraintF, GG>, + C: ProjectiveCurve, + I: InjectiveMap<C>, + W: Window, + GG: CurveVar<C, ConstraintF<C>>, + IG: InjectiveMapGadget<C, I, GG>, + for<'a> &'a GG: GroupOpsBounds<'a, C, GG>, { _compressor: PhantomData<I>, _compressor_gadget: PhantomData<IG>, - _crh: PedersenCommitmentGadget<G, ConstraintF, GG>, + _comm: PhantomData<CommGadget<C, GG, W>>, } -impl<G, I, ConstraintF, GG, IG, W> CommitmentGadget<PedersenCommCompressor<G, I, W>, ConstraintF> - for PedersenCommitmentCompressorGadget<G, I, ConstraintF, GG, IG> +impl<C, I, GG, IG, W> + crate::commitment::CommitmentGadget<PedersenCommCompressor<C, I, W>, ConstraintF<C>> + for CommitmentCompressorGadget<C, I, W, GG, IG> where - G: Group, - I: InjectiveMap<G>, - ConstraintF: PrimeField, - GG: GroupGadget<G, ConstraintF>, - IG: InjectiveMapGadget<G, I, ConstraintF, GG>, - W: PedersenWindow, + C: ProjectiveCurve, + I: InjectiveMap<C>, + GG: CurveVar<C, ConstraintF<C>>, + ConstraintF<C>: PrimeField, + IG: InjectiveMapGadget<C, I, GG>, + W: Window, + for<'a> &'a GG: GroupOpsBounds<'a, C, GG>, { - type OutputGadget = IG::OutputGadget; - type ParametersGadget = PedersenCommitmentGadgetParameters<G, W, ConstraintF>; - type RandomnessGadget = PedersenRandomnessGadget; + type OutputVar = IG::OutputVar; + type ParametersVar = ParametersVar<C, GG>; + type RandomnessVar = RandomnessVar<ConstraintF<C>>; - fn check_commitment_gadget<CS: ConstraintSystem<ConstraintF>>( - mut cs: CS, - parameters: &Self::ParametersGadget, - input: &[UInt8], - r: &Self::RandomnessGadget, - ) -> Result<Self::OutputGadget, SynthesisError> { - let result = PedersenCommitmentGadget::<G, ConstraintF, GG>::check_commitment_gadget( - cs.ns(|| "PedersenComm"), - parameters, - input, - r, - )?; - IG::evaluate_map(cs.ns(|| "InjectiveMap"), &result) + fn commit( + parameters: &Self::ParametersVar, + input: &[UInt8<ConstraintF<C>>], + r: &Self::RandomnessVar, + ) -> Result<Self::OutputVar, SynthesisError> { + let result = CommGadget::<C, GG, W>::commit(parameters, input, r)?; + IG::evaluate(&result) } }
@@ -2,32 +2,29 @@ use crate::Error;
use core::marker::PhantomData; use rand::Rng; -use super::{ - pedersen::{PedersenCommitment, PedersenParameters, PedersenRandomness, PedersenWindow}, - CommitmentScheme, -}; +use super::{pedersen, CommitmentScheme}; pub use crate::crh::injective_map::InjectiveMap; -use algebra_core::groups::Group; +use algebra_core::ProjectiveCurve; #[cfg(feature = "r1cs")] pub mod constraints; -pub struct PedersenCommCompressor<G: Group, I: InjectiveMap<G>, W: PedersenWindow> { - _group: PhantomData<G>, +pub struct PedersenCommCompressor<C: ProjectiveCurve, I: InjectiveMap<C>, W: pedersen::Window> { + _group: PhantomData<C>, _compressor: PhantomData<I>, - _comm: PedersenCommitment<G, W>, + _comm: pedersen::Commitment<C, W>, } -impl<G: Group, I: InjectiveMap<G>, W: PedersenWindow> CommitmentScheme - for PedersenCommCompressor<G, I, W> +impl<C: ProjectiveCurve, I: InjectiveMap<C>, W: pedersen::Window> CommitmentScheme + for PedersenCommCompressor<C, I, W> { type Output = I::Output; - type Parameters = PedersenParameters<G>; - type Randomness = PedersenRandomness<G>; + type Parameters = pedersen::Parameters<C>; + type Randomness = pedersen::Randomness<C>; fn setup<R: Rng>(rng: &mut R) -> Result<Self::Parameters, Error> { let time = start_timer!(|| format!("PedersenCompressor::Setup")); - let params = PedersenCommitment::<G, W>::setup(rng); + let params = pedersen::Commitment::<C, W>::setup(rng); end_timer!(time); params }@@ -38,7 +35,7 @@ input: &[u8],
randomness: &Self::Randomness, ) -> Result<Self::Output, Error> { let eval_time = start_timer!(|| "PedersenCompressor::Eval"); - let result = I::injective_map(&PedersenCommitment::<G, W>::commit( + let result = I::injective_map(&pedersen::Commitment::<C, W>::commit( parameters, input, randomness, )?)?; end_timer!(eval_time);
@@ -1,57 +1,63 @@
use crate::{ - commitment::pedersen::{PedersenCommitment, PedersenParameters, PedersenRandomness}, - crh::pedersen::PedersenWindow, + commitment::pedersen::{Commitment, Parameters, Randomness}, + crh::pedersen::Window, Vec, }; use algebra_core::{ fields::{Field, PrimeField}, - to_bytes, Group, ToBytes, + to_bytes, ProjectiveCurve, ToBytes, Zero, }; -use r1cs_core::{ConstraintSystem, SynthesisError}; +use r1cs_core::{Namespace, SynthesisError}; -use crate::commitment::CommitmentGadget; use core::{borrow::Borrow, marker::PhantomData}; use r1cs_std::prelude::*; +type ConstraintF<C> = <<C as ProjectiveCurve>::BaseField as Field>::BasePrimeField; + #[derive(Derivative)] -#[derivative(Clone(bound = "G: Group, W: PedersenWindow, ConstraintF: Field"))] -pub struct PedersenCommitmentGadgetParameters<G: Group, W: PedersenWindow, ConstraintF: Field> { - params: PedersenParameters<G>, +#[derivative(Clone(bound = "C: ProjectiveCurve, GG: CurveVar<C, ConstraintF<C>>"))] +pub struct ParametersVar<C: ProjectiveCurve, GG: CurveVar<C, ConstraintF<C>>> +where + for<'a> &'a GG: GroupOpsBounds<'a, C, GG>, +{ + params: Parameters<C>, #[doc(hidden)] - _group: PhantomData<G>, - #[doc(hidden)] - _engine: PhantomData<ConstraintF>, - #[doc(hidden)] - _window: PhantomData<W>, + _group_var: PhantomData<GG>, } #[derive(Clone, Debug)] -pub struct PedersenRandomnessGadget(Vec<UInt8>); +pub struct RandomnessVar<F: Field>(Vec<UInt8<F>>); -pub struct PedersenCommitmentGadget<G: Group, ConstraintF: Field, GG: GroupGadget<G, ConstraintF>>( - #[doc(hidden)] PhantomData<*const G>, - #[doc(hidden)] PhantomData<*const GG>, - PhantomData<ConstraintF>, -); +pub struct CommGadget<C: ProjectiveCurve, GG: CurveVar<C, ConstraintF<C>>, W: Window> +where + for<'a> &'a GG: GroupOpsBounds<'a, C, GG>, +{ + #[doc(hidden)] + _curve: PhantomData<*const C>, + #[doc(hidden)] + _group_var: PhantomData<*const GG>, + #[doc(hidden)] + _window: PhantomData<*const W>, +} -impl<ConstraintF, G, GG, W> CommitmentGadget<PedersenCommitment<G, W>, ConstraintF> - for PedersenCommitmentGadget<G, ConstraintF, GG> +impl<C, GG, W> crate::commitment::CommitmentGadget<Commitment<C, W>, ConstraintF<C>> + for CommGadget<C, GG, W> where - ConstraintF: PrimeField, - G: Group, - GG: GroupGadget<G, ConstraintF>, - W: PedersenWindow, + C: ProjectiveCurve, + GG: CurveVar<C, ConstraintF<C>>, + W: Window, + for<'a> &'a GG: GroupOpsBounds<'a, C, GG>, + ConstraintF<C>: PrimeField, { - type OutputGadget = GG; - type ParametersGadget = PedersenCommitmentGadgetParameters<G, W, ConstraintF>; - type RandomnessGadget = PedersenRandomnessGadget; + type OutputVar = GG; + type ParametersVar = ParametersVar<C, GG>; + type RandomnessVar = RandomnessVar<ConstraintF<C>>; - fn check_commitment_gadget<CS: ConstraintSystem<ConstraintF>>( - mut cs: CS, - parameters: &Self::ParametersGadget, - input: &[UInt8], - r: &Self::RandomnessGadget, - ) -> Result<Self::OutputGadget, SynthesisError> { + fn commit( + parameters: &Self::ParametersVar, + input: &[UInt8<ConstraintF<C>>], + r: &Self::RandomnessVar, + ) -> Result<Self::OutputVar, SynthesisError> { assert!((input.len() * 8) <= (W::WINDOW_SIZE * W::NUM_WINDOWS)); let mut padded_input = input.to_vec();@@ -72,16 +78,12 @@ .iter()
.flat_map(|byte| byte.into_bits_le()) .collect(); let input_in_bits = input_in_bits.chunks(W::WINDOW_SIZE); - let mut result = GG::precomputed_base_multiscalar_mul( - cs.ns(|| "multiexp"), - ¶meters.params.generators, - input_in_bits, - )?; + let mut result = + GG::precomputed_base_multiscalar_mul(¶meters.params.generators, input_in_bits)?; // Compute h^r let rand_bits: Vec<_> = r.0.iter().flat_map(|byte| byte.into_bits_le()).collect(); result.precomputed_base_scalar_mul( - cs.ns(|| "Randomizer"), rand_bits .iter() .zip(¶meters.params.randomness_generator),@@ -91,109 +93,41 @@ Ok(result)
} } -impl<G, W, ConstraintF> AllocGadget<PedersenParameters<G>, ConstraintF> - for PedersenCommitmentGadgetParameters<G, W, ConstraintF> +impl<C, GG> AllocVar<Parameters<C>, ConstraintF<C>> for ParametersVar<C, GG> where - G: Group, - W: PedersenWindow, - ConstraintF: PrimeField, + C: ProjectiveCurve, + GG: CurveVar<C, ConstraintF<C>>, + for<'a> &'a GG: GroupOpsBounds<'a, C, GG>, { - fn alloc_constant<T, CS: ConstraintSystem<ConstraintF>>( - _cs: CS, - val: T, - ) -> Result<Self, SynthesisError> - where - T: Borrow<PedersenParameters<G>>, - { - let parameters = val.borrow().clone(); - - Ok(PedersenCommitmentGadgetParameters { - params: parameters, - _group: PhantomData, - _engine: PhantomData, - _window: PhantomData, - }) - } - - fn alloc<F, T, CS: ConstraintSystem<ConstraintF>>( - cs: CS, - value_gen: F, - ) -> Result<Self, SynthesisError> - where - F: FnOnce() -> Result<T, SynthesisError>, - T: Borrow<PedersenParameters<G>>, - { - let temp = value_gen()?; - Self::alloc_constant(cs, temp) - } - - fn alloc_input<F, T, CS: ConstraintSystem<ConstraintF>>( - _cs: CS, - value_gen: F, - ) -> Result<Self, SynthesisError> - where - F: FnOnce() -> Result<T, SynthesisError>, - T: Borrow<PedersenParameters<G>>, - { - let temp = value_gen()?; - let parameters = temp.borrow().clone(); - - Ok(PedersenCommitmentGadgetParameters { - params: parameters, - _group: PhantomData, - _engine: PhantomData, - _window: PhantomData, + fn new_variable<T: Borrow<Parameters<C>>>( + _cs: impl Into<Namespace<ConstraintF<C>>>, + f: impl FnOnce() -> Result<T, SynthesisError>, + _mode: AllocationMode, + ) -> Result<Self, SynthesisError> { + let params = f()?.borrow().clone(); + Ok(ParametersVar { + params, + _group_var: PhantomData, }) } } -impl<G, ConstraintF> AllocGadget<PedersenRandomness<G>, ConstraintF> for PedersenRandomnessGadget +impl<C, F> AllocVar<Randomness<C>, F> for RandomnessVar<F> where - G: Group, - ConstraintF: PrimeField, + C: ProjectiveCurve, + F: PrimeField, { - fn alloc_constant<T, CS: ConstraintSystem<ConstraintF>>( - mut cs: CS, - val: T, - ) -> Result<Self, SynthesisError> - where - T: Borrow<PedersenRandomness<G>>, - { - let mut result_bytes = vec![]; - for (i, byte) in to_bytes![val.borrow().0].unwrap().into_iter().enumerate() { - let cur = UInt8::alloc_constant(cs.ns(|| format!("byte {}", i)), byte)?; - result_bytes.push(cur); + fn new_variable<T: Borrow<Randomness<C>>>( + cs: impl Into<Namespace<F>>, + f: impl FnOnce() -> Result<T, SynthesisError>, + mode: AllocationMode, + ) -> Result<Self, SynthesisError> { + let r = to_bytes![&f().map(|b| b.borrow().0).unwrap_or(C::ScalarField::zero())].unwrap(); + match mode { + AllocationMode::Constant => Ok(Self(UInt8::constant_vec(&r))), + AllocationMode::Input => UInt8::new_input_vec(cs, &r).map(Self), + AllocationMode::Witness => UInt8::new_witness_vec(cs, &r).map(Self), } - Ok(PedersenRandomnessGadget(result_bytes)) - } - - fn alloc<F, T, CS: ConstraintSystem<ConstraintF>>( - cs: CS, - value_gen: F, - ) -> Result<Self, SynthesisError> - where - F: FnOnce() -> Result<T, SynthesisError>, - T: Borrow<PedersenRandomness<G>>, - { - let temp = value_gen()?; - let randomness = to_bytes![temp.borrow().0].unwrap(); - Ok(PedersenRandomnessGadget(UInt8::alloc_vec(cs, &randomness)?)) - } - - fn alloc_input<F, T, CS: ConstraintSystem<ConstraintF>>( - cs: CS, - value_gen: F, - ) -> Result<Self, SynthesisError> - where - F: FnOnce() -> Result<T, SynthesisError>, - T: Borrow<PedersenRandomness<G>>, - { - let temp = value_gen()?; - let randomness = to_bytes![temp.borrow().0].unwrap(); - Ok(PedersenRandomnessGadget(UInt8::alloc_input_vec( - cs, - &randomness, - )?)) } }@@ -201,31 +135,27 @@ #[cfg(test)]
mod test { use algebra::{ ed_on_bls12_381::{EdwardsProjective as JubJub, Fq, Fr}, - test_rng, ProjectiveCurve, UniformRand, + test_rng, UniformRand, }; use crate::{ commitment::{ - pedersen::{ - constraints::PedersenCommitmentGadget, PedersenCommitment, PedersenRandomness, - }, + pedersen::{constraints::CommGadget, Commitment, Randomness}, CommitmentGadget, CommitmentScheme, }, - crh::pedersen::PedersenWindow, + crh::pedersen, }; use r1cs_core::ConstraintSystem; - use r1cs_std::{ - ed_on_bls12_381::EdwardsGadget, prelude::*, test_constraint_system::TestConstraintSystem, - }; + use r1cs_std::{ed_on_bls12_381::EdwardsVar, prelude::*}; #[test] fn commitment_gadget_test() { - let mut cs = TestConstraintSystem::<Fq>::new(); + let cs = ConstraintSystem::<Fq>::new_ref(); #[derive(Clone, PartialEq, Eq, Hash)] pub(super) struct Window; - impl PedersenWindow for Window { + impl pedersen::Window for Window { const WINDOW_SIZE: usize = 4; const NUM_WINDOWS: usize = 8; }@@ -234,45 +164,37 @@ let input = [1u8; 4];
let rng = &mut test_rng(); - type TestCOMM = PedersenCommitment<JubJub, Window>; - type TestCOMMGadget = PedersenCommitmentGadget<JubJub, Fq, EdwardsGadget>; + type TestCOMM = Commitment<JubJub, Window>; + type TestCOMMGadget = CommGadget<JubJub, EdwardsVar, Window>; - let randomness = PedersenRandomness(Fr::rand(rng)); + let randomness = Randomness(Fr::rand(rng)); - let parameters = PedersenCommitment::<JubJub, Window>::setup(rng).unwrap(); + let parameters = Commitment::<JubJub, Window>::setup(rng).unwrap(); let primitive_result = - PedersenCommitment::<JubJub, Window>::commit(¶meters, &input, &randomness).unwrap(); + Commitment::<JubJub, Window>::commit(¶meters, &input, &randomness).unwrap(); - let mut input_bytes = vec![]; - for (byte_i, input_byte) in input.iter().enumerate() { - let cs = cs.ns(|| format!("input_byte_gadget_{}", byte_i)); - input_bytes.push(UInt8::alloc(cs, || Ok(*input_byte)).unwrap()); + let mut input_var = vec![]; + for input_byte in input.iter() { + input_var.push(UInt8::new_witness(cs.clone(), || Ok(*input_byte)).unwrap()); } - let randomness = - <TestCOMMGadget as CommitmentGadget<TestCOMM, Fq>>::RandomnessGadget::alloc( - &mut cs.ns(|| "gadget_randomness"), + let randomness_var = + <TestCOMMGadget as CommitmentGadget<TestCOMM, Fq>>::RandomnessVar::new_witness( + cs.ns("gadget_randomness"), || Ok(&randomness), ) .unwrap(); - let gadget_parameters = - <TestCOMMGadget as CommitmentGadget<TestCOMM, Fq>>::ParametersGadget::alloc( - &mut cs.ns(|| "gadget_parameters"), + let parameters_var = + <TestCOMMGadget as CommitmentGadget<TestCOMM, Fq>>::ParametersVar::new_witness( + cs.ns("gadget_parameters"), || Ok(¶meters), ) .unwrap(); - let gadget_result = - <TestCOMMGadget as CommitmentGadget<TestCOMM, Fq>>::check_commitment_gadget( - &mut cs.ns(|| "gadget_evaluation"), - &gadget_parameters, - &input_bytes, - &randomness, - ) - .unwrap(); + let result_var = + TestCOMMGadget::commit(¶meters_var, &input_var, &randomness_var).unwrap(); - let primitive_result = primitive_result.into_affine(); - assert_eq!(primitive_result.x, gadget_result.x.value.unwrap()); - assert_eq!(primitive_result.y, gadget_result.y.value.unwrap()); - assert!(cs.is_satisfied()); + let primitive_result = primitive_result; + assert_eq!(primitive_result, result_var.value().unwrap()); + assert!(cs.is_satisfied().unwrap()); } }
@@ -1,9 +1,8 @@
use crate::{Error, Vec}; use algebra_core::{ bytes::ToBytes, - groups::Group, io::{Result as IoResult, Write}, - BitIterator, Field, FpParameters, PrimeField, ToConstraintField, UniformRand, + BitIterator, Field, FpParameters, PrimeField, ProjectiveCurve, ToConstraintField, UniformRand, }; use core::marker::PhantomData;@@ -11,64 +10,55 @@ use rand::Rng;
use super::CommitmentScheme; -pub use crate::crh::pedersen::PedersenWindow; -use crate::crh::{ - pedersen::{PedersenCRH, PedersenParameters as PedersenCRHParameters}, - FixedLengthCRH, -}; +pub use crate::crh::pedersen::Window; +use crate::crh::{pedersen, FixedLengthCRH}; #[cfg(feature = "r1cs")] pub mod constraints; #[derive(Clone)] -pub struct PedersenParameters<G: Group> { - pub randomness_generator: Vec<G>, - pub generators: Vec<Vec<G>>, +pub struct Parameters<C: ProjectiveCurve> { + pub randomness_generator: Vec<C>, + pub generators: Vec<Vec<C>>, } -pub struct PedersenCommitment<G: Group, W: PedersenWindow> { - group: PhantomData<G>, +pub struct Commitment<C: ProjectiveCurve, W: Window> { + group: PhantomData<C>, window: PhantomData<W>, } #[derive(Derivative)] -#[derivative( - Clone(bound = "G: Group"), - PartialEq(bound = "G: Group"), - Debug(bound = "G: Group"), - Eq(bound = "G: Group"), - Default(bound = "G: Group") -)] -pub struct PedersenRandomness<G: Group>(pub G::ScalarField); +#[derivative(Clone, PartialEq, Debug, Eq, Default)] +pub struct Randomness<C: ProjectiveCurve>(pub C::ScalarField); -impl<G: Group> UniformRand for PedersenRandomness<G> { +impl<C: ProjectiveCurve> UniformRand for Randomness<C> { #[inline] fn rand<R: Rng + ?Sized>(rng: &mut R) -> Self { - PedersenRandomness(UniformRand::rand(rng)) + Randomness(UniformRand::rand(rng)) } } -impl<G: Group> ToBytes for PedersenRandomness<G> { +impl<C: ProjectiveCurve> ToBytes for Randomness<C> { fn write<W: Write>(&self, writer: W) -> IoResult<()> { self.0.write(writer) } } -impl<G: Group, W: PedersenWindow> CommitmentScheme for PedersenCommitment<G, W> { - type Parameters = PedersenParameters<G>; - type Randomness = PedersenRandomness<G>; - type Output = G; +impl<C: ProjectiveCurve, W: Window> CommitmentScheme for Commitment<C, W> { + type Parameters = Parameters<C>; + type Randomness = Randomness<C>; + type Output = C::Affine; fn setup<R: Rng>(rng: &mut R) -> Result<Self::Parameters, Error> { let time = start_timer!(|| format!( - "PedersenCOMM::Setup: {} {}-bit windows; {{0,1}}^{{{}}} -> G", + "PedersenCOMM::Setup: {} {}-bit windows; {{0,1}}^{{{}}} -> C", W::NUM_WINDOWS, W::WINDOW_SIZE, W::NUM_WINDOWS * W::WINDOW_SIZE )); - let num_powers = <G::ScalarField as PrimeField>::Params::MODULUS_BITS as usize; - let randomness_generator = PedersenCRH::<_, W>::generator_powers(num_powers, rng); - let generators = PedersenCRH::<_, W>::create_generators(rng); + let num_powers = <C::ScalarField as PrimeField>::Params::MODULUS_BITS as usize; + let randomness_generator = pedersen::CRH::<C, W>::generator_powers(num_powers, rng); + let generators = pedersen::CRH::<C, W>::create_generators(rng); end_timer!(time); Ok(Self::Parameters {@@ -102,10 +92,10 @@ assert_eq!(parameters.generators.len(), W::NUM_WINDOWS);
// Invoke Pedersen CRH here, to prevent code duplication. - let crh_parameters = PedersenCRHParameters { + let crh_parameters = pedersen::Parameters { generators: parameters.generators.clone(), }; - let mut result = PedersenCRH::<_, W>::evaluate(&crh_parameters, &input)?; + let mut result: C = pedersen::CRH::<C, W>::evaluate(&crh_parameters, &input)?.into(); let randomize_time = start_timer!(|| "Randomize"); // Compute h^r.@@ -122,12 +112,12 @@ }
end_timer!(randomize_time); end_timer!(commit_time); - Ok(result) + Ok(result.into()) } } -impl<ConstraintF: Field, G: Group + ToConstraintField<ConstraintF>> ToConstraintField<ConstraintF> - for PedersenParameters<G> +impl<ConstraintF: Field, C: ProjectiveCurve + ToConstraintField<ConstraintF>> + ToConstraintField<ConstraintF> for Parameters<C> { #[inline] fn to_field_elements(&self) -> Result<Vec<ConstraintF>, Error> {
@@ -1,61 +1,60 @@
-use core::{borrow::Borrow, hash::Hash, marker::PhantomData}; +use core::{borrow::Borrow, marker::PhantomData}; use crate::{ crh::{ - bowe_hopwood::{BoweHopwoodPedersenCRH, BoweHopwoodPedersenParameters, CHUNK_SIZE}, - pedersen::PedersenWindow, + bowe_hopwood::{Parameters, CHUNK_SIZE, CRH}, + pedersen::Window, FixedLengthCRHGadget, }, Vec, }; -use algebra_core::{groups::Group, Field}; -use r1cs_core::{ConstraintSystem, SynthesisError}; -use r1cs_std::{alloc::AllocGadget, groups::GroupGadget, uint8::UInt8}; +use algebra_core::{ + curves::{ModelParameters, TEModelParameters}, + Field, +}; +use r1cs_core::{Namespace, SynthesisError}; +use r1cs_std::{ + alloc::AllocVar, groups::curves::twisted_edwards::AffineVar, prelude::*, uint8::UInt8, +}; use r1cs_std::bits::boolean::Boolean; +type ConstraintF<P> = <<P as ModelParameters>::BaseField as Field>::BasePrimeField; + #[derive(Derivative)] -#[derivative(Clone( - bound = "G: Group, W: PedersenWindow, ConstraintF: Field, GG: GroupGadget<G, ConstraintF>" -))] -pub struct BoweHopwoodPedersenCRHGadgetParameters< - G: Group, - W: PedersenWindow, - ConstraintF: Field, - GG: GroupGadget<G, ConstraintF>, -> { - params: BoweHopwoodPedersenParameters<G>, - _group_g: PhantomData<GG>, - _engine: PhantomData<ConstraintF>, +#[derivative(Clone(bound = "P: TEModelParameters, W: Window"))] +pub struct ParametersVar<P: TEModelParameters, W: Window> { + params: Parameters<P>, + #[doc(hidden)] _window: PhantomData<W>, } -pub struct BoweHopwoodPedersenCRHGadget< - G: Group, - ConstraintF: Field, - GG: GroupGadget<G, ConstraintF>, -> { - _group: PhantomData<*const G>, - _group_gadget: PhantomData<*const GG>, - _engine: PhantomData<ConstraintF>, +pub struct CRHGadget<P: TEModelParameters, F: FieldVar<P::BaseField, ConstraintF<P>>> +where + for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, +{ + #[doc(hidden)] + _params: PhantomData<P>, + #[doc(hidden)] + _base_field: PhantomData<F>, } -impl<ConstraintF, G, GG, W> FixedLengthCRHGadget<BoweHopwoodPedersenCRH<G, W>, ConstraintF> - for BoweHopwoodPedersenCRHGadget<G, ConstraintF, GG> +impl<P, F, W> FixedLengthCRHGadget<CRH<P, W>, ConstraintF<P>> for CRHGadget<P, F> where - ConstraintF: Field, - G: Group + Hash, - GG: GroupGadget<G, ConstraintF>, - W: PedersenWindow, + for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, + F: FieldVar<P::BaseField, ConstraintF<P>>, + F: TwoBitLookupGadget<ConstraintF<P>, TableConstant = P::BaseField> + + ThreeBitCondNegLookupGadget<ConstraintF<P>, TableConstant = P::BaseField>, + P: TEModelParameters, + W: Window, { - type OutputGadget = GG; - type ParametersGadget = BoweHopwoodPedersenCRHGadgetParameters<G, W, ConstraintF, GG>; + type OutputVar = AffineVar<P, F>; + type ParametersVar = ParametersVar<P, W>; - fn check_evaluation_gadget<CS: ConstraintSystem<ConstraintF>>( - cs: CS, - parameters: &Self::ParametersGadget, - input: &[UInt8], - ) -> Result<Self::OutputGadget, SynthesisError> { + fn evaluate( + parameters: &Self::ParametersVar, + input: &[UInt8<ConstraintF<P>>], + ) -> Result<Self::OutputVar, SynthesisError> { // Pad the input if it is not the current length. let mut input_in_bits: Vec<_> = input.iter().flat_map(|byte| byte.into_bits_le()).collect(); if (input_in_bits.len()) % CHUNK_SIZE != 0 {@@ -75,8 +74,7 @@ let input_in_bits = input_in_bits
.chunks(W::WINDOW_SIZE * CHUNK_SIZE) .map(|x| x.chunks(CHUNK_SIZE).collect::<Vec<_>>()) .collect::<Vec<_>>(); - let result = GG::precomputed_base_3_bit_signed_digit_scalar_mul( - cs, + let result = AffineVar::precomputed_base_3_bit_signed_digit_scalar_mul( ¶meters.params.generators, &input_in_bits, )?;@@ -85,51 +83,19 @@ Ok(result)
} } -impl<G: Group, W: PedersenWindow, ConstraintF: Field, GG: GroupGadget<G, ConstraintF>> - AllocGadget<BoweHopwoodPedersenParameters<G>, ConstraintF> - for BoweHopwoodPedersenCRHGadgetParameters<G, W, ConstraintF, GG> +impl<P, W> AllocVar<Parameters<P>, ConstraintF<P>> for ParametersVar<P, W> +where + P: TEModelParameters, + W: Window, { - fn alloc_constant<T, CS: ConstraintSystem<ConstraintF>>( - _cs: CS, - val: T, - ) -> Result<Self, SynthesisError> - where - T: Borrow<BoweHopwoodPedersenParameters<G>>, - { - let params = val.borrow().clone(); - Ok(BoweHopwoodPedersenCRHGadgetParameters { + fn new_variable<T: Borrow<Parameters<P>>>( + _cs: impl Into<Namespace<ConstraintF<P>>>, + f: impl FnOnce() -> Result<T, SynthesisError>, + _mode: AllocationMode, + ) -> Result<Self, SynthesisError> { + let params = f()?.borrow().clone(); + Ok(ParametersVar { params, - _group_g: PhantomData, - _engine: PhantomData, - _window: PhantomData, - }) - } - - fn alloc<F, T, CS: ConstraintSystem<ConstraintF>>( - cs: CS, - value_gen: F, - ) -> Result<Self, SynthesisError> - where - F: FnOnce() -> Result<T, SynthesisError>, - T: Borrow<BoweHopwoodPedersenParameters<G>>, - { - let params = value_gen()?.borrow().clone(); - Self::alloc_constant(cs, params) - } - - fn alloc_input<F, T, CS: ConstraintSystem<ConstraintF>>( - _cs: CS, - value_gen: F, - ) -> Result<Self, SynthesisError> - where - F: FnOnce() -> Result<T, SynthesisError>, - T: Borrow<BoweHopwoodPedersenParameters<G>>, - { - let params = value_gen()?.borrow().clone(); - Ok(BoweHopwoodPedersenCRHGadgetParameters { - params, - _group_g: PhantomData, - _engine: PhantomData, _window: PhantomData, }) }@@ -140,22 +106,19 @@ mod test {
use rand::Rng; use crate::crh::{ - bowe_hopwood::{constraints::BoweHopwoodPedersenCRHGadget, BoweHopwoodPedersenCRH}, - pedersen::PedersenWindow, + bowe_hopwood::{constraints::CRHGadget, CRH}, + pedersen::Window as PedersenWindow, FixedLengthCRH, FixedLengthCRHGadget, }; use algebra::{ - ed_on_bls12_381::{EdwardsProjective as JubJub, Fq as Fr}, + ed_on_bls12_381::{EdwardsParameters, Fq as Fr}, test_rng, ProjectiveCurve, }; - use r1cs_core::ConstraintSystem; - use r1cs_std::{ - alloc::AllocGadget, ed_on_bls12_381::EdwardsGadget, - test_constraint_system::TestConstraintSystem, uint8::UInt8, - }; + use r1cs_core::{ConstraintSystem, ConstraintSystemRef}; + use r1cs_std::{alloc::AllocVar, ed_on_bls12_381::FqVar, uint8::UInt8, R1CSVar}; - type TestCRH = BoweHopwoodPedersenCRH<JubJub, Window>; - type TestCRHGadget = BoweHopwoodPedersenCRHGadget<JubJub, Fr, EdwardsGadget>; + type TestCRH = CRH<EdwardsParameters, Window>; + type TestCRHGadget = CRHGadget<EdwardsParameters, FqVar>; #[derive(Clone, PartialEq, Eq, Hash)] pub(super) struct Window;@@ -165,35 +128,34 @@ const WINDOW_SIZE: usize = 63;
const NUM_WINDOWS: usize = 8; } - fn generate_input<CS: ConstraintSystem<Fr>, R: Rng>( - mut cs: CS, + fn generate_input<R: Rng>( + cs: ConstraintSystemRef<Fr>, rng: &mut R, - ) -> ([u8; 189], Vec<UInt8>) { + ) -> ([u8; 189], Vec<UInt8<Fr>>) { let mut input = [1u8; 189]; rng.fill_bytes(&mut input); let mut input_bytes = vec![]; - for (byte_i, input_byte) in input.iter().enumerate() { - let cs = cs.ns(|| format!("input_byte_gadget_{}", byte_i)); - input_bytes.push(UInt8::alloc(cs, || Ok(*input_byte)).unwrap()); + for byte in input.iter() { + input_bytes.push(UInt8::new_witness(cs.clone(), || Ok(byte)).unwrap()); } (input, input_bytes) } #[test] - fn crh_primitive_gadget_test() { + fn test_native_equality() { let rng = &mut test_rng(); - let mut cs = TestConstraintSystem::<Fr>::new(); + let cs = ConstraintSystem::<Fr>::new_ref(); - let (input, input_bytes) = generate_input(&mut cs, rng); + let (input, input_var) = generate_input(cs.clone(), rng); println!("number of constraints for input: {}", cs.num_constraints()); let parameters = TestCRH::setup(rng).unwrap(); let primitive_result = TestCRH::evaluate(¶meters, &input).unwrap(); - let gadget_parameters = - <TestCRHGadget as FixedLengthCRHGadget<TestCRH, Fr>>::ParametersGadget::alloc( - &mut cs.ns(|| "gadget_parameters"), + let parameters_var = + <TestCRHGadget as FixedLengthCRHGadget<TestCRH, Fr>>::ParametersVar::new_witness( + cs.ns("parameters_var"), || Ok(¶meters), ) .unwrap();@@ -202,19 +164,12 @@ "number of constraints for input + params: {}",
cs.num_constraints() ); - let gadget_result = - <TestCRHGadget as FixedLengthCRHGadget<TestCRH, Fr>>::check_evaluation_gadget( - &mut cs.ns(|| "gadget_evaluation"), - &gadget_parameters, - &input_bytes, - ) - .unwrap(); + let result_var = TestCRHGadget::evaluate(¶meters_var, &input_var).unwrap(); println!("number of constraints total: {}", cs.num_constraints()); let primitive_result = primitive_result.into_affine(); - assert_eq!(primitive_result.x, gadget_result.x.value.unwrap()); - assert_eq!(primitive_result.y, gadget_result.y.value.unwrap()); - assert!(cs.is_satisfied()); + assert_eq!(primitive_result, result_var.value().unwrap().into_affine()); + assert!(cs.is_satisfied().unwrap()); } }
@@ -7,9 +7,12 @@ use rand::Rng;
#[cfg(feature = "parallel")] use rayon::prelude::*; -use super::pedersen::{bytes_to_bits, PedersenCRH, PedersenWindow}; +use super::pedersen; use crate::crh::FixedLengthCRH; -use algebra_core::{biginteger::BigInteger, fields::PrimeField, groups::Group}; +use algebra_core::{ + biginteger::BigInteger, curves::twisted_edwards_extended::GroupProjective as TEProjective, + fields::PrimeField, ProjectiveCurve, TEModelParameters, UniformRand, +}; use ff_fft::cfg_chunks; #[cfg(feature = "r1cs")]@@ -17,22 +20,23 @@ pub mod constraints;
pub const CHUNK_SIZE: usize = 3; -#[derive(Clone, Default)] -pub struct BoweHopwoodPedersenParameters<G: Group> { - pub generators: Vec<Vec<G>>, +#[derive(Derivative)] +#[derivative(Clone(bound = ""), Default(bound = ""))] +pub struct Parameters<P: TEModelParameters> { + pub generators: Vec<Vec<TEProjective<P>>>, } -pub struct BoweHopwoodPedersenCRH<G: Group, W: PedersenWindow> { - group: PhantomData<G>, +pub struct CRH<P: TEModelParameters, W: pedersen::Window> { + group: PhantomData<P>, window: PhantomData<W>, } -impl<G: Group, W: PedersenWindow> BoweHopwoodPedersenCRH<G, W> { - pub fn create_generators<R: Rng>(rng: &mut R) -> Vec<Vec<G>> { +impl<P: TEModelParameters, W: pedersen::Window> CRH<P, W> { + pub fn create_generators<R: Rng>(rng: &mut R) -> Vec<Vec<TEProjective<P>>> { let mut generators = Vec::new(); for _ in 0..W::NUM_WINDOWS { let mut generators_for_segment = Vec::new(); - let mut base = G::rand(rng); + let mut base = TEProjective::rand(rng); for _ in 0..W::WINDOW_SIZE { generators_for_segment.push(base); for _ in 0..4 {@@ -45,10 +49,10 @@ generators
} } -impl<G: Group, W: PedersenWindow> FixedLengthCRH for BoweHopwoodPedersenCRH<G, W> { - const INPUT_SIZE_BITS: usize = PedersenCRH::<G, W>::INPUT_SIZE_BITS; - type Output = G; - type Parameters = BoweHopwoodPedersenParameters<G>; +impl<P: TEModelParameters, W: pedersen::Window> FixedLengthCRH for CRH<P, W> { + const INPUT_SIZE_BITS: usize = pedersen::CRH::<TEProjective<P>, W>::INPUT_SIZE_BITS; + type Output = TEProjective<P>; + type Parameters = Parameters<P>; fn setup<R: Rng>(rng: &mut R) -> Result<Self::Parameters, Error> { fn calculate_num_chunks_in_segment<F: PrimeField>() -> usize {@@ -63,10 +67,10 @@
c } - let maximum_num_chunks_in_segment = calculate_num_chunks_in_segment::<G::ScalarField>(); + let maximum_num_chunks_in_segment = calculate_num_chunks_in_segment::<P::ScalarField>(); if W::WINDOW_SIZE > maximum_num_chunks_in_segment { return Err(format!( - "Bowe-Hopwood hash must have a window size resulting in scalars < (p-1)/2, \ + "Bowe-Hopwood-PedersenCRH hash must have a window size resulting in scalars < (p-1)/2, \ maximum segment size is {}", maximum_num_chunks_in_segment )@@ -74,7 +78,7 @@ .into());
} let time = start_timer!(|| format!( - "BoweHopwoodPedersenCRH::Setup: {} segments of {} 3-bit chunks; {{0,1}}^{{{}}} -> G", + "Bowe-Hopwood-PedersenCRH::Setup: {} segments of {} 3-bit chunks; {{0,1}}^{{{}}} -> P", W::NUM_WINDOWS, W::WINDOW_SIZE, W::WINDOW_SIZE * W::NUM_WINDOWS * CHUNK_SIZE@@ -98,7 +102,7 @@ );
} let mut padded_input = Vec::with_capacity(input.len()); - let input = bytes_to_bits(input); + let input = pedersen::bytes_to_bits(input); // Pad the input if it is not the current length. padded_input.extend_from_slice(&input); if input.len() % CHUNK_SIZE != 0 {@@ -143,13 +147,13 @@ if chunk_bits[1] {
encoded += &generator.double(); } if chunk_bits[2] { - encoded = encoded.neg(); + encoded = -encoded; } encoded }) - .sum::<G>() + .sum::<TEProjective<P>>() }) - .sum::<G>(); + .sum::<TEProjective<P>>(); end_timer!(eval_time);@@ -157,9 +161,9 @@ Ok(result)
} } -impl<G: Group> Debug for BoweHopwoodPedersenParameters<G> { +impl<P: TEModelParameters> Debug for Parameters<P> { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - write!(f, "Bowe-Hopwood Pedersen Hash Parameters {{\n")?; + write!(f, "Bowe-Hopwood-Pedersen Hash Parameters {{\n")?; for (i, g) in self.generators.iter().enumerate() { write!(f, "\t Generator {}: {:?}\n", i, g)?; }@@ -170,28 +174,23 @@
#[cfg(test)] mod test { use crate::{ - crh::{bowe_hopwood::BoweHopwoodPedersenCRH, pedersen::PedersenWindow}, + crh::{bowe_hopwood::CRH, pedersen::Window}, FixedLengthCRH, }; - use algebra::{ed_on_bls12_381::EdwardsProjective, test_rng}; + use algebra::{ed_on_bls12_381::EdwardsParameters, test_rng}; #[test] fn test_simple_bh() { #[derive(Clone)] struct TestWindow {} - impl PedersenWindow for TestWindow { + impl Window for TestWindow { const WINDOW_SIZE: usize = 63; const NUM_WINDOWS: usize = 8; } let rng = &mut test_rng(); - let params = - <BoweHopwoodPedersenCRH<EdwardsProjective, TestWindow> as FixedLengthCRH>::setup(rng) - .unwrap(); - <BoweHopwoodPedersenCRH<EdwardsProjective, TestWindow> as FixedLengthCRH>::evaluate( - ¶ms, - &[1, 2, 3], - ) - .unwrap(); + let params = <CRH<EdwardsParameters, TestWindow> as FixedLengthCRH>::setup(rng).unwrap(); + <CRH<EdwardsParameters, TestWindow> as FixedLengthCRH>::evaluate(¶ms, &[1, 2, 3]) + .unwrap(); } }
@@ -2,24 +2,24 @@ use algebra_core::Field;
use core::fmt::Debug; use crate::crh::FixedLengthCRH; -use r1cs_core::{ConstraintSystem, SynthesisError}; +use r1cs_core::SynthesisError; use r1cs_std::prelude::*; pub trait FixedLengthCRHGadget<H: FixedLengthCRH, ConstraintF: Field>: Sized { - type OutputGadget: ConditionalEqGadget<ConstraintF> - + EqGadget<ConstraintF> + type OutputVar: EqGadget<ConstraintF> + ToBytesGadget<ConstraintF> + CondSelectGadget<ConstraintF> - + AllocGadget<H::Output, ConstraintF> + + AllocVar<H::Output, ConstraintF> + + R1CSVar<ConstraintF> + Debug + Clone + Sized; - type ParametersGadget: AllocGadget<H::Parameters, ConstraintF> + Clone; - fn check_evaluation_gadget<CS: ConstraintSystem<ConstraintF>>( - cs: CS, - parameters: &Self::ParametersGadget, - input: &[UInt8], - ) -> Result<Self::OutputGadget, SynthesisError>; + type ParametersVar: AllocVar<H::Parameters, ConstraintF> + Clone; + + fn evaluate( + parameters: &Self::ParametersVar, + input: &[UInt8<ConstraintF>], + ) -> Result<Self::OutputVar, SynthesisError>; }
@@ -2,129 +2,96 @@ use core::{fmt::Debug, marker::PhantomData};
use crate::crh::{ injective_map::{InjectiveMap, PedersenCRHCompressor, TECompressor}, - pedersen::{ - constraints::{PedersenCRHGadget, PedersenCRHGadgetParameters}, - PedersenWindow, - }, + pedersen::{constraints as ped_constraints, Window}, FixedLengthCRHGadget, }; use algebra_core::{ curves::{ models::{ModelParameters, TEModelParameters}, - twisted_edwards_extended::{GroupAffine as TEAffine, GroupProjective as TEProjective}, + twisted_edwards_extended::GroupProjective as TEProjective, }, fields::{Field, PrimeField, SquareRootField}, - groups::Group, + ProjectiveCurve, }; -use r1cs_core::{ConstraintSystem, SynthesisError}; +use r1cs_core::SynthesisError; use r1cs_std::{ - fields::fp::FpGadget, - groups::{curves::twisted_edwards::AffineGadget as TwistedEdwardsGadget, GroupGadget}, + fields::fp::FpVar, + groups::{curves::twisted_edwards::AffineVar as TEVar, CurveVar}, prelude::*, }; +type ConstraintF<C> = <<C as ProjectiveCurve>::BaseField as Field>::BasePrimeField; + pub trait InjectiveMapGadget< - G: Group, - I: InjectiveMap<G>, - ConstraintF: Field, - GG: GroupGadget<G, ConstraintF>, -> + C: ProjectiveCurve, + I: InjectiveMap<C>, + GG: CurveVar<C, ConstraintF<C>>, +> where + for<'a> &'a GG: GroupOpsBounds<'a, C, GG>, { - type OutputGadget: EqGadget<ConstraintF> - + ToBytesGadget<ConstraintF> - + CondSelectGadget<ConstraintF> - + AllocGadget<I::Output, ConstraintF> + type OutputVar: EqGadget<ConstraintF<C>> + + ToBytesGadget<ConstraintF<C>> + + CondSelectGadget<ConstraintF<C>> + + AllocVar<I::Output, ConstraintF<C>> + + R1CSVar<ConstraintF<C>, Value = I::Output> + Debug + Clone + Sized; - fn evaluate_map<CS: ConstraintSystem<ConstraintF>>( - cs: CS, - ge: &GG, - ) -> Result<Self::OutputGadget, SynthesisError>; + fn evaluate(ge: &GG) -> Result<Self::OutputVar, SynthesisError>; } pub struct TECompressorGadget; -impl<ConstraintF, P> - InjectiveMapGadget< - TEAffine<P>, - TECompressor, - ConstraintF, - TwistedEdwardsGadget<P, ConstraintF, FpGadget<ConstraintF>>, - > for TECompressorGadget +impl<F, P> InjectiveMapGadget<TEProjective<P>, TECompressor, TEVar<P, FpVar<F>>> + for TECompressorGadget where - ConstraintF: PrimeField + SquareRootField, - P: TEModelParameters + ModelParameters<BaseField = ConstraintF>, + F: PrimeField + SquareRootField, + P: TEModelParameters + ModelParameters<BaseField = F>, { - type OutputGadget = FpGadget<ConstraintF>; + type OutputVar = FpVar<F>; - fn evaluate_map<CS: ConstraintSystem<ConstraintF>>( - _cs: CS, - ge: &TwistedEdwardsGadget<P, ConstraintF, FpGadget<ConstraintF>>, - ) -> Result<Self::OutputGadget, SynthesisError> { + fn evaluate(ge: &TEVar<P, FpVar<F>>) -> Result<Self::OutputVar, SynthesisError> { Ok(ge.x.clone()) } } -impl<ConstraintF, P> - InjectiveMapGadget< - TEProjective<P>, - TECompressor, - ConstraintF, - TwistedEdwardsGadget<P, ConstraintF, FpGadget<ConstraintF>>, - > for TECompressorGadget +pub struct PedersenCRHCompressorGadget<C, I, W, GG, IG> where - ConstraintF: PrimeField + SquareRootField, - P: TEModelParameters + ModelParameters<BaseField = ConstraintF>, -{ - type OutputGadget = FpGadget<ConstraintF>; - - fn evaluate_map<CS: ConstraintSystem<ConstraintF>>( - _cs: CS, - ge: &TwistedEdwardsGadget<P, ConstraintF, FpGadget<ConstraintF>>, - ) -> Result<Self::OutputGadget, SynthesisError> { - Ok(ge.x.clone()) - } -} - -pub struct PedersenCRHCompressorGadget<G, I, ConstraintF, GG, IG> -where - G: Group, - I: InjectiveMap<G>, - ConstraintF: Field, - GG: GroupGadget<G, ConstraintF>, - IG: InjectiveMapGadget<G, I, ConstraintF, GG>, + C: ProjectiveCurve, + I: InjectiveMap<C>, + W: Window, + GG: CurveVar<C, ConstraintF<C>>, + for<'a> &'a GG: GroupOpsBounds<'a, C, GG>, + IG: InjectiveMapGadget<C, I, GG>, { + #[doc(hidden)] _compressor: PhantomData<I>, + #[doc(hidden)] _compressor_gadget: PhantomData<IG>, - _crh: PedersenCRHGadget<G, ConstraintF, GG>, + #[doc(hidden)] + _crh: ped_constraints::CRHGadget<C, GG, W>, } -impl<G, I, ConstraintF, GG, IG, W> FixedLengthCRHGadget<PedersenCRHCompressor<G, I, W>, ConstraintF> - for PedersenCRHCompressorGadget<G, I, ConstraintF, GG, IG> +impl<C, I, GG, IG, W> FixedLengthCRHGadget<PedersenCRHCompressor<C, I, W>, ConstraintF<C>> + for PedersenCRHCompressorGadget<C, I, W, GG, IG> where - G: Group, - I: InjectiveMap<G>, - ConstraintF: Field, - GG: GroupGadget<G, ConstraintF>, - IG: InjectiveMapGadget<G, I, ConstraintF, GG>, - W: PedersenWindow, + C: ProjectiveCurve, + I: InjectiveMap<C>, + GG: CurveVar<C, ConstraintF<C>>, + for<'a> &'a GG: GroupOpsBounds<'a, C, GG>, + IG: InjectiveMapGadget<C, I, GG>, + W: Window, { - type OutputGadget = IG::OutputGadget; - type ParametersGadget = PedersenCRHGadgetParameters<G, W, ConstraintF, GG>; + type OutputVar = IG::OutputVar; + type ParametersVar = ped_constraints::CRHParametersVar<C, GG>; - fn check_evaluation_gadget<CS: ConstraintSystem<ConstraintF>>( - mut cs: CS, - parameters: &Self::ParametersGadget, - input: &[UInt8], - ) -> Result<Self::OutputGadget, SynthesisError> { - let result = PedersenCRHGadget::<G, ConstraintF, GG>::check_evaluation_gadget( - cs.ns(|| "PedCRH"), - parameters, - input, - )?; - IG::evaluate_map(cs.ns(|| "InjectiveMap"), &result) + fn evaluate( + parameters: &Self::ParametersVar, + input: &[UInt8<ConstraintF<C>>], + ) -> Result<Self::OutputVar, SynthesisError> { + let result = ped_constraints::CRHGadget::<C, GG, W>::evaluate(parameters, input)?; + IG::evaluate(&result) } }
@@ -3,30 +3,25 @@ use algebra_core::bytes::ToBytes;
use core::{fmt::Debug, hash::Hash, marker::PhantomData}; use rand::Rng; -use super::{ - pedersen::{PedersenCRH, PedersenParameters, PedersenWindow}, - FixedLengthCRH, -}; -use algebra_core::{ - curves::{ - models::{ModelParameters, TEModelParameters}, - twisted_edwards_extended::{GroupAffine as TEAffine, GroupProjective as TEProjective}, - ProjectiveCurve, - }, - groups::Group, +use super::{pedersen, FixedLengthCRH}; +use algebra_core::curves::{ + models::{ModelParameters, TEModelParameters}, + twisted_edwards_extended::{GroupAffine as TEAffine, GroupProjective as TEProjective}, + ProjectiveCurve, }; #[cfg(feature = "r1cs")] pub mod constraints; -pub trait InjectiveMap<G: Group> { +pub trait InjectiveMap<C: ProjectiveCurve> { type Output: ToBytes + Clone + Eq + Hash + Default + Debug; - fn injective_map(ge: &G) -> Result<Self::Output, CryptoError>; + + fn injective_map(ge: &C::Affine) -> Result<Self::Output, CryptoError>; } pub struct TECompressor; -impl<P: TEModelParameters> InjectiveMap<TEAffine<P>> for TECompressor { +impl<P: TEModelParameters> InjectiveMap<TEProjective<P>> for TECompressor { type Output = <P as ModelParameters>::BaseField; fn injective_map(ge: &TEAffine<P>) -> Result<Self::Output, CryptoError> {@@ -35,39 +30,29 @@ Ok(ge.x)
} } -impl<P: TEModelParameters> InjectiveMap<TEProjective<P>> for TECompressor { - type Output = <P as ModelParameters>::BaseField; - - fn injective_map(ge: &TEProjective<P>) -> Result<Self::Output, CryptoError> { - let ge = ge.into_affine(); - debug_assert!(ge.is_in_correct_subgroup_assuming_on_curve()); - Ok(ge.x) - } -} - -pub struct PedersenCRHCompressor<G: Group, I: InjectiveMap<G>, W: PedersenWindow> { - _group: PhantomData<G>, +pub struct PedersenCRHCompressor<C: ProjectiveCurve, I: InjectiveMap<C>, W: pedersen::Window> { + _group: PhantomData<C>, _compressor: PhantomData<I>, - _crh: PedersenCRH<G, W>, + _crh: pedersen::CRH<C, W>, } -impl<G: Group, I: InjectiveMap<G>, W: PedersenWindow> FixedLengthCRH - for PedersenCRHCompressor<G, I, W> +impl<C: ProjectiveCurve, I: InjectiveMap<C>, W: pedersen::Window> FixedLengthCRH + for PedersenCRHCompressor<C, I, W> { - const INPUT_SIZE_BITS: usize = PedersenCRH::<G, W>::INPUT_SIZE_BITS; + const INPUT_SIZE_BITS: usize = pedersen::CRH::<C, W>::INPUT_SIZE_BITS; type Output = I::Output; - type Parameters = PedersenParameters<G>; + type Parameters = pedersen::Parameters<C>; fn setup<R: Rng>(rng: &mut R) -> Result<Self::Parameters, Error> { let time = start_timer!(|| format!("PedersenCRHCompressor::Setup")); - let params = PedersenCRH::<G, W>::setup(rng); + let params = pedersen::CRH::<C, W>::setup(rng); end_timer!(time); params } fn evaluate(parameters: &Self::Parameters, input: &[u8]) -> Result<Self::Output, Error> { let eval_time = start_timer!(|| "PedersenCRHCompressor::Eval"); - let result = I::injective_map(&PedersenCRH::<G, W>::evaluate(parameters, input)?)?; + let result = I::injective_map(&pedersen::CRH::<C, W>::evaluate(parameters, input)?)?; end_timer!(eval_time); Ok(result) }
@@ -15,7 +15,8 @@ pub use constraints::*;
pub trait FixedLengthCRH { const INPUT_SIZE_BITS: usize; - type Output: ToBytes + Clone + Eq + Hash + Default; + + type Output: ToBytes + Clone + Eq + core::fmt::Debug + Hash + Default; type Parameters: Clone + Default; fn setup<R: Rng>(r: &mut R) -> Result<Self::Parameters, Error>;
@@ -1,57 +1,54 @@
use crate::{ crh::{ - pedersen::{PedersenCRH, PedersenParameters, PedersenWindow}, + pedersen::{Parameters, Window, CRH}, FixedLengthCRHGadget, }, Vec, }; -use algebra_core::{Field, Group}; -use r1cs_core::{ConstraintSystem, SynthesisError}; +use algebra_core::{Field, ProjectiveCurve}; +use r1cs_core::{Namespace, SynthesisError}; use r1cs_std::prelude::*; use core::{borrow::Borrow, marker::PhantomData}; #[derive(Derivative)] -#[derivative(Clone( - bound = "G: Group, W: PedersenWindow, ConstraintF: Field, GG: GroupGadget<G, ConstraintF>" -))] -pub struct PedersenCRHGadgetParameters< - G: Group, - W: PedersenWindow, - ConstraintF: Field, - GG: GroupGadget<G, ConstraintF>, -> { - params: PedersenParameters<G>, +#[derivative(Clone(bound = "C: ProjectiveCurve, GG: CurveVar<C, ConstraintF<C>>"))] +pub struct CRHParametersVar<C: ProjectiveCurve, GG: CurveVar<C, ConstraintF<C>>> +where + for<'a> &'a GG: GroupOpsBounds<'a, C, GG>, +{ + params: Parameters<C>, + #[doc(hidden)] _group_g: PhantomData<GG>, - _engine: PhantomData<ConstraintF>, - _window: PhantomData<W>, } -pub struct PedersenCRHGadget<G: Group, ConstraintF: Field, GG: GroupGadget<G, ConstraintF>> { - #[doc(hideen)] - _group: PhantomData<*const G>, - #[doc(hideen)] - _group_gadget: PhantomData<*const GG>, - #[doc(hideen)] - _engine: PhantomData<ConstraintF>, +type ConstraintF<C> = <<C as ProjectiveCurve>::BaseField as Field>::BasePrimeField; +pub struct CRHGadget<C: ProjectiveCurve, GG: CurveVar<C, ConstraintF<C>>, W: Window> +where + for<'a> &'a GG: GroupOpsBounds<'a, C, GG>, +{ + #[doc(hidden)] + _group: PhantomData<*const C>, + #[doc(hidden)] + _group_var: PhantomData<*const GG>, + #[doc(hidden)] + _window: PhantomData<*const W>, } -impl<ConstraintF, G, GG, W> FixedLengthCRHGadget<PedersenCRH<G, W>, ConstraintF> - for PedersenCRHGadget<G, ConstraintF, GG> +impl<C, GG, W> FixedLengthCRHGadget<CRH<C, W>, ConstraintF<C>> for CRHGadget<C, GG, W> where - ConstraintF: Field, - G: Group, - GG: GroupGadget<G, ConstraintF>, - W: PedersenWindow, + C: ProjectiveCurve, + GG: CurveVar<C, ConstraintF<C>>, + W: Window, + for<'a> &'a GG: GroupOpsBounds<'a, C, GG>, { - type OutputGadget = GG; - type ParametersGadget = PedersenCRHGadgetParameters<G, W, ConstraintF, GG>; + type OutputVar = GG; + type ParametersVar = CRHParametersVar<C, GG>; - fn check_evaluation_gadget<CS: ConstraintSystem<ConstraintF>>( - cs: CS, - parameters: &Self::ParametersGadget, - input: &[UInt8], - ) -> Result<Self::OutputGadget, SynthesisError> { + fn evaluate( + parameters: &Self::ParametersVar, + input: &[UInt8<ConstraintF<C>>], + ) -> Result<Self::OutputVar, SynthesisError> { let mut padded_input = input.to_vec(); // Pad the input if it is not the current length. if input.len() * 8 < W::WINDOW_SIZE * W::NUM_WINDOWS {@@ -64,145 +61,87 @@ assert_eq!(padded_input.len() * 8, W::WINDOW_SIZE * W::NUM_WINDOWS);
assert_eq!(parameters.params.generators.len(), W::NUM_WINDOWS); // Allocate new variable for the result. - let input_in_bits: Vec<_> = padded_input - .iter() - .flat_map(|byte| byte.into_bits_le()) - .collect(); + let input_in_bits: Vec<_> = padded_input.iter().flat_map(|b| b.into_bits_le()).collect(); let input_in_bits = input_in_bits.chunks(W::WINDOW_SIZE); let result = - GG::precomputed_base_multiscalar_mul(cs, ¶meters.params.generators, input_in_bits)?; + GG::precomputed_base_multiscalar_mul(¶meters.params.generators, input_in_bits)?; Ok(result) } } -impl<G: Group, W: PedersenWindow, ConstraintF: Field, GG: GroupGadget<G, ConstraintF>> - AllocGadget<PedersenParameters<G>, ConstraintF> - for PedersenCRHGadgetParameters<G, W, ConstraintF, GG> +impl<C, GG> AllocVar<Parameters<C>, ConstraintF<C>> for CRHParametersVar<C, GG> +where + C: ProjectiveCurve, + GG: CurveVar<C, ConstraintF<C>>, + for<'a> &'a GG: GroupOpsBounds<'a, C, GG>, { - fn alloc_constant<T, CS: ConstraintSystem<ConstraintF>>( - _cs: CS, - val: T, - ) -> Result<Self, SynthesisError> - where - T: Borrow<PedersenParameters<G>>, - { - let params = val.borrow().clone(); - Ok(PedersenCRHGadgetParameters { + fn new_variable<T: Borrow<Parameters<C>>>( + _cs: impl Into<Namespace<ConstraintF<C>>>, + f: impl FnOnce() -> Result<T, SynthesisError>, + _mode: AllocationMode, + ) -> Result<Self, SynthesisError> { + let params = f()?.borrow().clone(); + Ok(CRHParametersVar { params, _group_g: PhantomData, - _engine: PhantomData, - _window: PhantomData, - }) - } - - fn alloc<F, T, CS: ConstraintSystem<ConstraintF>>( - cs: CS, - value_gen: F, - ) -> Result<Self, SynthesisError> - where - F: FnOnce() -> Result<T, SynthesisError>, - T: Borrow<PedersenParameters<G>>, - { - let params = value_gen()?.borrow().clone(); - Self::alloc_constant(cs, params) - } - - fn alloc_input<F, T, CS: ConstraintSystem<ConstraintF>>( - _cs: CS, - value_gen: F, - ) -> Result<Self, SynthesisError> - where - F: FnOnce() -> Result<T, SynthesisError>, - T: Borrow<PedersenParameters<G>>, - { - let params = value_gen()?.borrow().clone(); - Ok(PedersenCRHGadgetParameters { - params, - _group_g: PhantomData, - _engine: PhantomData, - _window: PhantomData, }) } } #[cfg(test)] mod test { - use crate::crh::{ - pedersen::{constraints::PedersenCRHGadget, PedersenCRH, PedersenWindow}, - FixedLengthCRH, FixedLengthCRHGadget, - }; + use crate::crh::{pedersen, pedersen::constraints::*, FixedLengthCRH, FixedLengthCRHGadget}; use algebra::{ ed_on_bls12_381::{EdwardsProjective as JubJub, Fq as Fr}, - test_rng, ProjectiveCurve, - }; - use r1cs_core::ConstraintSystem; - use r1cs_std::{ - ed_on_bls12_381::EdwardsGadget, prelude::*, test_constraint_system::TestConstraintSystem, + test_rng, }; + use r1cs_core::{ConstraintSystem, ConstraintSystemRef}; + use r1cs_std::ed_on_bls12_381::EdwardsVar; use rand::Rng; - type TestCRH = PedersenCRH<JubJub, Window>; - type TestCRHGadget = PedersenCRHGadget<JubJub, Fr, EdwardsGadget>; + type TestCRH = pedersen::CRH<JubJub, Window>; + type TestCRHGadget = CRHGadget<JubJub, EdwardsVar, Window>; #[derive(Clone, PartialEq, Eq, Hash)] pub(super) struct Window; - impl PedersenWindow for Window { + impl pedersen::Window for Window { const WINDOW_SIZE: usize = 128; const NUM_WINDOWS: usize = 8; } - fn generate_input<CS: ConstraintSystem<Fr>, R: Rng>( - mut cs: CS, + fn generate_input<R: Rng>( + cs: ConstraintSystemRef<Fr>, rng: &mut R, - ) -> ([u8; 128], Vec<UInt8>) { + ) -> ([u8; 128], Vec<UInt8<Fr>>) { let mut input = [1u8; 128]; rng.fill_bytes(&mut input); let mut input_bytes = vec![]; - for (byte_i, input_byte) in input.iter().enumerate() { - let cs = cs.ns(|| format!("input_byte_gadget_{}", byte_i)); - input_bytes.push(UInt8::alloc(cs, || Ok(*input_byte)).unwrap()); + for byte in input.iter() { + input_bytes.push(UInt8::new_witness(cs.clone(), || Ok(byte)).unwrap()); } (input, input_bytes) } #[test] - fn crh_primitive_gadget_test() { + fn test_native_equality() { let rng = &mut test_rng(); - let mut cs = TestConstraintSystem::<Fr>::new(); + let cs = ConstraintSystem::<Fr>::new_ref(); - let (input, input_bytes) = generate_input(&mut cs, rng); - println!("number of constraints for input: {}", cs.num_constraints()); + let (input, input_var) = generate_input(cs.clone(), rng); let parameters = TestCRH::setup(rng).unwrap(); let primitive_result = TestCRH::evaluate(¶meters, &input).unwrap(); - let gadget_parameters = - <TestCRHGadget as FixedLengthCRHGadget<TestCRH, Fr>>::ParametersGadget::alloc( - &mut cs.ns(|| "gadget_parameters"), - || Ok(¶meters), - ) - .unwrap(); - println!( - "number of constraints for input + params: {}", - cs.num_constraints() - ); - - let gadget_result = - <TestCRHGadget as FixedLengthCRHGadget<TestCRH, Fr>>::check_evaluation_gadget( - &mut cs.ns(|| "gadget_evaluation"), - &gadget_parameters, - &input_bytes, - ) - .unwrap(); + let parameters_var = + CRHParametersVar::new_constant(cs.ns("CRH Parameters"), ¶meters).unwrap(); - println!("number of constraints total: {}", cs.num_constraints()); + let result_var = TestCRHGadget::evaluate(¶meters_var, &input_var).unwrap(); - let primitive_result = primitive_result.into_affine(); - assert_eq!(primitive_result.x, gadget_result.x.value.unwrap()); - assert_eq!(primitive_result.y, gadget_result.y.value.unwrap()); - assert!(cs.is_satisfied()); + let primitive_result = primitive_result; + assert_eq!(primitive_result, result_var.value().unwrap()); + assert!(cs.is_satisfied().unwrap()); } }
@@ -8,29 +8,29 @@ #[cfg(feature = "parallel")]
use rayon::prelude::*; use crate::crh::FixedLengthCRH; -use algebra_core::{groups::Group, Field, ToConstraintField}; +use algebra_core::{Field, ProjectiveCurve, ToConstraintField}; use ff_fft::cfg_chunks; #[cfg(feature = "r1cs")] pub mod constraints; -pub trait PedersenWindow: Clone { +pub trait Window: Clone { const WINDOW_SIZE: usize; const NUM_WINDOWS: usize; } #[derive(Clone, Default)] -pub struct PedersenParameters<G: Group> { - pub generators: Vec<Vec<G>>, +pub struct Parameters<C: ProjectiveCurve> { + pub generators: Vec<Vec<C>>, } -pub struct PedersenCRH<G: Group, W: PedersenWindow> { - group: PhantomData<G>, +pub struct CRH<C: ProjectiveCurve, W: Window> { + group: PhantomData<C>, window: PhantomData<W>, } -impl<G: Group, W: PedersenWindow> PedersenCRH<G, W> { - pub fn create_generators<R: Rng>(rng: &mut R) -> Vec<Vec<G>> { +impl<C: ProjectiveCurve, W: Window> CRH<C, W> { + pub fn create_generators<R: Rng>(rng: &mut R) -> Vec<Vec<C>> { let mut generators_powers = Vec::new(); for _ in 0..W::NUM_WINDOWS { generators_powers.push(Self::generator_powers(W::WINDOW_SIZE, rng));@@ -38,9 +38,9 @@ }
generators_powers } - pub fn generator_powers<R: Rng>(num_powers: usize, rng: &mut R) -> Vec<G> { + pub fn generator_powers<R: Rng>(num_powers: usize, rng: &mut R) -> Vec<C> { let mut cur_gen_powers = Vec::with_capacity(num_powers); - let mut base = G::rand(rng); + let mut base = C::rand(rng); for _ in 0..num_powers { cur_gen_powers.push(base); base.double_in_place();@@ -49,14 +49,14 @@ cur_gen_powers
} } -impl<G: Group, W: PedersenWindow> FixedLengthCRH for PedersenCRH<G, W> { +impl<C: ProjectiveCurve, W: Window> FixedLengthCRH for CRH<C, W> { const INPUT_SIZE_BITS: usize = W::WINDOW_SIZE * W::NUM_WINDOWS; - type Output = G; - type Parameters = PedersenParameters<G>; + type Output = C::Affine; + type Parameters = Parameters<C>; fn setup<R: Rng>(rng: &mut R) -> Result<Self::Parameters, Error> { let time = start_timer!(|| format!( - "PedersenCRH::Setup: {} {}-bit windows; {{0,1}}^{{{}}} -> G", + "PedersenCRH::Setup: {} {}-bit windows; {{0,1}}^{{{}}} -> C", W::NUM_WINDOWS, W::WINDOW_SIZE, W::NUM_WINDOWS * W::WINDOW_SIZE@@ -71,7 +71,7 @@ let eval_time = start_timer!(|| "PedersenCRH::Eval");
if (input.len() * 8) > W::WINDOW_SIZE * W::NUM_WINDOWS { panic!( - "incorrect input length {:?} for window params {:?}x{:?}", + "incorrect input length {:?} for window params {:?}✕{:?}", input.len(), W::WINDOW_SIZE, W::NUM_WINDOWS@@ -93,7 +93,7 @@
assert_eq!( parameters.generators.len(), W::NUM_WINDOWS, - "Incorrect pp of size {:?}x{:?} for window params {:?}x{:?}", + "Incorrect pp of size {:?}✕{:?} for window params {:?}✕{:?}", parameters.generators[0].len(), parameters.generators.len(), W::WINDOW_SIZE,@@ -105,7 +105,7 @@ let bits = bytes_to_bits(input);
let result = cfg_chunks!(bits, W::WINDOW_SIZE) .zip(¶meters.generators) .map(|(bits, generator_powers)| { - let mut encoded = G::zero(); + let mut encoded = C::zero(); for (bit, base) in bits.iter().zip(generator_powers.iter()) { if *bit { encoded += base;@@ -113,11 +113,11 @@ }
} encoded }) - .sum::<G>(); + .sum::<C>(); end_timer!(eval_time); - Ok(result) + Ok(result.into()) } }@@ -132,7 +132,7 @@ }
bits } -impl<G: Group> Debug for PedersenParameters<G> { +impl<C: ProjectiveCurve> Debug for Parameters<C> { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { write!(f, "Pedersen Hash Parameters {{\n")?; for (i, g) in self.generators.iter().enumerate() {@@ -142,8 +142,8 @@ write!(f, "}}\n")
} } -impl<ConstraintF: Field, G: Group + ToConstraintField<ConstraintF>> ToConstraintField<ConstraintF> - for PedersenParameters<G> +impl<ConstraintF: Field, C: ProjectiveCurve + ToConstraintField<ConstraintF>> + ToConstraintField<ConstraintF> for Parameters<C> { #[inline] fn to_field_elements(&self) -> Result<Vec<ConstraintF>, Error> {
@@ -25,17 +25,17 @@
pub use self::{ commitment::CommitmentScheme, crh::FixedLengthCRH, - merkle_tree::{MerkleHashTree, MerkleTreePath}, + merkle_tree::{MerkleTree, Path}, nizk::NIZK, prf::PRF, signature::SignatureScheme, }; #[cfg(feature = "r1cs")] +#[cfg(feature = "r1cs")] pub use self::{ - commitment::CommitmentGadget, crh::FixedLengthCRHGadget, - merkle_tree::constraints::MerkleTreePathGadget, nizk::NIZKVerifierGadget, prf::PRFGadget, - signature::SigRandomizePkGadget, + commitment::CommitmentGadget, crh::FixedLengthCRHGadget, merkle_tree::constraints::PathVar, + nizk::NIZKVerifierGadget, prf::PRFGadget, signature::SigRandomizePkGadget, }; pub type Error = Box<dyn algebra_core::Error>;
@@ -1,6 +1,6 @@
use algebra_core::Field; -use r1cs_core::{ConstraintSystem, SynthesisError}; -use r1cs_std::{boolean::AllocatedBit, prelude::*}; +use r1cs_core::{Namespace, SynthesisError}; +use r1cs_std::prelude::*; use crate::{ crh::{FixedLengthCRH, FixedLengthCRHGadget},@@ -9,58 +9,56 @@ };
use core::borrow::Borrow; -pub struct MerkleTreePathGadget<P, HGadget, ConstraintF> +pub struct PathVar<P, HGadget, ConstraintF> where - P: MerkleTreeConfig, + P: Config, HGadget: FixedLengthCRHGadget<P::H, ConstraintF>, ConstraintF: Field, { - path: Vec<(HGadget::OutputGadget, HGadget::OutputGadget)>, + path: Vec<(HGadget::OutputVar, HGadget::OutputVar)>, } -impl<P, CRHGadget, ConstraintF> MerkleTreePathGadget<P, CRHGadget, ConstraintF> +impl<P, CRHGadget, ConstraintF> PathVar<P, CRHGadget, ConstraintF> where - P: MerkleTreeConfig, + P: Config, ConstraintF: Field, CRHGadget: FixedLengthCRHGadget<P::H, ConstraintF>, + <CRHGadget::OutputVar as R1CSVar<ConstraintF>>::Value: PartialEq, { - pub fn check_membership<CS: ConstraintSystem<ConstraintF>>( + pub fn check_membership( &self, - cs: CS, - parameters: &CRHGadget::ParametersGadget, - root: &CRHGadget::OutputGadget, + parameters: &CRHGadget::ParametersVar, + root: &CRHGadget::OutputVar, leaf: impl ToBytesGadget<ConstraintF>, ) -> Result<(), SynthesisError> { - self.conditionally_check_membership(cs, parameters, root, leaf, &Boolean::Constant(true)) + self.conditionally_check_membership(parameters, root, leaf, &Boolean::Constant(true)) } - pub fn conditionally_check_membership<CS: ConstraintSystem<ConstraintF>>( + pub fn conditionally_check_membership( &self, - mut cs: CS, - parameters: &CRHGadget::ParametersGadget, - root: &CRHGadget::OutputGadget, + parameters: &CRHGadget::ParametersVar, + root: &CRHGadget::OutputVar, leaf: impl ToBytesGadget<ConstraintF>, - should_enforce: &Boolean, + should_enforce: &Boolean<ConstraintF>, ) -> Result<(), SynthesisError> { assert_eq!(self.path.len(), P::HEIGHT - 1); // Check that the hash of the given leaf matches the leaf hash in the membership // proof. - let leaf_bits = leaf.to_bytes(&mut cs.ns(|| "leaf_to_bytes"))?; - let leaf_hash = CRHGadget::check_evaluation_gadget( - cs.ns(|| "check_evaluation_gadget"), - parameters, - &leaf_bits, - )?; + let leaf_bits = leaf.to_bytes()?; + let leaf_hash = CRHGadget::evaluate(parameters, &leaf_bits)?; + let cs = leaf_hash + .cs() + .or(root.cs()) + .or(should_enforce.cs()) + .unwrap(); // Check if leaf is one of the bottom-most siblings. - let leaf_is_left = AllocatedBit::alloc(&mut cs.ns(|| "leaf_is_left"), || { - Ok(leaf_hash == self.path[0].0) - })? - .into(); - CRHGadget::OutputGadget::conditional_enforce_equal_or( - &mut cs.ns(|| "check_leaf_is_left"), + let leaf_is_left = Boolean::new_witness(cs.ns("leaf_is_left"), || { + Ok(leaf_hash.value()?.eq(&self.path[0].0.value()?)) + })?; + + leaf_hash.conditional_enforce_equal_or( &leaf_is_left, - &leaf_hash, &self.path[0].0, &self.path[0].1, should_enforce,@@ -68,133 +66,74 @@ )?;
// Check levels between leaf level and root. let mut previous_hash = leaf_hash; - for (i, &(ref left_hash, ref right_hash)) in self.path.iter().enumerate() { + let mut i = 0; + for &(ref left_hash, ref right_hash) in &self.path { // Check if the previous_hash matches the correct current hash. - let previous_is_left = - AllocatedBit::alloc(&mut cs.ns(|| format!("previous_is_left_{}", i)), || { - Ok(&previous_hash == left_hash) - })? - .into(); + let previous_is_left = Boolean::new_witness(cs.ns("previous_is_left"), || { + Ok(previous_hash.value()?.eq(&left_hash.value()?)) + })?; - CRHGadget::OutputGadget::conditional_enforce_equal_or( - &mut cs.ns(|| format!("check_equals_which_{}", i)), + let ns = cs.ns(format!( + "enforcing that inner hash is correct at i-th level{}", + i + )); + previous_hash.conditional_enforce_equal_or( &previous_is_left, - &previous_hash, left_hash, right_hash, should_enforce, )?; + drop(ns); - previous_hash = hash_inner_node_gadget::<P::H, CRHGadget, ConstraintF, _>( - &mut cs.ns(|| format!("hash_inner_node_{}", i)), - parameters, - left_hash, - right_hash, - )?; + previous_hash = + hash_inner_node::<P::H, CRHGadget, ConstraintF>(parameters, left_hash, right_hash)?; + i += 1; } - root.conditional_enforce_equal( - &mut cs.ns(|| "root_is_last"), - &previous_hash, - should_enforce, - ) + root.conditional_enforce_equal(&previous_hash, should_enforce) } } -pub(crate) fn hash_inner_node_gadget<H, HG, ConstraintF, CS>( - mut cs: CS, - parameters: &HG::ParametersGadget, - left_child: &HG::OutputGadget, - right_child: &HG::OutputGadget, -) -> Result<HG::OutputGadget, SynthesisError> +pub(crate) fn hash_inner_node<H, HG, ConstraintF>( + parameters: &HG::ParametersVar, + left_child: &HG::OutputVar, + right_child: &HG::OutputVar, +) -> Result<HG::OutputVar, SynthesisError> where ConstraintF: Field, - CS: ConstraintSystem<ConstraintF>, H: FixedLengthCRH, HG: FixedLengthCRHGadget<H, ConstraintF>, { - let left_bytes = left_child.to_bytes(&mut cs.ns(|| "left_to_bytes"))?; - let right_bytes = right_child.to_bytes(&mut cs.ns(|| "right_to_bytes"))?; + let left_bytes = left_child.to_bytes()?; + let right_bytes = right_child.to_bytes()?; let mut bytes = left_bytes; bytes.extend_from_slice(&right_bytes); - HG::check_evaluation_gadget(cs, parameters, &bytes) + HG::evaluate(parameters, &bytes) } -impl<P, HGadget, ConstraintF> AllocGadget<MerkleTreePath<P>, ConstraintF> - for MerkleTreePathGadget<P, HGadget, ConstraintF> +impl<P, HGadget, ConstraintF> AllocVar<Path<P>, ConstraintF> for PathVar<P, HGadget, ConstraintF> where - P: MerkleTreeConfig, + P: Config, HGadget: FixedLengthCRHGadget<P::H, ConstraintF>, ConstraintF: Field, { - fn alloc_constant<T, CS: ConstraintSystem<ConstraintF>>( - mut cs: CS, - val: T, - ) -> Result<Self, SynthesisError> - where - T: Borrow<MerkleTreePath<P>>, - { - let mut path = Vec::new(); - for (i, &(ref l, ref r)) in val.borrow().path.iter().enumerate() { - let l_hash = HGadget::OutputGadget::alloc_constant( - &mut cs.ns(|| format!("l_child_{}", i)), - l.clone(), - )?; - let r_hash = HGadget::OutputGadget::alloc_constant( - &mut cs.ns(|| format!("r_child_{}", i)), - r.clone(), - )?; - path.push((l_hash, r_hash)); - } - Ok(MerkleTreePathGadget { path }) - } - - fn alloc<F, T, CS: ConstraintSystem<ConstraintF>>( - mut cs: CS, - value_gen: F, - ) -> Result<Self, SynthesisError> - where - F: FnOnce() -> Result<T, SynthesisError>, - T: Borrow<MerkleTreePath<P>>, - { - let mut path = Vec::new(); - for (i, &(ref l, ref r)) in value_gen()?.borrow().path.iter().enumerate() { - let l_hash = - HGadget::OutputGadget::alloc(&mut cs.ns(|| format!("l_child_{}", i)), || { - Ok(l.clone()) - })?; - let r_hash = - HGadget::OutputGadget::alloc(&mut cs.ns(|| format!("r_child_{}", i)), || { - Ok(r.clone()) - })?; - path.push((l_hash, r_hash)); - } - Ok(MerkleTreePathGadget { path }) - } - - fn alloc_input<F, T, CS: ConstraintSystem<ConstraintF>>( - mut cs: CS, - value_gen: F, - ) -> Result<Self, SynthesisError> - where - F: FnOnce() -> Result<T, SynthesisError>, - T: Borrow<MerkleTreePath<P>>, - { - let mut path = Vec::new(); - for (i, &(ref l, ref r)) in value_gen()?.borrow().path.iter().enumerate() { - let l_hash = HGadget::OutputGadget::alloc_input( - &mut cs.ns(|| format!("l_child_{}", i)), - || Ok(l.clone()), - )?; - let r_hash = HGadget::OutputGadget::alloc_input( - &mut cs.ns(|| format!("r_child_{}", i)), - || Ok(r.clone()), - )?; - path.push((l_hash, r_hash)); - } - - Ok(MerkleTreePathGadget { path }) + fn new_variable<T: Borrow<Path<P>>>( + cs: impl Into<Namespace<ConstraintF>>, + f: impl FnOnce() -> Result<T, SynthesisError>, + mode: AllocationMode, + ) -> Result<Self, SynthesisError> { + let ns = cs.into(); + let cs = ns.cs(); + f().and_then(|val| { + let mut path = Vec::new(); + for &(ref l, ref r) in val.borrow().path.iter() { + let l_hash = HGadget::OutputVar::new_variable(cs.ns("l_child"), || Ok(l), mode)?; + let r_hash = HGadget::OutputVar::new_variable(cs.ns("r_child"), || Ok(r), mode)?; + path.push((l_hash, r_hash)); + } + Ok(PathVar { path }) + }) } }@@ -202,37 +141,37 @@ #[cfg(test)]
mod test { use crate::{ crh::{ - pedersen::{constraints::PedersenCRHGadget, PedersenCRH, PedersenWindow}, + pedersen::{self, constraints::CRHGadget}, FixedLengthCRH, FixedLengthCRHGadget, }, merkle_tree::*, }; - use algebra::ed_on_bls12_381::{EdwardsAffine as JubJub, Fq}; + use algebra::ed_on_bls12_381::{EdwardsProjective as JubJub, Fq}; use r1cs_core::ConstraintSystem; use rand::SeedableRng; use rand_xorshift::XorShiftRng; use super::*; - use r1cs_std::{ed_on_bls12_381::EdwardsGadget, test_constraint_system::TestConstraintSystem}; + use r1cs_std::ed_on_bls12_381::EdwardsVar; #[derive(Clone)] pub(super) struct Window4x256; - impl PedersenWindow for Window4x256 { + impl pedersen::Window for Window4x256 { const WINDOW_SIZE: usize = 4; const NUM_WINDOWS: usize = 256; } - type H = PedersenCRH<JubJub, Window4x256>; - type HG = PedersenCRHGadget<JubJub, Fq, EdwardsGadget>; + type H = pedersen::CRH<JubJub, Window4x256>; + type HG = CRHGadget<JubJub, EdwardsVar, Window4x256>; struct JubJubMerkleTreeParams; - impl MerkleTreeConfig for JubJubMerkleTreeParams { + impl Config for JubJubMerkleTreeParams { const HEIGHT: usize = 32; type H = H; } - type JubJubMerkleTree = MerkleHashTree<JubJubMerkleTreeParams>; + type JubJubMerkleTree = MerkleTree<JubJubMerkleTreeParams>; fn generate_merkle_tree(leaves: &[[u8; 30]], use_bad_root: bool) -> () { let mut rng = XorShiftRng::seed_from_u64(9174123u64);@@ -242,13 +181,13 @@ let tree = JubJubMerkleTree::new(crh_parameters.clone(), leaves).unwrap();
let root = tree.root(); let mut satisfied = true; for (i, leaf) in leaves.iter().enumerate() { - let mut cs = TestConstraintSystem::<Fq>::new(); + let cs = ConstraintSystem::<Fq>::new_ref(); let proof = tree.generate_proof(i, &leaf).unwrap(); assert!(proof.verify(&crh_parameters, &root, &leaf).unwrap()); // Allocate Merkle Tree Root - let root = <HG as FixedLengthCRHGadget<H, _>>::OutputGadget::alloc( - &mut cs.ns(|| format!("new_digest_{}", i)), + let root = <HG as FixedLengthCRHGadget<H, _>>::OutputVar::new_witness( + cs.ns("new_digest"), || { if use_bad_root { Ok(<H as FixedLengthCRH>::Output::default())@@ -263,9 +202,9 @@ let constraints_from_digest = cs.num_constraints();
println!("constraints from digest: {}", constraints_from_digest); // Allocate Parameters for CRH - let crh_parameters = <HG as FixedLengthCRHGadget<H, Fq>>::ParametersGadget::alloc( - &mut cs.ns(|| format!("new_parameters_{}", i)), - || Ok(crh_parameters.clone()), + let crh_parameters = <HG as FixedLengthCRHGadget<H, Fq>>::ParametersVar::new_constant( + cs.ns("new_parameter"), + &crh_parameters, ) .unwrap();@@ -283,26 +222,21 @@ cs.num_constraints() - constraints_from_parameters - constraints_from_digest;
println!("constraints from leaf: {}", constraints_from_leaf); // Allocate Merkle Tree Path - let cw = MerkleTreePathGadget::<_, HG, _>::alloc( - &mut cs.ns(|| format!("new_witness_{}", i)), - || Ok(proof), - ) - .unwrap(); + let cw = PathVar::<_, HG, _>::new_witness(cs.ns("new_witness"), || Ok(&proof)).unwrap(); + for (i, (l, r)) in cw.path.iter().enumerate() { + assert_eq!(l.value().unwrap(), proof.path[i].0); + assert_eq!(r.value().unwrap(), proof.path[i].1); + } let constraints_from_path = cs.num_constraints() - constraints_from_parameters - constraints_from_digest - constraints_from_leaf; println!("constraints from path: {}", constraints_from_path); - let leaf_g: &[UInt8] = leaf_g.as_slice(); - cw.check_membership( - &mut cs.ns(|| format!("new_witness_check_{}", i)), - &crh_parameters, - &root, - &leaf_g, - ) - .unwrap(); - if !cs.is_satisfied() { + let leaf_g: &[_] = leaf_g.as_slice(); + cw.check_membership(&crh_parameters, &root, &leaf_g) + .unwrap(); + if !cs.is_satisfied().unwrap() { satisfied = false; println!( "Unsatisfied constraint: {}",
@@ -1,11 +1,11 @@
-use crate::{crh::FixedLengthCRH, Error, Vec}; -use algebra_core::{bytes::ToBytes, io::Cursor}; +use crate::{crh::FixedLengthCRH, Vec}; +use algebra_core::bytes::ToBytes; use core::fmt; #[cfg(feature = "r1cs")] pub mod constraints; -pub trait MerkleTreeConfig { +pub trait Config { const HEIGHT: usize; type H: FixedLengthCRH; }@@ -14,20 +14,20 @@ /// Stores the hashes of a particular path (in order) from leaf to root.
/// Our path `is_left_child()` if the boolean in `path` is true. #[derive(Derivative)] #[derivative( - Clone(bound = "P: MerkleTreeConfig"), - Debug(bound = "P: MerkleTreeConfig, <P::H as FixedLengthCRH>::Output: fmt::Debug") + Clone(bound = "P: Config"), + Debug(bound = "P: Config, <P::H as FixedLengthCRH>::Output: fmt::Debug") )] -pub struct MerkleTreePath<P: MerkleTreeConfig> { +pub struct Path<P: Config> { pub(crate) path: Vec<( <P::H as FixedLengthCRH>::Output, <P::H as FixedLengthCRH>::Output, )>, } -pub type MerkleTreeParams<P> = <<P as MerkleTreeConfig>::H as FixedLengthCRH>::Parameters; -pub type MerkleTreeDigest<P> = <<P as MerkleTreeConfig>::H as FixedLengthCRH>::Output; +pub type Parameters<P> = <<P as Config>::H as FixedLengthCRH>::Parameters; +pub type Digest<P> = <<P as Config>::H as FixedLengthCRH>::Output; -impl<P: MerkleTreeConfig> Default for MerkleTreePath<P> { +impl<P: Config> Default for Path<P> { fn default() -> Self { let mut path = Vec::with_capacity(P::HEIGHT as usize); for _i in 1..P::HEIGHT as usize {@@ -40,13 +40,13 @@ Self { path }
} } -impl<P: MerkleTreeConfig> MerkleTreePath<P> { +impl<P: Config> Path<P> { pub fn verify<L: ToBytes>( &self, parameters: &<P::H as FixedLengthCRH>::Parameters, root_hash: &<P::H as FixedLengthCRH>::Output, leaf: &L, - ) -> Result<bool, Error> { + ) -> Result<bool, crate::Error> { if self.path.len() != (P::HEIGHT - 1) as usize { return Ok(false); }@@ -81,7 +81,7 @@ }
} } -pub struct MerkleHashTree<P: MerkleTreeConfig> { +pub struct MerkleTree<P: Config> { tree: Vec<<P::H as FixedLengthCRH>::Output>, padding_tree: Vec<( <P::H as FixedLengthCRH>::Output,@@ -91,11 +91,11 @@ parameters: <P::H as FixedLengthCRH>::Parameters,
root: Option<<P::H as FixedLengthCRH>::Output>, } -impl<P: MerkleTreeConfig> MerkleHashTree<P> { +impl<P: Config> MerkleTree<P> { pub const HEIGHT: u8 = P::HEIGHT as u8; pub fn blank(parameters: <P::H as FixedLengthCRH>::Parameters) -> Self { - MerkleHashTree { + MerkleTree { tree: Vec::new(), padding_tree: Vec::new(), root: None,@@ -106,7 +106,7 @@
pub fn new<L: ToBytes>( parameters: <P::H as FixedLengthCRH>::Parameters, leaves: &[L], - ) -> Result<Self, Error> { + ) -> Result<Self, crate::Error> { let new_time = start_timer!(|| "MerkleTree::New"); let last_level_size = leaves.len().next_power_of_two();@@ -174,7 +174,7 @@ cur_hash
}; end_timer!(new_time); - Ok(MerkleHashTree { + Ok(MerkleTree { tree, padding_tree, parameters,@@ -191,7 +191,7 @@ pub fn generate_proof<L: ToBytes>(
&self, index: usize, leaf: &L, - ) -> Result<MerkleTreePath<P>, Error> { + ) -> Result<Path<P>, crate::Error> { let prove_time = start_timer!(|| "MerkleTree::GenProof"); let mut path = Vec::new();@@ -203,7 +203,7 @@ let empty_hash = hash_empty::<P::H>(&self.parameters)?;
// Check that the given index corresponds to the correct leaf. if leaf_hash != self.tree[tree_index] { - return Err(MerkleTreeError::IncorrectLeafIndex(tree_index).into()); + return Err(Error::IncorrectLeafIndex(tree_index).into()); } // Iterate from the leaf up to the root, storing all intermediate hash values.@@ -233,32 +233,30 @@ }
} end_timer!(prove_time); if path.len() != (Self::HEIGHT - 1) as usize { - return Err(MerkleTreeError::IncorrectPathLength(path.len()).into()); + return Err(Error::IncorrectPathLength(path.len()).into()); } else { - Ok(MerkleTreePath { path }) + Ok(Path { path }) } } } #[derive(Debug)] -pub enum MerkleTreeError { +pub enum Error { IncorrectLeafIndex(usize), IncorrectPathLength(usize), } -impl core::fmt::Display for MerkleTreeError { +impl core::fmt::Display for Error { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { let msg = match self { - MerkleTreeError::IncorrectLeafIndex(index) => { - format!("incorrect leaf index: {}", index) - } - MerkleTreeError::IncorrectPathLength(len) => format!("incorrect path length: {}", len), + Error::IncorrectLeafIndex(index) => format!("incorrect leaf index: {}", index), + Error::IncorrectPathLength(len) => format!("incorrect path length: {}", len), }; write!(f, "{}", msg) } } -impl algebra_core::Error for MerkleTreeError {} +impl algebra_core::Error for Error {} /// Returns the log2 value of the given number. #[inline]@@ -333,14 +331,11 @@ parameters: &H::Parameters,
left: &H::Output, right: &H::Output, buffer: &mut [u8], -) -> Result<H::Output, Error> { - let mut writer = Cursor::new(&mut *buffer); - // Construct left input. - left.write(&mut writer)?; - - // Construct right input. - right.write(&mut writer)?; - +) -> Result<H::Output, crate::Error> { + let bytes = algebra_core::to_bytes![left]? + .into_iter() + .chain(algebra_core::to_bytes![right]?); + buffer.iter_mut().zip(bytes).for_each(|(b, l_b)| *b = l_b); H::evaluate(parameters, &buffer[..(H::INPUT_SIZE_BITS / 8)]) }@@ -349,16 +344,17 @@ pub(crate) fn hash_leaf<H: FixedLengthCRH, L: ToBytes>(
parameters: &H::Parameters, leaf: &L, buffer: &mut [u8], -) -> Result<H::Output, Error> { - let mut writer = Cursor::new(&mut *buffer); - leaf.write(&mut writer)?; - +) -> Result<H::Output, crate::Error> { + buffer + .iter_mut() + .zip(&algebra_core::to_bytes![leaf]?) + .for_each(|(b, l_b)| *b = *l_b); H::evaluate(parameters, &buffer[..(H::INPUT_SIZE_BITS / 8)]) } pub(crate) fn hash_empty<H: FixedLengthCRH>( parameters: &H::Parameters, -) -> Result<H::Output, Error> { +) -> Result<H::Output, crate::Error> { let empty_buffer = vec![0u8; H::INPUT_SIZE_BITS / 8]; H::evaluate(parameters, &empty_buffer) }@@ -366,29 +362,29 @@
#[cfg(test)] mod test { use crate::{ - crh::{pedersen::*, *}, + crh::{pedersen, *}, merkle_tree::*, }; - use algebra::{ed_on_bls12_381::EdwardsAffine as JubJub, Zero}; + use algebra::{ed_on_bls12_381::EdwardsProjective as JubJub, Zero}; use rand::SeedableRng; use rand_xorshift::XorShiftRng; #[derive(Clone)] pub(super) struct Window4x256; - impl PedersenWindow for Window4x256 { + impl pedersen::Window for Window4x256 { const WINDOW_SIZE: usize = 4; const NUM_WINDOWS: usize = 256; } - type H = PedersenCRH<JubJub, Window4x256>; + type H = pedersen::CRH<JubJub, Window4x256>; struct JubJubMerkleTreeParams; - impl MerkleTreeConfig for JubJubMerkleTreeParams { + impl Config for JubJubMerkleTreeParams { const HEIGHT: usize = 8; type H = H; } - type JubJubMerkleTree = MerkleHashTree<JubJubMerkleTreeParams>; + type JubJubMerkleTree = MerkleTree<JubJubMerkleTreeParams>; fn generate_merkle_tree<L: ToBytes + Clone + Eq>(leaves: &[L]) -> () { let mut rng = XorShiftRng::seed_from_u64(9174123u64);@@ -435,7 +431,7 @@ let mut rng = XorShiftRng::seed_from_u64(13423423u64);
let crh_parameters = H::setup(&mut rng).unwrap(); let tree = JubJubMerkleTree::new(crh_parameters.clone(), &leaves).unwrap(); - let root = JubJub::zero(); + let root = JubJub::zero().into(); for (i, leaf) in leaves.iter().enumerate() { let proof = tree.generate_proof(i, &leaf).unwrap(); assert!(proof.verify(&crh_parameters, &root, &leaf).unwrap());
@@ -1,47 +1,59 @@
use algebra_core::Field; -use r1cs_core::{ConstraintSystem, SynthesisError}; +use core::borrow::Borrow; +use r1cs_core::{Namespace, SynthesisError}; use r1cs_std::prelude::*; use crate::nizk::NIZK; pub trait NIZKVerifierGadget<N: NIZK, ConstraintF: Field> { - type PreparedVerificationKeyGadget; - type VerificationKeyGadget: AllocGadget<N::VerificationParameters, ConstraintF> + type PreparedVerificationKeyVar; + type VerificationKeyVar: AllocVar<N::VerificationParameters, ConstraintF> + ToBytesGadget<ConstraintF>; - type ProofGadget: AllocGadget<N::Proof, ConstraintF>; + type ProofVar: AllocVar<N::Proof, ConstraintF>; - fn check_verify<'a, CS, I, T>( - cs: CS, - verification_key: &Self::VerificationKeyGadget, - input: I, - proof: &Self::ProofGadget, - ) -> Result<(), SynthesisError> - where - CS: ConstraintSystem<ConstraintF>, - I: Iterator<Item = &'a T>, - T: 'a + ToBitsGadget<ConstraintF> + ?Sized; + /// Optionally allocates `N::Proof` in `cs` without performing + /// subgroup checks. + /// + /// The default implementation doesn't omit these checks. + fn new_proof_unchecked<T: Borrow<N::Proof>>( + cs: impl Into<Namespace<ConstraintF>>, + f: impl FnOnce() -> Result<T, SynthesisError>, + mode: AllocationMode, + ) -> Result<Self::ProofVar, SynthesisError> { + Self::ProofVar::new_variable(cs, f, mode) + } - fn conditional_check_verify<'a, CS, I, T>( - cs: CS, - verification_key: &Self::VerificationKeyGadget, - input: I, - proof: &Self::ProofGadget, - condition: &Boolean, - ) -> Result<(), SynthesisError> - where - CS: ConstraintSystem<ConstraintF>, - I: Iterator<Item = &'a T>, - T: 'a + ToBitsGadget<ConstraintF> + ?Sized; + /// Optionally allocates `N::VerificationParameters` in `cs` + /// without performing subgroup checks. + /// + /// The default implementation doesn't omit these checks. + fn new_verification_key_unchecked<T: Borrow<N::VerificationParameters>>( + cs: impl Into<Namespace<ConstraintF>>, + f: impl FnOnce() -> Result<T, SynthesisError>, + mode: AllocationMode, + ) -> Result<Self::VerificationKeyVar, SynthesisError> { + Self::VerificationKeyVar::new_variable(cs, f, mode) + } - fn conditional_check_verify_prepared<'a, CS, I, T>( - cs: CS, - prepared_verification_key: &Self::PreparedVerificationKeyGadget, - input: I, - proof: &Self::ProofGadget, - condition: &Boolean, - ) -> Result<(), SynthesisError> - where - CS: ConstraintSystem<ConstraintF>, - I: Iterator<Item = &'a T>, - T: 'a + ToBitsGadget<ConstraintF> + ?Sized; + fn verify<'a, T: 'a + ToBitsGadget<ConstraintF> + ?Sized>( + verification_key: &Self::VerificationKeyVar, + input: impl Iterator<Item = &'a T>, + proof: &Self::ProofVar, + ) -> Result<(), SynthesisError> { + Self::conditional_verify(verification_key, input, proof, &Boolean::constant(true)) + } + + fn conditional_verify<'a, T: 'a + ToBitsGadget<ConstraintF> + ?Sized>( + verification_key: &Self::VerificationKeyVar, + input: impl Iterator<Item = &'a T>, + proof: &Self::ProofVar, + condition: &Boolean<ConstraintF>, + ) -> Result<(), SynthesisError>; + + fn conditional_verify_prepared<'a, T: 'a + ToBitsGadget<ConstraintF> + ?Sized>( + prepared_verification_key: &Self::PreparedVerificationKeyVar, + input: impl Iterator<Item = &'a T>, + proof: &Self::ProofVar, + condition: &Boolean<ConstraintF>, + ) -> Result<(), SynthesisError>; }
@@ -2,57 +2,43 @@ use crate::{
nizk::{gm17::Gm17, NIZKVerifierGadget}, Vec, }; -use algebra_core::{AffineCurve, Field, PairingEngine, ToConstraintField}; -use r1cs_core::{ConstraintSynthesizer, ConstraintSystem, SynthesisError}; +use algebra_core::{AffineCurve, PairingEngine, ToConstraintField}; +use r1cs_core::{ConstraintSynthesizer, Namespace, SynthesisError}; use r1cs_std::prelude::*; use core::{borrow::Borrow, marker::PhantomData}; use gm17::{PreparedVerifyingKey, Proof, VerifyingKey}; #[derive(Derivative)] -#[derivative(Clone(bound = "P::G1Gadget: Clone, P::G2Gadget: Clone"))] -pub struct ProofGadget< - PairingE: PairingEngine, - ConstraintF: Field, - P: PairingGadget<PairingE, ConstraintF>, -> { - pub a: P::G1Gadget, - pub b: P::G2Gadget, - pub c: P::G1Gadget, +#[derivative(Clone(bound = "P::G1Var: Clone, P::G2Var: Clone"))] +pub struct ProofVar<E: PairingEngine, P: PairingVar<E>> { + pub a: P::G1Var, + pub b: P::G2Var, + pub c: P::G1Var, } #[derive(Derivative)] -#[derivative(Clone( - bound = "P::G1Gadget: Clone, P::GTGadget: Clone, P::G1PreparedGadget: Clone, \ - P::G2PreparedGadget: Clone, " -))] -pub struct VerifyingKeyGadget< - PairingE: PairingEngine, - ConstraintF: Field, - P: PairingGadget<PairingE, ConstraintF>, -> { - pub h_g2: P::G2Gadget, - pub g_alpha_g1: P::G1Gadget, - pub h_beta_g2: P::G2Gadget, - pub g_gamma_g1: P::G1Gadget, - pub h_gamma_g2: P::G2Gadget, - pub query: Vec<P::G1Gadget>, +#[derivative( + Clone(bound = "P::G1Var: Clone, P::GTVar: Clone, P::G1PreparedVar: Clone, \ + P::G2PreparedVar: Clone, ") +)] +pub struct VerifyingKeyVar<E: PairingEngine, P: PairingVar<E>> { + pub h_g2: P::G2Var, + pub g_alpha_g1: P::G1Var, + pub h_beta_g2: P::G2Var, + pub g_gamma_g1: P::G1Var, + pub h_gamma_g2: P::G2Var, + pub query: Vec<P::G1Var>, } -impl<PairingE: PairingEngine, ConstraintF: Field, P: PairingGadget<PairingE, ConstraintF>> - VerifyingKeyGadget<PairingE, ConstraintF, P> -{ - pub fn prepare<CS: ConstraintSystem<ConstraintF>>( - &self, - mut cs: CS, - ) -> Result<PreparedVerifyingKeyGadget<PairingE, ConstraintF, P>, SynthesisError> { - let mut cs = cs.ns(|| "Preparing verifying key"); - let g_alpha_pc = P::prepare_g1(&mut cs.ns(|| "Prepare g_alpha_g1"), &self.g_alpha_g1)?; - let h_beta_pc = P::prepare_g2(&mut cs.ns(|| "Prepare h_beta_g2"), &self.h_beta_g2)?; - let g_gamma_pc = P::prepare_g1(&mut cs.ns(|| "Prepare g_gamma_pc"), &self.g_gamma_g1)?; - let h_gamma_pc = P::prepare_g2(&mut cs.ns(|| "Prepare h_gamma_pc"), &self.h_gamma_g2)?; - let h_pc = P::prepare_g2(&mut cs.ns(|| "Prepare h_pc"), &self.h_g2)?; - Ok(PreparedVerifyingKeyGadget { +impl<E: PairingEngine, P: PairingVar<E>> VerifyingKeyVar<E, P> { + pub fn prepare(&self) -> Result<PreparedVerifyingKeyVar<E, P>, SynthesisError> { + let g_alpha_pc = P::prepare_g1(&self.g_alpha_g1)?; + let h_beta_pc = P::prepare_g2(&self.h_beta_g2)?; + let g_gamma_pc = P::prepare_g1(&self.g_gamma_g1)?; + let h_gamma_pc = P::prepare_g2(&self.h_gamma_g2)?; + let h_pc = P::prepare_g2(&self.h_g2)?; + Ok(PreparedVerifyingKeyVar { g_alpha: self.g_alpha_g1.clone(), h_beta: self.h_beta_g2.clone(), g_alpha_pc,@@ -66,133 +52,180 @@ }
} #[derive(Derivative)] -#[derivative(Clone( - bound = "P::G1Gadget: Clone, P::GTGadget: Clone, P::G1PreparedGadget: Clone, \ - P::G2PreparedGadget: Clone, " -))] -pub struct PreparedVerifyingKeyGadget< - PairingE: PairingEngine, - ConstraintF: Field, - P: PairingGadget<PairingE, ConstraintF>, -> { - pub g_alpha: P::G1Gadget, - pub h_beta: P::G2Gadget, - pub g_alpha_pc: P::G1PreparedGadget, - pub h_beta_pc: P::G2PreparedGadget, - pub g_gamma_pc: P::G1PreparedGadget, - pub h_gamma_pc: P::G2PreparedGadget, - pub h_pc: P::G2PreparedGadget, - pub query: Vec<P::G1Gadget>, +#[derivative( + Clone(bound = "P::G1Var: Clone, P::GTVar: Clone, P::G1PreparedVar: Clone, \ + P::G2PreparedVar: Clone, ") +)] +pub struct PreparedVerifyingKeyVar<E: PairingEngine, P: PairingVar<E>> { + pub g_alpha: P::G1Var, + pub h_beta: P::G2Var, + pub g_alpha_pc: P::G1PreparedVar, + pub h_beta_pc: P::G2PreparedVar, + pub g_gamma_pc: P::G1PreparedVar, + pub h_gamma_pc: P::G2PreparedVar, + pub h_pc: P::G2PreparedVar, + pub query: Vec<P::G1Var>, } -pub struct Gm17VerifierGadget<PairingE, ConstraintF, P> +pub struct Gm17VerifierGadget<E, P> where - PairingE: PairingEngine, - ConstraintF: Field, - P: PairingGadget<PairingE, ConstraintF>, + E: PairingEngine, + P: PairingVar<E>, { - _pairing_engine: PhantomData<PairingE>, - _engine: PhantomData<ConstraintF>, + _pairing_engine: PhantomData<E>, _pairing_gadget: PhantomData<P>, } -impl<PairingE, ConstraintF, P, C, V> NIZKVerifierGadget<Gm17<PairingE, C, V>, ConstraintF> - for Gm17VerifierGadget<PairingE, ConstraintF, P> +impl<E, P, C, V> NIZKVerifierGadget<Gm17<E, C, V>, E::Fq> for Gm17VerifierGadget<E, P> where - PairingE: PairingEngine, - ConstraintF: Field, - C: ConstraintSynthesizer<PairingE::Fr>, - V: ToConstraintField<PairingE::Fr>, - P: PairingGadget<PairingE, ConstraintF>, + E: PairingEngine, + C: ConstraintSynthesizer<E::Fr>, + V: ToConstraintField<E::Fr>, + P: PairingVar<E>, { - type PreparedVerificationKeyGadget = PreparedVerifyingKeyGadget<PairingE, ConstraintF, P>; - type VerificationKeyGadget = VerifyingKeyGadget<PairingE, ConstraintF, P>; - type ProofGadget = ProofGadget<PairingE, ConstraintF, P>; + type PreparedVerificationKeyVar = PreparedVerifyingKeyVar<E, P>; + type VerificationKeyVar = VerifyingKeyVar<E, P>; + type ProofVar = ProofVar<E, P>; - fn check_verify<'a, CS, I, T>( - cs: CS, - vk: &Self::VerificationKeyGadget, - public_inputs: I, - proof: &Self::ProofGadget, - ) -> Result<(), SynthesisError> - where - CS: ConstraintSystem<ConstraintF>, - I: Iterator<Item = &'a T>, - T: 'a + ToBitsGadget<ConstraintF> + ?Sized, - { - <Self as NIZKVerifierGadget<Gm17<PairingE, C, V>, ConstraintF>>::conditional_check_verify( - cs, - vk, - public_inputs, - proof, - &Boolean::constant(true), - ) + /// Allocates `N::Proof` in `cs` without performing + /// subgroup checks. + fn new_proof_unchecked<T: Borrow<Proof<E>>>( + cs: impl Into<Namespace<E::Fq>>, + f: impl FnOnce() -> Result<T, SynthesisError>, + mode: AllocationMode, + ) -> Result<Self::ProofVar, SynthesisError> { + let ns = cs.into(); + let cs = ns.cs(); + f().and_then(|proof| { + let proof = proof.borrow(); + let a = CurveVar::new_variable_omit_prime_order_check( + cs.ns("Proof.a"), + || Ok(proof.a.into_projective()), + mode, + )?; + let b = CurveVar::new_variable_omit_prime_order_check( + cs.ns("Proof.b"), + || Ok(proof.b.into_projective()), + mode, + )?; + let c = CurveVar::new_variable_omit_prime_order_check( + cs.ns("Proof.c"), + || Ok(proof.c.into_projective()), + mode, + )?; + Ok(ProofVar { a, b, c }) + }) } - fn conditional_check_verify<'a, CS, I, T>( - mut cs: CS, - vk: &Self::VerificationKeyGadget, - public_inputs: I, - proof: &Self::ProofGadget, - condition: &Boolean, - ) -> Result<(), SynthesisError> - where - CS: ConstraintSystem<ConstraintF>, - I: Iterator<Item = &'a T>, - T: 'a + ToBitsGadget<ConstraintF> + ?Sized, - { - let pvk = vk.prepare(&mut cs.ns(|| "Prepare vk"))?; - <Self as NIZKVerifierGadget<Gm17<PairingE, C, V>, ConstraintF>>::conditional_check_verify_prepared(cs, &pvk, public_inputs, proof, condition) + /// Allocates `N::Proof` in `cs` without performing + /// subgroup checks. + fn new_verification_key_unchecked<T: Borrow<VerifyingKey<E>>>( + cs: impl Into<Namespace<E::Fq>>, + f: impl FnOnce() -> Result<T, SynthesisError>, + mode: AllocationMode, + ) -> Result<Self::VerificationKeyVar, SynthesisError> { + let ns = cs.into(); + let cs = ns.cs(); + f().and_then(|vk| { + let vk = vk.borrow(); + let g_alpha_g1 = P::G1Var::new_variable_omit_prime_order_check( + cs.ns("g_alpha"), + || Ok(vk.g_alpha_g1.into_projective()), + mode, + )?; + let h_g2 = P::G2Var::new_variable_omit_prime_order_check( + cs.ns("h"), + || Ok(vk.h_g2.into_projective()), + mode, + )?; + let h_beta_g2 = P::G2Var::new_variable_omit_prime_order_check( + cs.ns("h_beta"), + || Ok(vk.h_beta_g2.into_projective()), + mode, + )?; + let g_gamma_g1 = P::G1Var::new_variable_omit_prime_order_check( + cs.ns("g_gamma"), + || Ok(vk.g_gamma_g1.into_projective()), + mode, + )?; + let h_gamma_g2 = P::G2Var::new_variable_omit_prime_order_check( + cs.ns("h_gamma"), + || Ok(vk.h_gamma_g2.into_projective()), + mode, + )?; + + let query = vk + .query + .iter() + .map(|g| { + P::G1Var::new_variable_omit_prime_order_check( + cs.ns("g"), + || Ok(g.into_projective()), + mode, + ) + }) + .collect::<Result<Vec<_>, _>>()?; + Ok(VerifyingKeyVar { + g_alpha_g1, + h_g2, + h_beta_g2, + g_gamma_g1, + h_gamma_g2, + query, + }) + }) + } + + fn conditional_verify<'a, T: 'a + ToBitsGadget<E::Fq> + ?Sized>( + vk: &Self::VerificationKeyVar, + input: impl Iterator<Item = &'a T>, + proof: &Self::ProofVar, + condition: &Boolean<E::Fq>, + ) -> Result<(), SynthesisError> { + let pvk = vk.prepare()?; + <Self as NIZKVerifierGadget<Gm17<E, C, V>, E::Fq>>::conditional_verify_prepared( + &pvk, input, proof, condition, + ) } - fn conditional_check_verify_prepared<'a, CS, I, T>( - mut cs: CS, - pvk: &Self::PreparedVerificationKeyGadget, - mut public_inputs: I, - proof: &Self::ProofGadget, - condition: &Boolean, - ) -> Result<(), SynthesisError> - where - CS: ConstraintSystem<ConstraintF>, - I: Iterator<Item = &'a T>, - T: 'a + ToBitsGadget<ConstraintF> + ?Sized, - { + fn conditional_verify_prepared<'a, T: 'a + ToBitsGadget<E::Fq> + ?Sized>( + pvk: &Self::PreparedVerificationKeyVar, + mut input: impl Iterator<Item = &'a T>, + proof: &Self::ProofVar, + condition: &Boolean<E::Fq>, + ) -> Result<(), SynthesisError> { let pvk = pvk.clone(); // e(A*G^{alpha}, B*H^{beta}) = e(G^{alpha}, H^{beta}) * e(G^{psi}, H^{gamma}) * // e(C, H) where psi = \sum_{i=0}^l input_i pvk.query[i] let g_psi = { - let mut cs = cs.ns(|| "Process input"); let mut g_psi = pvk.query[0].clone(); let mut input_len = 1; - for (i, (input, b)) in public_inputs - .by_ref() - .zip(pvk.query.iter().skip(1)) - .enumerate() - { - let input_bits = input.to_bits(cs.ns(|| format!("Input {}", i)))?; - g_psi = b.mul_bits(cs.ns(|| format!("Mul {}", i)), &g_psi, input_bits.iter())?; + for (input, b) in input.by_ref().zip(pvk.query.iter().skip(1)) { + let input_bits = input.to_bits()?; + g_psi += b.mul_bits(input_bits.iter())?; input_len += 1; } // Check that the input and the query in the verification are of the // same length. - assert!(input_len == pvk.query.len() && public_inputs.next().is_none()); + assert!(input_len == pvk.query.len() && input.next().is_none()); g_psi }; - let mut test1_a_g_alpha = proof.a.add(cs.ns(|| "A * G^{alpha}"), &pvk.g_alpha)?; - let test1_b_h_beta = proof.b.add(cs.ns(|| "B * H^{beta}"), &pvk.h_beta)?; + let mut test1_a_g_alpha = proof.a.clone(); + test1_a_g_alpha += pvk.g_alpha.clone(); + let mut test1_b_h_beta = proof.b.clone(); + test1_b_h_beta += pvk.h_beta.clone(); let test1_exp = { - test1_a_g_alpha = test1_a_g_alpha.negate(cs.ns(|| "neg 1"))?; - let test1_a_g_alpha_prep = P::prepare_g1(cs.ns(|| "First prep"), &test1_a_g_alpha)?; - let test1_b_h_beta_prep = P::prepare_g2(cs.ns(|| "Second prep"), &test1_b_h_beta)?; + test1_a_g_alpha = test1_a_g_alpha.negate()?; + let test1_a_g_alpha_prep = P::prepare_g1(&test1_a_g_alpha)?; + let test1_b_h_beta_prep = P::prepare_g2(&test1_b_h_beta)?; - let g_psi_prep = P::prepare_g1(cs.ns(|| "Third prep"), &g_psi)?; + let g_psi_prep = P::prepare_g1(&g_psi)?; - let c_prep = P::prepare_g1(cs.ns(|| "Fourth prep"), &proof.c)?; + let c_prep = P::prepare_g1(&proof.c)?; P::miller_loop( - cs.ns(|| "Miller loop 1"), &[ test1_a_g_alpha_prep, g_psi_prep,@@ -208,318 +241,95 @@ ],
)? }; - let test1 = P::final_exponentiation(cs.ns(|| "Final Exp 1"), &test1_exp).unwrap(); + let test1 = P::final_exponentiation(&test1_exp).unwrap(); // e(A, H^{gamma}) = e(G^{gamma}, B) let test2_exp = { - let a_prep = P::prepare_g1(cs.ns(|| "Fifth prep"), &proof.a)?; + let a_prep = P::prepare_g1(&proof.a)?; // pvk.h_gamma_pc //&pvk.g_gamma_pc - let proof_b = proof.b.negate(cs.ns(|| "Negate b"))?; - let b_prep = P::prepare_g2(cs.ns(|| "Sixth prep"), &proof_b)?; - P::miller_loop( - cs.ns(|| "Miller loop 4"), - &[a_prep, pvk.g_gamma_pc.clone()], - &[pvk.h_gamma_pc, b_prep], - )? + let proof_b = proof.b.negate()?; + let b_prep = P::prepare_g2(&proof_b)?; + P::miller_loop(&[a_prep, pvk.g_gamma_pc.clone()], &[pvk.h_gamma_pc, b_prep])? }; - let test2 = P::final_exponentiation(cs.ns(|| "Final Exp 2"), &test2_exp)?; + let test2 = P::final_exponentiation(&test2_exp)?; - let one = P::GTGadget::one(cs.ns(|| "GT One"))?; - test1.conditional_enforce_equal(cs.ns(|| "Test 1"), &one, condition)?; - test2.conditional_enforce_equal(cs.ns(|| "Test 2"), &one, condition)?; + let one = P::GTVar::one(); + test1.conditional_enforce_equal(&one, condition)?; + test2.conditional_enforce_equal(&one, condition)?; Ok(()) } } -impl<PairingE, ConstraintF, P> AllocGadget<PreparedVerifyingKey<PairingE>, ConstraintF> - for PreparedVerifyingKeyGadget<PairingE, ConstraintF, P> -where - PairingE: PairingEngine, - ConstraintF: Field, - P: PairingGadget<PairingE, ConstraintF>, - P::G1PreparedGadget: AllocGadget<PairingE::G1Prepared, ConstraintF>, - P::G2PreparedGadget: AllocGadget<PairingE::G2Prepared, ConstraintF>, -{ - #[inline] - fn alloc_constant<T, CS: ConstraintSystem<ConstraintF>>( - mut cs: CS, - val: T, - ) -> Result<Self, SynthesisError> - where - T: Borrow<PreparedVerifyingKey<PairingE>>, - { - let pvk = val.borrow().clone(); - - let g_alpha = - P::G1Gadget::alloc_constant(cs.ns(|| "g_alpha"), pvk.g_alpha.into_projective())?; - let h_beta = P::G2Gadget::alloc_constant(cs.ns(|| "h_beta"), pvk.h_beta.into_projective())?; - let g_alpha_pc = - P::G1PreparedGadget::alloc_constant(cs.ns(|| "g_alpha_pc"), pvk.g_alpha.into())?; - let h_beta_pc = - P::G2PreparedGadget::alloc_constant(cs.ns(|| "h_beta_pc"), pvk.h_beta.into())?; - let g_gamma_pc = - P::G1PreparedGadget::alloc_constant(cs.ns(|| "g_gamma_pc"), pvk.g_gamma_pc)?; - let h_gamma_pc = - P::G2PreparedGadget::alloc_constant(cs.ns(|| "h_gamma_pc"), pvk.h_gamma_pc)?; - let h_pc = P::G2PreparedGadget::alloc_constant(cs.ns(|| "h_pc"), pvk.h_pc)?; - - let mut query = Vec::<P::G1Gadget>::new(); - for (i, item) in pvk.query.iter().enumerate() { - query.push(P::G1Gadget::alloc_constant( - &mut cs.ns(|| format!("query_{}", i)), - item.borrow().into_projective(), - )?); - } - - Ok(Self { - g_alpha, - h_beta, - g_alpha_pc, - h_beta_pc, - g_gamma_pc, - h_gamma_pc, - h_pc, - query, - }) - } - - #[inline] - fn alloc<FN, T, CS: ConstraintSystem<ConstraintF>>( - mut cs: CS, - value_gen: FN, - ) -> Result<Self, SynthesisError> - where - FN: FnOnce() -> Result<T, SynthesisError>, - T: Borrow<PreparedVerifyingKey<PairingE>>, - { - let pvk = value_gen()?.borrow().clone(); - - let g_alpha = - P::G1Gadget::alloc(cs.ns(|| "g_alpha"), || Ok(pvk.g_alpha.into_projective()))?; - let h_beta = P::G2Gadget::alloc(cs.ns(|| "h_beta"), || Ok(pvk.h_beta.into_projective()))?; - let g_alpha_pc = - P::G1PreparedGadget::alloc(cs.ns(|| "g_alpha_pc"), || Ok(pvk.g_alpha.into()))?; - let h_beta_pc = - P::G2PreparedGadget::alloc(cs.ns(|| "h_beta_pc"), || Ok(pvk.h_beta.into()))?; - let g_gamma_pc = - P::G1PreparedGadget::alloc(cs.ns(|| "g_gamma_pc"), || Ok(&pvk.g_gamma_pc))?; - let h_gamma_pc = - P::G2PreparedGadget::alloc(cs.ns(|| "h_gamma_pc"), || Ok(&pvk.h_gamma_pc))?; - let h_pc = P::G2PreparedGadget::alloc(cs.ns(|| "h_pc"), || Ok(&pvk.h_pc))?; - - let mut query = Vec::<P::G1Gadget>::new(); - for (i, item) in pvk.query.iter().enumerate() { - query.push(P::G1Gadget::alloc( - cs.ns(|| format!("query_{}", i)), - || Ok(item.borrow().into_projective()), - )?); - } - - Ok(Self { - g_alpha, - h_beta, - g_alpha_pc, - h_beta_pc, - g_gamma_pc, - h_gamma_pc, - h_pc, - query, - }) - } - - #[inline] - fn alloc_input<FN, T, CS: ConstraintSystem<ConstraintF>>( - mut cs: CS, - value_gen: FN, - ) -> Result<Self, SynthesisError> - where - FN: FnOnce() -> Result<T, SynthesisError>, - T: Borrow<PreparedVerifyingKey<PairingE>>, - { - let pvk = value_gen()?.borrow().clone(); - - let g_alpha = - P::G1Gadget::alloc_input(cs.ns(|| "g_alpha"), || Ok(pvk.g_alpha.into_projective()))?; - let h_beta = - P::G2Gadget::alloc_input(cs.ns(|| "h_beta"), || Ok(pvk.h_beta.into_projective()))?; - let g_alpha_pc = - P::G1PreparedGadget::alloc_input(cs.ns(|| "g_alpha_pc"), || Ok(pvk.g_alpha.into()))?; - let h_beta_pc = - P::G2PreparedGadget::alloc_input(cs.ns(|| "h_beta_pc"), || Ok(pvk.h_beta.into()))?; - let g_gamma_pc = - P::G1PreparedGadget::alloc_input(cs.ns(|| "g_gamma_pc"), || Ok(&pvk.g_gamma_pc))?; - let h_gamma_pc = - P::G2PreparedGadget::alloc_input(cs.ns(|| "h_gamma_pc"), || Ok(&pvk.h_gamma_pc))?; - let h_pc = P::G2PreparedGadget::alloc_input(cs.ns(|| "h_pc"), || Ok(&pvk.h_pc))?; - - let mut query = Vec::<P::G1Gadget>::new(); - for (i, item) in pvk.query.iter().enumerate() { - query.push(P::G1Gadget::alloc_input( - &mut cs.ns(|| format!("query_{}", i)), - || Ok(item.borrow().into_projective()), - )?); - } - - Ok(Self { - g_alpha, - h_beta, - g_alpha_pc, - h_beta_pc, - g_gamma_pc, - h_gamma_pc, - h_pc, - query, - }) - } -} - -impl<PairingE, ConstraintF, P> AllocGadget<VerifyingKey<PairingE>, ConstraintF> - for VerifyingKeyGadget<PairingE, ConstraintF, P> +impl<E, P> AllocVar<PreparedVerifyingKey<E>, E::Fq> for PreparedVerifyingKeyVar<E, P> where - PairingE: PairingEngine, - ConstraintF: Field, - P: PairingGadget<PairingE, ConstraintF>, + E: PairingEngine, + P: PairingVar<E>, + P::G1PreparedVar: AllocVar<E::G1Prepared, E::Fq>, + P::G2PreparedVar: AllocVar<E::G2Prepared, E::Fq>, { - #[inline] - fn alloc_constant<T, CS: ConstraintSystem<ConstraintF>>( - mut cs: CS, - val: T, - ) -> Result<Self, SynthesisError> - where - T: Borrow<VerifyingKey<PairingE>>, - { - let VerifyingKey { - h_g2, - g_alpha_g1, - h_beta_g2, - g_gamma_g1, - h_gamma_g2, - query, - } = val.borrow().clone(); - let h_g2 = P::G2Gadget::alloc_constant(cs.ns(|| "h_g2"), h_g2.into_projective())?; - let g_alpha_g1 = - P::G1Gadget::alloc_constant(cs.ns(|| "g_alpha"), g_alpha_g1.into_projective())?; - let h_beta_g2 = - P::G2Gadget::alloc_constant(cs.ns(|| "h_beta"), h_beta_g2.into_projective())?; - let g_gamma_g1 = - P::G1Gadget::alloc_constant(cs.ns(|| "g_gamma_g1"), g_gamma_g1.into_projective())?; - let h_gamma_g2 = - P::G2Gadget::alloc_constant(cs.ns(|| "h_gamma_g2"), h_gamma_g2.into_projective())?; + fn new_variable<T: Borrow<PreparedVerifyingKey<E>>>( + cs: impl Into<Namespace<E::Fq>>, + f: impl FnOnce() -> Result<T, SynthesisError>, + mode: AllocationMode, + ) -> Result<Self, SynthesisError> { + let ns = cs.into(); + let cs = ns.cs(); - let query = query - .into_iter() - .enumerate() - .map(|(i, query_i)| { - P::G1Gadget::alloc_constant( - cs.ns(|| format!("query_{}", i)), - query_i.into_projective(), - ) - }) - .collect::<Vec<_>>() - .into_iter() - .collect::<Result<_, _>>()?; - Ok(Self { - h_g2, - g_alpha_g1, - h_beta_g2, - g_gamma_g1, - h_gamma_g2, - query, - }) - } + f().and_then(|pvk| { + let pvk = pvk.borrow(); + let g_alpha = P::G1Var::new_variable(cs.ns("g_alpha"), || Ok(pvk.g_alpha), mode)?; + let h_beta = P::G2Var::new_variable(cs.ns("h_beta"), || Ok(pvk.h_beta), mode)?; + let g_alpha_pc = P::G1PreparedVar::new_variable( + cs.ns("g_alpha_pc"), + || Ok(pvk.g_alpha.into()), + mode, + )?; + let h_beta_pc = + P::G2PreparedVar::new_variable(cs.ns("h_beta_pc"), || Ok(pvk.h_beta.into()), mode)?; + let g_gamma_pc = + P::G1PreparedVar::new_variable(cs.ns("g_gamma_pc"), || Ok(&pvk.g_gamma_pc), mode)?; + let h_gamma_pc = + P::G2PreparedVar::new_variable(cs.ns("h_gamma_pc"), || Ok(&pvk.h_gamma_pc), mode)?; + let h_pc = P::G2PreparedVar::new_variable(cs.ns("h_pc"), || Ok(&pvk.h_pc), mode)?; + let query = Vec::new_variable(cs.ns("query"), || Ok(pvk.query.clone()), mode)?; - #[inline] - fn alloc<FN, T, CS: ConstraintSystem<ConstraintF>>( - mut cs: CS, - value_gen: FN, - ) -> Result<Self, SynthesisError> - where - FN: FnOnce() -> Result<T, SynthesisError>, - T: Borrow<VerifyingKey<PairingE>>, - { - value_gen().and_then(|vk| { - let VerifyingKey { - h_g2, - g_alpha_g1, - h_beta_g2, - g_gamma_g1, - h_gamma_g2, - query, - } = vk.borrow().clone(); - let h_g2 = P::G2Gadget::alloc(cs.ns(|| "h_g2"), || Ok(h_g2.into_projective()))?; - let g_alpha_g1 = - P::G1Gadget::alloc(cs.ns(|| "g_alpha"), || Ok(g_alpha_g1.into_projective()))?; - let h_beta_g2 = - P::G2Gadget::alloc(cs.ns(|| "h_beta"), || Ok(h_beta_g2.into_projective()))?; - let g_gamma_g1 = - P::G1Gadget::alloc(cs.ns(|| "g_gamma_g1"), || Ok(g_gamma_g1.into_projective()))?; - let h_gamma_g2 = - P::G2Gadget::alloc(cs.ns(|| "h_gamma_g2"), || Ok(h_gamma_g2.into_projective()))?; - - let query = query - .into_iter() - .enumerate() - .map(|(i, query_i)| { - P::G1Gadget::alloc(cs.ns(|| format!("query_{}", i)), || { - Ok(query_i.into_projective()) - }) - }) - .collect::<Vec<_>>() - .into_iter() - .collect::<Result<_, _>>()?; Ok(Self { - h_g2, - g_alpha_g1, - h_beta_g2, - g_gamma_g1, - h_gamma_g2, + g_alpha, + h_beta, + g_alpha_pc, + h_beta_pc, + g_gamma_pc, + h_gamma_pc, + h_pc, query, }) }) } +} - #[inline] - fn alloc_input<FN, T, CS: ConstraintSystem<ConstraintF>>( - mut cs: CS, - value_gen: FN, - ) -> Result<Self, SynthesisError> - where - FN: FnOnce() -> Result<T, SynthesisError>, - T: Borrow<VerifyingKey<PairingE>>, - { - value_gen().and_then(|vk| { - let VerifyingKey { - h_g2, - g_alpha_g1, - h_beta_g2, - g_gamma_g1, - h_gamma_g2, - query, - } = vk.borrow().clone(); - let h_g2 = P::G2Gadget::alloc_input(cs.ns(|| "h_g2"), || Ok(h_g2.into_projective()))?; - let g_alpha_g1 = - P::G1Gadget::alloc_input(cs.ns(|| "g_alpha"), || Ok(g_alpha_g1.into_projective()))?; - let h_beta_g2 = - P::G2Gadget::alloc_input(cs.ns(|| "h_beta"), || Ok(h_beta_g2.into_projective()))?; - let g_gamma_g1 = P::G1Gadget::alloc_input(cs.ns(|| "g_gamma_g1"), || { - Ok(g_gamma_g1.into_projective()) - })?; - let h_gamma_g2 = P::G2Gadget::alloc_input(cs.ns(|| "h_gamma_g2"), || { - Ok(h_gamma_g2.into_projective()) - })?; +impl<E, P> AllocVar<VerifyingKey<E>, E::Fq> for VerifyingKeyVar<E, P> +where + E: PairingEngine, - let query = query - .into_iter() - .enumerate() - .map(|(i, query_i)| { - P::G1Gadget::alloc_input(cs.ns(|| format!("query_{}", i)), || { - Ok(query_i.into_projective()) - }) - }) - .collect::<Vec<_>>() - .into_iter() - .collect::<Result<_, _>>()?; + P: PairingVar<E>, +{ + fn new_variable<T: Borrow<VerifyingKey<E>>>( + cs: impl Into<Namespace<E::Fq>>, + f: impl FnOnce() -> Result<T, SynthesisError>, + mode: AllocationMode, + ) -> Result<Self, SynthesisError> { + let ns = cs.into(); + let cs = ns.cs(); + + f().and_then(|vk| { + let vk = vk.borrow(); + let g_alpha_g1 = P::G1Var::new_variable(cs.ns("g_alpha"), || Ok(vk.g_alpha_g1), mode)?; + let h_g2 = P::G2Var::new_variable(cs.ns("h"), || Ok(vk.h_g2), mode)?; + let h_beta_g2 = P::G2Var::new_variable(cs.ns("h_beta"), || Ok(vk.h_beta_g2), mode)?; + let g_gamma_g1 = P::G1Var::new_variable(cs.ns("g_gamma"), || Ok(&vk.g_gamma_g1), mode)?; + let h_gamma_g2 = P::G2Var::new_variable(cs.ns("h_gamma"), || Ok(&vk.h_gamma_g2), mode)?; + let query = Vec::new_variable(cs.ns("query"), || Ok(vk.query.clone()), mode)?; Ok(Self { h_g2, g_alpha_g1,@@ -532,104 +342,47 @@ })
} } -impl<PairingE, ConstraintF, P> AllocGadget<Proof<PairingE>, ConstraintF> - for ProofGadget<PairingE, ConstraintF, P> +impl<E, P> AllocVar<Proof<E>, E::Fq> for ProofVar<E, P> where - PairingE: PairingEngine, - ConstraintF: Field, - P: PairingGadget<PairingE, ConstraintF>, + E: PairingEngine, + + P: PairingVar<E>, { #[inline] - fn alloc_constant<T, CS: ConstraintSystem<ConstraintF>>( - mut cs: CS, - val: T, - ) -> Result<Self, SynthesisError> - where - T: Borrow<Proof<PairingE>>, - { - let Proof { a, b, c } = val.borrow().clone(); - let a = P::G1Gadget::alloc_constant(cs.ns(|| "a"), a.into_projective())?; - let b = P::G2Gadget::alloc_constant(cs.ns(|| "b"), b.into_projective())?; - let c = P::G1Gadget::alloc_constant(cs.ns(|| "c"), c.into_projective())?; - Ok(Self { a, b, c }) - } + fn new_variable<T: Borrow<Proof<E>>>( + cs: impl Into<Namespace<E::Fq>>, + f: impl FnOnce() -> Result<T, SynthesisError>, + mode: AllocationMode, + ) -> Result<Self, SynthesisError> { + let ns = cs.into(); + let cs = ns.cs(); - #[inline] - fn alloc<FN, T, CS: ConstraintSystem<ConstraintF>>( - mut cs: CS, - value_gen: FN, - ) -> Result<Self, SynthesisError> - where - FN: FnOnce() -> Result<T, SynthesisError>, - T: Borrow<Proof<PairingE>>, - { - value_gen().and_then(|proof| { + f().and_then(|proof| { let Proof { a, b, c } = proof.borrow().clone(); - let a = P::G1Gadget::alloc_checked(cs.ns(|| "a"), || Ok(a.into_projective()))?; - let b = P::G2Gadget::alloc_checked(cs.ns(|| "b"), || Ok(b.into_projective()))?; - let c = P::G1Gadget::alloc_checked(cs.ns(|| "c"), || Ok(c.into_projective()))?; - Ok(Self { a, b, c }) - }) - } - - #[inline] - fn alloc_input<FN, T, CS: ConstraintSystem<ConstraintF>>( - mut cs: CS, - value_gen: FN, - ) -> Result<Self, SynthesisError> - where - FN: FnOnce() -> Result<T, SynthesisError>, - T: Borrow<Proof<PairingE>>, - { - value_gen().and_then(|proof| { - let Proof { a, b, c } = proof.borrow().clone(); - // We don't need to check here because the prime order check can be performed - // in plain. - let a = P::G1Gadget::alloc_input(cs.ns(|| "a"), || Ok(a.into_projective()))?; - let b = P::G2Gadget::alloc_input(cs.ns(|| "b"), || Ok(b.into_projective()))?; - let c = P::G1Gadget::alloc_input(cs.ns(|| "c"), || Ok(c.into_projective()))?; + let a = P::G1Var::new_variable(cs.ns("a"), || Ok(a), mode)?; + let b = P::G2Var::new_variable(cs.ns("b"), || Ok(b), mode)?; + let c = P::G1Var::new_variable(cs.ns("c"), || Ok(c), mode)?; Ok(Self { a, b, c }) }) } } -impl<PairingE, ConstraintF, P> ToBytesGadget<ConstraintF> - for VerifyingKeyGadget<PairingE, ConstraintF, P> +impl<E, P> ToBytesGadget<E::Fq> for VerifyingKeyVar<E, P> where - PairingE: PairingEngine, - ConstraintF: Field, - P: PairingGadget<PairingE, ConstraintF>, + E: PairingEngine, + + P: PairingVar<E>, { #[inline] - fn to_bytes<CS: ConstraintSystem<ConstraintF>>( - &self, - mut cs: CS, - ) -> Result<Vec<UInt8>, SynthesisError> { + fn to_bytes(&self) -> Result<Vec<UInt8<E::Fq>>, SynthesisError> { let mut bytes = Vec::new(); - bytes.extend_from_slice(&self.h_g2.to_bytes(&mut cs.ns(|| "h_g2 to bytes"))?); - bytes.extend_from_slice( - &self - .g_alpha_g1 - .to_bytes(&mut cs.ns(|| "g_alpha_g1 to bytes"))?, - ); - bytes.extend_from_slice( - &self - .h_beta_g2 - .to_bytes(&mut cs.ns(|| "h_beta_g2 to bytes"))?, - ); - bytes.extend_from_slice( - &self - .g_gamma_g1 - .to_bytes(&mut cs.ns(|| "g_gamma_g1 to bytes"))?, - ); - bytes.extend_from_slice( - &self - .h_gamma_g2 - .to_bytes(&mut cs.ns(|| "h_gamma_g2 to bytes"))?, - ); - for (i, q) in self.query.iter().enumerate() { - let mut cs = cs.ns(|| format!("Iteration {}", i)); - bytes.extend_from_slice(&q.to_bytes(&mut cs.ns(|| "q"))?); + bytes.extend_from_slice(&self.h_g2.to_bytes()?); + bytes.extend_from_slice(&self.g_alpha_g1.to_bytes()?); + bytes.extend_from_slice(&self.h_beta_g2.to_bytes()?); + bytes.extend_from_slice(&self.g_gamma_g1.to_bytes()?); + bytes.extend_from_slice(&self.h_gamma_g2.to_bytes()?); + for q in &self.query { + bytes.extend_from_slice(&q.to_bytes()?); } Ok(bytes) }@@ -638,23 +391,22 @@
#[cfg(test)] mod test { use gm17::*; - use r1cs_core::{ConstraintSynthesizer, ConstraintSystem, SynthesisError}; + use r1cs_core::{ + lc, ConstraintSynthesizer, ConstraintSystem, ConstraintSystemRef, SynthesisError, + }; use super::*; use algebra::{ bls12_377::{Bls12_377, Fq, Fr}, - test_rng, BitIterator, PrimeField, - }; - use r1cs_std::{ - bls12_377::PairingGadget as Bls12_377PairingGadget, boolean::Boolean, - test_constraint_system::TestConstraintSystem, + test_rng, BitIterator, Field, PrimeField, }; + use r1cs_std::{bls12_377::PairingVar as Bls12_377PairingVar, boolean::Boolean, Assignment}; use rand::Rng; type TestProofSystem = Gm17<Bls12_377, Bench<Fr>, Fr>; - type TestVerifierGadget = Gm17VerifierGadget<Bls12_377, Fq, Bls12_377PairingGadget>; - type TestProofGadget = ProofGadget<Bls12_377, Fq, Bls12_377PairingGadget>; - type TestVkGadget = VerifyingKeyGadget<Bls12_377, Fq, Bls12_377PairingGadget>; + type TestVerifierGadget = Gm17VerifierGadget<Bls12_377, Bls12_377PairingVar>; + type TestProofVar = ProofVar<Bls12_377, Bls12_377PairingVar>; + type TestVkVar = VerifyingKeyVar<Bls12_377, Bls12_377PairingVar>; struct Bench<F: Field> { inputs: Vec<Option<F>>,@@ -662,19 +414,13 @@ num_constraints: usize,
} impl<F: Field> ConstraintSynthesizer<F> for Bench<F> { - fn generate_constraints<CS: ConstraintSystem<F>>( - self, - cs: &mut CS, - ) -> Result<(), SynthesisError> { + fn generate_constraints(self, cs: ConstraintSystemRef<F>) -> Result<(), SynthesisError> { assert!(self.inputs.len() >= 2); assert!(self.num_constraints >= self.inputs.len()); let mut variables: Vec<_> = Vec::with_capacity(self.inputs.len()); - for (i, input) in self.inputs.into_iter().enumerate() { - let input_var = cs.alloc_input( - || format!("Input {}", i), - || input.ok_or(SynthesisError::AssignmentMissing), - )?; + for input in self.inputs { + let input_var = cs.new_input_variable(|| input.get())?; variables.push((input, input_var)); }@@ -684,16 +430,16 @@ let (input_1_val, input_1_var) = variables[i];
let (input_2_val, input_2_var) = variables[i + 1]; let result_val = input_1_val .and_then(|input_1| input_2_val.map(|input_2| input_1 * &input_2)); - let result_var = cs.alloc( - || format!("Result {}", i), - || result_val.ok_or(SynthesisError::AssignmentMissing), - )?; - cs.enforce( - || format!("Enforce constraint {}", i), - |lc| lc + input_1_var, - |lc| lc + input_2_var, - |lc| lc + result_var, - ); + let result_var = cs.new_witness_variable(|| { + result_val.ok_or(SynthesisError::AssignmentMissing) + })?; + cs.enforce_named_constraint( + format!("Enforce constraint {}", i), + lc!() + input_1_var, + lc!() + input_2_var, + lc!() + result_var, + ) + .unwrap(); (result_val, result_var) }; variables.push(new_entry);@@ -733,20 +479,19 @@ create_random_proof(c, ¶ms, rng).unwrap()
}; // assert!(!verify_proof(&pvk, &proof, &[a]).unwrap()); - let mut cs = TestConstraintSystem::<Fq>::new(); + let cs = ConstraintSystem::<Fq>::new_ref(); let inputs: Vec<_> = inputs.into_iter().map(|input| input.unwrap()).collect(); let mut input_gadgets = Vec::new(); { - let mut cs = cs.ns(|| "Allocate Input"); for (i, input) in inputs.into_iter().enumerate() { let mut input_bits = BitIterator::new(input.into_repr()).collect::<Vec<_>>(); // Input must be in little-endian, but BitIterator outputs in big-endian. input_bits.reverse(); let input_bits = - Vec::<Boolean>::alloc_input(cs.ns(|| format!("Input {}", i)), || { + Vec::<Boolean<Fq>>::new_input(cs.ns(format!("Input {}", i)), || { Ok(input_bits) }) .unwrap();@@ -754,18 +499,17 @@ input_gadgets.push(input_bits);
} } - let vk_gadget = TestVkGadget::alloc_input(cs.ns(|| "Vk"), || Ok(¶ms.vk)).unwrap(); + let vk_gadget = TestVkVar::new_input(cs.ns("Vk"), || Ok(¶ms.vk)).unwrap(); let proof_gadget = - TestProofGadget::alloc(cs.ns(|| "Proof"), || Ok(proof.clone())).unwrap(); + TestProofVar::new_witness(cs.ns("Proof"), || Ok(proof.clone())).unwrap(); println!("Time to verify!\n\n\n\n"); - <TestVerifierGadget as NIZKVerifierGadget<TestProofSystem, Fq>>::check_verify( - cs.ns(|| "Verify"), + <TestVerifierGadget as NIZKVerifierGadget<TestProofSystem, Fq>>::verify( &vk_gadget, input_gadgets.iter(), &proof_gadget, ) .unwrap(); - if !cs.is_satisfied() { + if !cs.is_satisfied().unwrap() { println!("========================================================="); println!("Unsatisfied constraints:"); println!("{:?}", cs.which_is_unsatisfied().unwrap());@@ -773,7 +517,7 @@ println!("=========================================================");
} // cs.print_named_objects(); - assert!(cs.is_satisfied()); + assert!(cs.is_satisfied().unwrap()); } } }@@ -781,31 +525,32 @@
#[cfg(test)] mod test_recursive { use gm17::*; - use r1cs_core::{ConstraintSynthesizer, ConstraintSystem, SynthesisError}; + use r1cs_core::{ + lc, ConstraintSynthesizer, ConstraintSystem, ConstraintSystemRef, SynthesisError, + }; use super::*; use algebra::{ fields::{FftParameters, FpParameters}, mnt4_298::{Fq as MNT4Fq, FqParameters as MNT4FqParameters, Fr as MNT4Fr, MNT4_298}, mnt6_298::{Fq as MNT6Fq, FqParameters as MNT6FqParameters, Fr as MNT6Fr, MNT6_298}, - test_rng, BigInteger, PrimeField, + test_rng, BigInteger, Field, PrimeField, }; use r1cs_std::{ - fields::fp::FpGadget, mnt4_298::PairingGadget as MNT4_298PairingGadget, - mnt6_298::PairingGadget as MNT6_298PairingGadget, - test_constraint_system::TestConstraintSystem, uint8::UInt8, + fields::fp::FpVar, mnt4_298::PairingVar as MNT4_298PairingVar, + mnt6_298::PairingVar as MNT6_298PairingVar, uint8::UInt8, Assignment, }; use rand::Rng; type TestProofSystem1 = Gm17<MNT6_298, Bench<MNT4Fq>, MNT6Fr>; - type TestVerifierGadget1 = Gm17VerifierGadget<MNT6_298, MNT6Fq, MNT6_298PairingGadget>; - type TestProofGadget1 = ProofGadget<MNT6_298, MNT6Fq, MNT6_298PairingGadget>; - type TestVkGadget1 = VerifyingKeyGadget<MNT6_298, MNT6Fq, MNT6_298PairingGadget>; + type TestVerifierGadget1 = Gm17VerifierGadget<MNT6_298, MNT6_298PairingVar>; + type TestProofVar1 = ProofVar<MNT6_298, MNT6_298PairingVar>; + type TestVkVar1 = VerifyingKeyVar<MNT6_298, MNT6_298PairingVar>; type TestProofSystem2 = Gm17<MNT4_298, Wrapper, MNT4Fr>; - type TestVerifierGadget2 = Gm17VerifierGadget<MNT4_298, MNT4Fq, MNT4_298PairingGadget>; - type TestProofGadget2 = ProofGadget<MNT4_298, MNT4Fq, MNT4_298PairingGadget>; - type TestVkGadget2 = VerifyingKeyGadget<MNT4_298, MNT4Fq, MNT4_298PairingGadget>; + type TestVerifierGadget2 = Gm17VerifierGadget<MNT4_298, MNT4_298PairingVar>; + type TestProofVar2 = ProofVar<MNT4_298, MNT4_298PairingVar>; + type TestVkVar2 = VerifyingKeyVar<MNT4_298, MNT4_298PairingVar>; #[derive(Clone)] struct Bench<F: Field> {@@ -814,19 +559,13 @@ num_constraints: usize,
} impl<F: Field> ConstraintSynthesizer<F> for Bench<F> { - fn generate_constraints<CS: ConstraintSystem<F>>( - self, - cs: &mut CS, - ) -> Result<(), SynthesisError> { + fn generate_constraints(self, cs: ConstraintSystemRef<F>) -> Result<(), SynthesisError> { assert!(self.inputs.len() >= 2); assert!(self.num_constraints >= self.inputs.len()); let mut variables: Vec<_> = Vec::with_capacity(self.inputs.len()); - for (i, input) in self.inputs.into_iter().enumerate() { - let input_var = cs.alloc_input( - || format!("Input {}", i), - || input.ok_or(SynthesisError::AssignmentMissing), - )?; + for input in self.inputs { + let input_var = cs.new_input_variable(|| input.get())?; variables.push((input, input_var)); }@@ -836,16 +575,16 @@ let (input_1_val, input_1_var) = variables[i];
let (input_2_val, input_2_var) = variables[i + 1]; let result_val = input_1_val .and_then(|input_1| input_2_val.map(|input_2| input_1 * &input_2)); - let result_var = cs.alloc( - || format!("Result {}", i), - || result_val.ok_or(SynthesisError::AssignmentMissing), - )?; - cs.enforce( - || format!("Enforce constraint {}", i), - |lc| lc + input_1_var, - |lc| lc + input_2_var, - |lc| lc + result_var, - ); + let result_var = cs.new_witness_variable(|| { + result_val.ok_or(SynthesisError::AssignmentMissing) + })?; + cs.enforce_named_constraint( + format!("Enforce constraint {}", i), + lc!() + input_1_var, + lc!() + input_2_var, + lc!() + result_var, + ) + .unwrap(); (result_val, result_var) }; variables.push(new_entry);@@ -861,9 +600,9 @@ proof: Proof<MNT6_298>,
} impl ConstraintSynthesizer<MNT6Fq> for Wrapper { - fn generate_constraints<CS: ConstraintSystem<MNT6Fq>>( + fn generate_constraints( self, - cs: &mut CS, + cs: ConstraintSystemRef<MNT6Fq>, ) -> Result<(), SynthesisError> { let params = self.params; let proof = self.proof;@@ -875,7 +614,6 @@ .collect();
let input_gadgets; { - let mut cs = cs.ns(|| "Allocate Input"); // Chain all input values in one large byte array. let input_bytes = inputs .clone()@@ -891,7 +629,7 @@ })
.collect::<Vec<_>>(); // Allocate this byte array as input packed into field elements. - let input_bytes = UInt8::alloc_input_vec(cs.ns(|| "Input"), &input_bytes[..])?; + let input_bytes = UInt8::new_input_vec(cs.ns("Input"), &input_bytes[..])?; // 40 byte let element_size = <MNT4FqParameters as FftParameters>::BigInt::NUM_LIMBS * 8; input_gadgets = input_bytes@@ -905,11 +643,10 @@ })
.collect::<Vec<_>>(); } - let vk_gadget = TestVkGadget1::alloc(cs.ns(|| "Vk"), || Ok(¶ms.vk))?; + let vk_gadget = TestVkVar1::new_witness(cs.ns("Vk"), || Ok(¶ms.vk))?; let proof_gadget = - TestProofGadget1::alloc(cs.ns(|| "Proof"), || Ok(proof.clone())).unwrap(); - <TestVerifierGadget1 as NIZKVerifierGadget<TestProofSystem1, MNT6Fq>>::check_verify( - cs.ns(|| "Verify"), + TestProofVar1::new_witness(cs.ns("Proof"), || Ok(proof.clone())).unwrap(); + <TestVerifierGadget1 as NIZKVerifierGadget<TestProofSystem1, MNT6Fq>>::verify( &vk_gadget, input_gadgets.iter(), &proof_gadget,@@ -945,7 +682,7 @@ let c = Bench {
inputs: inputs.clone(), num_constraints, }; - // Create a groth16 proof with our parameters. + // Create a gm17 proof with our parameters. create_random_proof(c, &inner_params, rng).unwrap() };@@ -969,11 +706,11 @@ inputs: inputs.clone(),
params: inner_params.clone(), proof: inner_proof.clone(), }; - // Create a groth16 proof with our parameters. + // Create a gm17 proof with our parameters. create_random_proof(c, ¶ms, rng).unwrap() }; - let mut cs = TestConstraintSystem::<MNT4Fq>::new(); + let cs = ConstraintSystem::<MNT4Fq>::new_ref(); let inputs: Vec<_> = inputs.into_iter().map(|input| input.unwrap()).collect(); let mut input_gadgets = Vec::new();@@ -981,16 +718,12 @@
{ let bigint_size = <MNT4FqParameters as FftParameters>::BigInt::NUM_LIMBS * 64; let mut input_bits = Vec::new(); - let mut cs = cs.ns(|| "Allocate Input"); for (i, input) in inputs.into_iter().enumerate() { let input_gadget = - FpGadget::alloc_input(cs.ns(|| format!("Input {}", i)), || Ok(input)) - .unwrap(); - let mut fp_bits = input_gadget - .to_bits(cs.ns(|| format!("To bits {}", i))) - .unwrap(); + FpVar::new_input(cs.ns(format!("Input {}", i)), || Ok(input)).unwrap(); + let mut fp_bits = input_gadget.to_bits().unwrap(); - // FpGadget::to_bits outputs a big-endian binary representation of + // FpVar::to_bits outputs a big-endian binary representation of // fe_gadget's value, so we have to reverse it to get the little-endian // form. fp_bits.reverse();@@ -1017,18 +750,17 @@ }
// assert!(!verify_proof(&pvk, &proof, &[a]).unwrap()); } - let vk_gadget = TestVkGadget2::alloc_input(cs.ns(|| "Vk"), || Ok(¶ms.vk)).unwrap(); + let vk_gadget = TestVkVar2::new_input(cs.ns("Vk"), || Ok(¶ms.vk)).unwrap(); let proof_gadget = - TestProofGadget2::alloc(cs.ns(|| "Proof"), || Ok(proof.clone())).unwrap(); + TestProofVar2::new_witness(cs.ns("Proof"), || Ok(proof.clone())).unwrap(); println!("Time to verify!\n\n\n\n"); - <TestVerifierGadget2 as NIZKVerifierGadget<TestProofSystem2, MNT4Fq>>::check_verify( - cs.ns(|| "Verify"), + <TestVerifierGadget2 as NIZKVerifierGadget<TestProofSystem2, MNT4Fq>>::verify( &vk_gadget, input_gadgets.iter(), &proof_gadget, ) .unwrap(); - if !cs.is_satisfied() { + if !cs.is_satisfied().unwrap() { println!("========================================================="); println!("Unsatisfied constraints:"); println!("{:?}", cs.which_is_unsatisfied().unwrap());@@ -1036,7 +768,7 @@ println!("=========================================================");
} // cs.print_named_objects(); - assert!(cs.is_satisfied()); + assert!(cs.is_satisfied().unwrap()); } } }
@@ -2,66 +2,44 @@ use crate::{
nizk::{groth16::Groth16, NIZKVerifierGadget}, Vec, }; -use algebra_core::{AffineCurve, Field, PairingEngine, ToConstraintField}; -use r1cs_core::{ConstraintSynthesizer, ConstraintSystem, SynthesisError}; +use algebra_core::{AffineCurve, PairingEngine, ToConstraintField}; +use r1cs_core::{ConstraintSynthesizer, Namespace, SynthesisError}; use r1cs_std::prelude::*; use core::{borrow::Borrow, marker::PhantomData}; use groth16::{PreparedVerifyingKey, Proof, VerifyingKey}; #[derive(Derivative)] -#[derivative(Clone(bound = "P::G1Gadget: Clone, P::G2Gadget: Clone"))] -pub struct ProofGadget< - PairingE: PairingEngine, - ConstraintF: Field, - P: PairingGadget<PairingE, ConstraintF>, -> { - pub a: P::G1Gadget, - pub b: P::G2Gadget, - pub c: P::G1Gadget, +#[derivative(Clone(bound = "P::G1Var: Clone, P::G2Var: Clone"))] +pub struct ProofVar<E: PairingEngine, P: PairingVar<E>> { + pub a: P::G1Var, + pub b: P::G2Var, + pub c: P::G1Var, } #[derive(Derivative)] -#[derivative(Clone( - bound = "P::G1Gadget: Clone, P::GTGadget: Clone, P::G1PreparedGadget: Clone, \ - P::G2PreparedGadget: Clone, " -))] -pub struct VerifyingKeyGadget< - PairingE: PairingEngine, - ConstraintF: Field, - P: PairingGadget<PairingE, ConstraintF>, -> { - pub alpha_g1: P::G1Gadget, - pub beta_g2: P::G2Gadget, - pub gamma_g2: P::G2Gadget, - pub delta_g2: P::G2Gadget, - pub gamma_abc_g1: Vec<P::G1Gadget>, +#[derivative( + Clone(bound = "P::G1Var: Clone, P::GTVar: Clone, P::G1PreparedVar: Clone, \ + P::G2PreparedVar: Clone, ") +)] +pub struct VerifyingKeyVar<E: PairingEngine, P: PairingVar<E>> { + pub alpha_g1: P::G1Var, + pub beta_g2: P::G2Var, + pub gamma_g2: P::G2Var, + pub delta_g2: P::G2Var, + pub gamma_abc_g1: Vec<P::G1Var>, } -impl<PairingE: PairingEngine, ConstraintF: Field, P: PairingGadget<PairingE, ConstraintF>> - VerifyingKeyGadget<PairingE, ConstraintF, P> -{ - pub fn prepare<CS: ConstraintSystem<ConstraintF>>( - &self, - mut cs: CS, - ) -> Result<PreparedVerifyingKeyGadget<PairingE, ConstraintF, P>, SynthesisError> { - let mut cs = cs.ns(|| "Preparing verifying key"); - let alpha_g1_pc = P::prepare_g1(&mut cs.ns(|| "Prepare alpha_g1"), &self.alpha_g1)?; - let beta_g2_pc = P::prepare_g2(&mut cs.ns(|| "Prepare beta_g2"), &self.beta_g2)?; - - let alpha_g1_beta_g2 = P::pairing( - &mut cs.ns(|| "Precompute e(alpha_g1, beta_g2)"), - alpha_g1_pc, - beta_g2_pc, - )?; - - let gamma_g2_neg = self.gamma_g2.negate(&mut cs.ns(|| "Negate gamma_g2"))?; - let gamma_g2_neg_pc = P::prepare_g2(&mut cs.ns(|| "Prepare gamma_g2_neg"), &gamma_g2_neg)?; +impl<E: PairingEngine, P: PairingVar<E>> VerifyingKeyVar<E, P> { + pub fn prepare(&self) -> Result<PreparedVerifyingKeyVar<E, P>, SynthesisError> { + let alpha_g1_pc = P::prepare_g1(&self.alpha_g1)?; + let beta_g2_pc = P::prepare_g2(&self.beta_g2)?; - let delta_g2_neg = self.delta_g2.negate(&mut cs.ns(|| "Negate delta_g2"))?; - let delta_g2_neg_pc = P::prepare_g2(&mut cs.ns(|| "Prepare delta_g2_neg"), &delta_g2_neg)?; + let alpha_g1_beta_g2 = P::pairing(alpha_g1_pc, beta_g2_pc)?; + let gamma_g2_neg_pc = P::prepare_g2(&self.gamma_g2.negate()?)?; + let delta_g2_neg_pc = P::prepare_g2(&self.delta_g2.negate()?)?; - Ok(PreparedVerifyingKeyGadget { + Ok(PreparedVerifyingKeyVar { alpha_g1_beta_g2, gamma_g2_neg_pc, delta_g2_neg_pc,@@ -71,106 +49,147 @@ }
} #[derive(Derivative)] -#[derivative(Clone( - bound = "P::G1Gadget: Clone, P::GTGadget: Clone, P::G1PreparedGadget: Clone, \ - P::G2PreparedGadget: Clone, " -))] -pub struct PreparedVerifyingKeyGadget< - PairingE: PairingEngine, - ConstraintF: Field, - P: PairingGadget<PairingE, ConstraintF>, -> { - pub alpha_g1_beta_g2: P::GTGadget, - pub gamma_g2_neg_pc: P::G2PreparedGadget, - pub delta_g2_neg_pc: P::G2PreparedGadget, - pub gamma_abc_g1: Vec<P::G1Gadget>, +#[derivative( + Clone(bound = "P::G1Var: Clone, P::GTVar: Clone, P::G1PreparedVar: Clone, \ + P::G2PreparedVar: Clone, ") +)] +pub struct PreparedVerifyingKeyVar<E: PairingEngine, P: PairingVar<E>> { + pub alpha_g1_beta_g2: P::GTVar, + pub gamma_g2_neg_pc: P::G2PreparedVar, + pub delta_g2_neg_pc: P::G2PreparedVar, + pub gamma_abc_g1: Vec<P::G1Var>, } -pub struct Groth16VerifierGadget<PairingE, ConstraintF, P> +pub struct Groth16VerifierGadget<E, P> where - PairingE: PairingEngine, - ConstraintF: Field, - P: PairingGadget<PairingE, ConstraintF>, + E: PairingEngine, + + P: PairingVar<E>, { - _pairing_engine: PhantomData<PairingE>, - _engine: PhantomData<ConstraintF>, + _pairing_engine: PhantomData<E>, _pairing_gadget: PhantomData<P>, } -impl<PairingE, ConstraintF, P, C, V> NIZKVerifierGadget<Groth16<PairingE, C, V>, ConstraintF> - for Groth16VerifierGadget<PairingE, ConstraintF, P> +impl<E, P, C, V> NIZKVerifierGadget<Groth16<E, C, V>, E::Fq> for Groth16VerifierGadget<E, P> where - PairingE: PairingEngine, - ConstraintF: Field, - C: ConstraintSynthesizer<PairingE::Fr>, - V: ToConstraintField<PairingE::Fr>, - P: PairingGadget<PairingE, ConstraintF>, + E: PairingEngine, + C: ConstraintSynthesizer<E::Fr>, + V: ToConstraintField<E::Fr>, + P: PairingVar<E>, { - type PreparedVerificationKeyGadget = PreparedVerifyingKeyGadget<PairingE, ConstraintF, P>; - type VerificationKeyGadget = VerifyingKeyGadget<PairingE, ConstraintF, P>; - type ProofGadget = ProofGadget<PairingE, ConstraintF, P>; + type PreparedVerificationKeyVar = PreparedVerifyingKeyVar<E, P>; + type VerificationKeyVar = VerifyingKeyVar<E, P>; + type ProofVar = ProofVar<E, P>; + + /// Allocates `N::Proof` in `cs` without performing + /// subgroup checks. + fn new_proof_unchecked<T: Borrow<Proof<E>>>( + cs: impl Into<Namespace<E::Fq>>, + f: impl FnOnce() -> Result<T, SynthesisError>, + mode: AllocationMode, + ) -> Result<Self::ProofVar, SynthesisError> { + let ns = cs.into(); + let cs = ns.cs(); + f().and_then(|proof| { + let proof = proof.borrow(); + let a = CurveVar::new_variable_omit_prime_order_check( + cs.ns("Proof.a"), + || Ok(proof.a.into_projective()), + mode, + )?; + let b = CurveVar::new_variable_omit_prime_order_check( + cs.ns("Proof.b"), + || Ok(proof.b.into_projective()), + mode, + )?; + let c = CurveVar::new_variable_omit_prime_order_check( + cs.ns("Proof.c"), + || Ok(proof.c.into_projective()), + mode, + )?; + Ok(ProofVar { a, b, c }) + }) + } + + /// Allocates `N::Proof` in `cs` without performing + /// subgroup checks. + fn new_verification_key_unchecked<T: Borrow<VerifyingKey<E>>>( + cs: impl Into<Namespace<E::Fq>>, + f: impl FnOnce() -> Result<T, SynthesisError>, + mode: AllocationMode, + ) -> Result<Self::VerificationKeyVar, SynthesisError> { + let ns = cs.into(); + let cs = ns.cs(); + f().and_then(|vk| { + let vk = vk.borrow(); + let alpha_g1 = P::G1Var::new_variable_omit_prime_order_check( + cs.ns("alpha_g1"), + || Ok(vk.alpha_g1.into_projective()), + mode, + )?; + let beta_g2 = P::G2Var::new_variable_omit_prime_order_check( + cs.ns("beta_g2"), + || Ok(vk.beta_g2.into_projective()), + mode, + )?; + let gamma_g2 = P::G2Var::new_variable_omit_prime_order_check( + cs.ns("gamma_g2"), + || Ok(vk.gamma_g2.into_projective()), + mode, + )?; + let delta_g2 = P::G2Var::new_variable_omit_prime_order_check( + cs.ns("delta_g2"), + || Ok(vk.delta_g2.into_projective()), + mode, + )?; - fn check_verify<'a, CS, I, T>( - cs: CS, - vk: &Self::VerificationKeyGadget, - public_inputs: I, - proof: &Self::ProofGadget, - ) -> Result<(), SynthesisError> - where - CS: ConstraintSystem<ConstraintF>, - I: Iterator<Item = &'a T>, - T: 'a + ToBitsGadget<ConstraintF> + ?Sized, - { - <Self as NIZKVerifierGadget<Groth16<PairingE, C, V>, ConstraintF>>::conditional_check_verify( - cs, - vk, - public_inputs, - proof, - &Boolean::constant(true), - ) + let gamma_abc_g1 = vk + .gamma_abc_g1 + .iter() + .map(|g| { + P::G1Var::new_variable_omit_prime_order_check( + cs.ns("g"), + || Ok(g.into_projective()), + mode, + ) + }) + .collect::<Result<Vec<_>, _>>()?; + Ok(VerifyingKeyVar { + alpha_g1, + beta_g2, + gamma_g2, + delta_g2, + gamma_abc_g1, + }) + }) } - fn conditional_check_verify<'a, CS, I, T>( - mut cs: CS, - vk: &Self::VerificationKeyGadget, - public_inputs: I, - proof: &Self::ProofGadget, - condition: &Boolean, - ) -> Result<(), SynthesisError> - where - CS: ConstraintSystem<ConstraintF>, - I: Iterator<Item = &'a T>, - T: 'a + ToBitsGadget<ConstraintF> + ?Sized, - { - let pvk = vk.prepare(&mut cs.ns(|| "Prepare vk"))?; - <Self as NIZKVerifierGadget<Groth16<PairingE, C, V>, ConstraintF>>::conditional_check_verify_prepared(cs, &pvk, public_inputs, proof, condition) + fn conditional_verify<'a, T: 'a + ToBitsGadget<E::Fq> + ?Sized>( + vk: &Self::VerificationKeyVar, + input: impl Iterator<Item = &'a T>, + proof: &Self::ProofVar, + condition: &Boolean<E::Fq>, + ) -> Result<(), SynthesisError> { + let pvk = vk.prepare()?; + <Self as NIZKVerifierGadget<Groth16<E, C, V>, E::Fq>>::conditional_verify_prepared( + &pvk, input, proof, condition, + ) } - fn conditional_check_verify_prepared<'a, CS, I, T>( - mut cs: CS, - pvk: &Self::PreparedVerificationKeyGadget, - mut public_inputs: I, - proof: &Self::ProofGadget, - condition: &Boolean, - ) -> Result<(), SynthesisError> - where - CS: ConstraintSystem<ConstraintF>, - I: Iterator<Item = &'a T>, - T: 'a + ToBitsGadget<ConstraintF> + ?Sized, - { + fn conditional_verify_prepared<'a, T: 'a + ToBitsGadget<E::Fq> + ?Sized>( + pvk: &Self::PreparedVerificationKeyVar, + mut public_inputs: impl Iterator<Item = &'a T>, + proof: &Self::ProofVar, + condition: &Boolean<E::Fq>, + ) -> Result<(), SynthesisError> { let pvk = pvk.clone(); let g_ic = { - let mut cs = cs.ns(|| "Process input"); - let mut g_ic = pvk.gamma_abc_g1[0].clone(); + let mut g_ic: P::G1Var = pvk.gamma_abc_g1[0].clone(); let mut input_len = 1; - for (i, (input, b)) in public_inputs - .by_ref() - .zip(pvk.gamma_abc_g1.iter().skip(1)) - .enumerate() - { - let input_bits = input.to_bits(cs.ns(|| format!("Input {}", i)))?; - g_ic = b.mul_bits(cs.ns(|| format!("Mul {}", i)), &g_ic, input_bits.iter())?; + for (input, b) in public_inputs.by_ref().zip(pvk.gamma_abc_g1.iter().skip(1)) { + let encoded_input_i: P::G1Var = b.mul_bits(input.to_bits()?.iter())?; + g_ic += encoded_input_i; input_len += 1; } // Check that the input and the query in the verification are of the@@ -180,14 +199,13 @@ g_ic
}; let test_exp = { - let proof_a_prep = P::prepare_g1(cs.ns(|| "Prepare proof a"), &proof.a)?; - let proof_b_prep = P::prepare_g2(cs.ns(|| "Prepare proof b"), &proof.b)?; - let proof_c_prep = P::prepare_g1(cs.ns(|| "Prepare proof c"), &proof.c)?; + let proof_a_prep = P::prepare_g1(&proof.a)?; + let proof_b_prep = P::prepare_g2(&proof.b)?; + let proof_c_prep = P::prepare_g1(&proof.c)?; - let g_ic_prep = P::prepare_g1(cs.ns(|| "Prepare g_ic"), &g_ic)?; + let g_ic_prep = P::prepare_g1(&g_ic)?; P::miller_loop( - cs.ns(|| "Miller loop 1"), &[proof_a_prep, g_ic_prep, proof_c_prep], &[ proof_b_prep,@@ -197,238 +215,74 @@ ],
)? }; - let test = P::final_exponentiation(cs.ns(|| "Final Exp"), &test_exp).unwrap(); + let test = P::final_exponentiation(&test_exp).unwrap(); - test.conditional_enforce_equal(cs.ns(|| "Test 1"), &pvk.alpha_g1_beta_g2, condition)?; + test.conditional_enforce_equal(&pvk.alpha_g1_beta_g2, condition)?; Ok(()) } } -impl<PairingE, ConstraintF, P> AllocGadget<PreparedVerifyingKey<PairingE>, ConstraintF> - for PreparedVerifyingKeyGadget<PairingE, ConstraintF, P> +impl<E, P> AllocVar<PreparedVerifyingKey<E>, E::Fq> for PreparedVerifyingKeyVar<E, P> where - PairingE: PairingEngine, - ConstraintF: Field, - P: PairingGadget<PairingE, ConstraintF>, - P::G2PreparedGadget: AllocGadget<PairingE::G2Prepared, ConstraintF>, + E: PairingEngine, + P: PairingVar<E>, { - fn alloc_constant<T, CS: ConstraintSystem<ConstraintF>>( - mut cs: CS, - val: T, - ) -> Result<Self, SynthesisError> - where - T: Borrow<PreparedVerifyingKey<PairingE>>, - { - let pvk = val.borrow().clone(); + fn new_variable<T: Borrow<PreparedVerifyingKey<E>>>( + cs: impl Into<Namespace<E::Fq>>, + f: impl FnOnce() -> Result<T, SynthesisError>, + mode: AllocationMode, + ) -> Result<Self, SynthesisError> { + let ns = cs.into(); + let cs = ns.cs(); - let alpha_g1_beta_g2 = - P::GTGadget::alloc_constant(cs.ns(|| "alpha_g1_beta_g2"), pvk.alpha_g1_beta_g2)?; - - let gamma_g2_neg_pc = - P::G2PreparedGadget::alloc_constant(cs.ns(|| "gamma_g2_neg_pc"), pvk.gamma_g2_neg_pc)?; - - let delta_g2_neg_pc = - P::G2PreparedGadget::alloc_constant(cs.ns(|| "delta_g2_neg_pc"), pvk.delta_g2_neg_pc)?; - - let mut gamma_abc_g1 = Vec::<P::G1Gadget>::new(); - for (i, item) in pvk.gamma_abc_g1.iter().enumerate() { - gamma_abc_g1.push(P::G1Gadget::alloc_constant( - cs.ns(|| format!("query_{}", i)), - item.borrow().into_projective(), - )?); - } - - Ok(Self { - alpha_g1_beta_g2, - gamma_g2_neg_pc, - delta_g2_neg_pc, - gamma_abc_g1, - }) - } - - fn alloc<F, T, CS: ConstraintSystem<ConstraintF>>( - mut cs: CS, - f: F, - ) -> Result<Self, SynthesisError> - where - F: FnOnce() -> Result<T, SynthesisError>, - T: Borrow<PreparedVerifyingKey<PairingE>>, - { - let pvk = f()?.borrow().clone(); - - let alpha_g1_beta_g2 = - P::GTGadget::alloc(cs.ns(|| "alpha_g1_beta_g2"), || Ok(pvk.alpha_g1_beta_g2))?; - - let gamma_g2_neg_pc = - P::G2PreparedGadget::alloc(cs.ns(|| "gamma_g2_neg_pc"), || Ok(&pvk.gamma_g2_neg_pc))?; - - let delta_g2_neg_pc = - P::G2PreparedGadget::alloc(cs.ns(|| "delta_g2_neg_pc"), || Ok(&pvk.delta_g2_neg_pc))?; - - let mut gamma_abc_g1 = Vec::<P::G1Gadget>::new(); - for (i, item) in pvk.gamma_abc_g1.iter().enumerate() { - gamma_abc_g1.push(P::G1Gadget::alloc( - cs.ns(|| format!("query_{}", i)), - || Ok(item.borrow().into_projective()), - )?); - } + f().and_then(|pvk| { + let pvk = pvk.borrow(); + let alpha_g1_beta_g2 = P::GTVar::new_variable( + cs.ns("alpha_g1_beta_g2"), + || Ok(pvk.alpha_g1_beta_g2), + mode, + )?; - Ok(Self { - alpha_g1_beta_g2, - gamma_g2_neg_pc, - delta_g2_neg_pc, - gamma_abc_g1, - }) - } + let gamma_g2_neg_pc = P::G2PreparedVar::new_variable( + cs.ns("gamma_g2_neg_pc"), + || Ok(pvk.gamma_g2_neg_pc.clone()), + mode, + )?; - fn alloc_input<F, T, CS: ConstraintSystem<ConstraintF>>( - mut cs: CS, - f: F, - ) -> Result<Self, SynthesisError> - where - F: FnOnce() -> Result<T, SynthesisError>, - T: Borrow<PreparedVerifyingKey<PairingE>>, - { - let pvk = f()?.borrow().clone(); - - let alpha_g1_beta_g2 = - P::GTGadget::alloc_input(cs.ns(|| "alpha_g1_beta_g2"), || Ok(pvk.alpha_g1_beta_g2))?; - - let gamma_g2_neg_pc = - P::G2PreparedGadget::alloc_input(cs.ns(|| "gamma_g2_neg_pc"), || { - Ok(&pvk.gamma_g2_neg_pc) - })?; - - let delta_g2_neg_pc = - P::G2PreparedGadget::alloc_input(cs.ns(|| "delta_g2_neg_pc"), || { - Ok(&pvk.delta_g2_neg_pc) - })?; + let delta_g2_neg_pc = P::G2PreparedVar::new_variable( + cs.ns("delta_g2_neg_pc"), + || Ok(pvk.delta_g2_neg_pc.clone()), + mode, + )?; - let mut gamma_abc_g1 = Vec::<P::G1Gadget>::new(); - for (i, item) in pvk.gamma_abc_g1.iter().enumerate() { - gamma_abc_g1.push(P::G1Gadget::alloc_input( - cs.ns(|| format!("query_{}", i)), - || Ok(item.borrow().into_projective()), - )?); - } + let gamma_abc_g1 = + Vec::new_variable(cs.ns("gamma_abc_g1"), || Ok(pvk.gamma_abc_g1.clone()), mode)?; - Ok(Self { - alpha_g1_beta_g2, - gamma_g2_neg_pc, - delta_g2_neg_pc, - gamma_abc_g1, + Ok(Self { + alpha_g1_beta_g2, + gamma_g2_neg_pc, + delta_g2_neg_pc, + gamma_abc_g1, + }) }) } } -impl<PairingE, ConstraintF, P> AllocGadget<VerifyingKey<PairingE>, ConstraintF> - for VerifyingKeyGadget<PairingE, ConstraintF, P> +impl<E, P> AllocVar<VerifyingKey<E>, E::Fq> for VerifyingKeyVar<E, P> where - PairingE: PairingEngine, - ConstraintF: Field, - P: PairingGadget<PairingE, ConstraintF>, -{ - #[inline] - fn alloc_constant<T, CS: ConstraintSystem<ConstraintF>>( - mut cs: CS, - val: T, - ) -> Result<Self, SynthesisError> - where - T: Borrow<VerifyingKey<PairingE>>, - { - let VerifyingKey { - alpha_g1, - beta_g2, - gamma_g2, - delta_g2, - gamma_abc_g1, - } = val.borrow().clone(); - let alpha_g1 = - P::G1Gadget::alloc_constant(cs.ns(|| "alpha_g1"), alpha_g1.into_projective())?; - let beta_g2 = P::G2Gadget::alloc_constant(cs.ns(|| "beta_g2"), beta_g2.into_projective())?; - let gamma_g2 = - P::G2Gadget::alloc_constant(cs.ns(|| "gamma_g2"), gamma_g2.into_projective())?; - let delta_g2 = - P::G2Gadget::alloc_constant(cs.ns(|| "delta_g2"), delta_g2.into_projective())?; + E: PairingEngine, - let gamma_abc_g1 = gamma_abc_g1 - .into_iter() - .enumerate() - .map(|(i, gamma_abc_i)| { - P::G1Gadget::alloc_constant( - cs.ns(|| format!("gamma_abc_{}", i)), - gamma_abc_i.into_projective(), - ) - }) - .collect::<Vec<_>>() - .into_iter() - .collect::<Result<_, _>>()?; - Ok(Self { - alpha_g1, - beta_g2, - gamma_g2, - delta_g2, - gamma_abc_g1, - }) - } - - #[inline] - fn alloc<FN, T, CS: ConstraintSystem<ConstraintF>>( - mut cs: CS, - value_gen: FN, - ) -> Result<Self, SynthesisError> - where - FN: FnOnce() -> Result<T, SynthesisError>, - T: Borrow<VerifyingKey<PairingE>>, - { - value_gen().and_then(|vk| { - let VerifyingKey { - alpha_g1, - beta_g2, - gamma_g2, - delta_g2, - gamma_abc_g1, - } = vk.borrow().clone(); - let alpha_g1 = - P::G1Gadget::alloc(cs.ns(|| "alpha_g1"), || Ok(alpha_g1.into_projective()))?; - let beta_g2 = - P::G2Gadget::alloc(cs.ns(|| "beta_g2"), || Ok(beta_g2.into_projective()))?; - let gamma_g2 = - P::G2Gadget::alloc(cs.ns(|| "gamma_g2"), || Ok(gamma_g2.into_projective()))?; - let delta_g2 = - P::G2Gadget::alloc(cs.ns(|| "delta_g2"), || Ok(delta_g2.into_projective()))?; - - let gamma_abc_g1 = gamma_abc_g1 - .into_iter() - .enumerate() - .map(|(i, gamma_abc_i)| { - P::G1Gadget::alloc(cs.ns(|| format!("gamma_abc_{}", i)), || { - Ok(gamma_abc_i.into_projective()) - }) - }) - .collect::<Vec<_>>() - .into_iter() - .collect::<Result<_, _>>()?; - Ok(Self { - alpha_g1, - beta_g2, - gamma_g2, - delta_g2, - gamma_abc_g1, - }) - }) - } + P: PairingVar<E>, +{ + fn new_variable<T: Borrow<VerifyingKey<E>>>( + cs: impl Into<Namespace<E::Fq>>, + f: impl FnOnce() -> Result<T, SynthesisError>, + mode: AllocationMode, + ) -> Result<Self, SynthesisError> { + let ns = cs.into(); + let cs = ns.cs(); - #[inline] - fn alloc_input<FN, T, CS: ConstraintSystem<ConstraintF>>( - mut cs: CS, - value_gen: FN, - ) -> Result<Self, SynthesisError> - where - FN: FnOnce() -> Result<T, SynthesisError>, - T: Borrow<VerifyingKey<PairingE>>, - { - value_gen().and_then(|vk| { + f().and_then(|vk| { let VerifyingKey { alpha_g1, beta_g2,@@ -436,27 +290,12 @@ gamma_g2,
delta_g2, gamma_abc_g1, } = vk.borrow().clone(); - let alpha_g1 = - P::G1Gadget::alloc_input(cs.ns(|| "alpha_g1"), || Ok(alpha_g1.into_projective()))?; - let beta_g2 = - P::G2Gadget::alloc_input(cs.ns(|| "beta_g2"), || Ok(beta_g2.into_projective()))?; - let gamma_g2 = - P::G2Gadget::alloc_input(cs.ns(|| "gamma_g2"), || Ok(gamma_g2.into_projective()))?; - let delta_g2 = - P::G2Gadget::alloc_input(cs.ns(|| "delta_g2"), || Ok(delta_g2.into_projective()))?; + let alpha_g1 = P::G1Var::new_variable(cs.ns("alpha_g1"), || Ok(alpha_g1), mode)?; + let beta_g2 = P::G2Var::new_variable(cs.ns("beta_g2"), || Ok(beta_g2), mode)?; + let gamma_g2 = P::G2Var::new_variable(cs.ns("gamma_g2"), || Ok(gamma_g2), mode)?; + let delta_g2 = P::G2Var::new_variable(cs.ns("delta_g2"), || Ok(delta_g2), mode)?; - let gamma_abc_g1 = gamma_abc_g1 - .into_iter() - .enumerate() - .map(|(i, gamma_abc_i)| { - P::G1Gadget::alloc_input(cs.ns(|| format!("gamma_abc_{}", i)), || { - Ok(gamma_abc_i.into_projective()) - }) - }) - .collect::<Vec<_>>() - .into_iter() - .collect::<Result<_, _>>()?; - + let gamma_abc_g1 = Vec::new_variable(cs.clone(), || Ok(gamma_abc_g1), mode)?; Ok(Self { alpha_g1, beta_g2,@@ -468,87 +307,43 @@ })
} } -impl<PairingE, ConstraintF, P> AllocGadget<Proof<PairingE>, ConstraintF> - for ProofGadget<PairingE, ConstraintF, P> +impl<E, P> AllocVar<Proof<E>, E::Fq> for ProofVar<E, P> where - PairingE: PairingEngine, - ConstraintF: Field, - P: PairingGadget<PairingE, ConstraintF>, + E: PairingEngine, + P: PairingVar<E>, { - #[inline] - fn alloc_constant<T, CS: ConstraintSystem<ConstraintF>>( - mut cs: CS, - val: T, - ) -> Result<Self, SynthesisError> - where - T: Borrow<Proof<PairingE>>, - { - let Proof { a, b, c } = val.borrow().clone(); - let a = P::G1Gadget::alloc_constant(cs.ns(|| "a"), a.into_projective())?; - let b = P::G2Gadget::alloc_constant(cs.ns(|| "b"), b.into_projective())?; - let c = P::G1Gadget::alloc_constant(cs.ns(|| "c"), c.into_projective())?; - Ok(Self { a, b, c }) - } + fn new_variable<T: Borrow<Proof<E>>>( + cs: impl Into<Namespace<E::Fq>>, + f: impl FnOnce() -> Result<T, SynthesisError>, + mode: AllocationMode, + ) -> Result<Self, SynthesisError> { + let ns = cs.into(); + let cs = ns.cs(); - #[inline] - fn alloc<FN, T, CS: ConstraintSystem<ConstraintF>>( - mut cs: CS, - value_gen: FN, - ) -> Result<Self, SynthesisError> - where - FN: FnOnce() -> Result<T, SynthesisError>, - T: Borrow<Proof<PairingE>>, - { - value_gen().and_then(|proof| { + f().and_then(|proof| { let Proof { a, b, c } = proof.borrow().clone(); - let a = P::G1Gadget::alloc_checked(cs.ns(|| "a"), || Ok(a.into_projective()))?; - let b = P::G2Gadget::alloc_checked(cs.ns(|| "b"), || Ok(b.into_projective()))?; - let c = P::G1Gadget::alloc_checked(cs.ns(|| "c"), || Ok(c.into_projective()))?; - Ok(Self { a, b, c }) - }) - } - - #[inline] - fn alloc_input<FN, T, CS: ConstraintSystem<ConstraintF>>( - mut cs: CS, - value_gen: FN, - ) -> Result<Self, SynthesisError> - where - FN: FnOnce() -> Result<T, SynthesisError>, - T: Borrow<Proof<PairingE>>, - { - value_gen().and_then(|proof| { - let Proof { a, b, c } = proof.borrow().clone(); - // We don't need to check here because the prime order check can be performed - // in plain. - let a = P::G1Gadget::alloc_input(cs.ns(|| "a"), || Ok(a.into_projective()))?; - let b = P::G2Gadget::alloc_input(cs.ns(|| "b"), || Ok(b.into_projective()))?; - let c = P::G1Gadget::alloc_input(cs.ns(|| "c"), || Ok(c.into_projective()))?; + let a = P::G1Var::new_variable(cs.ns("a"), || Ok(a), mode)?; + let b = P::G2Var::new_variable(cs.ns("b"), || Ok(b), mode)?; + let c = P::G1Var::new_variable(cs.ns("c"), || Ok(c), mode)?; Ok(Self { a, b, c }) }) } } -impl<PairingE, ConstraintF, P> ToBytesGadget<ConstraintF> - for VerifyingKeyGadget<PairingE, ConstraintF, P> +impl<E, P> ToBytesGadget<E::Fq> for VerifyingKeyVar<E, P> where - PairingE: PairingEngine, - ConstraintF: Field, - P: PairingGadget<PairingE, ConstraintF>, + E: PairingEngine, + P: PairingVar<E>, { #[inline] - fn to_bytes<CS: ConstraintSystem<ConstraintF>>( - &self, - mut cs: CS, - ) -> Result<Vec<UInt8>, SynthesisError> { + fn to_bytes(&self) -> Result<Vec<UInt8<E::Fq>>, SynthesisError> { let mut bytes = Vec::new(); - bytes.extend_from_slice(&self.alpha_g1.to_bytes(&mut cs.ns(|| "alpha_g1 to bytes"))?); - bytes.extend_from_slice(&self.beta_g2.to_bytes(&mut cs.ns(|| "beta_g2 to bytes"))?); - bytes.extend_from_slice(&self.gamma_g2.to_bytes(&mut cs.ns(|| "gamma_g2 to bytes"))?); - bytes.extend_from_slice(&self.delta_g2.to_bytes(&mut cs.ns(|| "delta_g2 to bytes"))?); - for (i, g) in self.gamma_abc_g1.iter().enumerate() { - let mut cs = cs.ns(|| format!("Iteration {}", i)); - bytes.extend_from_slice(&g.to_bytes(&mut cs.ns(|| "g"))?); + bytes.extend_from_slice(&self.alpha_g1.to_bytes()?); + bytes.extend_from_slice(&self.beta_g2.to_bytes()?); + bytes.extend_from_slice(&self.gamma_g2.to_bytes()?); + bytes.extend_from_slice(&self.delta_g2.to_bytes()?); + for g in &self.gamma_abc_g1 { + bytes.extend_from_slice(&g.to_bytes()?); } Ok(bytes) }@@ -557,23 +352,22 @@
#[cfg(test)] mod test { use groth16::*; - use r1cs_core::{ConstraintSynthesizer, ConstraintSystem, SynthesisError}; + use r1cs_core::{ + lc, ConstraintSynthesizer, ConstraintSystem, ConstraintSystemRef, SynthesisError, + }; use super::*; use algebra::{ bls12_377::{Bls12_377, Fq, Fr}, - test_rng, BitIterator, PrimeField, + test_rng, BitIterator, Field, PrimeField, }; - use r1cs_std::{ - bls12_377::PairingGadget as Bls12_377PairingGadget, boolean::Boolean, - test_constraint_system::TestConstraintSystem, - }; + use r1cs_std::{bls12_377::PairingVar as Bls12_377PairingVar, boolean::Boolean, Assignment}; use rand::Rng; type TestProofSystem = Groth16<Bls12_377, Bench<Fr>, Fr>; - type TestVerifierGadget = Groth16VerifierGadget<Bls12_377, Fq, Bls12_377PairingGadget>; - type TestProofGadget = ProofGadget<Bls12_377, Fq, Bls12_377PairingGadget>; - type TestVkGadget = VerifyingKeyGadget<Bls12_377, Fq, Bls12_377PairingGadget>; + type TestVerifierGadget = Groth16VerifierGadget<Bls12_377, Bls12_377PairingVar>; + type TestProofVar = ProofVar<Bls12_377, Bls12_377PairingVar>; + type TestVkVar = VerifyingKeyVar<Bls12_377, Bls12_377PairingVar>; struct Bench<F: Field> { inputs: Vec<Option<F>>,@@ -581,19 +375,13 @@ num_constraints: usize,
} impl<F: Field> ConstraintSynthesizer<F> for Bench<F> { - fn generate_constraints<CS: ConstraintSystem<F>>( - self, - cs: &mut CS, - ) -> Result<(), SynthesisError> { + fn generate_constraints(self, cs: ConstraintSystemRef<F>) -> Result<(), SynthesisError> { assert!(self.inputs.len() >= 2); assert!(self.num_constraints >= self.inputs.len()); let mut variables: Vec<_> = Vec::with_capacity(self.inputs.len()); - for (i, input) in self.inputs.into_iter().enumerate() { - let input_var = cs.alloc_input( - || format!("Input {}", i), - || input.ok_or(SynthesisError::AssignmentMissing), - )?; + for input in self.inputs { + let input_var = cs.new_input_variable(|| input.get())?; variables.push((input, input_var)); }@@ -603,16 +391,16 @@ let (input_1_val, input_1_var) = variables[i];
let (input_2_val, input_2_var) = variables[i + 1]; let result_val = input_1_val .and_then(|input_1| input_2_val.map(|input_2| input_1 * &input_2)); - let result_var = cs.alloc( - || format!("Result {}", i), - || result_val.ok_or(SynthesisError::AssignmentMissing), - )?; - cs.enforce( - || format!("Enforce constraint {}", i), - |lc| lc + input_1_var, - |lc| lc + input_2_var, - |lc| lc + result_var, - ); + let result_var = cs.new_witness_variable(|| { + result_val.ok_or(SynthesisError::AssignmentMissing) + })?; + cs.enforce_named_constraint( + format!("Enforce constraint {}", i), + lc!() + input_1_var, + lc!() + input_2_var, + lc!() + result_var, + ) + .unwrap(); (result_val, result_var) }; variables.push(new_entry);@@ -652,20 +440,19 @@ create_random_proof(c, ¶ms, rng).unwrap()
}; // assert!(!verify_proof(&pvk, &proof, &[a]).unwrap()); - let mut cs = TestConstraintSystem::<Fq>::new(); + let cs = ConstraintSystem::<Fq>::new_ref(); let inputs: Vec<_> = inputs.into_iter().map(|input| input.unwrap()).collect(); let mut input_gadgets = Vec::new(); { - let mut cs = cs.ns(|| "Allocate Input"); for (i, input) in inputs.into_iter().enumerate() { let mut input_bits = BitIterator::new(input.into_repr()).collect::<Vec<_>>(); // Input must be in little-endian, but BitIterator outputs in big-endian. input_bits.reverse(); let input_bits = - Vec::<Boolean>::alloc_input(cs.ns(|| format!("Input {}", i)), || { + Vec::<Boolean<Fq>>::new_input(cs.ns(format!("Input {}", i)), || { Ok(input_bits) }) .unwrap();@@ -673,18 +460,17 @@ input_gadgets.push(input_bits);
} } - let vk_gadget = TestVkGadget::alloc_input(cs.ns(|| "Vk"), || Ok(¶ms.vk)).unwrap(); + let vk_gadget = TestVkVar::new_input(cs.ns("Vk"), || Ok(¶ms.vk)).unwrap(); let proof_gadget = - TestProofGadget::alloc(cs.ns(|| "Proof"), || Ok(proof.clone())).unwrap(); + TestProofVar::new_witness(cs.ns("Proof"), || Ok(proof.clone())).unwrap(); println!("Time to verify!\n\n\n\n"); - <TestVerifierGadget as NIZKVerifierGadget<TestProofSystem, Fq>>::check_verify( - cs.ns(|| "Verify"), + <TestVerifierGadget as NIZKVerifierGadget<TestProofSystem, Fq>>::verify( &vk_gadget, input_gadgets.iter(), &proof_gadget, ) .unwrap(); - if !cs.is_satisfied() { + if !cs.is_satisfied().unwrap() { println!("========================================================="); println!("Unsatisfied constraints:"); println!("{:?}", cs.which_is_unsatisfied().unwrap());@@ -692,7 +478,7 @@ println!("=========================================================");
} // cs.print_named_objects(); - assert!(cs.is_satisfied()); + assert!(cs.is_satisfied().unwrap()); } } }@@ -700,31 +486,32 @@
#[cfg(test)] mod test_recursive { use groth16::*; - use r1cs_core::{ConstraintSynthesizer, ConstraintSystem, SynthesisError}; + use r1cs_core::{ + lc, ConstraintSynthesizer, ConstraintSystem, ConstraintSystemRef, SynthesisError, + }; use super::*; use algebra::{ fields::{FftParameters, FpParameters}, mnt4_298::{Fq as MNT4Fq, FqParameters as MNT4FqParameters, Fr as MNT4Fr, MNT4_298}, mnt6_298::{Fq as MNT6Fq, FqParameters as MNT6FqParameters, Fr as MNT6Fr, MNT6_298}, - test_rng, BigInteger, PrimeField, + test_rng, BigInteger, Field, PrimeField, }; use r1cs_std::{ - fields::fp::FpGadget, mnt4_298::PairingGadget as MNT4_298PairingGadget, - mnt6_298::PairingGadget as MNT6_298PairingGadget, - test_constraint_system::TestConstraintSystem, uint8::UInt8, + fields::fp::FpVar, mnt4_298::PairingVar as MNT4_298PairingVar, + mnt6_298::PairingVar as MNT6_298PairingVar, uint8::UInt8, Assignment, }; use rand::Rng; type TestProofSystem1 = Groth16<MNT6_298, Bench<MNT4Fq>, MNT6Fr>; - type TestVerifierGadget1 = Groth16VerifierGadget<MNT6_298, MNT6Fq, MNT6_298PairingGadget>; - type TestProofGadget1 = ProofGadget<MNT6_298, MNT6Fq, MNT6_298PairingGadget>; - type TestVkGadget1 = VerifyingKeyGadget<MNT6_298, MNT6Fq, MNT6_298PairingGadget>; + type TestVerifierGadget1 = Groth16VerifierGadget<MNT6_298, MNT6_298PairingVar>; + type TestProofVar1 = ProofVar<MNT6_298, MNT6_298PairingVar>; + type TestVkVar1 = VerifyingKeyVar<MNT6_298, MNT6_298PairingVar>; type TestProofSystem2 = Groth16<MNT4_298, Wrapper, MNT4Fr>; - type TestVerifierGadget2 = Groth16VerifierGadget<MNT4_298, MNT4Fq, MNT4_298PairingGadget>; - type TestProofGadget2 = ProofGadget<MNT4_298, MNT4Fq, MNT4_298PairingGadget>; - type TestVkGadget2 = VerifyingKeyGadget<MNT4_298, MNT4Fq, MNT4_298PairingGadget>; + type TestVerifierGadget2 = Groth16VerifierGadget<MNT4_298, MNT4_298PairingVar>; + type TestProofVar2 = ProofVar<MNT4_298, MNT4_298PairingVar>; + type TestVkVar2 = VerifyingKeyVar<MNT4_298, MNT4_298PairingVar>; #[derive(Clone)] struct Bench<F: Field> {@@ -733,19 +520,13 @@ num_constraints: usize,
} impl<F: Field> ConstraintSynthesizer<F> for Bench<F> { - fn generate_constraints<CS: ConstraintSystem<F>>( - self, - cs: &mut CS, - ) -> Result<(), SynthesisError> { + fn generate_constraints(self, cs: ConstraintSystemRef<F>) -> Result<(), SynthesisError> { assert!(self.inputs.len() >= 2); assert!(self.num_constraints >= self.inputs.len()); let mut variables: Vec<_> = Vec::with_capacity(self.inputs.len()); - for (i, input) in self.inputs.into_iter().enumerate() { - let input_var = cs.alloc_input( - || format!("Input {}", i), - || input.ok_or(SynthesisError::AssignmentMissing), - )?; + for input in self.inputs { + let input_var = cs.new_input_variable(|| input.get())?; variables.push((input, input_var)); }@@ -755,16 +536,16 @@ let (input_1_val, input_1_var) = variables[i];
let (input_2_val, input_2_var) = variables[i + 1]; let result_val = input_1_val .and_then(|input_1| input_2_val.map(|input_2| input_1 * &input_2)); - let result_var = cs.alloc( - || format!("Result {}", i), - || result_val.ok_or(SynthesisError::AssignmentMissing), - )?; - cs.enforce( - || format!("Enforce constraint {}", i), - |lc| lc + input_1_var, - |lc| lc + input_2_var, - |lc| lc + result_var, - ); + let result_var = cs.new_witness_variable(|| { + result_val.ok_or(SynthesisError::AssignmentMissing) + })?; + cs.enforce_named_constraint( + format!("Enforce constraint {}", i), + lc!() + input_1_var, + lc!() + input_2_var, + lc!() + result_var, + ) + .unwrap(); (result_val, result_var) }; variables.push(new_entry);@@ -780,9 +561,9 @@ proof: Proof<MNT6_298>,
} impl ConstraintSynthesizer<MNT6Fq> for Wrapper { - fn generate_constraints<CS: ConstraintSystem<MNT6Fq>>( + fn generate_constraints( self, - cs: &mut CS, + cs: ConstraintSystemRef<MNT6Fq>, ) -> Result<(), SynthesisError> { let params = self.params; let proof = self.proof;@@ -794,7 +575,6 @@ .collect();
let input_gadgets; { - let mut cs = cs.ns(|| "Allocate Input"); // Chain all input values in one large byte array. let input_bytes = inputs .clone()@@ -810,7 +590,7 @@ })
.collect::<Vec<_>>(); // Allocate this byte array as input packed into field elements. - let input_bytes = UInt8::alloc_input_vec(cs.ns(|| "Input"), &input_bytes[..])?; + let input_bytes = UInt8::new_input_vec(cs.ns("Input"), &input_bytes[..])?; // 40 byte let element_size = <MNT4FqParameters as FftParameters>::BigInt::NUM_LIMBS * 8; input_gadgets = input_bytes@@ -824,11 +604,10 @@ })
.collect::<Vec<_>>(); } - let vk_gadget = TestVkGadget1::alloc(cs.ns(|| "Vk"), || Ok(¶ms.vk))?; + let vk_gadget = TestVkVar1::new_witness(cs.ns("Vk"), || Ok(¶ms.vk))?; let proof_gadget = - TestProofGadget1::alloc(cs.ns(|| "Proof"), || Ok(proof.clone())).unwrap(); - <TestVerifierGadget1 as NIZKVerifierGadget<TestProofSystem1, MNT6Fq>>::check_verify( - cs.ns(|| "Verify"), + TestProofVar1::new_witness(cs.ns("Proof"), || Ok(proof.clone())).unwrap(); + <TestVerifierGadget1 as NIZKVerifierGadget<TestProofSystem1, MNT6Fq>>::verify( &vk_gadget, input_gadgets.iter(), &proof_gadget,@@ -892,7 +671,7 @@ // Create a groth16 proof with our parameters.
create_random_proof(c, ¶ms, rng).unwrap() }; - let mut cs = TestConstraintSystem::<MNT4Fq>::new(); + let cs = ConstraintSystem::<MNT4Fq>::new_ref(); let inputs: Vec<_> = inputs.into_iter().map(|input| input.unwrap()).collect(); let mut input_gadgets = Vec::new();@@ -900,16 +679,12 @@
{ let bigint_size = <MNT4FqParameters as FftParameters>::BigInt::NUM_LIMBS * 64; let mut input_bits = Vec::new(); - let mut cs = cs.ns(|| "Allocate Input"); for (i, input) in inputs.into_iter().enumerate() { let input_gadget = - FpGadget::alloc_input(cs.ns(|| format!("Input {}", i)), || Ok(input)) - .unwrap(); - let mut fp_bits = input_gadget - .to_bits(cs.ns(|| format!("To bits {}", i))) - .unwrap(); + FpVar::new_input(cs.ns(format!("Input {}", i)), || Ok(input)).unwrap(); + let mut fp_bits = input_gadget.to_bits().unwrap(); - // FpGadget::to_bits outputs a big-endian binary representation of + // FpVar::to_bits outputs a big-endian binary representation of // fe_gadget's value, so we have to reverse it to get the little-endian // form. fp_bits.reverse();@@ -936,18 +711,17 @@ }
// assert!(!verify_proof(&pvk, &proof, &[a]).unwrap()); } - let vk_gadget = TestVkGadget2::alloc_input(cs.ns(|| "Vk"), || Ok(¶ms.vk)).unwrap(); + let vk_gadget = TestVkVar2::new_input(cs.ns("Vk"), || Ok(¶ms.vk)).unwrap(); let proof_gadget = - TestProofGadget2::alloc(cs.ns(|| "Proof"), || Ok(proof.clone())).unwrap(); + TestProofVar2::new_witness(cs.ns("Proof"), || Ok(proof.clone())).unwrap(); println!("Time to verify!\n\n\n\n"); - <TestVerifierGadget2 as NIZKVerifierGadget<TestProofSystem2, MNT4Fq>>::check_verify( - cs.ns(|| "Verify"), + <TestVerifierGadget2 as NIZKVerifierGadget<TestProofSystem2, MNT4Fq>>::verify( &vk_gadget, input_gadgets.iter(), &proof_gadget, ) .unwrap(); - if !cs.is_satisfied() { + if !cs.is_satisfied().unwrap() { println!("========================================================="); println!("Unsatisfied constraints:"); println!("{:?}", cs.which_is_unsatisfied().unwrap());@@ -955,7 +729,7 @@ println!("=========================================================");
} // cs.print_named_objects(); - assert!(cs.is_satisfied()); + assert!(cs.is_satisfied().unwrap()); } } }
@@ -63,7 +63,7 @@ use algebra::{
bls12_377::{Bls12_377, Fr}, One, }; - use r1cs_core::{ConstraintSynthesizer, ConstraintSystem, SynthesisError}; + use r1cs_core::{lc, ConstraintSynthesizer, ConstraintSystemRef, SynthesisError, Variable}; #[derive(Copy, Clone)] struct R1CSCircuit {@@ -83,20 +83,20 @@ }
} impl ConstraintSynthesizer<Fr> for R1CSCircuit { - fn generate_constraints<CS: ConstraintSystem<Fr>>( + fn generate_constraints( self, - cs: &mut CS, + cs: ConstraintSystemRef<Fr>, ) -> Result<(), SynthesisError> { - let input = cs.alloc_input(|| "x", || Ok(self.x.unwrap()))?; - let sum = cs.alloc_input(|| "sum", || Ok(self.sum.unwrap()))?; - let witness = cs.alloc(|| "w", || Ok(self.w.unwrap()))?; + let input = cs.new_input_variable(|| Ok(self.x.unwrap()))?; + let sum = cs.new_input_variable(|| Ok(self.sum.unwrap()))?; + let witness = cs.new_witness_variable(|| Ok(self.w.unwrap()))?; - cs.enforce( - || "check_one", - |lc| lc + sum, - |lc| lc + CS::one(), - |lc| lc + input + witness, - ); + cs.enforce_named_constraint( + "enforce sum", + lc!() + sum, + lc!() + Variable::One, + lc!() + input + witness, + )?; Ok(()) } }
@@ -1,5 +1,5 @@
use algebra_core::PrimeField; -use r1cs_core::{ConstraintSystem, SynthesisError}; +use r1cs_core::{ConstraintSystemRef, Namespace, SynthesisError}; use crate::{prf::PRFGadget, Vec}; use r1cs_std::prelude::*;@@ -76,30 +76,23 @@ // |
// END FUNCTION. // -fn mixing_g<ConstraintF: PrimeField, CS: ConstraintSystem<ConstraintF>>( - mut cs: CS, - v: &mut [UInt32], +fn mixing_g<ConstraintF: PrimeField>( + v: &mut [UInt32<ConstraintF>], a: usize, b: usize, c: usize, d: usize, - x: &UInt32, - y: &UInt32, + x: &UInt32<ConstraintF>, + y: &UInt32<ConstraintF>, ) -> Result<(), SynthesisError> { - v[a] = UInt32::addmany( - cs.ns(|| "mixing step 1"), - &[v[a].clone(), v[b].clone(), x.clone()], - )?; - v[d] = v[d].xor(cs.ns(|| "mixing step 2"), &v[a])?.rotr(R1); - v[c] = UInt32::addmany(cs.ns(|| "mixing step 3"), &[v[c].clone(), v[d].clone()])?; - v[b] = v[b].xor(cs.ns(|| "mixing step 4"), &v[c])?.rotr(R2); - v[a] = UInt32::addmany( - cs.ns(|| "mixing step 5"), - &[v[a].clone(), v[b].clone(), y.clone()], - )?; - v[d] = v[d].xor(cs.ns(|| "mixing step 6"), &v[a])?.rotr(R3); - v[c] = UInt32::addmany(cs.ns(|| "mixing step 7"), &[v[c].clone(), v[d].clone()])?; - v[b] = v[b].xor(cs.ns(|| "mixing step 8"), &v[c])?.rotr(R4); + v[a] = UInt32::addmany(&[v[a].clone(), v[b].clone(), x.clone()])?; + v[d] = v[d].xor(&v[a])?.rotr(R1); + v[c] = UInt32::addmany(&[v[c].clone(), v[d].clone()])?; + v[b] = v[b].xor(&v[c])?.rotr(R2); + v[a] = UInt32::addmany(&[v[a].clone(), v[b].clone(), y.clone()])?; + v[d] = v[d].xor(&v[a])?.rotr(R3); + v[c] = UInt32::addmany(&[v[c].clone(), v[d].clone()])?; + v[b] = v[b].xor(&v[c])?.rotr(R4); Ok(()) }@@ -107,7 +100,7 @@
// 3.2. Compression Function F // Compression function F takes as an argument the state vector "h", // message block vector "m" (last block is padded with zeros to full -// block size, if required), 2w-bit_gadget offset counter "t", and final block +// block size, if required), 2w-bit offset counter "t", and final block // indicator flag "f". Local vector v[0..15] is used in processing. F // returns a new state vector. The number of rounds, "r", is 12 for // BLAKE2b and 10 for BLAKE2s. Rounds are numbered from 0 to r - 1.@@ -151,10 +144,9 @@ // |
// END FUNCTION. // -fn blake2s_compression<ConstraintF: PrimeField, CS: ConstraintSystem<ConstraintF>>( - mut cs: CS, - h: &mut [UInt32], - m: &[UInt32], +fn blake2s_compression<ConstraintF: PrimeField>( + h: &mut [UInt32<ConstraintF>], + m: &[UInt32<ConstraintF>], t: u64, f: bool, ) -> Result<(), SynthesisError> {@@ -181,106 +173,29 @@ v.push(UInt32::constant(0x5BE0CD19));
assert_eq!(v.len(), 16); - v[12] = v[12].xor(cs.ns(|| "first xor"), &UInt32::constant(t as u32))?; - v[13] = v[13].xor(cs.ns(|| "second xor"), &UInt32::constant((t >> 32) as u32))?; + v[12] = v[12].xor(&UInt32::constant(t as u32))?; + v[13] = v[13].xor(&UInt32::constant((t >> 32) as u32))?; if f { - v[14] = v[14].xor(cs.ns(|| "third xor"), &UInt32::constant(u32::max_value()))?; + v[14] = v[14].xor(&UInt32::constant(u32::max_value()))?; } for i in 0..10 { - let mut cs = cs.ns(|| format!("round {}", i)); - let s = SIGMA[i % 10]; - mixing_g( - cs.ns(|| "mixing invocation 1"), - &mut v, - 0, - 4, - 8, - 12, - &m[s[0]], - &m[s[1]], - )?; - mixing_g( - cs.ns(|| "mixing invocation 2"), - &mut v, - 1, - 5, - 9, - 13, - &m[s[2]], - &m[s[3]], - )?; - mixing_g( - cs.ns(|| "mixing invocation 3"), - &mut v, - 2, - 6, - 10, - 14, - &m[s[4]], - &m[s[5]], - )?; - mixing_g( - cs.ns(|| "mixing invocation 4"), - &mut v, - 3, - 7, - 11, - 15, - &m[s[6]], - &m[s[7]], - )?; - - mixing_g( - cs.ns(|| "mixing invocation 5"), - &mut v, - 0, - 5, - 10, - 15, - &m[s[8]], - &m[s[9]], - )?; - mixing_g( - cs.ns(|| "mixing invocation 6"), - &mut v, - 1, - 6, - 11, - 12, - &m[s[10]], - &m[s[11]], - )?; - mixing_g( - cs.ns(|| "mixing invocation 7"), - &mut v, - 2, - 7, - 8, - 13, - &m[s[12]], - &m[s[13]], - )?; - mixing_g( - cs.ns(|| "mixing invocation 8"), - &mut v, - 3, - 4, - 9, - 14, - &m[s[14]], - &m[s[15]], - )?; + mixing_g(&mut v, 0, 4, 8, 12, &m[s[0]], &m[s[1]])?; + mixing_g(&mut v, 1, 5, 9, 13, &m[s[2]], &m[s[3]])?; + mixing_g(&mut v, 2, 6, 10, 14, &m[s[4]], &m[s[5]])?; + mixing_g(&mut v, 3, 7, 11, 15, &m[s[6]], &m[s[7]])?; + mixing_g(&mut v, 0, 5, 10, 15, &m[s[8]], &m[s[9]])?; + mixing_g(&mut v, 1, 6, 11, 12, &m[s[10]], &m[s[11]])?; + mixing_g(&mut v, 2, 7, 8, 13, &m[s[12]], &m[s[13]])?; + mixing_g(&mut v, 3, 4, 9, 14, &m[s[14]], &m[s[15]])?; } for i in 0..8 { - let mut cs = cs.ns(|| format!("h[{i}] ^ v[{i}] ^ v[{i} + 8]", i = i)); - - h[i] = h[i].xor(cs.ns(|| "first xor"), &v[i])?; - h[i] = h[i].xor(cs.ns(|| "second xor"), &v[i + 8])?; + h[i] = h[i].xor(&v[i])?; + h[i] = h[i].xor(&v[i + 8])?; } Ok(())@@ -312,53 +227,32 @@ // |
// END FUNCTION. // -pub fn blake2s_gadget<ConstraintF: PrimeField, CS: ConstraintSystem<ConstraintF>>( - cs: CS, - input: &[Boolean], -) -> Result<Vec<UInt32>, SynthesisError> { +pub fn evaluate_blake2s<ConstraintF: PrimeField>( + input: &[Boolean<ConstraintF>], +) -> Result<Vec<UInt32<ConstraintF>>, SynthesisError> { assert!(input.len() % 8 == 0); let mut parameters = [0; 8]; parameters[0] = 0x01010000 ^ 32; - blake2s_gadget_with_parameters(cs, input, ¶meters) + evaluate_blake2s_with_parameters(input, ¶meters) } -pub fn blake2s_gadget_with_parameters< - ConstraintF: PrimeField, - CS: ConstraintSystem<ConstraintF>, ->( - mut cs: CS, - input: &[Boolean], +pub fn evaluate_blake2s_with_parameters<F: PrimeField>( + input: &[Boolean<F>], parameters: &[u32; 8], -) -> Result<Vec<UInt32>, SynthesisError> { +) -> Result<Vec<UInt32<F>>, SynthesisError> { assert!(input.len() % 8 == 0); let mut h = Vec::with_capacity(8); - h.push( - UInt32::constant(0x6A09E667).xor(cs.ns(|| "xor h[0]"), &UInt32::constant(parameters[0]))?, - ); - h.push( - UInt32::constant(0xBB67AE85).xor(cs.ns(|| "xor h[1]"), &UInt32::constant(parameters[1]))?, - ); - h.push( - UInt32::constant(0x3C6EF372).xor(cs.ns(|| "xor h[2]"), &UInt32::constant(parameters[2]))?, - ); - h.push( - UInt32::constant(0xA54FF53A).xor(cs.ns(|| "xor h[3]"), &UInt32::constant(parameters[3]))?, - ); - h.push( - UInt32::constant(0x510E527F).xor(cs.ns(|| "xor h[4]"), &UInt32::constant(parameters[4]))?, - ); - h.push( - UInt32::constant(0x9B05688C).xor(cs.ns(|| "xor h[5]"), &UInt32::constant(parameters[5]))?, - ); - h.push( - UInt32::constant(0x1F83D9AB).xor(cs.ns(|| "xor h[6]"), &UInt32::constant(parameters[6]))?, - ); - h.push( - UInt32::constant(0x5BE0CD19).xor(cs.ns(|| "xor h[7]"), &UInt32::constant(parameters[7]))?, - ); + h.push(UInt32::constant(0x6A09E667).xor(&UInt32::constant(parameters[0]))?); + h.push(UInt32::constant(0xBB67AE85).xor(&UInt32::constant(parameters[1]))?); + h.push(UInt32::constant(0x3C6EF372).xor(&UInt32::constant(parameters[2]))?); + h.push(UInt32::constant(0xA54FF53A).xor(&UInt32::constant(parameters[3]))?); + h.push(UInt32::constant(0x510E527F).xor(&UInt32::constant(parameters[4]))?); + h.push(UInt32::constant(0x9B05688C).xor(&UInt32::constant(parameters[5]))?); + h.push(UInt32::constant(0x1F83D9AB).xor(&UInt32::constant(parameters[6]))?); + h.push(UInt32::constant(0x5BE0CD19).xor(&UInt32::constant(parameters[7]))?); - let mut blocks: Vec<Vec<UInt32>> = vec![]; + let mut blocks: Vec<Vec<UInt32<F>>> = vec![]; for block in input.chunks(512) { let mut this_block = Vec::with_capacity(16);@@ -380,22 +274,15 @@ blocks.push((0..16).map(|_| UInt32::constant(0)).collect());
} for (i, block) in blocks[0..blocks.len() - 1].iter().enumerate() { - let cs = cs.ns(|| format!("block {}", i)); - - blake2s_compression(cs, &mut h, block, ((i as u64) + 1) * 64, false)?; + blake2s_compression(&mut h, block, ((i as u64) + 1) * 64, false)?; } - { - let cs = cs.ns(|| "final block"); - - blake2s_compression( - cs, - &mut h, - &blocks[blocks.len() - 1], - (input.len() / 8) as u64, - true, - )?; - } + blake2s_compression( + &mut h, + &blocks[blocks.len() - 1], + (input.len() / 8) as u64, + true, + )?; Ok(h) }@@ -404,134 +291,93 @@ use crate::prf::Blake2s;
pub struct Blake2sGadget; #[derive(Clone, Debug)] -pub struct Blake2sOutputGadget(pub Vec<UInt8>); +pub struct OutputVar<ConstraintF: PrimeField>(pub Vec<UInt8<ConstraintF>>); -impl PartialEq for Blake2sOutputGadget { - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 +impl<ConstraintF: PrimeField> EqGadget<ConstraintF> for OutputVar<ConstraintF> { + fn is_eq(&self, other: &Self) -> Result<Boolean<ConstraintF>, SynthesisError> { + self.0.is_eq(&other.0) } -} - -impl Eq for Blake2sOutputGadget {} -impl<ConstraintF: PrimeField> EqGadget<ConstraintF> for Blake2sOutputGadget {} - -impl<ConstraintF: PrimeField> ConditionalEqGadget<ConstraintF> for Blake2sOutputGadget { - #[inline] - fn conditional_enforce_equal<CS: ConstraintSystem<ConstraintF>>( + /// If `should_enforce == true`, enforce that `self` and `other` are equal; else, + /// enforce a vacuously true statement. + fn conditional_enforce_equal( &self, - mut cs: CS, other: &Self, - condition: &Boolean, + should_enforce: &Boolean<ConstraintF>, ) -> Result<(), SynthesisError> { - for (i, (a, b)) in self.0.iter().zip(other.0.iter()).enumerate() { - a.conditional_enforce_equal( - &mut cs.ns(|| format!("blake2s_equal_{}", i)), - b, - condition, - )?; - } - Ok(()) + self.0.conditional_enforce_equal(&other.0, should_enforce) } - fn cost() -> usize { - 32 * <UInt8 as ConditionalEqGadget<ConstraintF>>::cost() + /// If `should_enforce == true`, enforce that `self` and `other` are not equal; else, + /// enforce a vacuously true statement. + fn conditional_enforce_not_equal( + &self, + other: &Self, + should_enforce: &Boolean<ConstraintF>, + ) -> Result<(), SynthesisError> { + self.0 + .as_slice() + .conditional_enforce_not_equal(other.0.as_slice(), should_enforce) } } -impl<ConstraintF: PrimeField> ToBytesGadget<ConstraintF> for Blake2sOutputGadget { +impl<ConstraintF: PrimeField> ToBytesGadget<ConstraintF> for OutputVar<ConstraintF> { #[inline] - fn to_bytes<CS: ConstraintSystem<ConstraintF>>( - &self, - _cs: CS, - ) -> Result<Vec<UInt8>, SynthesisError> { + fn to_bytes(&self) -> Result<Vec<UInt8<ConstraintF>>, SynthesisError> { Ok(self.0.clone()) } } -impl<ConstraintF: PrimeField> AllocGadget<[u8; 32], ConstraintF> for Blake2sOutputGadget { - #[inline] - fn alloc_constant<T, CS: ConstraintSystem<ConstraintF>>( - mut cs: CS, - val: T, - ) -> Result<Self, SynthesisError> - where - T: Borrow<[u8; 32]>, - { - let mut bytes = vec![]; - for (i, b) in val.borrow().iter().enumerate() { - bytes.push(UInt8::alloc_constant(cs.ns(|| format!("value {}", i)), b)?) +impl<ConstraintF: PrimeField> AllocVar<[u8; 32], ConstraintF> for OutputVar<ConstraintF> { + fn new_variable<T: Borrow<[u8; 32]>>( + cs: impl Into<Namespace<ConstraintF>>, + f: impl FnOnce() -> Result<T, SynthesisError>, + mode: AllocationMode, + ) -> Result<Self, SynthesisError> { + let bytes = f().map(|b| *b.borrow()).unwrap_or([0u8; 32]); + match mode { + AllocationMode::Constant => Ok(Self(UInt8::constant_vec(&bytes))), + AllocationMode::Input => UInt8::new_input_vec(cs, &bytes).map(Self), + AllocationMode::Witness => UInt8::new_witness_vec(cs, &bytes).map(Self), } - - Ok(Blake2sOutputGadget(bytes)) } +} - #[inline] - fn alloc<F, T, CS: ConstraintSystem<ConstraintF>>( - cs: CS, - value_gen: F, - ) -> Result<Self, SynthesisError> - where - F: FnOnce() -> Result<T, SynthesisError>, - T: Borrow<[u8; 32]>, - { - let zeros = [0u8; 32]; - let value = match value_gen() { - Ok(val) => *(val.borrow()), - Err(_) => zeros, - }; - let bytes = <UInt8>::alloc_vec(cs, &value)?; +impl<F: PrimeField> R1CSVar<F> for OutputVar<F> { + type Value = [u8; 32]; - Ok(Blake2sOutputGadget(bytes)) + fn cs(&self) -> Option<ConstraintSystemRef<F>> { + self.0.cs() } - #[inline] - fn alloc_input<F, T, CS: ConstraintSystem<ConstraintF>>( - cs: CS, - value_gen: F, - ) -> Result<Self, SynthesisError> - where - F: FnOnce() -> Result<T, SynthesisError>, - T: Borrow<[u8; 32]>, - { - let zeros = [0u8; 32]; - let value = match value_gen() { - Ok(val) => *(val.borrow()), - Err(_) => zeros, - }; - let bytes = <UInt8>::alloc_input_vec(cs, &value)?; - - Ok(Blake2sOutputGadget(bytes)) + fn value(&self) -> Result<Self::Value, SynthesisError> { + let mut value = [0u8; 32]; + for (val_i, self_i) in value.iter_mut().zip(&self.0) { + *val_i = self_i.value()?; + } + Ok(value) } } -impl<ConstraintF: PrimeField> PRFGadget<Blake2s, ConstraintF> for Blake2sGadget { - type OutputGadget = Blake2sOutputGadget; +impl<F: PrimeField> PRFGadget<Blake2s, F> for Blake2sGadget { + type OutputVar = OutputVar<F>; - fn new_seed<CS: ConstraintSystem<ConstraintF>>(mut cs: CS, seed: &[u8; 32]) -> Vec<UInt8> { - UInt8::alloc_vec(&mut cs.ns(|| "alloc_seed"), seed).unwrap() + fn new_seed(cs: ConstraintSystemRef<F>, seed: &[u8; 32]) -> Vec<UInt8<F>> { + UInt8::new_witness_vec(cs.ns("New Blake2s seed"), seed).unwrap() } - fn check_evaluation_gadget<CS: ConstraintSystem<ConstraintF>>( - mut cs: CS, - seed: &[UInt8], - input: &[UInt8], - ) -> Result<Self::OutputGadget, SynthesisError> { + fn evaluate(seed: &[UInt8<F>], input: &[UInt8<F>]) -> Result<Self::OutputVar, SynthesisError> { assert_eq!(seed.len(), 32); - // assert_eq!(input.len(), 32); - let mut gadget_input = Vec::with_capacity(512); - for byte in seed.iter().chain(input) { - gadget_input.extend_from_slice(&byte.into_bits_le()); - } - let mut result = Vec::new(); - for (i, int) in blake2s_gadget(cs.ns(|| "Blake2s Eval"), &gadget_input)? + let input: Vec<_> = seed + .iter() + .chain(input) + .flat_map(|b| b.into_bits_le()) + .collect(); + let result: Vec<_> = evaluate_blake2s(&input)? .into_iter() - .enumerate() - { - let chunk = int.to_bytes(&mut cs.ns(|| format!("Result ToBytes {}", i)))?; - result.extend_from_slice(&chunk); - } - Ok(Blake2sOutputGadget(result)) + .flat_map(|int| int.to_bytes().unwrap()) + .collect(); + Ok(OutputVar(result)) } }@@ -541,27 +387,21 @@ use algebra::ed_on_bls12_381::Fq as Fr;
use rand::{Rng, SeedableRng}; use rand_xorshift::XorShiftRng; - use crate::prf::blake2s::{constraints::blake2s_gadget, Blake2s as B2SPRF}; + use crate::prf::blake2s::{constraints::evaluate_blake2s, Blake2s as B2SPRF}; use blake2::VarBlake2s; use r1cs_core::ConstraintSystem; use super::Blake2sGadget; - use r1cs_std::{ - boolean::AllocatedBit, prelude::*, test_constraint_system::TestConstraintSystem, - }; + use r1cs_std::prelude::*; #[test] fn test_blake2s_constraints() { - let mut cs = TestConstraintSystem::<Fr>::new(); + let cs = ConstraintSystem::<Fr>::new_ref(); let input_bits: Vec<_> = (0..512) - .map(|i| { - AllocatedBit::alloc(cs.ns(|| format!("input bit_gadget {}", i)), || Ok(true)) - .unwrap() - .into() - }) + .map(|i| Boolean::new_witness(cs.ns(format!("input bit {}", i)), || Ok(true)).unwrap()) .collect(); - blake2s_gadget(&mut cs, &input_bits).unwrap(); - assert!(cs.is_satisfied()); + evaluate_blake2s(&input_bits).unwrap(); + assert!(cs.is_satisfied().unwrap()); assert_eq!(cs.num_constraints(), 21792); }@@ -571,7 +411,7 @@ use crate::prf::{PRFGadget, PRF};
use rand::Rng; let mut rng = XorShiftRng::seed_from_u64(1231275789u64); - let mut cs = TestConstraintSystem::<Fr>::new(); + let cs = ConstraintSystem::<Fr>::new_ref(); let mut seed = [0u8; 32]; rng.fill(&mut seed);@@ -579,32 +419,25 @@
let mut input = [0u8; 32]; rng.fill(&mut input); - let seed_gadget = Blake2sGadget::new_seed(&mut cs.ns(|| "declare_seed"), &seed); - let input_gadget = UInt8::alloc_vec(&mut cs.ns(|| "declare_input"), &input).unwrap(); + let seed_var = Blake2sGadget::new_seed(cs.clone(), &seed); + let input_var = UInt8::new_witness_vec(cs.ns("declare_input"), &input).unwrap(); let out = B2SPRF::evaluate(&seed, &input).unwrap(); - let actual_out_gadget = <Blake2sGadget as PRFGadget<_, Fr>>::OutputGadget::alloc( - &mut cs.ns(|| "declare_output"), + let actual_out_var = <Blake2sGadget as PRFGadget<_, Fr>>::OutputVar::new_witness( + cs.ns("declare_output"), || Ok(out), ) .unwrap(); - let output_gadget = Blake2sGadget::check_evaluation_gadget( - &mut cs.ns(|| "eval_blake2s"), - &seed_gadget, - &input_gadget, - ) - .unwrap(); - output_gadget - .enforce_equal(&mut cs, &actual_out_gadget) - .unwrap(); + let output_var = Blake2sGadget::evaluate(&seed_var, &input_var).unwrap(); + output_var.enforce_equal(&actual_out_var).unwrap(); - if !cs.is_satisfied() { + if !cs.is_satisfied().unwrap() { println!( "which is unsatisfied: {:?}", cs.which_is_unsatisfied().unwrap() ); } - assert!(cs.is_satisfied()); + assert!(cs.is_satisfied().unwrap()); } #[test]@@ -612,27 +445,27 @@ fn test_blake2s_precomp_constraints() {
// Test that 512 fixed leading bits (constants) // doesn't result in more constraints. - let mut cs = TestConstraintSystem::<Fr>::new(); + let cs = ConstraintSystem::<Fr>::new_ref(); let mut rng = XorShiftRng::seed_from_u64(1231275789u64); let input_bits: Vec<_> = (0..512) .map(|_| Boolean::constant(rng.gen())) .chain((0..512).map(|i| { - AllocatedBit::alloc(cs.ns(|| format!("input bit_gadget {}", i)), || Ok(true)) - .unwrap() - .into() + Boolean::new_witness(cs.ns(format!("input bit {}", i)), || Ok(true)).unwrap() })) .collect(); - blake2s_gadget(&mut cs, &input_bits).unwrap(); - assert!(cs.is_satisfied()); + evaluate_blake2s(&input_bits).unwrap(); + assert!(cs.is_satisfied().unwrap()); assert_eq!(cs.num_constraints(), 21792); } #[test] fn test_blake2s_constant_constraints() { - let mut cs = TestConstraintSystem::<Fr>::new(); + let cs = ConstraintSystem::<Fr>::new_ref(); let mut rng = XorShiftRng::seed_from_u64(1231275789u64); - let input_bits: Vec<_> = (0..512).map(|_| Boolean::constant(rng.gen())).collect(); - blake2s_gadget(&mut cs, &input_bits).unwrap(); + let input_bits: Vec<_> = (0..512) + .map(|_| Boolean::<Fr>::constant(rng.gen())) + .collect(); + evaluate_blake2s(&input_bits).unwrap(); assert_eq!(cs.num_constraints(), 0); }@@ -651,25 +484,24 @@
let mut hash_result = Vec::with_capacity(h.output_size()); h.variable_result(|res| hash_result.extend_from_slice(res)); - let mut cs = TestConstraintSystem::<Fr>::new(); + let cs = ConstraintSystem::<Fr>::new_ref(); let mut input_bits = vec![]; for (byte_i, input_byte) in data.into_iter().enumerate() { for bit_i in 0..8 { - let cs = cs.ns(|| format!("input bit_gadget {} {}", byte_i, bit_i)); + let cs = cs.ns(format!("input bit {} {}", byte_i, bit_i)); input_bits.push( - AllocatedBit::alloc(cs, || Ok((input_byte >> bit_i) & 1u8 == 1u8)) - .unwrap() - .into(), + Boolean::new_witness(cs, || Ok((input_byte >> bit_i) & 1u8 == 1u8)) + .unwrap(), ); } } - let r = blake2s_gadget(&mut cs, &input_bits).unwrap(); + let r = evaluate_blake2s(&input_bits).unwrap(); - assert!(cs.is_satisfied()); + assert!(cs.is_satisfied().unwrap()); let mut s = hash_result .iter()@@ -679,10 +511,10 @@ for chunk in r {
for b in chunk.to_bits_le() { match b { Boolean::Is(b) => { - assert!(s.next().unwrap() == b.get_value().unwrap()); + assert!(s.next().unwrap() == b.value().unwrap()); } Boolean::Not(b) => { - assert!(s.next().unwrap() != b.get_value().unwrap()); + assert!(s.next().unwrap() != b.value().unwrap()); } Boolean::Constant(b) => { assert!(input_len == 0);
@@ -2,22 +2,19 @@ use algebra_core::Field;
use core::fmt::Debug; use crate::{prf::PRF, Vec}; -use r1cs_core::{ConstraintSystem, SynthesisError}; +use r1cs_core::{ConstraintSystemRef, SynthesisError}; use r1cs_std::prelude::*; -pub trait PRFGadget<P: PRF, ConstraintF: Field> { - type OutputGadget: EqGadget<ConstraintF> - + ToBytesGadget<ConstraintF> - + AllocGadget<P::Output, ConstraintF> +pub trait PRFGadget<P: PRF, F: Field> { + type OutputVar: EqGadget<F> + + ToBytesGadget<F> + + AllocVar<P::Output, F> + + R1CSVar<F, Value = P::Output> + Clone + Debug; - fn new_seed<CS: ConstraintSystem<ConstraintF>>(cs: CS, output: &P::Seed) -> Vec<UInt8>; + fn new_seed(cs: ConstraintSystemRef<F>, seed: &P::Seed) -> Vec<UInt8<F>>; - fn check_evaluation_gadget<CS: ConstraintSystem<ConstraintF>>( - cs: CS, - seed: &[UInt8], - input: &[UInt8], - ) -> Result<Self::OutputGadget, SynthesisError>; + fn evaluate(seed: &[UInt8<F>], input: &[UInt8<F>]) -> Result<Self::OutputVar, SynthesisError>; }
@@ -13,7 +13,7 @@ pub use self::blake2s::*;
pub trait PRF { type Input: FromBytes + Default; - type Output: ToBytes + Eq + Clone + Default + Hash; + type Output: ToBytes + Eq + Clone + Debug + Default + Hash; type Seed: FromBytes + ToBytes + Clone + Default + Debug; fn evaluate(seed: &Self::Seed, input: &Self::Input) -> Result<Self::Output, CryptoError>;
@@ -1,21 +1,20 @@
use algebra_core::Field; -use r1cs_core::{ConstraintSystem, SynthesisError}; +use r1cs_core::SynthesisError; use r1cs_std::prelude::*; use crate::signature::SignatureScheme; pub trait SigRandomizePkGadget<S: SignatureScheme, ConstraintF: Field> { - type ParametersGadget: AllocGadget<S::Parameters, ConstraintF> + Clone; + type ParametersVar: AllocVar<S::Parameters, ConstraintF> + Clone; - type PublicKeyGadget: ToBytesGadget<ConstraintF> + type PublicKeyVar: ToBytesGadget<ConstraintF> + EqGadget<ConstraintF> - + AllocGadget<S::PublicKey, ConstraintF> + + AllocVar<S::PublicKey, ConstraintF> + Clone; - fn check_randomization_gadget<CS: ConstraintSystem<ConstraintF>>( - cs: CS, - parameters: &Self::ParametersGadget, - public_key: &Self::PublicKeyGadget, - randomness: &[UInt8], - ) -> Result<Self::PublicKeyGadget, SynthesisError>; + fn randomize( + parameters: &Self::ParametersVar, + public_key: &Self::PublicKeyVar, + randomness: &[UInt8<ConstraintF>], + ) -> Result<Self::PublicKeyVar, SynthesisError>; }
@@ -52,9 +52,9 @@ }
#[cfg(test)] mod test { - use crate::{signature::schnorr::SchnorrSignature, SignatureScheme}; + use crate::signature::{schnorr, *}; use algebra::{ - ed_on_bls12_381::EdwardsAffine as JubJub, groups::Group, test_rng, to_bytes, ToBytes, + ed_on_bls12_381::EdwardsProjective as JubJub, groups::Group, test_rng, to_bytes, ToBytes, UniformRand, }; use blake2::Blake2s;@@ -90,13 +90,13 @@ #[test]
fn schnorr_signature_test() { let message = "Hi, I am a Schnorr signature!"; let rng = &mut test_rng(); - sign_and_verify::<SchnorrSignature<JubJub, Blake2s>>(message.as_bytes()); - failed_verification::<SchnorrSignature<JubJub, Blake2s>>( + sign_and_verify::<schnorr::Schnorr<JubJub, Blake2s>>(message.as_bytes()); + failed_verification::<schnorr::Schnorr<JubJub, Blake2s>>( message.as_bytes(), "Bad message".as_bytes(), ); let random_scalar = to_bytes!(<JubJub as Group>::ScalarField::rand(rng)).unwrap(); - randomize_and_verify::<SchnorrSignature<JubJub, Blake2s>>( + randomize_and_verify::<schnorr::Schnorr<JubJub, Blake2s>>( message.as_bytes(), &random_scalar.as_slice(), );
@@ -1,242 +1,157 @@
use crate::Vec; -use algebra_core::{groups::Group, Field}; -use r1cs_core::{ConstraintSystem, SynthesisError}; +use algebra_core::{Field, ProjectiveCurve}; +use r1cs_core::{Namespace, SynthesisError}; use r1cs_std::prelude::*; use crate::signature::SigRandomizePkGadget; use core::{borrow::Borrow, marker::PhantomData}; -use crate::signature::schnorr::{SchnorrPublicKey, SchnorrSigParameters, SchnorrSignature}; +use crate::signature::schnorr::{Parameters, PublicKey, Schnorr}; use digest::Digest; -pub struct SchnorrSigGadgetParameters<G: Group, ConstraintF: Field, GG: GroupGadget<G, ConstraintF>> -{ - generator: GG, - _group: PhantomData<*const G>, - _engine: PhantomData<*const ConstraintF>, -} +type ConstraintF<C> = <<C as ProjectiveCurve>::BaseField as Field>::BasePrimeField; -impl<G: Group, ConstraintF: Field, GG: GroupGadget<G, ConstraintF>> Clone - for SchnorrSigGadgetParameters<G, ConstraintF, GG> +#[derive(Clone)] +pub struct ParametersVar<C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>> +where + for<'a> &'a GC: GroupOpsBounds<'a, C, GC>, { - fn clone(&self) -> Self { - Self { - generator: self.generator.clone(), - _group: PhantomData, - _engine: PhantomData, - } - } + generator: GC, + _curve: PhantomData<C>, } #[derive(Derivative)] #[derivative( - Debug(bound = "G: Group, ConstraintF: Field, GG: GroupGadget<G, ConstraintF>"), - Clone(bound = "G: Group, ConstraintF: Field, GG: GroupGadget<G, ConstraintF>"), - PartialEq(bound = "G: Group, ConstraintF: Field, GG: GroupGadget<G, ConstraintF>"), - Eq(bound = "G: Group, ConstraintF: Field, GG: GroupGadget<G, ConstraintF>") + Debug(bound = "C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>"), + Clone(bound = "C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>") )] -pub struct SchnorrSigGadgetPk<G: Group, ConstraintF: Field, GG: GroupGadget<G, ConstraintF>> { - pub_key: GG, - #[doc(hidden)] - _group: PhantomData<*const G>, +pub struct PublicKeyVar<C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>> +where + for<'a> &'a GC: GroupOpsBounds<'a, C, GC>, +{ + pub_key: GC, #[doc(hidden)] - _engine: PhantomData<*const ConstraintF>, + _group: PhantomData<*const C>, } -pub struct SchnorrRandomizePkGadget<G: Group, ConstraintF: Field, GG: GroupGadget<G, ConstraintF>> { - #[doc(hidden)] - _group: PhantomData<*const G>, +pub struct SchnorrRandomizePkGadget<C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>> +where + for<'a> &'a GC: GroupOpsBounds<'a, C, GC>, +{ #[doc(hidden)] - _group_gadget: PhantomData<*const GG>, + _group: PhantomData<*const C>, #[doc(hidden)] - _engine: PhantomData<*const ConstraintF>, + _group_gadget: PhantomData<*const GC>, } -impl<G, GG, D, ConstraintF> SigRandomizePkGadget<SchnorrSignature<G, D>, ConstraintF> - for SchnorrRandomizePkGadget<G, ConstraintF, GG> +impl<C, GC, D> SigRandomizePkGadget<Schnorr<C, D>, ConstraintF<C>> + for SchnorrRandomizePkGadget<C, GC> where - G: Group, - GG: GroupGadget<G, ConstraintF>, + C: ProjectiveCurve, + GC: CurveVar<C, ConstraintF<C>>, D: Digest + Send + Sync, - ConstraintF: Field, + for<'a> &'a GC: GroupOpsBounds<'a, C, GC>, { - type ParametersGadget = SchnorrSigGadgetParameters<G, ConstraintF, GG>; - type PublicKeyGadget = SchnorrSigGadgetPk<G, ConstraintF, GG>; + type ParametersVar = ParametersVar<C, GC>; + type PublicKeyVar = PublicKeyVar<C, GC>; - fn check_randomization_gadget<CS: ConstraintSystem<ConstraintF>>( - mut cs: CS, - parameters: &Self::ParametersGadget, - public_key: &Self::PublicKeyGadget, - randomness: &[UInt8], - ) -> Result<Self::PublicKeyGadget, SynthesisError> { + fn randomize( + parameters: &Self::ParametersVar, + public_key: &Self::PublicKeyVar, + randomness: &[UInt8<ConstraintF<C>>], + ) -> Result<Self::PublicKeyVar, SynthesisError> { let base = parameters.generator.clone(); let randomness = randomness .iter() .flat_map(|b| b.into_bits_le()) .collect::<Vec<_>>(); - let rand_pk = base.mul_bits( - &mut cs.ns(|| "Compute Randomizer"), - &public_key.pub_key, - randomness.iter(), - )?; - Ok(SchnorrSigGadgetPk { + let rand_pk = &public_key.pub_key + &base.mul_bits(randomness.iter())?; + Ok(PublicKeyVar { pub_key: rand_pk, _group: PhantomData, - _engine: PhantomData, }) } } -impl<G, ConstraintF, GG, D> AllocGadget<SchnorrSigParameters<G, D>, ConstraintF> - for SchnorrSigGadgetParameters<G, ConstraintF, GG> +impl<C, GC, D> AllocVar<Parameters<C, D>, ConstraintF<C>> for ParametersVar<C, GC> where - G: Group, - ConstraintF: Field, - GG: GroupGadget<G, ConstraintF>, + C: ProjectiveCurve, + GC: CurveVar<C, ConstraintF<C>>, D: Digest, + for<'a> &'a GC: GroupOpsBounds<'a, C, GC>, { - fn alloc_constant<T, CS: ConstraintSystem<ConstraintF>>( - cs: CS, - val: T, - ) -> Result<Self, SynthesisError> - where - T: Borrow<SchnorrSigParameters<G, D>>, - { - let generator = GG::alloc_constant(cs, val.borrow().generator)?; - Ok(Self { - generator, - _engine: PhantomData, - _group: PhantomData, - }) - } - - fn alloc<F, T, CS: ConstraintSystem<ConstraintF>>(cs: CS, f: F) -> Result<Self, SynthesisError> - where - F: FnOnce() -> Result<T, SynthesisError>, - T: Borrow<SchnorrSigParameters<G, D>>, - { - let generator = GG::alloc_checked(cs, || f().map(|pp| pp.borrow().generator))?; + fn new_variable<T: Borrow<Parameters<C, D>>>( + cs: impl Into<Namespace<ConstraintF<C>>>, + f: impl FnOnce() -> Result<T, SynthesisError>, + mode: AllocationMode, + ) -> Result<Self, SynthesisError> { + let generator = GC::new_variable(cs, || f().map(|g| g.borrow().generator), mode)?; Ok(Self { generator, - _engine: PhantomData, - _group: PhantomData, - }) - } - - fn alloc_input<F, T, CS: ConstraintSystem<ConstraintF>>( - cs: CS, - f: F, - ) -> Result<Self, SynthesisError> - where - F: FnOnce() -> Result<T, SynthesisError>, - T: Borrow<SchnorrSigParameters<G, D>>, - { - let generator = GG::alloc_input(cs, || f().map(|pp| pp.borrow().generator))?; - Ok(Self { - generator, - _engine: PhantomData, - _group: PhantomData, + _curve: PhantomData, }) } } -impl<G, ConstraintF, GG> AllocGadget<SchnorrPublicKey<G>, ConstraintF> - for SchnorrSigGadgetPk<G, ConstraintF, GG> +impl<C, GC> AllocVar<PublicKey<C>, ConstraintF<C>> for PublicKeyVar<C, GC> where - G: Group, - ConstraintF: Field, - GG: GroupGadget<G, ConstraintF>, + C: ProjectiveCurve, + GC: CurveVar<C, ConstraintF<C>>, + for<'a> &'a GC: GroupOpsBounds<'a, C, GC>, { - fn alloc_constant<T, CS: ConstraintSystem<ConstraintF>>( - cs: CS, - val: T, - ) -> Result<Self, SynthesisError> - where - T: Borrow<SchnorrPublicKey<G>>, - { - let pub_key = GG::alloc_constant(cs, val.borrow())?; - Ok(Self { - pub_key, - _engine: PhantomData, - _group: PhantomData, - }) - } - - fn alloc<F, T, CS: ConstraintSystem<ConstraintF>>(cs: CS, f: F) -> Result<Self, SynthesisError> - where - F: FnOnce() -> Result<T, SynthesisError>, - T: Borrow<SchnorrPublicKey<G>>, - { - let pub_key = GG::alloc_input(cs, || f().map(|pk| *pk.borrow()))?; - Ok(Self { - pub_key, - _engine: PhantomData, - _group: PhantomData, - }) - } - - fn alloc_input<F, T, CS: ConstraintSystem<ConstraintF>>( - cs: CS, - f: F, - ) -> Result<Self, SynthesisError> - where - F: FnOnce() -> Result<T, SynthesisError>, - T: Borrow<SchnorrPublicKey<G>>, - { - let pub_key = GG::alloc_input(cs, || f().map(|pk| *pk.borrow()))?; + fn new_variable<T: Borrow<PublicKey<C>>>( + cs: impl Into<Namespace<ConstraintF<C>>>, + f: impl FnOnce() -> Result<T, SynthesisError>, + mode: AllocationMode, + ) -> Result<Self, SynthesisError> { + let pub_key = GC::new_variable(cs, f, mode)?; Ok(Self { pub_key, - _engine: PhantomData, _group: PhantomData, }) } } -impl<G, ConstraintF, GG> ConditionalEqGadget<ConstraintF> for SchnorrSigGadgetPk<G, ConstraintF, GG> +impl<C, GC> EqGadget<ConstraintF<C>> for PublicKeyVar<C, GC> where - G: Group, - ConstraintF: Field, - GG: GroupGadget<G, ConstraintF>, + C: ProjectiveCurve, + GC: CurveVar<C, ConstraintF<C>>, + for<'a> &'a GC: GroupOpsBounds<'a, C, GC>, { #[inline] - fn conditional_enforce_equal<CS: ConstraintSystem<ConstraintF>>( + fn is_eq(&self, other: &Self) -> Result<Boolean<ConstraintF<C>>, SynthesisError> { + self.pub_key.is_eq(&other.pub_key) + } + + #[inline] + fn conditional_enforce_equal( &self, - mut cs: CS, other: &Self, - condition: &Boolean, + condition: &Boolean<ConstraintF<C>>, ) -> Result<(), SynthesisError> { - self.pub_key.conditional_enforce_equal( - &mut cs.ns(|| "PubKey equality"), - &other.pub_key, - condition, - )?; - Ok(()) + self.pub_key + .conditional_enforce_equal(&other.pub_key, condition) } - fn cost() -> usize { - <GG as ConditionalEqGadget<ConstraintF>>::cost() + #[inline] + fn conditional_enforce_not_equal( + &self, + other: &Self, + condition: &Boolean<ConstraintF<C>>, + ) -> Result<(), SynthesisError> { + self.pub_key + .conditional_enforce_not_equal(&other.pub_key, condition) } } -impl<G, ConstraintF, GG> EqGadget<ConstraintF> for SchnorrSigGadgetPk<G, ConstraintF, GG> -where - G: Group, - ConstraintF: Field, - GG: GroupGadget<G, ConstraintF>, -{ -} - -impl<G, ConstraintF, GG> ToBytesGadget<ConstraintF> for SchnorrSigGadgetPk<G, ConstraintF, GG> +impl<C, GC> ToBytesGadget<ConstraintF<C>> for PublicKeyVar<C, GC> where - G: Group, - ConstraintF: Field, - GG: GroupGadget<G, ConstraintF>, + C: ProjectiveCurve, + GC: CurveVar<C, ConstraintF<C>>, + for<'a> &'a GC: GroupOpsBounds<'a, C, GC>, { - fn to_bytes<CS: ConstraintSystem<ConstraintF>>( - &self, - mut cs: CS, - ) -> Result<Vec<UInt8>, SynthesisError> { - self.pub_key.to_bytes(&mut cs.ns(|| "PubKey To Bytes")) + fn to_bytes(&self) -> Result<Vec<UInt8<ConstraintF<C>>>, SynthesisError> { + self.pub_key.to_bytes() } }
@@ -2,9 +2,8 @@ use crate::{Error, SignatureScheme, Vec};
use algebra_core::{ bytes::ToBytes, fields::{Field, PrimeField}, - groups::Group, io::{Result as IoResult, Write}, - to_bytes, One, ToConstraintField, UniformRand, Zero, + to_bytes, AffineCurve, One, ProjectiveCurve, ToConstraintField, UniformRand, Zero, }; use core::{hash::Hash, marker::PhantomData}; use digest::Digest;@@ -13,57 +12,55 @@
#[cfg(feature = "r1cs")] pub mod constraints; -pub struct SchnorrSignature<G: Group, D: Digest> { - _group: PhantomData<G>, +pub struct Schnorr<C: ProjectiveCurve, D: Digest> { + _group: PhantomData<C>, _hash: PhantomData<D>, } #[derive(Derivative)] -#[derivative(Clone(bound = "G: Group, H: Digest"))] -pub struct SchnorrSigParameters<G: Group, H: Digest> { +#[derivative(Clone(bound = "C: ProjectiveCurve, H: Digest"), Debug)] +pub struct Parameters<C: ProjectiveCurve, H: Digest> { _hash: PhantomData<H>, - pub generator: G, + pub generator: C::Affine, pub salt: [u8; 32], } -pub type SchnorrPublicKey<G> = G; +pub type PublicKey<C> = <C as ProjectiveCurve>::Affine; -#[derive(Derivative)] -#[derivative(Clone(bound = "G: Group"), Default(bound = "G: Group"))] -pub struct SchnorrSecretKey<G: Group>(pub G::ScalarField); +#[derive(Clone, Default, Debug)] +pub struct SecretKey<C: ProjectiveCurve>(pub C::ScalarField); -impl<G: Group> ToBytes for SchnorrSecretKey<G> { +impl<C: ProjectiveCurve> ToBytes for SecretKey<C> { #[inline] fn write<W: Write>(&self, writer: W) -> IoResult<()> { self.0.write(writer) } } -#[derive(Derivative)] -#[derivative(Clone(bound = "G: Group"), Default(bound = "G: Group"))] -pub struct SchnorrSig<G: Group> { - pub prover_response: G::ScalarField, - pub verifier_challenge: G::ScalarField, +#[derive(Clone, Default, Debug)] +pub struct Signature<C: ProjectiveCurve> { + pub prover_response: C::ScalarField, + pub verifier_challenge: C::ScalarField, } -impl<G: Group + Hash, D: Digest + Send + Sync> SignatureScheme for SchnorrSignature<G, D> +impl<C: ProjectiveCurve + Hash, D: Digest + Send + Sync> SignatureScheme for Schnorr<C, D> where - G::ScalarField: PrimeField, + C::ScalarField: PrimeField, { - type Parameters = SchnorrSigParameters<G, D>; - type PublicKey = G; - type SecretKey = SchnorrSecretKey<G>; - type Signature = SchnorrSig<G>; + type Parameters = Parameters<C, D>; + type PublicKey = PublicKey<C>; + type SecretKey = SecretKey<C>; + type Signature = Signature<C>; fn setup<R: Rng>(rng: &mut R) -> Result<Self::Parameters, Error> { let setup_time = start_timer!(|| "SchnorrSig::Setup"); let mut salt = [0u8; 32]; rng.fill_bytes(&mut salt); - let generator = G::rand(rng); + let generator = C::rand(rng).into(); end_timer!(setup_time); - Ok(SchnorrSigParameters { + Ok(Parameters { _hash: PhantomData, generator, salt,@@ -76,11 +73,11 @@ rng: &mut R,
) -> Result<(Self::PublicKey, Self::SecretKey), Error> { let keygen_time = start_timer!(|| "SchnorrSig::KeyGen"); - let secret_key = G::ScalarField::rand(rng); - let public_key = parameters.generator.mul(&secret_key); + let secret_key = C::ScalarField::rand(rng); + let public_key = parameters.generator.mul(secret_key).into(); end_timer!(keygen_time); - Ok((public_key, SchnorrSecretKey(secret_key))) + Ok((public_key, SecretKey(secret_key))) } fn sign<R: Rng>(@@ -93,10 +90,10 @@ let sign_time = start_timer!(|| "SchnorrSig::Sign");
// (k, e); let (random_scalar, verifier_challenge) = loop { // Sample a random scalar `k` from the prime scalar field. - let random_scalar: G::ScalarField = G::ScalarField::rand(rng); - // Commit to the random scalar via r := k · g. + let random_scalar: C::ScalarField = C::ScalarField::rand(rng); + // Commit to the random scalar via r := k · G. // This is the prover's first msg in the Sigma protocol. - let prover_commitment: G = parameters.generator.mul(&random_scalar); + let prover_commitment = parameters.generator.mul(random_scalar).into_affine(); // Hash everything to get verifier challenge. let mut hash_input = Vec::new();@@ -106,7 +103,7 @@ hash_input.extend_from_slice(message);
// Compute the supposed verifier response: e := H(salt || r || msg); if let Some(verifier_challenge) = - G::ScalarField::from_random_bytes(&D::digest(&hash_input)) + C::ScalarField::from_random_bytes(&D::digest(&hash_input)) { break (random_scalar, verifier_challenge); };@@ -114,7 +111,7 @@ };
// k - xe; let prover_response = random_scalar - &(verifier_challenge * &sk.0); - let signature = SchnorrSig { + let signature = Signature { prover_response, verifier_challenge, };@@ -131,13 +128,14 @@ signature: &Self::Signature,
) -> Result<bool, Error> { let verify_time = start_timer!(|| "SchnorrSig::Verify"); - let SchnorrSig { + let Signature { prover_response, verifier_challenge, } = signature; - let mut claimed_prover_commitment = parameters.generator.mul(prover_response); - let public_key_times_verifier_challenge = pk.mul(verifier_challenge); + let mut claimed_prover_commitment = parameters.generator.mul(*prover_response); + let public_key_times_verifier_challenge = pk.mul(*verifier_challenge); claimed_prover_commitment += &public_key_times_verifier_challenge; + let claimed_prover_commitment = claimed_prover_commitment.into_affine(); let mut hash_input = Vec::new(); hash_input.extend_from_slice(¶meters.salt);@@ -145,7 +143,7 @@ hash_input.extend_from_slice(&to_bytes![claimed_prover_commitment]?);
hash_input.extend_from_slice(&message); let obtained_verifier_challenge = if let Some(obtained_verifier_challenge) = - G::ScalarField::from_random_bytes(&D::digest(&hash_input)) + C::ScalarField::from_random_bytes(&D::digest(&hash_input)) { obtained_verifier_challenge } else {@@ -162,20 +160,26 @@ randomness: &[u8],
) -> Result<Self::PublicKey, Error> { let rand_pk_time = start_timer!(|| "SchnorrSig::RandomizePubKey"); - let mut randomized_pk = *public_key; - let mut base = parameters.generator; - let mut encoded = G::zero(); - for bit in bytes_to_bits(randomness) { + let randomized_pk = *public_key; + let base = parameters.generator; + let mut encoded = C::zero(); + let mut found_one = false; + for bit in bytes_to_bits(randomness).into_iter().rev() { + if found_one { + encoded.double_in_place(); + } else { + found_one |= bit; + } + if bit { - encoded += &base; + encoded.add_assign_mixed(&base) } - base.double_in_place(); } - randomized_pk += &encoded; + encoded.add_assign_mixed(&randomized_pk); end_timer!(rand_pk_time); - Ok(randomized_pk) + Ok(encoded.into()) } fn randomize_signature(@@ -184,12 +188,12 @@ signature: &Self::Signature,
randomness: &[u8], ) -> Result<Self::Signature, Error> { let rand_signature_time = start_timer!(|| "SchnorrSig::RandomizeSig"); - let SchnorrSig { + let Signature { prover_response, verifier_challenge, } = signature; - let mut base = G::ScalarField::one(); - let mut multiplier = G::ScalarField::zero(); + let mut base = C::ScalarField::one(); + let mut multiplier = C::ScalarField::zero(); for bit in bytes_to_bits(randomness) { if bit { multiplier += &base;@@ -197,7 +201,7 @@ }
base.double_in_place(); } - let new_sig = SchnorrSig { + let new_sig = Signature { prover_response: *prover_response - &(*verifier_challenge * &multiplier), verifier_challenge: *verifier_challenge, };@@ -217,11 +221,11 @@ }
bits } -impl<ConstraintF: Field, G: Group + ToConstraintField<ConstraintF>, D: Digest> - ToConstraintField<ConstraintF> for SchnorrSigParameters<G, D> +impl<ConstraintF: Field, C: ProjectiveCurve + ToConstraintField<ConstraintF>, D: Digest> + ToConstraintField<ConstraintF> for Parameters<C, D> { #[inline] fn to_field_elements(&self) -> Result<Vec<ConstraintF>, Error> { - self.generator.to_field_elements() + self.generator.into_projective().to_field_elements() } }