From 3bb3697c130603348cc32b0640160140348177f3 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Mon, 24 Aug 2020 00:50:08 -0700 Subject: [PATCH] Update `crypto-primitives` and their contraints. --- cp-benches/Cargo.toml | 8 +- cp-benches/benches/crypto_primitives/comm.rs | 16 +- cp-benches/benches/crypto_primitives/crh.rs | 8 +- cp-benches/benches/crypto_primitives/nizk.rs | 121 --- .../benches/crypto_primitives/signature.rs | 243 ++--- crypto-primitives/Cargo.toml | 4 +- .../src/commitment/blake2s/constraints.rs | 205 ++-- .../src/commitment/blake2s/mod.rs | 8 +- .../src/commitment/constraints.rs | 24 +- .../commitment/injective_map/constraints.rs | 79 +- .../src/commitment/injective_map/mod.rs | 25 +- .../src/commitment/pedersen/constraints.rs | 266 ++--- .../src/commitment/pedersen/mod.rs | 64 +- .../src/crh/bowe_hopwood/constraints.rs | 189 ++-- crypto-primitives/src/crh/bowe_hopwood/mod.rs | 67 +- crypto-primitives/src/crh/constraints.rs | 20 +- .../src/crh/injective_map/constraints.rs | 137 +-- .../src/crh/injective_map/mod.rs | 51 +- crypto-primitives/src/crh/mod.rs | 3 +- .../src/crh/pedersen/constraints.rs | 201 ++-- crypto-primitives/src/crh/pedersen/mod.rs | 44 +- crypto-primitives/src/lib.rs | 8 +- .../src/merkle_tree/constraints.rs | 252 ++--- crypto-primitives/src/merkle_tree/mod.rs | 90 +- crypto-primitives/src/nizk/constraints.rs | 84 +- .../src/nizk/gm17/constraints.rs | 938 +++++++----------- .../src/nizk/groth16/constraints.rs | 834 ++++++---------- crypto-primitives/src/nizk/mod.rs | 26 +- .../src/prf/blake2s/constraints.rs | 456 +++------ crypto-primitives/src/prf/constraints.rs | 19 +- crypto-primitives/src/prf/mod.rs | 2 +- .../src/signature/constraints.rs | 19 +- crypto-primitives/src/signature/mod.rs | 10 +- .../src/signature/schnorr/constraints.rs | 259 ++--- .../src/signature/schnorr/mod.rs | 108 +- 35 files changed, 1771 insertions(+), 3117 deletions(-) delete mode 100644 cp-benches/benches/crypto_primitives/nizk.rs diff --git a/cp-benches/Cargo.toml b/cp-benches/Cargo.toml index ddf788c..556a7e9 100644 --- a/cp-benches/Cargo.toml +++ b/cp-benches/Cargo.toml @@ -49,10 +49,4 @@ harness = false [[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 \ No newline at end of file diff --git a/cp-benches/benches/crypto_primitives/comm.rs b/cp-benches/benches/crypto_primitives/comm.rs index 3132656..c94d53a 100644 --- a/cp-benches/benches/crypto_primitives/comm.rs +++ b/cp-benches/benches/crypto_primitives/comm.rs @@ -10,7 +10,7 @@ use crypto_primitives::commitment::{pedersen::*, CommitmentScheme}; #[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::::setup(&mut rng).unwrap() + Commitment::::setup(&mut rng).unwrap() }) }); } fn pedersen_comm_eval(c: &mut Criterion) { let mut rng = &mut rand::thread_rng(); - let parameters = PedersenCommitment::::setup(&mut rng).unwrap(); + let parameters = Commitment::::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::::commit( - ¶meters, - &input, - &commitment_randomness, - ) - .unwrap(); + let commitment_randomness = Randomness::rand(rng); + Commitment::::commit(¶meters, &input, &commitment_randomness) + .unwrap(); }) }); } diff --git a/cp-benches/benches/crypto_primitives/crh.rs b/cp-benches/benches/crypto_primitives/crh.rs index 97628c9..975e42b 100644 --- a/cp-benches/benches/crypto_primitives/crh.rs +++ b/cp-benches/benches/crypto_primitives/crh.rs @@ -10,7 +10,7 @@ use crypto_primitives::crh::{pedersen::*, FixedLengthCRH}; #[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::::setup(&mut rng).unwrap() + CRH::::setup(&mut rng).unwrap() }) }); } fn pedersen_crh_eval(c: &mut Criterion) { let mut rng = &mut rand::thread_rng(); - let parameters = PedersenCRH::::setup(&mut rng).unwrap(); + let parameters = CRH::::setup(&mut rng).unwrap(); let input = vec![5u8; 128]; c.bench_function("Pedersen CRH Eval", move |b| { b.iter(|| { - PedersenCRH::::evaluate(¶meters, &input).unwrap(); + CRH::::evaluate(¶meters, &input).unwrap(); }) }); } diff --git a/cp-benches/benches/crypto_primitives/nizk.rs b/cp-benches/benches/crypto_primitives/nizk.rs deleted file mode 100644 index 991a405..0000000 --- a/cp-benches/benches/crypto_primitives/nizk.rs +++ /dev/null @@ -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, Fr>; - -struct Bench { - inputs: Vec>, - num_constraints: usize, -} - -impl ConstraintSynthesizer for Bench { - fn generate_constraints>( - 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> = 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:: { - 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> = Vec::with_capacity(num_inputs); - for _ in 0..num_inputs { - inputs.push(Some(rng.gen())); - } - - let params = TestProofSystem::setup( - Bench:: { - 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); diff --git a/cp-benches/benches/crypto_primitives/signature.rs b/cp-benches/benches/crypto_primitives/signature.rs index 4096194..b53d4bc 100644 --- a/cp-benches/benches/crypto_primitives/signature.rs +++ b/cp-benches/benches/crypto_primitives/signature.rs @@ -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}; - - type SchnorrEdwards = SchnorrSignature; - 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() - }) - }); - } - - 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() - }) - }); - } - - 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() - }) - }); - } - - 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()) - }); - } - - 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()) - }); - } - - 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 - } +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 = Schnorr; +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() + }) + }); } -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; - 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]; +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: Sign", move |b| { - b.iter(|| { - let mut rng = &mut rand::thread_rng(); - SchnorrEdwards::sign(¶meters, &sk, &message, &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_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_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("SchnorrEdwards: Sign", move |b| { + b.iter(|| { + let mut rng = &mut rand::thread_rng(); + 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_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_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("SchnorrEdwards: Verify", move |b| { + b.iter(|| SchnorrEdwards::verify(¶meters, &pk, &message, &signature).unwrap()) + }); +} - c.bench_function("SchnorrEdwardsProjective: Randomize PubKey", move |b| { - b.iter(|| SchnorrEdwards::randomize_public_key(¶meters, &pk, &randomness).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_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("SchnorrEdwards: Randomize PubKey", move |b| { + b.iter(|| SchnorrEdwards::randomize_public_key(¶meters, &pk, &randomness).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 - } +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("SchnorrEdwards: Randomize Signature", move |b| { + b.iter(|| { + SchnorrEdwards::randomize_signature(¶meters, &signature, &randomness).unwrap() + }) + }); +} +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); diff --git a/crypto-primitives/Cargo.toml b/crypto-primitives/Cargo.toml index 6014326..08ee900 100644 --- a/crypto-primitives/Cargo.toml +++ b/crypto-primitives/Cargo.toml @@ -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] diff --git a/crypto-primitives/src/commitment/blake2s/constraints.rs b/crypto-primitives/src/commitment/blake2s/constraints.rs index 81c078d..9305e1b 100644 --- a/crypto-primitives/src/commitment/blake2s/constraints.rs +++ b/crypto-primitives/src/commitment/blake2s/constraints.rs @@ -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 r1cs_std::prelude::*; use core::borrow::Borrow; #[derive(Clone)] -pub struct Blake2sParametersGadget; +pub struct ParametersVar; #[derive(Clone)] -pub struct Blake2sRandomnessGadget(pub Vec); - -pub struct Blake2sCommitmentGadget; - -impl CommitmentGadget - for Blake2sCommitmentGadget -{ - type OutputGadget = Blake2sOutputGadget; - type ParametersGadget = Blake2sParametersGadget; - type RandomnessGadget = Blake2sRandomnessGadget; - - fn check_commitment_gadget>( - mut cs: CS, - _: &Self::ParametersGadget, - input: &[UInt8], - r: &Self::RandomnessGadget, - ) -> Result { +pub struct RandomnessVar(pub Vec>); + +pub struct CommGadget; + +impl CommitmentGadget for CommGadget { + type OutputVar = OutputVar; + type ParametersVar = ParametersVar; + type RandomnessVar = RandomnessVar; + + fn commit( + _: &Self::ParametersVar, + input: &[UInt8], + r: &Self::RandomnessVar, + ) -> Result { 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 AllocGadget<(), ConstraintF> for Blake2sParametersGadget { - fn alloc_constant>( - cs: CS, - val: T, - ) -> Result - where - T: Borrow<()>, - { - Self::alloc(cs, || Ok(val)) - } - - fn alloc>(_: CS, _: F) -> Result - where - F: FnOnce() -> Result, - T: Borrow<()>, - { - Ok(Blake2sParametersGadget) - } - - fn alloc_input>( - _: CS, - _: F, - ) -> Result - where - F: FnOnce() -> Result, - T: Borrow<()>, - { - Ok(Blake2sParametersGadget) +impl AllocVar<(), ConstraintF> for ParametersVar { + fn new_variable>( + _cs: impl Into>, + _f: impl FnOnce() -> Result, + _mode: AllocationMode, + ) -> Result { + Ok(ParametersVar) } } -impl AllocGadget<[u8; 32], ConstraintF> for Blake2sRandomnessGadget { - #[inline] - fn alloc_constant>( - mut cs: CS, - val: T, - ) -> Result - 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 AllocVar<[u8; 32], ConstraintF> for RandomnessVar { + fn new_variable>( + cs: impl Into>, + f: impl FnOnce() -> Result, + mode: AllocationMode, + ) -> Result { + 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>( - cs: CS, - value_gen: F, - ) -> Result - where - F: FnOnce() -> Result, - T: Borrow<[u8; 32]>, - { - let zeros = [0u8; 32]; - let value = match value_gen() { - Ok(val) => *(val.borrow()), - Err(_) => zeros, - }; - let bytes = ::alloc_vec(cs, &value)?; - - Ok(Blake2sRandomnessGadget(bytes)) - } - - #[inline] - fn alloc_input>( - cs: CS, - value_gen: F, - ) -> Result - where - F: FnOnce() -> Result, - T: Borrow<[u8; 32]>, - { - let zeros = [0u8; 32]; - let value = match value_gen() { - Ok(val) => *(val.borrow()), - Err(_) => zeros, - }; - let bytes = ::alloc_input_vec(cs, &value)?; - - Ok(Blake2sRandomnessGadget(bytes)) } } @@ -138,64 +71,60 @@ impl AllocGadget<[u8; 32], ConstraintF> for Blake2sRand 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::::new(); + let cs = ConstraintSystem::::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 = - >::ParametersGadget::alloc( - &mut cs.ns(|| "gadget_parameters"), + let parameters_var = + >::ParametersVar::new_witness( + cs.ns("gadget_parameters"), || Ok(¶meters), ) .unwrap(); - let gadget_result = - >::check_commitment_gadget( - &mut cs.ns(|| "gadget_evaluation"), - &gadget_parameters, - &input_bytes, - &randomness_bytes, - ) - .unwrap(); + let result_var = >::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()); } } diff --git a/crypto-primitives/src/commitment/blake2s/mod.rs b/crypto-primitives/src/commitment/blake2s/mod.rs index 0b8104c..06b5b3c 100644 --- a/crypto-primitives/src/commitment/blake2s/mod.rs +++ b/crypto-primitives/src/commitment/blake2s/mod.rs @@ -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 @@ impl CommitmentScheme for Blake2sCommitment { fn commit( _: &Self::Parameters, input: &[u8], - randomness: &Self::Randomness, + r: &Self::Randomness, ) -> Result { 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) diff --git a/crypto-primitives/src/commitment/constraints.rs b/crypto-primitives/src/commitment/constraints.rs index c6a897d..981f9f9 100644 --- a/crypto-primitives/src/commitment/constraints.rs +++ b/crypto-primitives/src/commitment/constraints.rs @@ -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 { - type OutputGadget: EqGadget + type OutputVar: EqGadget + ToBytesGadget - + AllocGadget + + AllocVar + + R1CSVar + Clone + Sized + Debug; - type ParametersGadget: AllocGadget + Clone; - type RandomnessGadget: AllocGadget + Clone; + type ParametersVar: AllocVar + Clone; + type RandomnessVar: AllocVar + Clone; - fn check_commitment_gadget>( - cs: CS, - parameters: &Self::ParametersGadget, - input: &[UInt8], - r: &Self::RandomnessGadget, - ) -> Result; + fn commit( + parameters: &Self::ParametersVar, + input: &[UInt8], + r: &Self::RandomnessVar, + ) -> Result; } diff --git a/crypto-primitives/src/commitment/injective_map/constraints.rs b/crypto-primitives/src/commitment/injective_map/constraints.rs index 2afe0bc..9961b68 100644 --- a/crypto-primitives/src/commitment/injective_map/constraints.rs +++ b/crypto-primitives/src/commitment/injective_map/constraints.rs @@ -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 +type ConstraintF = <::BaseField as Field>::BasePrimeField; + +pub struct CommitmentCompressorGadget where - G: Group, - I: InjectiveMap, - ConstraintF: Field, - GG: GroupGadget, - IG: InjectiveMapGadget, + C: ProjectiveCurve, + I: InjectiveMap, + W: Window, + GG: CurveVar>, + IG: InjectiveMapGadget, + for<'a> &'a GG: GroupOpsBounds<'a, C, GG>, { _compressor: PhantomData, _compressor_gadget: PhantomData, - _crh: PedersenCommitmentGadget, + _comm: PhantomData>, } -impl CommitmentGadget, ConstraintF> - for PedersenCommitmentCompressorGadget +impl + crate::commitment::CommitmentGadget, ConstraintF> + for CommitmentCompressorGadget where - G: Group, - I: InjectiveMap, - ConstraintF: PrimeField, - GG: GroupGadget, - IG: InjectiveMapGadget, - W: PedersenWindow, + C: ProjectiveCurve, + I: InjectiveMap, + GG: CurveVar>, + ConstraintF: PrimeField, + IG: InjectiveMapGadget, + W: Window, + for<'a> &'a GG: GroupOpsBounds<'a, C, GG>, { - type OutputGadget = IG::OutputGadget; - type ParametersGadget = PedersenCommitmentGadgetParameters; - type RandomnessGadget = PedersenRandomnessGadget; + type OutputVar = IG::OutputVar; + type ParametersVar = ParametersVar; + type RandomnessVar = RandomnessVar>; - fn check_commitment_gadget>( - mut cs: CS, - parameters: &Self::ParametersGadget, - input: &[UInt8], - r: &Self::RandomnessGadget, - ) -> Result { - let result = PedersenCommitmentGadget::::check_commitment_gadget( - cs.ns(|| "PedersenComm"), - parameters, - input, - r, - )?; - IG::evaluate_map(cs.ns(|| "InjectiveMap"), &result) + fn commit( + parameters: &Self::ParametersVar, + input: &[UInt8>], + r: &Self::RandomnessVar, + ) -> Result { + let result = CommGadget::::commit(parameters, input, r)?; + IG::evaluate(&result) } } diff --git a/crypto-primitives/src/commitment/injective_map/mod.rs b/crypto-primitives/src/commitment/injective_map/mod.rs index cbb41c5..8a69b43 100644 --- a/crypto-primitives/src/commitment/injective_map/mod.rs +++ b/crypto-primitives/src/commitment/injective_map/mod.rs @@ -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, W: PedersenWindow> { - _group: PhantomData, +pub struct PedersenCommCompressor, W: pedersen::Window> { + _group: PhantomData, _compressor: PhantomData, - _comm: PedersenCommitment, + _comm: pedersen::Commitment, } -impl, W: PedersenWindow> CommitmentScheme - for PedersenCommCompressor +impl, W: pedersen::Window> CommitmentScheme + for PedersenCommCompressor { type Output = I::Output; - type Parameters = PedersenParameters; - type Randomness = PedersenRandomness; + type Parameters = pedersen::Parameters; + type Randomness = pedersen::Randomness; fn setup(rng: &mut R) -> Result { let time = start_timer!(|| format!("PedersenCompressor::Setup")); - let params = PedersenCommitment::::setup(rng); + let params = pedersen::Commitment::::setup(rng); end_timer!(time); params } @@ -38,7 +35,7 @@ impl, W: PedersenWindow> CommitmentScheme randomness: &Self::Randomness, ) -> Result { let eval_time = start_timer!(|| "PedersenCompressor::Eval"); - let result = I::injective_map(&PedersenCommitment::::commit( + let result = I::injective_map(&pedersen::Commitment::::commit( parameters, input, randomness, )?)?; end_timer!(eval_time); diff --git a/crypto-primitives/src/commitment/pedersen/constraints.rs b/crypto-primitives/src/commitment/pedersen/constraints.rs index b0ef499..5bff1b4 100644 --- a/crypto-primitives/src/commitment/pedersen/constraints.rs +++ b/crypto-primitives/src/commitment/pedersen/constraints.rs @@ -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 = <::BaseField as Field>::BasePrimeField; + #[derive(Derivative)] -#[derivative(Clone(bound = "G: Group, W: PedersenWindow, ConstraintF: Field"))] -pub struct PedersenCommitmentGadgetParameters { - params: PedersenParameters, - #[doc(hidden)] - _group: PhantomData, - #[doc(hidden)] - _engine: PhantomData, +#[derivative(Clone(bound = "C: ProjectiveCurve, GG: CurveVar>"))] +pub struct ParametersVar>> +where + for<'a> &'a GG: GroupOpsBounds<'a, C, GG>, +{ + params: Parameters, #[doc(hidden)] - _window: PhantomData, + _group_var: PhantomData, } #[derive(Clone, Debug)] -pub struct PedersenRandomnessGadget(Vec); - -pub struct PedersenCommitmentGadget>( - #[doc(hidden)] PhantomData<*const G>, - #[doc(hidden)] PhantomData<*const GG>, - PhantomData, -); +pub struct RandomnessVar(Vec>); -impl CommitmentGadget, ConstraintF> - for PedersenCommitmentGadget +pub struct CommGadget>, W: Window> where - ConstraintF: PrimeField, - G: Group, - GG: GroupGadget, - W: PedersenWindow, + for<'a> &'a GG: GroupOpsBounds<'a, C, GG>, { - type OutputGadget = GG; - type ParametersGadget = PedersenCommitmentGadgetParameters; - type RandomnessGadget = PedersenRandomnessGadget; + #[doc(hidden)] + _curve: PhantomData<*const C>, + #[doc(hidden)] + _group_var: PhantomData<*const GG>, + #[doc(hidden)] + _window: PhantomData<*const W>, +} - fn check_commitment_gadget>( - mut cs: CS, - parameters: &Self::ParametersGadget, - input: &[UInt8], - r: &Self::RandomnessGadget, - ) -> Result { +impl crate::commitment::CommitmentGadget, ConstraintF> + for CommGadget +where + C: ProjectiveCurve, + GG: CurveVar>, + W: Window, + for<'a> &'a GG: GroupOpsBounds<'a, C, GG>, + ConstraintF: PrimeField, +{ + type OutputVar = GG; + type ParametersVar = ParametersVar; + type RandomnessVar = RandomnessVar>; + + fn commit( + parameters: &Self::ParametersVar, + input: &[UInt8>], + r: &Self::RandomnessVar, + ) -> Result { assert!((input.len() * 8) <= (W::WINDOW_SIZE * W::NUM_WINDOWS)); let mut padded_input = input.to_vec(); @@ -72,16 +78,12 @@ where .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 @@ where } } -impl AllocGadget, ConstraintF> - for PedersenCommitmentGadgetParameters +impl AllocVar, ConstraintF> for ParametersVar where - G: Group, - W: PedersenWindow, - ConstraintF: PrimeField, + C: ProjectiveCurve, + GG: CurveVar>, + for<'a> &'a GG: GroupOpsBounds<'a, C, GG>, { - fn alloc_constant>( - _cs: CS, - val: T, - ) -> Result - where - T: Borrow>, - { - let parameters = val.borrow().clone(); - - Ok(PedersenCommitmentGadgetParameters { - params: parameters, - _group: PhantomData, - _engine: PhantomData, - _window: PhantomData, - }) - } - - fn alloc>( - cs: CS, - value_gen: F, - ) -> Result - where - F: FnOnce() -> Result, - T: Borrow>, - { - let temp = value_gen()?; - Self::alloc_constant(cs, temp) - } - - fn alloc_input>( - _cs: CS, - value_gen: F, - ) -> Result - where - F: FnOnce() -> Result, - T: Borrow>, - { - let temp = value_gen()?; - let parameters = temp.borrow().clone(); - - Ok(PedersenCommitmentGadgetParameters { - params: parameters, - _group: PhantomData, - _engine: PhantomData, - _window: PhantomData, + fn new_variable>>( + _cs: impl Into>>, + f: impl FnOnce() -> Result, + _mode: AllocationMode, + ) -> Result { + let params = f()?.borrow().clone(); + Ok(ParametersVar { + params, + _group_var: PhantomData, }) } } -impl AllocGadget, ConstraintF> for PedersenRandomnessGadget +impl AllocVar, F> for RandomnessVar where - G: Group, - ConstraintF: PrimeField, + C: ProjectiveCurve, + F: PrimeField, { - fn alloc_constant>( - mut cs: CS, - val: T, - ) -> Result - where - T: Borrow>, - { - 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>>( + cs: impl Into>, + f: impl FnOnce() -> Result, + mode: AllocationMode, + ) -> Result { + 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>( - cs: CS, - value_gen: F, - ) -> Result - where - F: FnOnce() -> Result, - T: Borrow>, - { - let temp = value_gen()?; - let randomness = to_bytes![temp.borrow().0].unwrap(); - Ok(PedersenRandomnessGadget(UInt8::alloc_vec(cs, &randomness)?)) - } - - fn alloc_input>( - cs: CS, - value_gen: F, - ) -> Result - where - F: FnOnce() -> Result, - T: Borrow>, - { - let temp = value_gen()?; - let randomness = to_bytes![temp.borrow().0].unwrap(); - Ok(PedersenRandomnessGadget(UInt8::alloc_input_vec( - cs, - &randomness, - )?)) } } @@ -201,31 +135,27 @@ where 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::::new(); + let cs = ConstraintSystem::::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 @@ mod test { let rng = &mut test_rng(); - type TestCOMM = PedersenCommitment; - type TestCOMMGadget = PedersenCommitmentGadget; + type TestCOMM = Commitment; + type TestCOMMGadget = CommGadget; - let randomness = PedersenRandomness(Fr::rand(rng)); + let randomness = Randomness(Fr::rand(rng)); - let parameters = PedersenCommitment::::setup(rng).unwrap(); + let parameters = Commitment::::setup(rng).unwrap(); let primitive_result = - PedersenCommitment::::commit(¶meters, &input, &randomness).unwrap(); + 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 input_byte in input.iter() { + input_var.push(UInt8::new_witness(cs.clone(), || Ok(*input_byte)).unwrap()); } - let randomness = - >::RandomnessGadget::alloc( - &mut cs.ns(|| "gadget_randomness"), + let randomness_var = + >::RandomnessVar::new_witness( + cs.ns("gadget_randomness"), || Ok(&randomness), ) .unwrap(); - let gadget_parameters = - >::ParametersGadget::alloc( - &mut cs.ns(|| "gadget_parameters"), + let parameters_var = + >::ParametersVar::new_witness( + cs.ns("gadget_parameters"), || Ok(¶meters), ) .unwrap(); - let gadget_result = - >::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()); } } diff --git a/crypto-primitives/src/commitment/pedersen/mod.rs b/crypto-primitives/src/commitment/pedersen/mod.rs index 369c19b..a668eb9 100644 --- a/crypto-primitives/src/commitment/pedersen/mod.rs +++ b/crypto-primitives/src/commitment/pedersen/mod.rs @@ -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 { - pub randomness_generator: Vec, - pub generators: Vec>, +pub struct Parameters { + pub randomness_generator: Vec, + pub generators: Vec>, } -pub struct PedersenCommitment { - group: PhantomData, +pub struct Commitment { + group: PhantomData, window: PhantomData, } #[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(pub G::ScalarField); - -impl UniformRand for PedersenRandomness { +#[derivative(Clone, PartialEq, Debug, Eq, Default)] +pub struct Randomness(pub C::ScalarField); + +impl UniformRand for Randomness { #[inline] fn rand(rng: &mut R) -> Self { - PedersenRandomness(UniformRand::rand(rng)) + Randomness(UniformRand::rand(rng)) } } -impl ToBytes for PedersenRandomness { +impl ToBytes for Randomness { fn write(&self, writer: W) -> IoResult<()> { self.0.write(writer) } } -impl CommitmentScheme for PedersenCommitment { - type Parameters = PedersenParameters; - type Randomness = PedersenRandomness; - type Output = G; +impl CommitmentScheme for Commitment { + type Parameters = Parameters; + type Randomness = Randomness; + type Output = C::Affine; fn setup(rng: &mut R) -> Result { 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 = ::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 = ::Params::MODULUS_BITS as usize; + let randomness_generator = pedersen::CRH::::generator_powers(num_powers, rng); + let generators = pedersen::CRH::::create_generators(rng); end_timer!(time); Ok(Self::Parameters { @@ -102,10 +92,10 @@ impl CommitmentScheme for PedersenCommitment // 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::::evaluate(&crh_parameters, &input)?.into(); let randomize_time = start_timer!(|| "Randomize"); // Compute h^r. @@ -122,12 +112,12 @@ impl CommitmentScheme for PedersenCommitment end_timer!(randomize_time); end_timer!(commit_time); - Ok(result) + Ok(result.into()) } } -impl> ToConstraintField - for PedersenParameters +impl> + ToConstraintField for Parameters { #[inline] fn to_field_elements(&self) -> Result, Error> { diff --git a/crypto-primitives/src/crh/bowe_hopwood/constraints.rs b/crypto-primitives/src/crh/bowe_hopwood/constraints.rs index 62a4c81..d1309bb 100644 --- a/crypto-primitives/src/crh/bowe_hopwood/constraints.rs +++ b/crypto-primitives/src/crh/bowe_hopwood/constraints.rs @@ -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

= <

::BaseField as Field>::BasePrimeField; + #[derive(Derivative)] -#[derivative(Clone( - bound = "G: Group, W: PedersenWindow, ConstraintF: Field, GG: GroupGadget" -))] -pub struct BoweHopwoodPedersenCRHGadgetParameters< - G: Group, - W: PedersenWindow, - ConstraintF: Field, - GG: GroupGadget, -> { - params: BoweHopwoodPedersenParameters, - _group_g: PhantomData, - _engine: PhantomData, +#[derivative(Clone(bound = "P: TEModelParameters, W: Window"))] +pub struct ParametersVar { + params: Parameters

, + #[doc(hidden)] _window: PhantomData, } -pub struct BoweHopwoodPedersenCRHGadget< - G: Group, - ConstraintF: Field, - GG: GroupGadget, -> { - _group: PhantomData<*const G>, - _group_gadget: PhantomData<*const GG>, - _engine: PhantomData, +pub struct CRHGadget>> +where + for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, +{ + #[doc(hidden)] + _params: PhantomData

, + #[doc(hidden)] + _base_field: PhantomData, } -impl FixedLengthCRHGadget, ConstraintF> - for BoweHopwoodPedersenCRHGadget +impl FixedLengthCRHGadget, ConstraintF

> for CRHGadget where - ConstraintF: Field, - G: Group + Hash, - GG: GroupGadget, - W: PedersenWindow, + for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, + F: FieldVar>, + F: TwoBitLookupGadget, TableConstant = P::BaseField> + + ThreeBitCondNegLookupGadget, TableConstant = P::BaseField>, + P: TEModelParameters, + W: Window, { - type OutputGadget = GG; - type ParametersGadget = BoweHopwoodPedersenCRHGadgetParameters; - - fn check_evaluation_gadget>( - cs: CS, - parameters: &Self::ParametersGadget, - input: &[UInt8], - ) -> Result { + type OutputVar = AffineVar; + type ParametersVar = ParametersVar; + + fn evaluate( + parameters: &Self::ParametersVar, + input: &[UInt8>], + ) -> Result { // 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 @@ where .chunks(W::WINDOW_SIZE * CHUNK_SIZE) .map(|x| x.chunks(CHUNK_SIZE).collect::>()) .collect::>(); - 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 @@ where } } -impl> - AllocGadget, ConstraintF> - for BoweHopwoodPedersenCRHGadgetParameters +impl AllocVar, ConstraintF

> for ParametersVar +where + P: TEModelParameters, + W: Window, { - fn alloc_constant>( - _cs: CS, - val: T, - ) -> Result - where - T: Borrow>, - { - let params = val.borrow().clone(); - Ok(BoweHopwoodPedersenCRHGadgetParameters { + fn new_variable>>( + _cs: impl Into>>, + f: impl FnOnce() -> Result, + _mode: AllocationMode, + ) -> Result { + let params = f()?.borrow().clone(); + Ok(ParametersVar { params, - _group_g: PhantomData, - _engine: PhantomData, - _window: PhantomData, - }) - } - - fn alloc>( - cs: CS, - value_gen: F, - ) -> Result - where - F: FnOnce() -> Result, - T: Borrow>, - { - let params = value_gen()?.borrow().clone(); - Self::alloc_constant(cs, params) - } - - fn alloc_input>( - _cs: CS, - value_gen: F, - ) -> Result - where - F: FnOnce() -> Result, - T: Borrow>, - { - 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; - type TestCRHGadget = BoweHopwoodPedersenCRHGadget; + type TestCRH = CRH; + type TestCRHGadget = CRHGadget; #[derive(Clone, PartialEq, Eq, Hash)] pub(super) struct Window; @@ -165,35 +128,34 @@ mod test { const NUM_WINDOWS: usize = 8; } - fn generate_input, R: Rng>( - mut cs: CS, + fn generate_input( + cs: ConstraintSystemRef, rng: &mut R, - ) -> ([u8; 189], Vec) { + ) -> ([u8; 189], Vec>) { 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::::new(); + let cs = ConstraintSystem::::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 = - >::ParametersGadget::alloc( - &mut cs.ns(|| "gadget_parameters"), + let parameters_var = + >::ParametersVar::new_witness( + cs.ns("parameters_var"), || Ok(¶meters), ) .unwrap(); @@ -202,19 +164,12 @@ mod test { cs.num_constraints() ); - let gadget_result = - >::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()); } } diff --git a/crypto-primitives/src/crh/bowe_hopwood/mod.rs b/crypto-primitives/src/crh/bowe_hopwood/mod.rs index 4d84efa..e3417eb 100644 --- a/crypto-primitives/src/crh/bowe_hopwood/mod.rs +++ b/crypto-primitives/src/crh/bowe_hopwood/mod.rs @@ -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 { - pub generators: Vec>, +#[derive(Derivative)] +#[derivative(Clone(bound = ""), Default(bound = ""))] +pub struct Parameters { + pub generators: Vec>>, } -pub struct BoweHopwoodPedersenCRH { - group: PhantomData, +pub struct CRH { + group: PhantomData

, window: PhantomData, } -impl BoweHopwoodPedersenCRH { - pub fn create_generators(rng: &mut R) -> Vec> { +impl CRH { + pub fn create_generators(rng: &mut R) -> Vec>> { 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 @@ impl BoweHopwoodPedersenCRH { } } -impl FixedLengthCRH for BoweHopwoodPedersenCRH { - const INPUT_SIZE_BITS: usize = PedersenCRH::::INPUT_SIZE_BITS; - type Output = G; - type Parameters = BoweHopwoodPedersenParameters; +impl FixedLengthCRH for CRH { + const INPUT_SIZE_BITS: usize = pedersen::CRH::, W>::INPUT_SIZE_BITS; + type Output = TEProjective

; + type Parameters = Parameters

; fn setup(rng: &mut R) -> Result { fn calculate_num_chunks_in_segment() -> usize { @@ -63,10 +67,10 @@ impl FixedLengthCRH for BoweHopwoodPedersenCRH(); + let maximum_num_chunks_in_segment = calculate_num_chunks_in_segment::(); 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 @@ impl FixedLengthCRH for BoweHopwoodPedersenCRH 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 @@ impl FixedLengthCRH for BoweHopwoodPedersenCRH FixedLengthCRH for BoweHopwoodPedersenCRH() + .sum::>() }) - .sum::(); + .sum::>(); end_timer!(eval_time); @@ -157,9 +161,9 @@ impl FixedLengthCRH for BoweHopwoodPedersenCRH Debug for BoweHopwoodPedersenParameters { +impl Debug for Parameters

{ 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 @@ impl Debug for BoweHopwoodPedersenParameters { #[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 = - as FixedLengthCRH>::setup(rng) - .unwrap(); - as FixedLengthCRH>::evaluate( - ¶ms, - &[1, 2, 3], - ) - .unwrap(); + let params = as FixedLengthCRH>::setup(rng).unwrap(); + as FixedLengthCRH>::evaluate(¶ms, &[1, 2, 3]) + .unwrap(); } } diff --git a/crypto-primitives/src/crh/constraints.rs b/crypto-primitives/src/crh/constraints.rs index 7429ad6..16eeba6 100644 --- a/crypto-primitives/src/crh/constraints.rs +++ b/crypto-primitives/src/crh/constraints.rs @@ -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: Sized { - type OutputGadget: ConditionalEqGadget - + EqGadget + type OutputVar: EqGadget + ToBytesGadget + CondSelectGadget - + AllocGadget + + AllocVar + + R1CSVar + Debug + Clone + Sized; - type ParametersGadget: AllocGadget + Clone; - fn check_evaluation_gadget>( - cs: CS, - parameters: &Self::ParametersGadget, - input: &[UInt8], - ) -> Result; + type ParametersVar: AllocVar + Clone; + + fn evaluate( + parameters: &Self::ParametersVar, + input: &[UInt8], + ) -> Result; } diff --git a/crypto-primitives/src/crh/injective_map/constraints.rs b/crypto-primitives/src/crh/injective_map/constraints.rs index 599e5f3..617db70 100644 --- a/crypto-primitives/src/crh/injective_map/constraints.rs +++ b/crypto-primitives/src/crh/injective_map/constraints.rs @@ -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 = <::BaseField as Field>::BasePrimeField; + pub trait InjectiveMapGadget< - G: Group, - I: InjectiveMap, - ConstraintF: Field, - GG: GroupGadget, -> + C: ProjectiveCurve, + I: InjectiveMap, + GG: CurveVar>, +> where + for<'a> &'a GG: GroupOpsBounds<'a, C, GG>, { - type OutputGadget: EqGadget - + ToBytesGadget - + CondSelectGadget - + AllocGadget + type OutputVar: EqGadget> + + ToBytesGadget> + + CondSelectGadget> + + AllocVar> + + R1CSVar, Value = I::Output> + Debug + Clone + Sized; - fn evaluate_map>( - cs: CS, - ge: &GG, - ) -> Result; + fn evaluate(ge: &GG) -> Result; } pub struct TECompressorGadget; -impl - InjectiveMapGadget< - TEAffine

, - TECompressor, - ConstraintF, - TwistedEdwardsGadget>, - > for TECompressorGadget -where - ConstraintF: PrimeField + SquareRootField, - P: TEModelParameters + ModelParameters, -{ - type OutputGadget = FpGadget; - - fn evaluate_map>( - _cs: CS, - ge: &TwistedEdwardsGadget>, - ) -> Result { - Ok(ge.x.clone()) - } -} - -impl - InjectiveMapGadget< - TEProjective

, - TECompressor, - ConstraintF, - TwistedEdwardsGadget>, - > for TECompressorGadget +impl InjectiveMapGadget, TECompressor, TEVar>> + for TECompressorGadget where - ConstraintF: PrimeField + SquareRootField, - P: TEModelParameters + ModelParameters, + F: PrimeField + SquareRootField, + P: TEModelParameters + ModelParameters, { - type OutputGadget = FpGadget; + type OutputVar = FpVar; - fn evaluate_map>( - _cs: CS, - ge: &TwistedEdwardsGadget>, - ) -> Result { + fn evaluate(ge: &TEVar>) -> Result { Ok(ge.x.clone()) } } -pub struct PedersenCRHCompressorGadget +pub struct PedersenCRHCompressorGadget where - G: Group, - I: InjectiveMap, - ConstraintF: Field, - GG: GroupGadget, - IG: InjectiveMapGadget, + C: ProjectiveCurve, + I: InjectiveMap, + W: Window, + GG: CurveVar>, + for<'a> &'a GG: GroupOpsBounds<'a, C, GG>, + IG: InjectiveMapGadget, { + #[doc(hidden)] _compressor: PhantomData, + #[doc(hidden)] _compressor_gadget: PhantomData, - _crh: PedersenCRHGadget, + #[doc(hidden)] + _crh: ped_constraints::CRHGadget, } -impl FixedLengthCRHGadget, ConstraintF> - for PedersenCRHCompressorGadget +impl FixedLengthCRHGadget, ConstraintF> + for PedersenCRHCompressorGadget where - G: Group, - I: InjectiveMap, - ConstraintF: Field, - GG: GroupGadget, - IG: InjectiveMapGadget, - W: PedersenWindow, + C: ProjectiveCurve, + I: InjectiveMap, + GG: CurveVar>, + for<'a> &'a GG: GroupOpsBounds<'a, C, GG>, + IG: InjectiveMapGadget, + W: Window, { - type OutputGadget = IG::OutputGadget; - type ParametersGadget = PedersenCRHGadgetParameters; + type OutputVar = IG::OutputVar; + type ParametersVar = ped_constraints::CRHParametersVar; - fn check_evaluation_gadget>( - mut cs: CS, - parameters: &Self::ParametersGadget, - input: &[UInt8], - ) -> Result { - let result = PedersenCRHGadget::::check_evaluation_gadget( - cs.ns(|| "PedCRH"), - parameters, - input, - )?; - IG::evaluate_map(cs.ns(|| "InjectiveMap"), &result) + fn evaluate( + parameters: &Self::ParametersVar, + input: &[UInt8>], + ) -> Result { + let result = ped_constraints::CRHGadget::::evaluate(parameters, input)?; + IG::evaluate(&result) } } diff --git a/crypto-primitives/src/crh/injective_map/mod.rs b/crypto-primitives/src/crh/injective_map/mod.rs index 0f88f28..51dde7f 100644 --- a/crypto-primitives/src/crh/injective_map/mod.rs +++ b/crypto-primitives/src/crh/injective_map/mod.rs @@ -3,71 +3,56 @@ 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 { +pub trait InjectiveMap { type Output: ToBytes + Clone + Eq + Hash + Default + Debug; - fn injective_map(ge: &G) -> Result; + + fn injective_map(ge: &C::Affine) -> Result; } pub struct TECompressor; -impl InjectiveMap> for TECompressor { - type Output =

::BaseField; - - fn injective_map(ge: &TEAffine

) -> Result { - debug_assert!(ge.is_in_correct_subgroup_assuming_on_curve()); - Ok(ge.x) - } -} - impl InjectiveMap> for TECompressor { type Output =

::BaseField; - fn injective_map(ge: &TEProjective

) -> Result { - let ge = ge.into_affine(); + fn injective_map(ge: &TEAffine

) -> Result { debug_assert!(ge.is_in_correct_subgroup_assuming_on_curve()); Ok(ge.x) } } -pub struct PedersenCRHCompressor, W: PedersenWindow> { - _group: PhantomData, +pub struct PedersenCRHCompressor, W: pedersen::Window> { + _group: PhantomData, _compressor: PhantomData, - _crh: PedersenCRH, + _crh: pedersen::CRH, } -impl, W: PedersenWindow> FixedLengthCRH - for PedersenCRHCompressor +impl, W: pedersen::Window> FixedLengthCRH + for PedersenCRHCompressor { - const INPUT_SIZE_BITS: usize = PedersenCRH::::INPUT_SIZE_BITS; + const INPUT_SIZE_BITS: usize = pedersen::CRH::::INPUT_SIZE_BITS; type Output = I::Output; - type Parameters = PedersenParameters; + type Parameters = pedersen::Parameters; fn setup(rng: &mut R) -> Result { let time = start_timer!(|| format!("PedersenCRHCompressor::Setup")); - let params = PedersenCRH::::setup(rng); + let params = pedersen::CRH::::setup(rng); end_timer!(time); params } fn evaluate(parameters: &Self::Parameters, input: &[u8]) -> Result { let eval_time = start_timer!(|| "PedersenCRHCompressor::Eval"); - let result = I::injective_map(&PedersenCRH::::evaluate(parameters, input)?)?; + let result = I::injective_map(&pedersen::CRH::::evaluate(parameters, input)?)?; end_timer!(eval_time); Ok(result) } diff --git a/crypto-primitives/src/crh/mod.rs b/crypto-primitives/src/crh/mod.rs index 626d787..a560a32 100644 --- a/crypto-primitives/src/crh/mod.rs +++ b/crypto-primitives/src/crh/mod.rs @@ -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: &mut R) -> Result; diff --git a/crypto-primitives/src/crh/pedersen/constraints.rs b/crypto-primitives/src/crh/pedersen/constraints.rs index c7f9488..f6d7871 100644 --- a/crypto-primitives/src/crh/pedersen/constraints.rs +++ b/crypto-primitives/src/crh/pedersen/constraints.rs @@ -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" -))] -pub struct PedersenCRHGadgetParameters< - G: Group, - W: PedersenWindow, - ConstraintF: Field, - GG: GroupGadget, -> { - params: PedersenParameters, +#[derivative(Clone(bound = "C: ProjectiveCurve, GG: CurveVar>"))] +pub struct CRHParametersVar>> +where + for<'a> &'a GG: GroupOpsBounds<'a, C, GG>, +{ + params: Parameters, + #[doc(hidden)] _group_g: PhantomData, - _engine: PhantomData, - _window: PhantomData, } -pub struct PedersenCRHGadget> { - #[doc(hideen)] - _group: PhantomData<*const G>, - #[doc(hideen)] - _group_gadget: PhantomData<*const GG>, - #[doc(hideen)] - _engine: PhantomData, +type ConstraintF = <::BaseField as Field>::BasePrimeField; +pub struct CRHGadget>, 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 FixedLengthCRHGadget, ConstraintF> - for PedersenCRHGadget +impl FixedLengthCRHGadget, ConstraintF> for CRHGadget where - ConstraintF: Field, - G: Group, - GG: GroupGadget, - W: PedersenWindow, + C: ProjectiveCurve, + GG: CurveVar>, + W: Window, + for<'a> &'a GG: GroupOpsBounds<'a, C, GG>, { - type OutputGadget = GG; - type ParametersGadget = PedersenCRHGadgetParameters; - - fn check_evaluation_gadget>( - cs: CS, - parameters: &Self::ParametersGadget, - input: &[UInt8], - ) -> Result { + type OutputVar = GG; + type ParametersVar = CRHParametersVar; + + fn evaluate( + parameters: &Self::ParametersVar, + input: &[UInt8>], + ) -> Result { 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 @@ where 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> - AllocGadget, ConstraintF> - for PedersenCRHGadgetParameters +impl AllocVar, ConstraintF> for CRHParametersVar +where + C: ProjectiveCurve, + GG: CurveVar>, + for<'a> &'a GG: GroupOpsBounds<'a, C, GG>, { - fn alloc_constant>( - _cs: CS, - val: T, - ) -> Result - where - T: Borrow>, - { - let params = val.borrow().clone(); - Ok(PedersenCRHGadgetParameters { + fn new_variable>>( + _cs: impl Into>>, + f: impl FnOnce() -> Result, + _mode: AllocationMode, + ) -> Result { + let params = f()?.borrow().clone(); + Ok(CRHParametersVar { params, _group_g: PhantomData, - _engine: PhantomData, - _window: PhantomData, - }) - } - - fn alloc>( - cs: CS, - value_gen: F, - ) -> Result - where - F: FnOnce() -> Result, - T: Borrow>, - { - let params = value_gen()?.borrow().clone(); - Self::alloc_constant(cs, params) - } - - fn alloc_input>( - _cs: CS, - value_gen: F, - ) -> Result - where - F: FnOnce() -> Result, - T: Borrow>, - { - 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; - type TestCRHGadget = PedersenCRHGadget; + type TestCRH = pedersen::CRH; + type TestCRHGadget = CRHGadget; #[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, R: Rng>( - mut cs: CS, + fn generate_input( + cs: ConstraintSystemRef, rng: &mut R, - ) -> ([u8; 128], Vec) { + ) -> ([u8; 128], Vec>) { 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::::new(); + let cs = ConstraintSystem::::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 = - >::ParametersGadget::alloc( - &mut cs.ns(|| "gadget_parameters"), - || Ok(¶meters), - ) - .unwrap(); - println!( - "number of constraints for input + params: {}", - cs.num_constraints() - ); - - let gadget_result = - >::check_evaluation_gadget( - &mut cs.ns(|| "gadget_evaluation"), - &gadget_parameters, - &input_bytes, - ) - .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()); + let parameters_var = + CRHParametersVar::new_constant(cs.ns("CRH Parameters"), ¶meters).unwrap(); + + let result_var = TestCRHGadget::evaluate(¶meters_var, &input_var).unwrap(); + + let primitive_result = primitive_result; + assert_eq!(primitive_result, result_var.value().unwrap()); + assert!(cs.is_satisfied().unwrap()); } } diff --git a/crypto-primitives/src/crh/pedersen/mod.rs b/crypto-primitives/src/crh/pedersen/mod.rs index d1d6000..22db5dd 100644 --- a/crypto-primitives/src/crh/pedersen/mod.rs +++ b/crypto-primitives/src/crh/pedersen/mod.rs @@ -8,29 +8,29 @@ use rand::Rng; 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 { - pub generators: Vec>, +pub struct Parameters { + pub generators: Vec>, } -pub struct PedersenCRH { - group: PhantomData, +pub struct CRH { + group: PhantomData, window: PhantomData, } -impl PedersenCRH { - pub fn create_generators(rng: &mut R) -> Vec> { +impl CRH { + pub fn create_generators(rng: &mut R) -> Vec> { 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 @@ impl PedersenCRH { generators_powers } - pub fn generator_powers(num_powers: usize, rng: &mut R) -> Vec { + pub fn generator_powers(num_powers: usize, rng: &mut R) -> Vec { 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 @@ impl PedersenCRH { } } -impl FixedLengthCRH for PedersenCRH { +impl FixedLengthCRH for CRH { const INPUT_SIZE_BITS: usize = W::WINDOW_SIZE * W::NUM_WINDOWS; - type Output = G; - type Parameters = PedersenParameters; + type Output = C::Affine; + type Parameters = Parameters; fn setup(rng: &mut R) -> Result { 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 @@ impl FixedLengthCRH for PedersenCRH { 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 @@ impl FixedLengthCRH for PedersenCRH { 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 @@ impl FixedLengthCRH for PedersenCRH { 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 @@ impl FixedLengthCRH for PedersenCRH { } encoded }) - .sum::(); + .sum::(); end_timer!(eval_time); - Ok(result) + Ok(result.into()) } } @@ -132,7 +132,7 @@ pub fn bytes_to_bits(bytes: &[u8]) -> Vec { bits } -impl Debug for PedersenParameters { +impl Debug for Parameters { 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 @@ impl Debug for PedersenParameters { } } -impl> ToConstraintField - for PedersenParameters +impl> + ToConstraintField for Parameters { #[inline] fn to_field_elements(&self) -> Result, Error> { diff --git a/crypto-primitives/src/lib.rs b/crypto-primitives/src/lib.rs index 9fcd806..a6cee90 100644 --- a/crypto-primitives/src/lib.rs +++ b/crypto-primitives/src/lib.rs @@ -25,17 +25,17 @@ pub mod signature; 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; diff --git a/crypto-primitives/src/merkle_tree/constraints.rs b/crypto-primitives/src/merkle_tree/constraints.rs index 7b13579..0ac863e 100644 --- a/crypto-primitives/src/merkle_tree/constraints.rs +++ b/crypto-primitives/src/merkle_tree/constraints.rs @@ -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 crate::{ use core::borrow::Borrow; -pub struct MerkleTreePathGadget +pub struct PathVar where - P: MerkleTreeConfig, + P: Config, HGadget: FixedLengthCRHGadget, ConstraintF: Field, { - path: Vec<(HGadget::OutputGadget, HGadget::OutputGadget)>, + path: Vec<(HGadget::OutputVar, HGadget::OutputVar)>, } -impl MerkleTreePathGadget +impl PathVar where - P: MerkleTreeConfig, + P: Config, ConstraintF: Field, CRHGadget: FixedLengthCRHGadget, + >::Value: PartialEq, { - pub fn check_membership>( + pub fn check_membership( &self, - cs: CS, - parameters: &CRHGadget::ParametersGadget, - root: &CRHGadget::OutputGadget, + parameters: &CRHGadget::ParametersVar, + root: &CRHGadget::OutputVar, leaf: impl ToBytesGadget, ) -> 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>( + pub fn conditionally_check_membership( &self, - mut cs: CS, - parameters: &CRHGadget::ParametersGadget, - root: &CRHGadget::OutputGadget, + parameters: &CRHGadget::ParametersVar, + root: &CRHGadget::OutputVar, leaf: impl ToBytesGadget, - should_enforce: &Boolean, + should_enforce: &Boolean, ) -> 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 @@ where // 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(); - - CRHGadget::OutputGadget::conditional_enforce_equal_or( - &mut cs.ns(|| format!("check_equals_which_{}", i)), + let previous_is_left = Boolean::new_witness(cs.ns("previous_is_left"), || { + Ok(previous_hash.value()?.eq(&left_hash.value()?)) + })?; + + 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::( - &mut cs.ns(|| format!("hash_inner_node_{}", i)), - parameters, - left_hash, - right_hash, - )?; + previous_hash = + hash_inner_node::(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( - mut cs: CS, - parameters: &HG::ParametersGadget, - left_child: &HG::OutputGadget, - right_child: &HG::OutputGadget, -) -> Result +pub(crate) fn hash_inner_node( + parameters: &HG::ParametersVar, + left_child: &HG::OutputVar, + right_child: &HG::OutputVar, +) -> Result where ConstraintF: Field, - CS: ConstraintSystem, H: FixedLengthCRH, HG: FixedLengthCRHGadget, { - 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 AllocGadget, ConstraintF> - for MerkleTreePathGadget +impl AllocVar, ConstraintF> for PathVar where - P: MerkleTreeConfig, + P: Config, HGadget: FixedLengthCRHGadget, ConstraintF: Field, { - fn alloc_constant>( - mut cs: CS, - val: T, - ) -> Result - where - T: Borrow>, - { - 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>( - mut cs: CS, - value_gen: F, - ) -> Result - where - F: FnOnce() -> Result, - T: Borrow>, - { - 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>( - mut cs: CS, - value_gen: F, - ) -> Result - where - F: FnOnce() -> Result, - T: Borrow>, - { - 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>>( + cs: impl Into>, + f: impl FnOnce() -> Result, + mode: AllocationMode, + ) -> Result { + 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 @@ where 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; - type HG = PedersenCRHGadget; + type H = pedersen::CRH; + type HG = CRHGadget; struct JubJubMerkleTreeParams; - impl MerkleTreeConfig for JubJubMerkleTreeParams { + impl Config for JubJubMerkleTreeParams { const HEIGHT: usize = 32; type H = H; } - type JubJubMerkleTree = MerkleHashTree; + type JubJubMerkleTree = MerkleTree; fn generate_merkle_tree(leaves: &[[u8; 30]], use_bad_root: bool) -> () { let mut rng = XorShiftRng::seed_from_u64(9174123u64); @@ -242,13 +181,13 @@ mod test { let root = tree.root(); let mut satisfied = true; for (i, leaf) in leaves.iter().enumerate() { - let mut cs = TestConstraintSystem::::new(); + let cs = ConstraintSystem::::new_ref(); let proof = tree.generate_proof(i, &leaf).unwrap(); assert!(proof.verify(&crh_parameters, &root, &leaf).unwrap()); // Allocate Merkle Tree Root - let root = >::OutputGadget::alloc( - &mut cs.ns(|| format!("new_digest_{}", i)), + let root = >::OutputVar::new_witness( + cs.ns("new_digest"), || { if use_bad_root { Ok(::Output::default()) @@ -263,9 +202,9 @@ mod test { println!("constraints from digest: {}", constraints_from_digest); // Allocate Parameters for CRH - let crh_parameters = >::ParametersGadget::alloc( - &mut cs.ns(|| format!("new_parameters_{}", i)), - || Ok(crh_parameters.clone()), + let crh_parameters = >::ParametersVar::new_constant( + cs.ns("new_parameter"), + &crh_parameters, ) .unwrap(); @@ -283,26 +222,21 @@ mod test { 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: {}", diff --git a/crypto-primitives/src/merkle_tree/mod.rs b/crypto-primitives/src/merkle_tree/mod.rs index 7d7bcec..236826e 100644 --- a/crypto-primitives/src/merkle_tree/mod.rs +++ b/crypto-primitives/src/merkle_tree/mod.rs @@ -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 @@ pub trait MerkleTreeConfig { /// Our path `is_left_child()` if the boolean in `path` is true. #[derive(Derivative)] #[derivative( - Clone(bound = "P: MerkleTreeConfig"), - Debug(bound = "P: MerkleTreeConfig, ::Output: fmt::Debug") + Clone(bound = "P: Config"), + Debug(bound = "P: Config, ::Output: fmt::Debug") )] -pub struct MerkleTreePath { +pub struct Path { pub(crate) path: Vec<( ::Output, ::Output, )>, } -pub type MerkleTreeParams

= <

::H as FixedLengthCRH>::Parameters; -pub type MerkleTreeDigest

= <

::H as FixedLengthCRH>::Output; +pub type Parameters

= <

::H as FixedLengthCRH>::Parameters; +pub type Digest

= <

::H as FixedLengthCRH>::Output; -impl Default for MerkleTreePath

{ +impl Default for Path

{ 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 @@ impl Default for MerkleTreePath

{ } } -impl MerkleTreePath

{ +impl Path

{ pub fn verify( &self, parameters: &::Parameters, root_hash: &::Output, leaf: &L, - ) -> Result { + ) -> Result { if self.path.len() != (P::HEIGHT - 1) as usize { return Ok(false); } @@ -81,7 +81,7 @@ impl MerkleTreePath

{ } } -pub struct MerkleHashTree { +pub struct MerkleTree { tree: Vec<::Output>, padding_tree: Vec<( ::Output, @@ -91,11 +91,11 @@ pub struct MerkleHashTree { root: Option<::Output>, } -impl MerkleHashTree

{ +impl MerkleTree

{ pub const HEIGHT: u8 = P::HEIGHT as u8; pub fn blank(parameters: ::Parameters) -> Self { - MerkleHashTree { + MerkleTree { tree: Vec::new(), padding_tree: Vec::new(), root: None, @@ -106,7 +106,7 @@ impl MerkleHashTree

{ pub fn new( parameters: ::Parameters, leaves: &[L], - ) -> Result { + ) -> Result { let new_time = start_timer!(|| "MerkleTree::New"); let last_level_size = leaves.len().next_power_of_two(); @@ -174,7 +174,7 @@ impl MerkleHashTree

{ }; end_timer!(new_time); - Ok(MerkleHashTree { + Ok(MerkleTree { tree, padding_tree, parameters, @@ -191,7 +191,7 @@ impl MerkleHashTree

{ &self, index: usize, leaf: &L, - ) -> Result, Error> { + ) -> Result, crate::Error> { let prove_time = start_timer!(|| "MerkleTree::GenProof"); let mut path = Vec::new(); @@ -203,7 +203,7 @@ impl MerkleHashTree

{ // 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 @@ impl MerkleHashTree

{ } 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 @@ pub(crate) fn hash_inner_node( left: &H::Output, right: &H::Output, buffer: &mut [u8], -) -> Result { - let mut writer = Cursor::new(&mut *buffer); - // Construct left input. - left.write(&mut writer)?; - - // Construct right input. - right.write(&mut writer)?; - +) -> Result { + 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( parameters: &H::Parameters, leaf: &L, buffer: &mut [u8], -) -> Result { - let mut writer = Cursor::new(&mut *buffer); - leaf.write(&mut writer)?; - +) -> Result { + 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( parameters: &H::Parameters, -) -> Result { +) -> Result { let empty_buffer = vec![0u8; H::INPUT_SIZE_BITS / 8]; H::evaluate(parameters, &empty_buffer) } @@ -366,29 +362,29 @@ pub(crate) fn hash_empty( #[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; + type H = pedersen::CRH; struct JubJubMerkleTreeParams; - impl MerkleTreeConfig for JubJubMerkleTreeParams { + impl Config for JubJubMerkleTreeParams { const HEIGHT: usize = 8; type H = H; } - type JubJubMerkleTree = MerkleHashTree; + type JubJubMerkleTree = MerkleTree; fn generate_merkle_tree(leaves: &[L]) -> () { let mut rng = XorShiftRng::seed_from_u64(9174123u64); @@ -435,7 +431,7 @@ mod test { 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()); diff --git a/crypto-primitives/src/nizk/constraints.rs b/crypto-primitives/src/nizk/constraints.rs index 7b41463..40c91c7 100644 --- a/crypto-primitives/src/nizk/constraints.rs +++ b/crypto-primitives/src/nizk/constraints.rs @@ -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 { - type PreparedVerificationKeyGadget; - type VerificationKeyGadget: AllocGadget + type PreparedVerificationKeyVar; + type VerificationKeyVar: AllocVar + ToBytesGadget; - type ProofGadget: AllocGadget; + type ProofVar: AllocVar; - fn check_verify<'a, CS, I, T>( - cs: CS, - verification_key: &Self::VerificationKeyGadget, - input: I, - proof: &Self::ProofGadget, - ) -> Result<(), SynthesisError> - where - CS: ConstraintSystem, - I: Iterator, - T: 'a + ToBitsGadget + ?Sized; + /// Optionally allocates `N::Proof` in `cs` without performing + /// subgroup checks. + /// + /// The default implementation doesn't omit these checks. + fn new_proof_unchecked>( + cs: impl Into>, + f: impl FnOnce() -> Result, + mode: AllocationMode, + ) -> Result { + 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, - I: Iterator, - T: 'a + ToBitsGadget + ?Sized; + /// Optionally allocates `N::VerificationParameters` in `cs` + /// without performing subgroup checks. + /// + /// The default implementation doesn't omit these checks. + fn new_verification_key_unchecked>( + cs: impl Into>, + f: impl FnOnce() -> Result, + mode: AllocationMode, + ) -> Result { + 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, - I: Iterator, - T: 'a + ToBitsGadget + ?Sized; + fn verify<'a, T: 'a + ToBitsGadget + ?Sized>( + verification_key: &Self::VerificationKeyVar, + input: impl Iterator, + proof: &Self::ProofVar, + ) -> Result<(), SynthesisError> { + Self::conditional_verify(verification_key, input, proof, &Boolean::constant(true)) + } + + fn conditional_verify<'a, T: 'a + ToBitsGadget + ?Sized>( + verification_key: &Self::VerificationKeyVar, + input: impl Iterator, + proof: &Self::ProofVar, + condition: &Boolean, + ) -> Result<(), SynthesisError>; + + fn conditional_verify_prepared<'a, T: 'a + ToBitsGadget + ?Sized>( + prepared_verification_key: &Self::PreparedVerificationKeyVar, + input: impl Iterator, + proof: &Self::ProofVar, + condition: &Boolean, + ) -> Result<(), SynthesisError>; } diff --git a/crypto-primitives/src/nizk/gm17/constraints.rs b/crypto-primitives/src/nizk/gm17/constraints.rs index 0ff042d..6c293f1 100644 --- a/crypto-primitives/src/nizk/gm17/constraints.rs +++ b/crypto-primitives/src/nizk/gm17/constraints.rs @@ -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, -> { - pub a: P::G1Gadget, - pub b: P::G2Gadget, - pub c: P::G1Gadget, +#[derivative(Clone(bound = "P::G1Var: Clone, P::G2Var: Clone"))] +pub struct ProofVar> { + 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, -> { - 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, +#[derivative( + Clone(bound = "P::G1Var: Clone, P::GTVar: Clone, P::G1PreparedVar: Clone, \ + P::G2PreparedVar: Clone, ") +)] +pub struct VerifyingKeyVar> { + 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, } -impl> - VerifyingKeyGadget -{ - pub fn prepare>( - &self, - mut cs: CS, - ) -> Result, 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> VerifyingKeyVar { + pub fn prepare(&self) -> Result, 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 @@ impl, -> { - 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, +#[derivative( + Clone(bound = "P::G1Var: Clone, P::GTVar: Clone, P::G1PreparedVar: Clone, \ + P::G2PreparedVar: Clone, ") +)] +pub struct PreparedVerifyingKeyVar> { + 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, } -pub struct Gm17VerifierGadget +pub struct Gm17VerifierGadget where - PairingE: PairingEngine, - ConstraintF: Field, - P: PairingGadget, + E: PairingEngine, + P: PairingVar, { - _pairing_engine: PhantomData, - _engine: PhantomData, + _pairing_engine: PhantomData, _pairing_gadget: PhantomData

, } -impl NIZKVerifierGadget, ConstraintF> - for Gm17VerifierGadget +impl NIZKVerifierGadget, E::Fq> for Gm17VerifierGadget where - PairingE: PairingEngine, - ConstraintF: Field, - C: ConstraintSynthesizer, - V: ToConstraintField, - P: PairingGadget, + E: PairingEngine, + C: ConstraintSynthesizer, + V: ToConstraintField, + P: PairingVar, { - type PreparedVerificationKeyGadget = PreparedVerifyingKeyGadget; - type VerificationKeyGadget = VerifyingKeyGadget; - type ProofGadget = ProofGadget; - - fn check_verify<'a, CS, I, T>( - cs: CS, - vk: &Self::VerificationKeyGadget, - public_inputs: I, - proof: &Self::ProofGadget, - ) -> Result<(), SynthesisError> - where - CS: ConstraintSystem, - I: Iterator, - T: 'a + ToBitsGadget + ?Sized, - { - , ConstraintF>>::conditional_check_verify( - cs, - vk, - public_inputs, - proof, - &Boolean::constant(true), - ) + type PreparedVerificationKeyVar = PreparedVerifyingKeyVar; + type VerificationKeyVar = VerifyingKeyVar; + type ProofVar = ProofVar; + + /// Allocates `N::Proof` in `cs` without performing + /// subgroup checks. + fn new_proof_unchecked>>( + cs: impl Into>, + f: impl FnOnce() -> Result, + mode: AllocationMode, + ) -> Result { + 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>>( + cs: impl Into>, + f: impl FnOnce() -> Result, + mode: AllocationMode, + ) -> Result { + 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::, _>>()?; + Ok(VerifyingKeyVar { + g_alpha_g1, + h_g2, + h_beta_g2, + g_gamma_g1, + h_gamma_g2, + query, + }) + }) } - 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, - I: Iterator, - T: 'a + ToBitsGadget + ?Sized, - { - let pvk = vk.prepare(&mut cs.ns(|| "Prepare vk"))?; - , ConstraintF>>::conditional_check_verify_prepared(cs, &pvk, public_inputs, proof, condition) + fn conditional_verify<'a, T: 'a + ToBitsGadget + ?Sized>( + vk: &Self::VerificationKeyVar, + input: impl Iterator, + proof: &Self::ProofVar, + condition: &Boolean, + ) -> Result<(), SynthesisError> { + let pvk = vk.prepare()?; + , 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, - I: Iterator, - T: 'a + ToBitsGadget + ?Sized, - { + fn conditional_verify_prepared<'a, T: 'a + ToBitsGadget + ?Sized>( + pvk: &Self::PreparedVerificationKeyVar, + mut input: impl Iterator, + proof: &Self::ProofVar, + condition: &Boolean, + ) -> 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 @@ where )? }; - 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 AllocGadget, ConstraintF> - for PreparedVerifyingKeyGadget -where - PairingE: PairingEngine, - ConstraintF: Field, - P: PairingGadget, - P::G1PreparedGadget: AllocGadget, - P::G2PreparedGadget: AllocGadget, -{ - #[inline] - fn alloc_constant>( - mut cs: CS, - val: T, - ) -> Result - where - T: Borrow>, - { - 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::::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>( - mut cs: CS, - value_gen: FN, - ) -> Result - where - FN: FnOnce() -> Result, - T: Borrow>, - { - 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::::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>( - mut cs: CS, - value_gen: FN, - ) -> Result - where - FN: FnOnce() -> Result, - T: Borrow>, - { - 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::::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 AllocGadget, ConstraintF> - for VerifyingKeyGadget +impl AllocVar, E::Fq> for PreparedVerifyingKeyVar where - PairingE: PairingEngine, - ConstraintF: Field, - P: PairingGadget, + E: PairingEngine, + P: PairingVar, + P::G1PreparedVar: AllocVar, + P::G2PreparedVar: AllocVar, { - #[inline] - fn alloc_constant>( - mut cs: CS, - val: T, - ) -> Result - where - T: Borrow>, - { - 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())?; - - let query = query - .into_iter() - .enumerate() - .map(|(i, query_i)| { - P::G1Gadget::alloc_constant( - cs.ns(|| format!("query_{}", i)), - query_i.into_projective(), - ) - }) - .collect::>() - .into_iter() - .collect::>()?; - Ok(Self { - h_g2, - g_alpha_g1, - h_beta_g2, - g_gamma_g1, - h_gamma_g2, - query, - }) - } + fn new_variable>>( + cs: impl Into>, + f: impl FnOnce() -> Result, + mode: AllocationMode, + ) -> Result { + let ns = cs.into(); + let cs = ns.cs(); + + 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>( - mut cs: CS, - value_gen: FN, - ) -> Result - where - FN: FnOnce() -> Result, - T: Borrow>, - { - 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::>() - .into_iter() - .collect::>()?; 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>( - mut cs: CS, - value_gen: FN, - ) -> Result - where - FN: FnOnce() -> Result, - T: Borrow>, - { - 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()) - })?; - - 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::>() - .into_iter() - .collect::>()?; +impl AllocVar, E::Fq> for VerifyingKeyVar +where + E: PairingEngine, + + P: PairingVar, +{ + fn new_variable>>( + cs: impl Into>, + f: impl FnOnce() -> Result, + mode: AllocationMode, + ) -> Result { + 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 @@ where } } -impl AllocGadget, ConstraintF> - for ProofGadget +impl AllocVar, E::Fq> for ProofVar where - PairingE: PairingEngine, - ConstraintF: Field, - P: PairingGadget, -{ - #[inline] - fn alloc_constant>( - mut cs: CS, - val: T, - ) -> Result - where - T: Borrow>, - { - 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 }) - } - - #[inline] - fn alloc>( - mut cs: CS, - value_gen: FN, - ) -> Result - where - FN: FnOnce() -> Result, - T: Borrow>, - { - value_gen().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 }) - }) - } + E: PairingEngine, + P: PairingVar, +{ #[inline] - fn alloc_input>( - mut cs: CS, - value_gen: FN, - ) -> Result - where - FN: FnOnce() -> Result, - T: Borrow>, - { - value_gen().and_then(|proof| { + fn new_variable>>( + cs: impl Into>, + f: impl FnOnce() -> Result, + mode: AllocationMode, + ) -> Result { + let ns = cs.into(); + let cs = ns.cs(); + + f().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 ToBytesGadget - for VerifyingKeyGadget +impl ToBytesGadget for VerifyingKeyVar where - PairingE: PairingEngine, - ConstraintF: Field, - P: PairingGadget, + E: PairingEngine, + + P: PairingVar, { #[inline] - fn to_bytes>( - &self, - mut cs: CS, - ) -> Result, SynthesisError> { + fn to_bytes(&self) -> Result>, 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 @@ where #[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, Fr>; - type TestVerifierGadget = Gm17VerifierGadget; - type TestProofGadget = ProofGadget; - type TestVkGadget = VerifyingKeyGadget; + type TestVerifierGadget = Gm17VerifierGadget; + type TestProofVar = ProofVar; + type TestVkVar = VerifyingKeyVar; struct Bench { inputs: Vec>, @@ -662,19 +414,13 @@ mod test { } impl ConstraintSynthesizer for Bench { - fn generate_constraints>( - self, - cs: &mut CS, - ) -> Result<(), SynthesisError> { + fn generate_constraints(self, cs: ConstraintSystemRef) -> 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 @@ mod test { 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 @@ mod test { }; // assert!(!verify_proof(&pvk, &proof, &[a]).unwrap()); - let mut cs = TestConstraintSystem::::new(); + let cs = ConstraintSystem::::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::>(); // Input must be in little-endian, but BitIterator outputs in big-endian. input_bits.reverse(); let input_bits = - Vec::::alloc_input(cs.ns(|| format!("Input {}", i)), || { + Vec::>::new_input(cs.ns(format!("Input {}", i)), || { Ok(input_bits) }) .unwrap(); @@ -754,18 +499,17 @@ mod test { } } - 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"); - >::check_verify( - cs.ns(|| "Verify"), + >::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 @@ mod test { } // cs.print_named_objects(); - assert!(cs.is_satisfied()); + assert!(cs.is_satisfied().unwrap()); } } } @@ -781,31 +525,32 @@ mod test { #[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, MNT6Fr>; - type TestVerifierGadget1 = Gm17VerifierGadget; - type TestProofGadget1 = ProofGadget; - type TestVkGadget1 = VerifyingKeyGadget; + type TestVerifierGadget1 = Gm17VerifierGadget; + type TestProofVar1 = ProofVar; + type TestVkVar1 = VerifyingKeyVar; type TestProofSystem2 = Gm17; - type TestVerifierGadget2 = Gm17VerifierGadget; - type TestProofGadget2 = ProofGadget; - type TestVkGadget2 = VerifyingKeyGadget; + type TestVerifierGadget2 = Gm17VerifierGadget; + type TestProofVar2 = ProofVar; + type TestVkVar2 = VerifyingKeyVar; #[derive(Clone)] struct Bench { @@ -814,19 +559,13 @@ mod test_recursive { } impl ConstraintSynthesizer for Bench { - fn generate_constraints>( - self, - cs: &mut CS, - ) -> Result<(), SynthesisError> { + fn generate_constraints(self, cs: ConstraintSystemRef) -> 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 @@ mod test_recursive { 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 @@ mod test_recursive { } impl ConstraintSynthesizer for Wrapper { - fn generate_constraints>( + fn generate_constraints( self, - cs: &mut CS, + cs: ConstraintSystemRef, ) -> Result<(), SynthesisError> { let params = self.params; let proof = self.proof; @@ -875,7 +614,6 @@ mod test_recursive { 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 @@ mod test_recursive { .collect::>(); // 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 = ::BigInt::NUM_LIMBS * 8; input_gadgets = input_bytes @@ -905,11 +643,10 @@ mod test_recursive { .collect::>(); } - 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(); - >::check_verify( - cs.ns(|| "Verify"), + TestProofVar1::new_witness(cs.ns("Proof"), || Ok(proof.clone())).unwrap(); + >::verify( &vk_gadget, input_gadgets.iter(), &proof_gadget, @@ -945,7 +682,7 @@ mod test_recursive { 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 @@ mod test_recursive { 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::::new(); + let cs = ConstraintSystem::::new_ref(); let inputs: Vec<_> = inputs.into_iter().map(|input| input.unwrap()).collect(); let mut input_gadgets = Vec::new(); @@ -981,16 +718,12 @@ mod test_recursive { { let bigint_size = ::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 @@ mod test_recursive { // 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"); - >::check_verify( - cs.ns(|| "Verify"), + >::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 @@ mod test_recursive { } // cs.print_named_objects(); - assert!(cs.is_satisfied()); + assert!(cs.is_satisfied().unwrap()); } } } diff --git a/crypto-primitives/src/nizk/groth16/constraints.rs b/crypto-primitives/src/nizk/groth16/constraints.rs index bef31bd..5b90ad3 100644 --- a/crypto-primitives/src/nizk/groth16/constraints.rs +++ b/crypto-primitives/src/nizk/groth16/constraints.rs @@ -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, -> { - pub a: P::G1Gadget, - pub b: P::G2Gadget, - pub c: P::G1Gadget, +#[derivative(Clone(bound = "P::G1Var: Clone, P::G2Var: Clone"))] +pub struct ProofVar> { + 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, -> { - 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, +#[derivative( + Clone(bound = "P::G1Var: Clone, P::GTVar: Clone, P::G1PreparedVar: Clone, \ + P::G2PreparedVar: Clone, ") +)] +pub struct VerifyingKeyVar> { + 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, } -impl> - VerifyingKeyGadget -{ - pub fn prepare>( - &self, - mut cs: CS, - ) -> Result, 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)?; - - 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)?; - - Ok(PreparedVerifyingKeyGadget { +impl> VerifyingKeyVar { + pub fn prepare(&self) -> Result, SynthesisError> { + let alpha_g1_pc = P::prepare_g1(&self.alpha_g1)?; + let beta_g2_pc = P::prepare_g2(&self.beta_g2)?; + + 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(PreparedVerifyingKeyVar { alpha_g1_beta_g2, gamma_g2_neg_pc, delta_g2_neg_pc, @@ -71,106 +49,147 @@ impl, -> { - 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, +#[derivative( + Clone(bound = "P::G1Var: Clone, P::GTVar: Clone, P::G1PreparedVar: Clone, \ + P::G2PreparedVar: Clone, ") +)] +pub struct PreparedVerifyingKeyVar> { + 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, } -pub struct Groth16VerifierGadget +pub struct Groth16VerifierGadget where - PairingE: PairingEngine, - ConstraintF: Field, - P: PairingGadget, + E: PairingEngine, + + P: PairingVar, { - _pairing_engine: PhantomData, - _engine: PhantomData, + _pairing_engine: PhantomData, _pairing_gadget: PhantomData

, } -impl NIZKVerifierGadget, ConstraintF> - for Groth16VerifierGadget +impl NIZKVerifierGadget, E::Fq> for Groth16VerifierGadget where - PairingE: PairingEngine, - ConstraintF: Field, - C: ConstraintSynthesizer, - V: ToConstraintField, - P: PairingGadget, + E: PairingEngine, + C: ConstraintSynthesizer, + V: ToConstraintField, + P: PairingVar, { - type PreparedVerificationKeyGadget = PreparedVerifyingKeyGadget; - type VerificationKeyGadget = VerifyingKeyGadget; - type ProofGadget = ProofGadget; - - fn check_verify<'a, CS, I, T>( - cs: CS, - vk: &Self::VerificationKeyGadget, - public_inputs: I, - proof: &Self::ProofGadget, - ) -> Result<(), SynthesisError> - where - CS: ConstraintSystem, - I: Iterator, - T: 'a + ToBitsGadget + ?Sized, - { - , ConstraintF>>::conditional_check_verify( - cs, - vk, - public_inputs, - proof, - &Boolean::constant(true), - ) + type PreparedVerificationKeyVar = PreparedVerifyingKeyVar; + type VerificationKeyVar = VerifyingKeyVar; + type ProofVar = ProofVar; + + /// Allocates `N::Proof` in `cs` without performing + /// subgroup checks. + fn new_proof_unchecked>>( + cs: impl Into>, + f: impl FnOnce() -> Result, + mode: AllocationMode, + ) -> Result { + 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>>( + cs: impl Into>, + f: impl FnOnce() -> Result, + mode: AllocationMode, + ) -> Result { + 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, + )?; + + 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::, _>>()?; + 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, - I: Iterator, - T: 'a + ToBitsGadget + ?Sized, - { - let pvk = vk.prepare(&mut cs.ns(|| "Prepare vk"))?; - , ConstraintF>>::conditional_check_verify_prepared(cs, &pvk, public_inputs, proof, condition) + fn conditional_verify<'a, T: 'a + ToBitsGadget + ?Sized>( + vk: &Self::VerificationKeyVar, + input: impl Iterator, + proof: &Self::ProofVar, + condition: &Boolean, + ) -> Result<(), SynthesisError> { + let pvk = vk.prepare()?; + , 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, - I: Iterator, - T: 'a + ToBitsGadget + ?Sized, - { + fn conditional_verify_prepared<'a, T: 'a + ToBitsGadget + ?Sized>( + pvk: &Self::PreparedVerificationKeyVar, + mut public_inputs: impl Iterator, + proof: &Self::ProofVar, + condition: &Boolean, + ) -> 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 @@ where }; 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 @@ where )? }; - 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 AllocGadget, ConstraintF> - for PreparedVerifyingKeyGadget +impl AllocVar, E::Fq> for PreparedVerifyingKeyVar where - PairingE: PairingEngine, - ConstraintF: Field, - P: PairingGadget, - P::G2PreparedGadget: AllocGadget, + E: PairingEngine, + P: PairingVar, { - fn alloc_constant>( - mut cs: CS, - val: T, - ) -> Result - where - T: Borrow>, - { - let pvk = val.borrow().clone(); - - 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::::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>( - mut cs: CS, - f: F, - ) -> Result - where - F: FnOnce() -> Result, - T: Borrow>, - { - 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::::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()), - )?); - } + fn new_variable>>( + cs: impl Into>, + f: impl FnOnce() -> Result, + mode: AllocationMode, + ) -> Result { + let ns = cs.into(); + let cs = ns.cs(); + + 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>( - mut cs: CS, - f: F, - ) -> Result - where - F: FnOnce() -> Result, - T: Borrow>, - { - 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 mut gamma_abc_g1 = Vec::::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 delta_g2_neg_pc = P::G2PreparedVar::new_variable( + cs.ns("delta_g2_neg_pc"), + || Ok(pvk.delta_g2_neg_pc.clone()), + mode, + )?; - Ok(Self { - alpha_g1_beta_g2, - gamma_g2_neg_pc, - delta_g2_neg_pc, - gamma_abc_g1, - }) - } -} + let gamma_abc_g1 = + Vec::new_variable(cs.ns("gamma_abc_g1"), || Ok(pvk.gamma_abc_g1.clone()), mode)?; -impl AllocGadget, ConstraintF> - for VerifyingKeyGadget -where - PairingE: PairingEngine, - ConstraintF: Field, - P: PairingGadget, -{ - #[inline] - fn alloc_constant>( - mut cs: CS, - val: T, - ) -> Result - where - T: Borrow>, - { - 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())?; - - 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::>() - .into_iter() - .collect::>()?; - Ok(Self { - alpha_g1, - beta_g2, - gamma_g2, - delta_g2, - gamma_abc_g1, - }) - } - - #[inline] - fn alloc>( - mut cs: CS, - value_gen: FN, - ) -> Result - where - FN: FnOnce() -> Result, - T: Borrow>, - { - 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::>() - .into_iter() - .collect::>()?; Ok(Self { - alpha_g1, - beta_g2, - gamma_g2, - delta_g2, + alpha_g1_beta_g2, + gamma_g2_neg_pc, + delta_g2_neg_pc, gamma_abc_g1, }) }) } +} - #[inline] - fn alloc_input>( - mut cs: CS, - value_gen: FN, - ) -> Result - where - FN: FnOnce() -> Result, - T: Borrow>, - { - value_gen().and_then(|vk| { +impl AllocVar, E::Fq> for VerifyingKeyVar +where + E: PairingEngine, + + P: PairingVar, +{ + fn new_variable>>( + cs: impl Into>, + f: impl FnOnce() -> Result, + mode: AllocationMode, + ) -> Result { + let ns = cs.into(); + let cs = ns.cs(); + + f().and_then(|vk| { let VerifyingKey { alpha_g1, beta_g2, @@ -436,27 +290,12 @@ where 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 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::>() - .into_iter() - .collect::>()?; + 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 = Vec::new_variable(cs.clone(), || Ok(gamma_abc_g1), mode)?; Ok(Self { alpha_g1, beta_g2, @@ -468,87 +307,43 @@ where } } -impl AllocGadget, ConstraintF> - for ProofGadget +impl AllocVar, E::Fq> for ProofVar where - PairingE: PairingEngine, - ConstraintF: Field, - P: PairingGadget, + E: PairingEngine, + P: PairingVar, { - #[inline] - fn alloc_constant>( - mut cs: CS, - val: T, - ) -> Result - where - T: Borrow>, - { - 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 }) - } - - #[inline] - fn alloc>( - mut cs: CS, - value_gen: FN, - ) -> Result - where - FN: FnOnce() -> Result, - T: Borrow>, - { - value_gen().and_then(|proof| { + fn new_variable>>( + cs: impl Into>, + f: impl FnOnce() -> Result, + mode: AllocationMode, + ) -> Result { + let ns = cs.into(); + let cs = ns.cs(); + + 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>( - mut cs: CS, - value_gen: FN, - ) -> Result - where - FN: FnOnce() -> Result, - T: Borrow>, - { - 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 ToBytesGadget - for VerifyingKeyGadget +impl ToBytesGadget for VerifyingKeyVar where - PairingE: PairingEngine, - ConstraintF: Field, - P: PairingGadget, + E: PairingEngine, + P: PairingVar, { #[inline] - fn to_bytes>( - &self, - mut cs: CS, - ) -> Result, SynthesisError> { + fn to_bytes(&self) -> Result>, 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 @@ where #[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, - }; - 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 = Groth16, Fr>; - type TestVerifierGadget = Groth16VerifierGadget; - type TestProofGadget = ProofGadget; - type TestVkGadget = VerifyingKeyGadget; + type TestVerifierGadget = Groth16VerifierGadget; + type TestProofVar = ProofVar; + type TestVkVar = VerifyingKeyVar; struct Bench { inputs: Vec>, @@ -581,19 +375,13 @@ mod test { } impl ConstraintSynthesizer for Bench { - fn generate_constraints>( - self, - cs: &mut CS, - ) -> Result<(), SynthesisError> { + fn generate_constraints(self, cs: ConstraintSystemRef) -> 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 @@ mod test { 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 @@ mod test { }; // assert!(!verify_proof(&pvk, &proof, &[a]).unwrap()); - let mut cs = TestConstraintSystem::::new(); + let cs = ConstraintSystem::::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::>(); // Input must be in little-endian, but BitIterator outputs in big-endian. input_bits.reverse(); let input_bits = - Vec::::alloc_input(cs.ns(|| format!("Input {}", i)), || { + Vec::>::new_input(cs.ns(format!("Input {}", i)), || { Ok(input_bits) }) .unwrap(); @@ -673,18 +460,17 @@ mod test { } } - 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"); - >::check_verify( - cs.ns(|| "Verify"), + >::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 @@ mod test { } // cs.print_named_objects(); - assert!(cs.is_satisfied()); + assert!(cs.is_satisfied().unwrap()); } } } @@ -700,31 +486,32 @@ mod test { #[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, MNT6Fr>; - type TestVerifierGadget1 = Groth16VerifierGadget; - type TestProofGadget1 = ProofGadget; - type TestVkGadget1 = VerifyingKeyGadget; + type TestVerifierGadget1 = Groth16VerifierGadget; + type TestProofVar1 = ProofVar; + type TestVkVar1 = VerifyingKeyVar; type TestProofSystem2 = Groth16; - type TestVerifierGadget2 = Groth16VerifierGadget; - type TestProofGadget2 = ProofGadget; - type TestVkGadget2 = VerifyingKeyGadget; + type TestVerifierGadget2 = Groth16VerifierGadget; + type TestProofVar2 = ProofVar; + type TestVkVar2 = VerifyingKeyVar; #[derive(Clone)] struct Bench { @@ -733,19 +520,13 @@ mod test_recursive { } impl ConstraintSynthesizer for Bench { - fn generate_constraints>( - self, - cs: &mut CS, - ) -> Result<(), SynthesisError> { + fn generate_constraints(self, cs: ConstraintSystemRef) -> 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 @@ mod test_recursive { 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 @@ mod test_recursive { } impl ConstraintSynthesizer for Wrapper { - fn generate_constraints>( + fn generate_constraints( self, - cs: &mut CS, + cs: ConstraintSystemRef, ) -> Result<(), SynthesisError> { let params = self.params; let proof = self.proof; @@ -794,7 +575,6 @@ mod test_recursive { 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 @@ mod test_recursive { .collect::>(); // 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 = ::BigInt::NUM_LIMBS * 8; input_gadgets = input_bytes @@ -824,11 +604,10 @@ mod test_recursive { .collect::>(); } - 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(); - >::check_verify( - cs.ns(|| "Verify"), + TestProofVar1::new_witness(cs.ns("Proof"), || Ok(proof.clone())).unwrap(); + >::verify( &vk_gadget, input_gadgets.iter(), &proof_gadget, @@ -892,7 +671,7 @@ mod test_recursive { create_random_proof(c, ¶ms, rng).unwrap() }; - let mut cs = TestConstraintSystem::::new(); + let cs = ConstraintSystem::::new_ref(); let inputs: Vec<_> = inputs.into_iter().map(|input| input.unwrap()).collect(); let mut input_gadgets = Vec::new(); @@ -900,16 +679,12 @@ mod test_recursive { { let bigint_size = ::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 @@ mod test_recursive { // 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"); - >::check_verify( - cs.ns(|| "Verify"), + >::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 @@ mod test_recursive { } // cs.print_named_objects(); - assert!(cs.is_satisfied()); + assert!(cs.is_satisfied().unwrap()); } } } diff --git a/crypto-primitives/src/nizk/mod.rs b/crypto-primitives/src/nizk/mod.rs index 268c824..5366b22 100644 --- a/crypto-primitives/src/nizk/mod.rs +++ b/crypto-primitives/src/nizk/mod.rs @@ -63,7 +63,7 @@ mod test { 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 @@ mod test { } impl ConstraintSynthesizer for R1CSCircuit { - fn generate_constraints>( + fn generate_constraints( self, - cs: &mut CS, + cs: ConstraintSystemRef, ) -> 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()))?; - - cs.enforce( - || "check_one", - |lc| lc + sum, - |lc| lc + CS::one(), - |lc| lc + input + witness, - ); + 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_named_constraint( + "enforce sum", + lc!() + sum, + lc!() + Variable::One, + lc!() + input + witness, + )?; Ok(()) } } diff --git a/crypto-primitives/src/prf/blake2s/constraints.rs b/crypto-primitives/src/prf/blake2s/constraints.rs index f05c54a..9dd3103 100644 --- a/crypto-primitives/src/prf/blake2s/constraints.rs +++ b/crypto-primitives/src/prf/blake2s/constraints.rs @@ -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 @@ const SIGMA: [[usize; 16]; 10] = [ // END FUNCTION. // -fn mixing_g>( - mut cs: CS, - v: &mut [UInt32], +fn mixing_g( + v: &mut [UInt32], a: usize, b: usize, c: usize, d: usize, - x: &UInt32, - y: &UInt32, + x: &UInt32, + y: &UInt32, ) -> 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 @@ fn mixing_g>( // 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 @@ fn mixing_g>( // END FUNCTION. // -fn blake2s_compression>( - mut cs: CS, - h: &mut [UInt32], - m: &[UInt32], +fn blake2s_compression( + h: &mut [UInt32], + m: &[UInt32], t: u64, f: bool, ) -> Result<(), SynthesisError> { @@ -181,106 +173,29 @@ fn blake2s_compression> 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 @@ fn blake2s_compression>( - cs: CS, - input: &[Boolean], -) -> Result, SynthesisError> { +pub fn evaluate_blake2s( + input: &[Boolean], +) -> Result>, 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, ->( - mut cs: CS, - input: &[Boolean], +pub fn evaluate_blake2s_with_parameters( + input: &[Boolean], parameters: &[u32; 8], -) -> Result, SynthesisError> { +) -> Result>, 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]))?, - ); - - let mut blocks: Vec> = vec![]; + 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![]; for block in input.chunks(512) { let mut this_block = Vec::with_capacity(16); @@ -380,22 +274,15 @@ pub fn blake2s_gadget_with_parameters< } 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); +pub struct OutputVar(pub Vec>); -impl PartialEq for Blake2sOutputGadget { - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 +impl EqGadget for OutputVar { + fn is_eq(&self, other: &Self) -> Result, SynthesisError> { + self.0.is_eq(&other.0) } -} - -impl Eq for Blake2sOutputGadget {} -impl EqGadget for Blake2sOutputGadget {} - -impl ConditionalEqGadget for Blake2sOutputGadget { - #[inline] - fn conditional_enforce_equal>( + /// 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, ) -> 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 * >::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, + ) -> Result<(), SynthesisError> { + self.0 + .as_slice() + .conditional_enforce_not_equal(other.0.as_slice(), should_enforce) } } -impl ToBytesGadget for Blake2sOutputGadget { +impl ToBytesGadget for OutputVar { #[inline] - fn to_bytes>( - &self, - _cs: CS, - ) -> Result, SynthesisError> { + fn to_bytes(&self) -> Result>, SynthesisError> { Ok(self.0.clone()) } } -impl AllocGadget<[u8; 32], ConstraintF> for Blake2sOutputGadget { - #[inline] - fn alloc_constant>( - mut cs: CS, - val: T, - ) -> Result - 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 AllocVar<[u8; 32], ConstraintF> for OutputVar { + fn new_variable>( + cs: impl Into>, + f: impl FnOnce() -> Result, + mode: AllocationMode, + ) -> Result { + 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>( - cs: CS, - value_gen: F, - ) -> Result - where - F: FnOnce() -> Result, - T: Borrow<[u8; 32]>, - { - let zeros = [0u8; 32]; - let value = match value_gen() { - Ok(val) => *(val.borrow()), - Err(_) => zeros, - }; - let bytes = ::alloc_vec(cs, &value)?; - - Ok(Blake2sOutputGadget(bytes)) +impl R1CSVar for OutputVar { + type Value = [u8; 32]; + + fn cs(&self) -> Option> { + self.0.cs() } - #[inline] - fn alloc_input>( - cs: CS, - value_gen: F, - ) -> Result - where - F: FnOnce() -> Result, - T: Borrow<[u8; 32]>, - { - let zeros = [0u8; 32]; - let value = match value_gen() { - Ok(val) => *(val.borrow()), - Err(_) => zeros, - }; - let bytes = ::alloc_input_vec(cs, &value)?; - - Ok(Blake2sOutputGadget(bytes)) + fn value(&self) -> Result { + 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 PRFGadget for Blake2sGadget { - type OutputGadget = Blake2sOutputGadget; +impl PRFGadget for Blake2sGadget { + type OutputVar = OutputVar; - fn new_seed>(mut cs: CS, seed: &[u8; 32]) -> Vec { - UInt8::alloc_vec(&mut cs.ns(|| "alloc_seed"), seed).unwrap() + fn new_seed(cs: ConstraintSystemRef, seed: &[u8; 32]) -> Vec> { + UInt8::new_witness_vec(cs.ns("New Blake2s seed"), seed).unwrap() } - fn check_evaluation_gadget>( - mut cs: CS, - seed: &[UInt8], - input: &[UInt8], - ) -> Result { + fn evaluate(seed: &[UInt8], input: &[UInt8]) -> Result { 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 @@ mod test { 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::::new(); + let cs = ConstraintSystem::::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 @@ mod test { use rand::Rng; let mut rng = XorShiftRng::seed_from_u64(1231275789u64); - let mut cs = TestConstraintSystem::::new(); + let cs = ConstraintSystem::::new_ref(); let mut seed = [0u8; 32]; rng.fill(&mut seed); @@ -579,32 +419,25 @@ mod test { 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 = >::OutputGadget::alloc( - &mut cs.ns(|| "declare_output"), + let actual_out_var = >::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 @@ mod test { // Test that 512 fixed leading bits (constants) // doesn't result in more constraints. - let mut cs = TestConstraintSystem::::new(); + let cs = ConstraintSystem::::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::::new(); + let cs = ConstraintSystem::::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::::constant(rng.gen())) + .collect(); + evaluate_blake2s(&input_bits).unwrap(); assert_eq!(cs.num_constraints(), 0); } @@ -651,25 +484,24 @@ mod test { let mut hash_result = Vec::with_capacity(h.output_size()); h.variable_result(|res| hash_result.extend_from_slice(res)); - let mut cs = TestConstraintSystem::::new(); + let cs = ConstraintSystem::::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 @@ mod test { 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); diff --git a/crypto-primitives/src/prf/constraints.rs b/crypto-primitives/src/prf/constraints.rs index 69de337..393151d 100644 --- a/crypto-primitives/src/prf/constraints.rs +++ b/crypto-primitives/src/prf/constraints.rs @@ -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 { - type OutputGadget: EqGadget - + ToBytesGadget - + AllocGadget +pub trait PRFGadget { + type OutputVar: EqGadget + + ToBytesGadget + + AllocVar + + R1CSVar + Clone + Debug; - fn new_seed>(cs: CS, output: &P::Seed) -> Vec; + fn new_seed(cs: ConstraintSystemRef, seed: &P::Seed) -> Vec>; - fn check_evaluation_gadget>( - cs: CS, - seed: &[UInt8], - input: &[UInt8], - ) -> Result; + fn evaluate(seed: &[UInt8], input: &[UInt8]) -> Result; } diff --git a/crypto-primitives/src/prf/mod.rs b/crypto-primitives/src/prf/mod.rs index 398bd4b..9fd0338 100644 --- a/crypto-primitives/src/prf/mod.rs +++ b/crypto-primitives/src/prf/mod.rs @@ -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; diff --git a/crypto-primitives/src/signature/constraints.rs b/crypto-primitives/src/signature/constraints.rs index 6ae3bc2..ab9eee0 100644 --- a/crypto-primitives/src/signature/constraints.rs +++ b/crypto-primitives/src/signature/constraints.rs @@ -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 { - type ParametersGadget: AllocGadget + Clone; + type ParametersVar: AllocVar + Clone; - type PublicKeyGadget: ToBytesGadget + type PublicKeyVar: ToBytesGadget + EqGadget - + AllocGadget + + AllocVar + Clone; - fn check_randomization_gadget>( - cs: CS, - parameters: &Self::ParametersGadget, - public_key: &Self::PublicKeyGadget, - randomness: &[UInt8], - ) -> Result; + fn randomize( + parameters: &Self::ParametersVar, + public_key: &Self::PublicKeyVar, + randomness: &[UInt8], + ) -> Result; } diff --git a/crypto-primitives/src/signature/mod.rs b/crypto-primitives/src/signature/mod.rs index 8512b31..d59e079 100644 --- a/crypto-primitives/src/signature/mod.rs +++ b/crypto-primitives/src/signature/mod.rs @@ -52,9 +52,9 @@ pub trait SignatureScheme { #[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 @@ mod test { fn schnorr_signature_test() { let message = "Hi, I am a Schnorr signature!"; let rng = &mut test_rng(); - sign_and_verify::>(message.as_bytes()); - failed_verification::>( + sign_and_verify::>(message.as_bytes()); + failed_verification::>( message.as_bytes(), "Bad message".as_bytes(), ); let random_scalar = to_bytes!(::ScalarField::rand(rng)).unwrap(); - randomize_and_verify::>( + randomize_and_verify::>( message.as_bytes(), &random_scalar.as_slice(), ); diff --git a/crypto-primitives/src/signature/schnorr/constraints.rs b/crypto-primitives/src/signature/schnorr/constraints.rs index f3395dc..bdc176c 100644 --- a/crypto-primitives/src/signature/schnorr/constraints.rs +++ b/crypto-primitives/src/signature/schnorr/constraints.rs @@ -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> -{ - generator: GG, - _group: PhantomData<*const G>, - _engine: PhantomData<*const ConstraintF>, -} +type ConstraintF = <::BaseField as Field>::BasePrimeField; -impl> Clone - for SchnorrSigGadgetParameters +#[derive(Clone)] +pub struct ParametersVar>> +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, } #[derive(Derivative)] #[derivative( - Debug(bound = "G: Group, ConstraintF: Field, GG: GroupGadget"), - Clone(bound = "G: Group, ConstraintF: Field, GG: GroupGadget"), - PartialEq(bound = "G: Group, ConstraintF: Field, GG: GroupGadget"), - Eq(bound = "G: Group, ConstraintF: Field, GG: GroupGadget") + Debug(bound = "C: ProjectiveCurve, GC: CurveVar>"), + Clone(bound = "C: ProjectiveCurve, GC: CurveVar>") )] -pub struct SchnorrSigGadgetPk> { - pub_key: GG, - #[doc(hidden)] - _group: PhantomData<*const G>, +pub struct PublicKeyVar>> +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> { - #[doc(hidden)] - _group: PhantomData<*const G>, +pub struct SchnorrRandomizePkGadget>> +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 SigRandomizePkGadget, ConstraintF> - for SchnorrRandomizePkGadget +impl SigRandomizePkGadget, ConstraintF> + for SchnorrRandomizePkGadget where - G: Group, - GG: GroupGadget, + C: ProjectiveCurve, + GC: CurveVar>, D: Digest + Send + Sync, - ConstraintF: Field, + for<'a> &'a GC: GroupOpsBounds<'a, C, GC>, { - type ParametersGadget = SchnorrSigGadgetParameters; - type PublicKeyGadget = SchnorrSigGadgetPk; - - fn check_randomization_gadget>( - mut cs: CS, - parameters: &Self::ParametersGadget, - public_key: &Self::PublicKeyGadget, - randomness: &[UInt8], - ) -> Result { + type ParametersVar = ParametersVar; + type PublicKeyVar = PublicKeyVar; + + fn randomize( + parameters: &Self::ParametersVar, + public_key: &Self::PublicKeyVar, + randomness: &[UInt8>], + ) -> Result { let base = parameters.generator.clone(); let randomness = randomness .iter() .flat_map(|b| b.into_bits_le()) .collect::>(); - 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 AllocGadget, ConstraintF> - for SchnorrSigGadgetParameters +impl AllocVar, ConstraintF> for ParametersVar where - G: Group, - ConstraintF: Field, - GG: GroupGadget, + C: ProjectiveCurve, + GC: CurveVar>, D: Digest, + for<'a> &'a GC: GroupOpsBounds<'a, C, GC>, { - fn alloc_constant>( - cs: CS, - val: T, - ) -> Result - where - T: Borrow>, - { - let generator = GG::alloc_constant(cs, val.borrow().generator)?; + fn new_variable>>( + cs: impl Into>>, + f: impl FnOnce() -> Result, + mode: AllocationMode, + ) -> Result { + let generator = GC::new_variable(cs, || f().map(|g| g.borrow().generator), mode)?; Ok(Self { generator, - _engine: PhantomData, - _group: PhantomData, - }) - } - - fn alloc>(cs: CS, f: F) -> Result - where - F: FnOnce() -> Result, - T: Borrow>, - { - let generator = GG::alloc_checked(cs, || f().map(|pp| pp.borrow().generator))?; - Ok(Self { - generator, - _engine: PhantomData, - _group: PhantomData, - }) - } - - fn alloc_input>( - cs: CS, - f: F, - ) -> Result - where - F: FnOnce() -> Result, - T: Borrow>, - { - let generator = GG::alloc_input(cs, || f().map(|pp| pp.borrow().generator))?; - Ok(Self { - generator, - _engine: PhantomData, - _group: PhantomData, + _curve: PhantomData, }) } } -impl AllocGadget, ConstraintF> - for SchnorrSigGadgetPk +impl AllocVar, ConstraintF> for PublicKeyVar where - G: Group, - ConstraintF: Field, - GG: GroupGadget, + C: ProjectiveCurve, + GC: CurveVar>, + for<'a> &'a GC: GroupOpsBounds<'a, C, GC>, { - fn alloc_constant>( - cs: CS, - val: T, - ) -> Result - where - T: Borrow>, - { - let pub_key = GG::alloc_constant(cs, val.borrow())?; + fn new_variable>>( + cs: impl Into>>, + f: impl FnOnce() -> Result, + mode: AllocationMode, + ) -> Result { + let pub_key = GC::new_variable(cs, f, mode)?; Ok(Self { pub_key, - _engine: PhantomData, - _group: PhantomData, - }) - } - - fn alloc>(cs: CS, f: F) -> Result - where - F: FnOnce() -> Result, - T: Borrow>, - { - let pub_key = GG::alloc_input(cs, || f().map(|pk| *pk.borrow()))?; - Ok(Self { - pub_key, - _engine: PhantomData, - _group: PhantomData, - }) - } - - fn alloc_input>( - cs: CS, - f: F, - ) -> Result - where - F: FnOnce() -> Result, - T: Borrow>, - { - let pub_key = GG::alloc_input(cs, || f().map(|pk| *pk.borrow()))?; - Ok(Self { - pub_key, - _engine: PhantomData, _group: PhantomData, }) } } -impl ConditionalEqGadget for SchnorrSigGadgetPk +impl EqGadget> for PublicKeyVar where - G: Group, - ConstraintF: Field, - GG: GroupGadget, + C: ProjectiveCurve, + GC: CurveVar>, + for<'a> &'a GC: GroupOpsBounds<'a, C, GC>, { #[inline] - fn conditional_enforce_equal>( + fn is_eq(&self, other: &Self) -> Result>, SynthesisError> { + self.pub_key.is_eq(&other.pub_key) + } + + #[inline] + fn conditional_enforce_equal( &self, - mut cs: CS, other: &Self, - condition: &Boolean, + condition: &Boolean>, ) -> 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 { - >::cost() + #[inline] + fn conditional_enforce_not_equal( + &self, + other: &Self, + condition: &Boolean>, + ) -> Result<(), SynthesisError> { + self.pub_key + .conditional_enforce_not_equal(&other.pub_key, condition) } } -impl EqGadget for SchnorrSigGadgetPk -where - G: Group, - ConstraintF: Field, - GG: GroupGadget, -{ -} - -impl ToBytesGadget for SchnorrSigGadgetPk +impl ToBytesGadget> for PublicKeyVar where - G: Group, - ConstraintF: Field, - GG: GroupGadget, + C: ProjectiveCurve, + GC: CurveVar>, + for<'a> &'a GC: GroupOpsBounds<'a, C, GC>, { - fn to_bytes>( - &self, - mut cs: CS, - ) -> Result, SynthesisError> { - self.pub_key.to_bytes(&mut cs.ns(|| "PubKey To Bytes")) + fn to_bytes(&self) -> Result>>, SynthesisError> { + self.pub_key.to_bytes() } } diff --git a/crypto-primitives/src/signature/schnorr/mod.rs b/crypto-primitives/src/signature/schnorr/mod.rs index b7519bb..20f2d98 100644 --- a/crypto-primitives/src/signature/schnorr/mod.rs +++ b/crypto-primitives/src/signature/schnorr/mod.rs @@ -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 @@ use rand::Rng; #[cfg(feature = "r1cs")] pub mod constraints; -pub struct SchnorrSignature { - _group: PhantomData, +pub struct Schnorr { + _group: PhantomData, _hash: PhantomData, } #[derive(Derivative)] -#[derivative(Clone(bound = "G: Group, H: Digest"))] -pub struct SchnorrSigParameters { +#[derivative(Clone(bound = "C: ProjectiveCurve, H: Digest"), Debug)] +pub struct Parameters { _hash: PhantomData, - pub generator: G, + pub generator: C::Affine, pub salt: [u8; 32], } -pub type SchnorrPublicKey = G; +pub type PublicKey = ::Affine; -#[derive(Derivative)] -#[derivative(Clone(bound = "G: Group"), Default(bound = "G: Group"))] -pub struct SchnorrSecretKey(pub G::ScalarField); +#[derive(Clone, Default, Debug)] +pub struct SecretKey(pub C::ScalarField); -impl ToBytes for SchnorrSecretKey { +impl ToBytes for SecretKey { #[inline] fn write(&self, writer: W) -> IoResult<()> { self.0.write(writer) } } -#[derive(Derivative)] -#[derivative(Clone(bound = "G: Group"), Default(bound = "G: Group"))] -pub struct SchnorrSig { - pub prover_response: G::ScalarField, - pub verifier_challenge: G::ScalarField, +#[derive(Clone, Default, Debug)] +pub struct Signature { + pub prover_response: C::ScalarField, + pub verifier_challenge: C::ScalarField, } -impl SignatureScheme for SchnorrSignature +impl SignatureScheme for Schnorr where - G::ScalarField: PrimeField, + C::ScalarField: PrimeField, { - type Parameters = SchnorrSigParameters; - type PublicKey = G; - type SecretKey = SchnorrSecretKey; - type Signature = SchnorrSig; + type Parameters = Parameters; + type PublicKey = PublicKey; + type SecretKey = SecretKey; + type Signature = Signature; fn setup(rng: &mut R) -> Result { 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 @@ where ) -> 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( @@ -93,10 +90,10 @@ where // (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 @@ where // 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 @@ where // 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 @@ where ) -> Result { 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 @@ where 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 @@ where ) -> Result { 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 @@ where randomness: &[u8], ) -> Result { 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 @@ where 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 @@ pub fn bytes_to_bits(bytes: &[u8]) -> Vec { bits } -impl, D: Digest> - ToConstraintField for SchnorrSigParameters +impl, D: Digest> + ToConstraintField for Parameters { #[inline] fn to_field_elements(&self) -> Result, Error> { - self.generator.to_field_elements() + self.generator.into_projective().to_field_elements() } }