Skip to content

Commit 48c44f5

Browse files
committed
add testudo snark and nizk in separate files
1 parent 07ab741 commit 48c44f5

File tree

2 files changed

+560
-0
lines changed

2 files changed

+560
-0
lines changed

src/testudo_nizk.rs

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
use std::cmp::max;
2+
3+
use crate::errors::ProofVerifyError;
4+
use crate::r1csproof::R1CSVerifierProof;
5+
use crate::{
6+
poseidon_transcript::PoseidonTranscript,
7+
r1csproof::{R1CSGens, R1CSProof},
8+
transcript::Transcript,
9+
InputsAssignment, Instance, VarsAssignment,
10+
};
11+
use ark_crypto_primitives::sponge::poseidon::PoseidonConfig;
12+
use ark_crypto_primitives::sponge::Absorb;
13+
use ark_ec::pairing::Pairing;
14+
15+
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
16+
17+
#[derive(Debug, CanonicalSerialize, CanonicalDeserialize)]
18+
pub struct TestudoNizk<E: Pairing> {
19+
pub r1cs_verifier_proof: R1CSVerifierProof<E>,
20+
pub r: (Vec<E::ScalarField>, Vec<E::ScalarField>),
21+
}
22+
23+
pub struct TestudoNizkGens<E: Pairing> {
24+
gens_r1cs_sat: R1CSGens<E>,
25+
}
26+
27+
impl<E: Pairing> TestudoNizkGens<E> {
28+
/// Constructs a new `TestudoNizkGens` given the size of the R1CS statement
29+
/// `num_nz_entries` specifies the maximum number of non-zero entries in any of the three R1CS matrices
30+
pub fn new(
31+
num_cons: usize,
32+
num_vars: usize,
33+
num_inputs: usize,
34+
poseidon: PoseidonConfig<E::ScalarField>,
35+
) -> Self {
36+
// ensure num_vars is a power of 2
37+
let num_vars_padded = {
38+
let mut num_vars_padded = max(num_vars, num_inputs + 1);
39+
if num_vars_padded != num_vars_padded.next_power_of_two() {
40+
num_vars_padded = num_vars_padded.next_power_of_two();
41+
}
42+
num_vars_padded
43+
};
44+
45+
let num_cons_padded = {
46+
let mut num_cons_padded = num_cons;
47+
48+
// ensure that num_cons_padded is at least 2
49+
if num_cons_padded == 0 || num_cons_padded == 1 {
50+
num_cons_padded = 2;
51+
}
52+
53+
// ensure that num_cons_padded is a power of 2
54+
if num_cons.next_power_of_two() != num_cons {
55+
num_cons_padded = num_cons.next_power_of_two();
56+
}
57+
num_cons_padded
58+
};
59+
60+
let gens_r1cs_sat = R1CSGens::new(
61+
b"gens_r1cs_sat",
62+
num_cons_padded,
63+
num_vars_padded,
64+
num_inputs,
65+
poseidon,
66+
);
67+
TestudoNizkGens { gens_r1cs_sat }
68+
}
69+
}
70+
71+
impl<E: Pairing> TestudoNizk<E>
72+
where
73+
E::ScalarField: Absorb,
74+
{
75+
// Returns the Testudo SNARK proof which has two components:
76+
// * proof that the R1CS instance is satisfiable
77+
// * proof that the evlauation of matrices A, B and C on (x,y) are correct
78+
pub fn prove(
79+
inst: &Instance<E::ScalarField>,
80+
vars: VarsAssignment<E::ScalarField>,
81+
inputs: &InputsAssignment<E::ScalarField>,
82+
gens: &TestudoNizkGens<E>,
83+
transcript: &mut PoseidonTranscript<E::ScalarField>,
84+
poseidon: PoseidonConfig<E::ScalarField>,
85+
) -> Result<TestudoNizk<E>, ProofVerifyError> {
86+
transcript.append_bytes(b"", &inst.digest);
87+
88+
let c: E::ScalarField = transcript.challenge_scalar(b"");
89+
transcript.new_from_state(&c);
90+
91+
// we might need to pad variables
92+
let padded_vars = {
93+
let num_padded_vars = inst.inst.get_num_vars();
94+
let num_vars = vars.assignment.len();
95+
if num_padded_vars > num_vars {
96+
vars.pad(num_padded_vars)
97+
} else {
98+
vars
99+
}
100+
};
101+
102+
let (r1cs_sat_proof, rx, ry) = R1CSProof::prove(
103+
&inst.inst,
104+
padded_vars.assignment,
105+
&inputs.assignment,
106+
&gens.gens_r1cs_sat,
107+
transcript,
108+
);
109+
110+
let inst_evals = inst.inst.evaluate(&rx, &ry);
111+
112+
transcript.new_from_state(&c);
113+
let r1cs_verifier_proof = r1cs_sat_proof
114+
.prove_verifier(
115+
inst.inst.get_num_vars(),
116+
inst.inst.get_num_cons(),
117+
&inputs.assignment,
118+
&inst_evals,
119+
transcript,
120+
&gens.gens_r1cs_sat,
121+
poseidon,
122+
)
123+
.unwrap();
124+
Ok(TestudoNizk {
125+
r1cs_verifier_proof,
126+
r: (rx, ry),
127+
})
128+
}
129+
130+
// Verifies the Testudo SNARK proof ensuring the satisfiability of an R1CS
131+
// instance
132+
pub fn verify(
133+
&self,
134+
gens: &TestudoNizkGens<E>,
135+
inst: &Instance<E::ScalarField>,
136+
input: &InputsAssignment<E::ScalarField>,
137+
transcript: &mut PoseidonTranscript<E::ScalarField>,
138+
_poseidon: PoseidonConfig<E::ScalarField>,
139+
) -> Result<bool, ProofVerifyError> {
140+
transcript.append_bytes(b"", &inst.digest);
141+
let (claimed_rx, claimed_ry) = &self.r;
142+
let inst_evals = inst.inst.evaluate(claimed_rx, claimed_ry);
143+
144+
let sat_verified = self.r1cs_verifier_proof.verify(
145+
&input.assignment,
146+
&inst_evals,
147+
transcript,
148+
&gens.gens_r1cs_sat,
149+
)?;
150+
assert!(sat_verified == true);
151+
Ok(sat_verified)
152+
}
153+
}
154+
155+
#[cfg(test)]
156+
mod tests {
157+
use crate::{
158+
parameters::poseidon_params,
159+
poseidon_transcript::PoseidonTranscript,
160+
testudo_nizk::{TestudoNizk, TestudoNizkGens},
161+
Instance,
162+
};
163+
164+
#[test]
165+
pub fn check_testudo_nizk() {
166+
let num_vars = 256;
167+
let num_cons = num_vars;
168+
let num_inputs = 10;
169+
170+
type E = ark_bls12_377::Bls12_377;
171+
172+
// produce public generators
173+
let gens = TestudoNizkGens::<E>::new(num_cons, num_vars, num_inputs, poseidon_params());
174+
175+
// produce a synthetic R1CSInstance
176+
let (inst, vars, inputs) = Instance::produce_synthetic_r1cs(num_cons, num_vars, num_inputs);
177+
178+
let params = poseidon_params();
179+
180+
// produce a proof
181+
let mut prover_transcript = PoseidonTranscript::new(&params);
182+
let proof =
183+
TestudoNizk::prove(&inst, vars, &inputs, &gens, &mut prover_transcript, params).unwrap();
184+
185+
// verify the proof
186+
let mut verifier_transcript = PoseidonTranscript::new(&poseidon_params());
187+
assert!(proof
188+
.verify(
189+
&gens,
190+
&inst,
191+
&inputs,
192+
&mut verifier_transcript,
193+
poseidon_params()
194+
)
195+
.is_ok());
196+
}
197+
}

0 commit comments

Comments
 (0)