|
| 1 | +use ark_ff::{BigInteger, One, PrimeField, Zero}; |
| 2 | +use kzg::scheme::KzgScheme; |
| 3 | +use kzg::srs::Srs; |
| 4 | +use kzg::types::{BaseField, ScalarField}; |
| 5 | +use nova::circuit::{AugmentedCircuit, FCircuit, State}; |
| 6 | +use nova::ivc::{IVCProof, ZkIVCProof, IVC}; |
| 7 | +use nova::r1cs::{create_trivial_pair, FInstance, FWitness, R1CS}; |
| 8 | +use nova::transcript::Transcript; |
| 9 | +use nova::utils::{to_f_matrix, to_f_vec}; |
| 10 | +use sha2::Sha256; |
| 11 | + |
| 12 | +struct TestCircuit {} |
| 13 | +impl FCircuit for TestCircuit { |
| 14 | + fn run(&self, z_i: &State, w_i: &FWitness) -> State { |
| 15 | + let x = w_i.w[0]; |
| 16 | + let res = x * x * x + x + ScalarField::from(5); |
| 17 | + let base_res = BaseField::from_le_bytes_mod_order(&res.into_bigint().to_bytes_le()); |
| 18 | + |
| 19 | + State { |
| 20 | + state: z_i.state + base_res, |
| 21 | + } |
| 22 | + } |
| 23 | +} |
| 24 | +fn main() { |
| 25 | + // (x0^3 + x0 + 5) + (x1^3 + x1 + 5) + (x2^3 + x2 + 5) + (x3^3 + x2 + 5) = 130 |
| 26 | + // x0 = 3, x1 = 4, x2 = 1, x3 = 2 |
| 27 | + |
| 28 | + // generate R1CS, witnesses and public input, output. |
| 29 | + let (r1cs, witnesses, x) = gen_test_values::<ScalarField>(vec![3, 4, 1, 2]); |
| 30 | + let (matrix_a, _, _) = ( |
| 31 | + r1cs.matrix_a.clone(), |
| 32 | + r1cs.matrix_b.clone(), |
| 33 | + r1cs.matrix_c.clone(), |
| 34 | + ); |
| 35 | + |
| 36 | + // Trusted setup |
| 37 | + let domain_size = witnesses[0].len() + x[0].len() + 1; |
| 38 | + let srs = Srs::new(domain_size); |
| 39 | + let scheme = KzgScheme::new(srs); |
| 40 | + let x_len = x[0].len(); |
| 41 | + |
| 42 | + // Generate witnesses and instances |
| 43 | + let w: Vec<FWitness> = witnesses |
| 44 | + .iter() |
| 45 | + .map(|witness| FWitness::new(witness, matrix_a.len())) |
| 46 | + .collect(); |
| 47 | + let mut u: Vec<FInstance> = w |
| 48 | + .iter() |
| 49 | + .zip(x) |
| 50 | + .map(|(w, x)| w.commit(&scheme, &x)) |
| 51 | + .collect(); |
| 52 | + |
| 53 | + // step i |
| 54 | + let mut i = BaseField::zero(); |
| 55 | + |
| 56 | + // generate trivial instance-witness pair |
| 57 | + let (trivial_witness, trivial_instance) = |
| 58 | + create_trivial_pair(x_len, witnesses[0].len(), &scheme); |
| 59 | + |
| 60 | + // generate f_circuit instance |
| 61 | + let f_circuit = TestCircuit {}; |
| 62 | + |
| 63 | + // generate states |
| 64 | + let mut z = vec![ |
| 65 | + State { |
| 66 | + state: BaseField::from(0) |
| 67 | + }; |
| 68 | + 5 |
| 69 | + ]; |
| 70 | + for index in 1..5 { |
| 71 | + z[index] = f_circuit.run(&z[index - 1], &w[index - 1]); |
| 72 | + } |
| 73 | + |
| 74 | + let mut prover_transcript; |
| 75 | + let mut verifier_transcript = Transcript::<Sha256>::default(); |
| 76 | + |
| 77 | + // create F' |
| 78 | + let augmented_circuit = |
| 79 | + AugmentedCircuit::<Sha256, TestCircuit>::new(f_circuit, &trivial_instance, &z[0]); |
| 80 | + |
| 81 | + // generate IVC |
| 82 | + let mut ivc = IVC::<Sha256, TestCircuit> { |
| 83 | + scheme, |
| 84 | + augmented_circuit, |
| 85 | + }; |
| 86 | + |
| 87 | + // initialize IVC proof, zkIVCProof, folded witness and folded instance |
| 88 | + let mut ivc_proof = IVCProof::trivial_ivc_proof(&trivial_instance, &trivial_witness); |
| 89 | + let mut zk_ivc_proof = ZkIVCProof::trivial_zk_ivc_proof(&trivial_instance); |
| 90 | + let mut folded_witness = trivial_witness.clone(); |
| 91 | + let mut folded_instance = trivial_instance.clone(); |
| 92 | + |
| 93 | + let mut res; |
| 94 | + for step in 0..4 { |
| 95 | + println!("Step: {:?}", step); |
| 96 | + if step == 0 { |
| 97 | + res = ivc.augmented_circuit.run(&u[step], None, &w[step], None); |
| 98 | + } else { |
| 99 | + res = ivc.augmented_circuit.run( |
| 100 | + &ivc_proof.u_i, |
| 101 | + Some(&ivc_proof.big_u_i.clone()), |
| 102 | + &ivc_proof.w_i, |
| 103 | + Some(&zk_ivc_proof.com_t.clone().unwrap()), |
| 104 | + ); |
| 105 | + } |
| 106 | + |
| 107 | + if res.is_err() { |
| 108 | + println!("{:?}", res); |
| 109 | + } |
| 110 | + assert!(res.is_ok()); |
| 111 | + |
| 112 | + // verifier verify this step |
| 113 | + let verify = ivc.verify(&zk_ivc_proof, &mut verifier_transcript); |
| 114 | + if verify.is_err() { |
| 115 | + println!("{:?}", verify); |
| 116 | + } |
| 117 | + assert!(verify.is_ok()); |
| 118 | + |
| 119 | + // update for next step |
| 120 | + |
| 121 | + if step != 3 { |
| 122 | + // do not update if we have done with IVC |
| 123 | + ivc.augmented_circuit.next_step(); |
| 124 | + i += BaseField::one(); |
| 125 | + assert_eq!(ivc.augmented_circuit.z_i.state, z[step + 1].state); |
| 126 | + prover_transcript = Transcript::<Sha256>::default(); |
| 127 | + verifier_transcript = Transcript::<Sha256>::default(); |
| 128 | + |
| 129 | + let hash_x = AugmentedCircuit::<Sha256, TestCircuit>::hash_io( |
| 130 | + i, |
| 131 | + &z[0], |
| 132 | + &z[step + 1], |
| 133 | + &folded_instance, |
| 134 | + ); |
| 135 | + // convert u_1_x from BaseField into ScalarField |
| 136 | + u[step + 1].x = vec![ScalarField::from_le_bytes_mod_order( |
| 137 | + &hash_x.into_bigint().to_bytes_le(), |
| 138 | + )]; |
| 139 | + |
| 140 | + // generate ivc_proof and zkSNARK proof. |
| 141 | + ivc_proof = IVCProof::new( |
| 142 | + &u[step + 1], |
| 143 | + &w[step + 1], |
| 144 | + &folded_instance, |
| 145 | + &folded_witness, |
| 146 | + ); |
| 147 | + (folded_witness, folded_instance, zk_ivc_proof) = |
| 148 | + ivc.prove(&r1cs, &ivc_proof, &mut prover_transcript); |
| 149 | + } |
| 150 | + } |
| 151 | +} |
| 152 | + |
| 153 | +fn gen_test_values<F: PrimeField>(inputs: Vec<usize>) -> (R1CS<F>, Vec<Vec<F>>, Vec<Vec<F>>) { |
| 154 | + // R1CS for: x^3 + x + 5 = y (example from article |
| 155 | + // https://vitalik.eth.limo/general/2016/12/10/qap.html ) |
| 156 | + |
| 157 | + let a = to_f_matrix::<F>(&[ |
| 158 | + vec![1, 0, 0, 0, 0, 0], |
| 159 | + vec![0, 1, 0, 0, 0, 0], |
| 160 | + vec![1, 0, 1, 0, 0, 0], |
| 161 | + vec![0, 0, 0, 1, 0, 5], |
| 162 | + ]); |
| 163 | + let b = to_f_matrix::<F>(&[ |
| 164 | + vec![1, 0, 0, 0, 0, 0], |
| 165 | + vec![1, 0, 0, 0, 0, 0], |
| 166 | + vec![0, 0, 0, 0, 0, 1], |
| 167 | + vec![0, 0, 0, 0, 0, 1], |
| 168 | + ]); |
| 169 | + let c = to_f_matrix::<F>(&[ |
| 170 | + vec![0, 1, 0, 0, 0, 0], |
| 171 | + vec![0, 0, 1, 0, 0, 0], |
| 172 | + vec![0, 0, 0, 1, 0, 0], |
| 173 | + vec![0, 0, 0, 0, 1, 0], |
| 174 | + ]); |
| 175 | + |
| 176 | + // generate n witnesses |
| 177 | + let mut w: Vec<Vec<F>> = Vec::new(); |
| 178 | + let mut x: Vec<Vec<F>> = Vec::new(); |
| 179 | + for input in inputs { |
| 180 | + let w_i = to_f_vec::<F>(vec![ |
| 181 | + input, |
| 182 | + input * input, // x^2 |
| 183 | + input * input * input, // x^2 * x |
| 184 | + input * input * input + input, // x^3 + x |
| 185 | + ]); |
| 186 | + w.push(w_i.clone()); |
| 187 | + let x_i = to_f_vec::<F>(vec![input * input * input + input + 5]); // output: x^3 + x + 5 |
| 188 | + x.push(x_i.clone()); |
| 189 | + } |
| 190 | + |
| 191 | + let r1cs = R1CS::<F> { |
| 192 | + matrix_a: a, |
| 193 | + matrix_b: b, |
| 194 | + matrix_c: c, |
| 195 | + num_io: 1, |
| 196 | + num_vars: 4, |
| 197 | + }; |
| 198 | + (r1cs, w, x) |
| 199 | +} |
0 commit comments