mirror of
https://github.com/arnaucube/ark-r1cs-std.git
synced 2026-01-12 00:41:32 +01:00
Initial commit to extract crypto-primitives to new crate
This commit is contained in:
22
crypto-primitives/src/nizk/constraints.rs
Normal file
22
crypto-primitives/src/nizk/constraints.rs
Normal file
@@ -0,0 +1,22 @@
|
||||
use algebra::Field;
|
||||
use r1cs_core::{ConstraintSystem, SynthesisError};
|
||||
use r1cs_std::prelude::*;
|
||||
|
||||
use crate::nizk::NIZK;
|
||||
|
||||
pub trait NIZKVerifierGadget<N: NIZK, ConstraintF: Field> {
|
||||
type VerificationKeyGadget: AllocGadget<N::VerificationParameters, ConstraintF> + ToBytesGadget<ConstraintF>;
|
||||
|
||||
type ProofGadget: AllocGadget<N::Proof, ConstraintF>;
|
||||
|
||||
fn check_verify<'a, CS, I, T>(
|
||||
cs: CS,
|
||||
verification_key: &Self::VerificationKeyGadget,
|
||||
input: I,
|
||||
proof: &Self::ProofGadget,
|
||||
) -> Result<(), SynthesisError>
|
||||
where
|
||||
CS: ConstraintSystem<ConstraintF>,
|
||||
I: Iterator<Item = &'a T>,
|
||||
T: 'a + ToBitsGadget<ConstraintF> + ?Sized;
|
||||
}
|
||||
543
crypto-primitives/src/nizk/gm17/constraints.rs
Normal file
543
crypto-primitives/src/nizk/gm17/constraints.rs
Normal file
@@ -0,0 +1,543 @@
|
||||
use crate::nizk::{gm17::Gm17, NIZKVerifierGadget};
|
||||
use algebra::{Field, ToConstraintField, AffineCurve, PairingEngine};
|
||||
use r1cs_core::{ConstraintSynthesizer, ConstraintSystem, SynthesisError};
|
||||
use r1cs_std::prelude::*;
|
||||
|
||||
use gm17::{Proof, VerifyingKey};
|
||||
use std::{borrow::Borrow, marker::PhantomData};
|
||||
|
||||
#[derive(Derivative)]
|
||||
#[derivative(Clone(bound = "P::G1Gadget: Clone, P::G2Gadget: Clone"))]
|
||||
pub struct ProofGadget<
|
||||
PairingE: PairingEngine,
|
||||
ConstraintF: Field,
|
||||
P: PairingGadget<PairingE, ConstraintF>,
|
||||
> {
|
||||
pub a: P::G1Gadget,
|
||||
pub b: P::G2Gadget,
|
||||
pub c: P::G1Gadget,
|
||||
}
|
||||
|
||||
#[derive(Derivative)]
|
||||
#[derivative(Clone(
|
||||
bound = "P::G1Gadget: Clone, P::GTGadget: Clone, P::G1PreparedGadget: Clone, \
|
||||
P::G2PreparedGadget: Clone, "
|
||||
))]
|
||||
pub struct VerifyingKeyGadget<
|
||||
PairingE: PairingEngine,
|
||||
ConstraintF: Field,
|
||||
P: PairingGadget<PairingE, ConstraintF>,
|
||||
> {
|
||||
pub h_g2: P::G2Gadget,
|
||||
pub g_alpha_g1: P::G1Gadget,
|
||||
pub h_beta_g2: P::G2Gadget,
|
||||
pub g_gamma_g1: P::G1Gadget,
|
||||
pub h_gamma_g2: P::G2Gadget,
|
||||
pub query: Vec<P::G1Gadget>,
|
||||
}
|
||||
|
||||
impl<
|
||||
PairingE: PairingEngine,
|
||||
ConstraintF: Field,
|
||||
P: PairingGadget<PairingE, ConstraintF>,
|
||||
> VerifyingKeyGadget<PairingE, ConstraintF, P>
|
||||
{
|
||||
pub fn prepare<CS: ConstraintSystem<ConstraintF>>(
|
||||
&self,
|
||||
mut cs: CS,
|
||||
) -> Result<PreparedVerifyingKeyGadget<PairingE, ConstraintF, P>, SynthesisError> {
|
||||
let mut cs = cs.ns(|| "Preparing verifying key");
|
||||
let g_alpha_pc = P::prepare_g1(&mut cs.ns(|| "Prepare g_alpha_g1"), &self.g_alpha_g1)?;
|
||||
let h_beta_pc = P::prepare_g2(&mut cs.ns(|| "Prepare h_beta_g2"), &self.h_beta_g2)?;
|
||||
let g_gamma_pc = P::prepare_g1(&mut cs.ns(|| "Prepare g_gamma_pc"), &self.g_gamma_g1)?;
|
||||
let h_gamma_pc = P::prepare_g2(&mut cs.ns(|| "Prepare h_gamma_pc"), &self.h_gamma_g2)?;
|
||||
let h_pc = P::prepare_g2(&mut cs.ns(|| "Prepare h_pc"), &self.h_g2)?;
|
||||
Ok(PreparedVerifyingKeyGadget {
|
||||
g_alpha: self.g_alpha_g1.clone(),
|
||||
h_beta: self.h_beta_g2.clone(),
|
||||
g_alpha_pc,
|
||||
h_beta_pc,
|
||||
g_gamma_pc,
|
||||
h_gamma_pc,
|
||||
h_pc,
|
||||
query: self.query.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Derivative)]
|
||||
#[derivative(Clone(
|
||||
bound = "P::G1Gadget: Clone, P::GTGadget: Clone, P::G1PreparedGadget: Clone, \
|
||||
P::G2PreparedGadget: Clone, "
|
||||
))]
|
||||
pub struct PreparedVerifyingKeyGadget<
|
||||
PairingE: PairingEngine,
|
||||
ConstraintF: Field,
|
||||
P: PairingGadget<PairingE, ConstraintF>,
|
||||
> {
|
||||
pub g_alpha: P::G1Gadget,
|
||||
pub h_beta: P::G2Gadget,
|
||||
pub g_alpha_pc: P::G1PreparedGadget,
|
||||
pub h_beta_pc: P::G2PreparedGadget,
|
||||
pub g_gamma_pc: P::G1PreparedGadget,
|
||||
pub h_gamma_pc: P::G2PreparedGadget,
|
||||
pub h_pc: P::G2PreparedGadget,
|
||||
pub query: Vec<P::G1Gadget>,
|
||||
}
|
||||
|
||||
pub struct Gm17VerifierGadget<PairingE, ConstraintF, P>
|
||||
where
|
||||
PairingE: PairingEngine,
|
||||
ConstraintF: Field,
|
||||
P: PairingGadget<PairingE, ConstraintF>,
|
||||
{
|
||||
_pairing_engine: PhantomData<PairingE>,
|
||||
_engine: PhantomData<ConstraintF>,
|
||||
_pairing_gadget: PhantomData<P>,
|
||||
}
|
||||
|
||||
impl<PairingE, ConstraintF, P, C, V> NIZKVerifierGadget<Gm17<PairingE, C, V>, ConstraintF>
|
||||
for Gm17VerifierGadget<PairingE, ConstraintF, P>
|
||||
where
|
||||
PairingE: PairingEngine,
|
||||
ConstraintF: Field,
|
||||
C: ConstraintSynthesizer<PairingE::Fr>,
|
||||
V: ToConstraintField<PairingE::Fr>,
|
||||
P: PairingGadget<PairingE, ConstraintF>,
|
||||
{
|
||||
type VerificationKeyGadget = VerifyingKeyGadget<PairingE, ConstraintF, P>;
|
||||
type ProofGadget = ProofGadget<PairingE, ConstraintF, P>;
|
||||
|
||||
fn check_verify<'a, CS, I, T>(
|
||||
mut cs: CS,
|
||||
vk: &Self::VerificationKeyGadget,
|
||||
mut public_inputs: I,
|
||||
proof: &Self::ProofGadget,
|
||||
) -> Result<(), SynthesisError>
|
||||
where
|
||||
CS: ConstraintSystem<ConstraintF>,
|
||||
I: Iterator<Item = &'a T>,
|
||||
T: 'a + ToBitsGadget<ConstraintF> + ?Sized,
|
||||
{
|
||||
let pvk = vk.prepare(&mut cs.ns(|| "Prepare vk"))?;
|
||||
// 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())?;
|
||||
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());
|
||||
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 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)?;
|
||||
|
||||
let g_psi_prep = P::prepare_g1(cs.ns(|| "Third prep"), &g_psi)?;
|
||||
|
||||
let c_prep = P::prepare_g1(cs.ns(|| "Fourth prep"), &proof.c)?;
|
||||
|
||||
P::miller_loop(
|
||||
cs.ns(|| "Miller loop 1"),
|
||||
&[
|
||||
test1_a_g_alpha_prep,
|
||||
g_psi_prep,
|
||||
c_prep,
|
||||
pvk.g_alpha_pc.clone(),
|
||||
],
|
||||
&[
|
||||
test1_b_h_beta_prep,
|
||||
pvk.h_gamma_pc.clone(),
|
||||
pvk.h_pc.clone(),
|
||||
pvk.h_beta_pc.clone(),
|
||||
],
|
||||
)?
|
||||
};
|
||||
|
||||
let test1 = P::final_exponentiation(cs.ns(|| "Final Exp 1"), &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)?;
|
||||
// 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.clone(), b_prep],
|
||||
)?
|
||||
};
|
||||
let test2 = P::final_exponentiation(cs.ns(|| "Final Exp 2"), &test2_exp)?;
|
||||
|
||||
let one = P::GTGadget::one(cs.ns(|| "GT One"))?;
|
||||
test1.enforce_equal(cs.ns(|| "Test 1"), &one)?;
|
||||
test2.enforce_equal(cs.ns(|| "Test 2"), &one)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<PairingE, ConstraintF, P> AllocGadget<VerifyingKey<PairingE>, ConstraintF>
|
||||
for VerifyingKeyGadget<PairingE, ConstraintF, P>
|
||||
where
|
||||
PairingE: PairingEngine,
|
||||
ConstraintF: Field,
|
||||
P: PairingGadget<PairingE, ConstraintF>,
|
||||
{
|
||||
#[inline]
|
||||
fn alloc<FN, T, CS: ConstraintSystem<ConstraintF>>(
|
||||
mut cs: CS,
|
||||
value_gen: FN,
|
||||
) -> Result<Self, SynthesisError>
|
||||
where
|
||||
FN: FnOnce() -> Result<T, SynthesisError>,
|
||||
T: Borrow<VerifyingKey<PairingE>>,
|
||||
{
|
||||
value_gen().and_then(|vk| {
|
||||
let VerifyingKey {
|
||||
h_g2,
|
||||
g_alpha_g1,
|
||||
h_beta_g2,
|
||||
g_gamma_g1,
|
||||
h_gamma_g2,
|
||||
query,
|
||||
} = vk.borrow().clone();
|
||||
let h_g2 = P::G2Gadget::alloc(cs.ns(|| "h_g2"), || Ok(h_g2.into_projective()))?;
|
||||
let g_alpha_g1 =
|
||||
P::G1Gadget::alloc(cs.ns(|| "g_alpha"), || Ok(g_alpha_g1.into_projective()))?;
|
||||
let h_beta_g2 =
|
||||
P::G2Gadget::alloc(cs.ns(|| "h_beta"), || Ok(h_beta_g2.into_projective()))?;
|
||||
let g_gamma_g1 =
|
||||
P::G1Gadget::alloc(cs.ns(|| "g_gamma_g1"), || Ok(g_gamma_g1.into_projective()))?;
|
||||
let h_gamma_g2 =
|
||||
P::G2Gadget::alloc(cs.ns(|| "h_gamma_g2"), || Ok(h_gamma_g2.into_projective()))?;
|
||||
|
||||
let query = query
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(i, query_i)| {
|
||||
P::G1Gadget::alloc(cs.ns(|| format!("query_{}", i)), || {
|
||||
Ok(query_i.into_projective())
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.into_iter()
|
||||
.collect::<Result<_, _>>()?;
|
||||
Ok(Self {
|
||||
h_g2,
|
||||
g_alpha_g1,
|
||||
h_beta_g2,
|
||||
g_gamma_g1,
|
||||
h_gamma_g2,
|
||||
query,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn alloc_input<FN, T, CS: ConstraintSystem<ConstraintF>>(
|
||||
mut cs: CS,
|
||||
value_gen: FN,
|
||||
) -> Result<Self, SynthesisError>
|
||||
where
|
||||
FN: FnOnce() -> Result<T, SynthesisError>,
|
||||
T: Borrow<VerifyingKey<PairingE>>,
|
||||
{
|
||||
value_gen().and_then(|vk| {
|
||||
let VerifyingKey {
|
||||
h_g2,
|
||||
g_alpha_g1,
|
||||
h_beta_g2,
|
||||
g_gamma_g1,
|
||||
h_gamma_g2,
|
||||
query,
|
||||
} = vk.borrow().clone();
|
||||
let h_g2 = P::G2Gadget::alloc_input(cs.ns(|| "h_g2"), || Ok(h_g2.into_projective()))?;
|
||||
let g_alpha_g1 =
|
||||
P::G1Gadget::alloc_input(cs.ns(|| "g_alpha"), || Ok(g_alpha_g1.into_projective()))?;
|
||||
let h_beta_g2 =
|
||||
P::G2Gadget::alloc_input(cs.ns(|| "h_beta"), || Ok(h_beta_g2.into_projective()))?;
|
||||
let g_gamma_g1 = P::G1Gadget::alloc_input(cs.ns(|| "g_gamma_g1"), || {
|
||||
Ok(g_gamma_g1.into_projective())
|
||||
})?;
|
||||
let h_gamma_g2 = P::G2Gadget::alloc_input(cs.ns(|| "h_gamma_g2"), || {
|
||||
Ok(h_gamma_g2.into_projective())
|
||||
})?;
|
||||
|
||||
let query = query
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(i, query_i)| {
|
||||
P::G1Gadget::alloc_input(cs.ns(|| format!("query_{}", i)), || {
|
||||
Ok(query_i.into_projective())
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.into_iter()
|
||||
.collect::<Result<_, _>>()?;
|
||||
Ok(Self {
|
||||
h_g2,
|
||||
g_alpha_g1,
|
||||
h_beta_g2,
|
||||
g_gamma_g1,
|
||||
h_gamma_g2,
|
||||
query,
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<PairingE, ConstraintF, P> AllocGadget<Proof<PairingE>, ConstraintF>
|
||||
for ProofGadget<PairingE, ConstraintF, P>
|
||||
where
|
||||
PairingE: PairingEngine,
|
||||
ConstraintF: Field,
|
||||
P: PairingGadget<PairingE, ConstraintF>,
|
||||
{
|
||||
#[inline]
|
||||
fn alloc<FN, T, CS: ConstraintSystem<ConstraintF>>(
|
||||
mut cs: CS,
|
||||
value_gen: FN,
|
||||
) -> Result<Self, SynthesisError>
|
||||
where
|
||||
FN: FnOnce() -> Result<T, SynthesisError>,
|
||||
T: Borrow<Proof<PairingE>>,
|
||||
{
|
||||
value_gen().and_then(|proof| {
|
||||
let Proof { a, b, c } = proof.borrow().clone();
|
||||
let a = P::G1Gadget::alloc_checked(cs.ns(|| "a"), || Ok(a.into_projective()))?;
|
||||
let b = P::G2Gadget::alloc_checked(cs.ns(|| "b"), || Ok(b.into_projective()))?;
|
||||
let c = P::G1Gadget::alloc_checked(cs.ns(|| "c"), || Ok(c.into_projective()))?;
|
||||
Ok(Self { a, b, c })
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn alloc_input<FN, T, CS: ConstraintSystem<ConstraintF>>(
|
||||
mut cs: CS,
|
||||
value_gen: FN,
|
||||
) -> Result<Self, SynthesisError>
|
||||
where
|
||||
FN: FnOnce() -> Result<T, SynthesisError>,
|
||||
T: Borrow<Proof<PairingE>>,
|
||||
{
|
||||
value_gen().and_then(|proof| {
|
||||
let Proof { a, b, c } = proof.borrow().clone();
|
||||
// We don't need to check here because the prime order check can be performed
|
||||
// in plain.
|
||||
let a = P::G1Gadget::alloc_input(cs.ns(|| "a"), || Ok(a.into_projective()))?;
|
||||
let b = P::G2Gadget::alloc_input(cs.ns(|| "b"), || Ok(b.into_projective()))?;
|
||||
let c = P::G1Gadget::alloc_input(cs.ns(|| "c"), || Ok(c.into_projective()))?;
|
||||
Ok(Self { a, b, c })
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<PairingE, ConstraintF, P> ToBytesGadget<ConstraintF>
|
||||
for VerifyingKeyGadget<PairingE, ConstraintF, P>
|
||||
where
|
||||
PairingE: PairingEngine,
|
||||
ConstraintF: Field,
|
||||
P: PairingGadget<PairingE, ConstraintF>,
|
||||
{
|
||||
#[inline]
|
||||
fn to_bytes<CS: ConstraintSystem<ConstraintF>>(
|
||||
&self,
|
||||
mut cs: CS,
|
||||
) -> Result<Vec<UInt8>, 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"))?);
|
||||
}
|
||||
Ok(bytes)
|
||||
}
|
||||
|
||||
fn to_bytes_strict<CS: ConstraintSystem<ConstraintF>>(
|
||||
&self,
|
||||
cs: CS,
|
||||
) -> Result<Vec<UInt8>, SynthesisError> {
|
||||
self.to_bytes(cs)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use gm17::*;
|
||||
use r1cs_core::{ConstraintSynthesizer, ConstraintSystem, SynthesisError};
|
||||
|
||||
use super::*;
|
||||
use algebra::{
|
||||
curves::bls12_377::Bls12_377,
|
||||
fields::bls12_377::Fr,
|
||||
fields::bls12_377::Fq,
|
||||
BitIterator, PrimeField,
|
||||
};
|
||||
use rand::{thread_rng, Rng};
|
||||
use r1cs_std::{
|
||||
boolean::Boolean, pairing::bls12_377::PairingGadget as Bls12_377PairingGadget,
|
||||
test_constraint_system::TestConstraintSystem,
|
||||
};
|
||||
|
||||
type TestProofSystem = Gm17<Bls12_377, Bench<Fr>, Fr>;
|
||||
type TestVerifierGadget = Gm17VerifierGadget<Bls12_377, Fq, Bls12_377PairingGadget>;
|
||||
type TestProofGadget = ProofGadget<Bls12_377, Fq, Bls12_377PairingGadget>;
|
||||
type TestVkGadget = VerifyingKeyGadget<Bls12_377, Fq, Bls12_377PairingGadget>;
|
||||
|
||||
struct Bench<F: Field> {
|
||||
inputs: Vec<Option<F>>,
|
||||
num_constraints: usize,
|
||||
}
|
||||
|
||||
impl<F: Field> ConstraintSynthesizer<F> for Bench<F> {
|
||||
fn generate_constraints<CS: ConstraintSystem<F>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
|
||||
assert!(self.inputs.len() >= 2);
|
||||
assert!(self.num_constraints >= self.inputs.len());
|
||||
|
||||
let mut variables: Vec<_> = Vec::with_capacity(self.inputs.len());
|
||||
for (i, input) in self.inputs.into_iter().enumerate() {
|
||||
let input_var = cs.alloc_input(
|
||||
|| format!("Input {}", i),
|
||||
|| input.ok_or(SynthesisError::AssignmentMissing),
|
||||
)?;
|
||||
variables.push((input, input_var));
|
||||
}
|
||||
|
||||
for i in 0..self.num_constraints {
|
||||
let new_entry = {
|
||||
let (input_1_val, input_1_var) = variables[i];
|
||||
let (input_2_val, input_2_var) = variables[i + 1];
|
||||
let result_val = input_1_val
|
||||
.and_then(|input_1| input_2_val.map(|input_2| input_1 * &input_2));
|
||||
let result_var = cs.alloc(
|
||||
|| format!("Result {}", i),
|
||||
|| result_val.ok_or(SynthesisError::AssignmentMissing),
|
||||
)?;
|
||||
cs.enforce(
|
||||
|| format!("Enforce constraint {}", i),
|
||||
|lc| lc + input_1_var,
|
||||
|lc| lc + input_2_var,
|
||||
|lc| lc + result_var,
|
||||
);
|
||||
(result_val, result_var)
|
||||
};
|
||||
variables.push(new_entry);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gm17_verifier_test() {
|
||||
let num_inputs = 100;
|
||||
let num_constraints = num_inputs;
|
||||
let rng = &mut thread_rng();
|
||||
let mut inputs: Vec<Option<Fr>> = Vec::with_capacity(num_inputs);
|
||||
for _ in 0..num_inputs {
|
||||
inputs.push(Some(rng.gen()));
|
||||
}
|
||||
let params = {
|
||||
let c = Bench::<Fr> {
|
||||
inputs: vec![None; num_inputs],
|
||||
num_constraints,
|
||||
};
|
||||
|
||||
generate_random_parameters(c, rng).unwrap()
|
||||
};
|
||||
|
||||
{
|
||||
let proof = {
|
||||
// Create an instance of our circuit (with the
|
||||
// witness)
|
||||
let c = Bench {
|
||||
inputs: inputs.clone(),
|
||||
num_constraints,
|
||||
};
|
||||
// Create a gm17 proof with our parameters.
|
||||
create_random_proof(c, ¶ms, rng).unwrap()
|
||||
};
|
||||
|
||||
// assert!(!verify_proof(&pvk, &proof, &[a]).unwrap());
|
||||
let mut cs = TestConstraintSystem::<Fq>::new();
|
||||
|
||||
let inputs: Vec<_> = inputs.into_iter().map(|input| input.unwrap()).collect();
|
||||
let mut input_gadgets = Vec::new();
|
||||
|
||||
{
|
||||
let mut cs = cs.ns(|| "Allocate Input");
|
||||
for (i, input) in inputs.into_iter().enumerate() {
|
||||
let mut input_bits = BitIterator::new(input.into_repr()).collect::<Vec<_>>();
|
||||
// Input must be in little-endian, but BitIterator outputs in big-endian.
|
||||
input_bits.reverse();
|
||||
|
||||
let input_bits =
|
||||
Vec::<Boolean>::alloc_input(cs.ns(|| format!("Input {}", i)), || {
|
||||
Ok(input_bits)
|
||||
})
|
||||
.unwrap();
|
||||
input_gadgets.push(input_bits);
|
||||
}
|
||||
}
|
||||
|
||||
let vk_gadget = TestVkGadget::alloc_input(cs.ns(|| "Vk"), || Ok(¶ms.vk)).unwrap();
|
||||
let proof_gadget =
|
||||
TestProofGadget::alloc(cs.ns(|| "Proof"), || Ok(proof.clone())).unwrap();
|
||||
println!("Time to verify!\n\n\n\n");
|
||||
<TestVerifierGadget as NIZKVerifierGadget<TestProofSystem, Fq>>::check_verify(
|
||||
cs.ns(|| "Verify"),
|
||||
&vk_gadget,
|
||||
input_gadgets.iter(),
|
||||
&proof_gadget,
|
||||
)
|
||||
.unwrap();
|
||||
if !cs.is_satisfied() {
|
||||
println!("=========================================================");
|
||||
println!("Unsatisfied constraints:");
|
||||
println!("{:?}", cs.which_is_unsatisfied().unwrap());
|
||||
println!("=========================================================");
|
||||
}
|
||||
|
||||
// cs.print_named_objects();
|
||||
assert!(cs.is_satisfied());
|
||||
}
|
||||
}
|
||||
}
|
||||
81
crypto-primitives/src/nizk/gm17/mod.rs
Normal file
81
crypto-primitives/src/nizk/gm17/mod.rs
Normal file
@@ -0,0 +1,81 @@
|
||||
use algebra::PairingEngine;
|
||||
use crate::Error;
|
||||
use rand::Rng;
|
||||
use gm17::{
|
||||
create_random_proof, generate_random_parameters, prepare_verifying_key, verify_proof,
|
||||
Parameters, PreparedVerifyingKey, Proof, VerifyingKey,
|
||||
};
|
||||
use r1cs_core::ConstraintSynthesizer;
|
||||
|
||||
use algebra::ToConstraintField;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use super::NIZK;
|
||||
|
||||
#[cfg(feature = "r1cs")]
|
||||
pub mod constraints;
|
||||
|
||||
/// Note: V should serialize its contents to `Vec<E::Fr>` in the same order as
|
||||
/// during the constraint generation.
|
||||
pub struct Gm17<E: PairingEngine, C: ConstraintSynthesizer<E::Fr>, V: ToConstraintField<E::Fr> + ?Sized> {
|
||||
#[doc(hidden)]
|
||||
_engine: PhantomData<E>,
|
||||
#[doc(hidden)]
|
||||
_circuit: PhantomData<C>,
|
||||
#[doc(hidden)]
|
||||
_verifier_input: PhantomData<V>,
|
||||
}
|
||||
|
||||
impl<E: PairingEngine, C: ConstraintSynthesizer<E::Fr>, V: ToConstraintField<E::Fr> + ?Sized> NIZK for Gm17<E, C, V> {
|
||||
type Circuit = C;
|
||||
type AssignedCircuit = C;
|
||||
type ProvingParameters = Parameters<E>;
|
||||
type VerificationParameters = VerifyingKey<E>;
|
||||
type PreparedVerificationParameters = PreparedVerifyingKey<E>;
|
||||
type VerifierInput = V;
|
||||
type Proof = Proof<E>;
|
||||
|
||||
fn setup<R: Rng>(
|
||||
circuit: Self::Circuit,
|
||||
rng: &mut R,
|
||||
) -> Result<
|
||||
(
|
||||
Self::ProvingParameters,
|
||||
Self::PreparedVerificationParameters,
|
||||
),
|
||||
Error,
|
||||
> {
|
||||
let nizk_time = start_timer!(|| "{Groth-Maller 2017}::Setup");
|
||||
let pp = generate_random_parameters::<E, Self::Circuit, R>(circuit, rng)?;
|
||||
let vk = prepare_verifying_key(&pp.vk);
|
||||
end_timer!(nizk_time);
|
||||
Ok((pp, vk))
|
||||
}
|
||||
|
||||
fn prove<R: Rng>(
|
||||
pp: &Self::ProvingParameters,
|
||||
input_and_witness: Self::AssignedCircuit,
|
||||
rng: &mut R,
|
||||
) -> Result<Self::Proof, Error> {
|
||||
let proof_time = start_timer!(|| "{Groth-Maller 2017}::Prove");
|
||||
let result = create_random_proof::<E, _, _>(input_and_witness, pp, rng)?;
|
||||
end_timer!(proof_time);
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn verify(
|
||||
vk: &Self::PreparedVerificationParameters,
|
||||
input: &Self::VerifierInput,
|
||||
proof: &Self::Proof,
|
||||
) -> Result<bool, Error> {
|
||||
let verify_time = start_timer!(|| "{Groth-Maller 2017}::Verify");
|
||||
let conversion_time = start_timer!(|| "Convert input to E::Fr");
|
||||
let input = input.to_field_elements()?;
|
||||
end_timer!(conversion_time);
|
||||
let verification = start_timer!(|| format!("Verify proof w/ input len: {}", input.len()));
|
||||
let result = verify_proof(&vk, proof, &input)?;
|
||||
end_timer!(verification);
|
||||
end_timer!(verify_time);
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
112
crypto-primitives/src/nizk/mod.rs
Normal file
112
crypto-primitives/src/nizk/mod.rs
Normal file
@@ -0,0 +1,112 @@
|
||||
use algebra::bytes::ToBytes;
|
||||
use rand::Rng;
|
||||
|
||||
#[cfg(feature = "gm17")]
|
||||
pub mod gm17;
|
||||
#[cfg(feature = "gm17")]
|
||||
pub use self::gm17::Gm17;
|
||||
|
||||
#[cfg(feature = "r1cs")]
|
||||
pub mod constraints;
|
||||
#[cfg(feature = "r1cs")]
|
||||
pub use constraints::*;
|
||||
|
||||
use crate::Error;
|
||||
|
||||
pub trait NIZK {
|
||||
type Circuit;
|
||||
type AssignedCircuit;
|
||||
type VerifierInput: ?Sized;
|
||||
type ProvingParameters: Clone;
|
||||
type VerificationParameters: Clone + Default + From<Self::PreparedVerificationParameters>;
|
||||
type PreparedVerificationParameters: Clone + Default + From<Self::VerificationParameters>;
|
||||
type Proof: ToBytes + Clone + Default;
|
||||
|
||||
fn setup<R: Rng>(
|
||||
circuit: Self::Circuit,
|
||||
rng: &mut R,
|
||||
) -> Result<
|
||||
(
|
||||
Self::ProvingParameters,
|
||||
Self::PreparedVerificationParameters,
|
||||
),
|
||||
Error,
|
||||
>;
|
||||
|
||||
fn prove<R: Rng>(
|
||||
parameter: &Self::ProvingParameters,
|
||||
input_and_witness: Self::AssignedCircuit,
|
||||
rng: &mut R,
|
||||
) -> Result<Self::Proof, Error>;
|
||||
|
||||
fn verify(
|
||||
verifier_key: &Self::PreparedVerificationParameters,
|
||||
input: &Self::VerifierInput,
|
||||
proof: &Self::Proof,
|
||||
) -> Result<bool, Error>;
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "gm17", test))]
|
||||
mod test {
|
||||
use rand::thread_rng;
|
||||
use std::ops::AddAssign;
|
||||
|
||||
#[test]
|
||||
fn test_gm17() {
|
||||
use crate::nizk::{gm17::Gm17, NIZK};
|
||||
use algebra::{curves::bls12_381::Bls12_381, fields::bls12_381::Fr, Field};
|
||||
use r1cs_core::{ConstraintSynthesizer, ConstraintSystem, SynthesisError};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct R1CSCircuit {
|
||||
x: Option<Fr>,
|
||||
sum: Option<Fr>,
|
||||
w: Option<Fr>,
|
||||
}
|
||||
|
||||
impl R1CSCircuit {
|
||||
pub(super) fn new(x: Fr, sum: Fr, w: Fr) -> Self {
|
||||
Self {
|
||||
x: Some(x),
|
||||
sum: Some(sum),
|
||||
w: Some(w),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ConstraintSynthesizer<Fr> for R1CSCircuit {
|
||||
fn generate_constraints<CS: ConstraintSystem<Fr>>(
|
||||
self,
|
||||
cs: &mut CS,
|
||||
) -> 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,
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
let mut sum = Fr::one();
|
||||
sum.add_assign(&Fr::one());
|
||||
let circuit = R1CSCircuit::new(Fr::one(), sum, Fr::one());
|
||||
|
||||
let rng = &mut thread_rng();
|
||||
|
||||
let parameters = Gm17::<Bls12_381, R1CSCircuit, [Fr]>::setup(circuit, rng).unwrap();
|
||||
|
||||
let proof =
|
||||
Gm17::<Bls12_381, R1CSCircuit, [Fr]>::prove(¶meters.0, circuit, rng).unwrap();
|
||||
|
||||
let result =
|
||||
Gm17::<Bls12_381, R1CSCircuit, [Fr]>::verify(¶meters.1, &[Fr::one(), sum], &proof)
|
||||
.unwrap();
|
||||
assert!(result);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user