circom-compat/src/zkey.rs
src/zkey.rsRaw
1//! ZKey Parsing
2//!
3//! Each ZKey file is broken into sections:
4//! Header(1)
5//! Prover Type 1 Groth
6//! HeaderGroth(2)
7//! n8q
8//! q
9//! n8r
10//! r
11//! NVars
12//! NPub
13//! DomainSize (multiple of 2
14//! alpha1
15//! beta1
16//! delta1
17//! beta2
18//! gamma2
19//! delta2
20//! IC(3)
21//! Coefs(4)
22//! PointsA(5)
23//! PointsB1(6)
24//! PointsB2(7)
25//! PointsC(8)
26//! PointsH(9)
27//! Contributions(10)
28use ark_ff::{BigInteger256, FromBytes, PrimeField};
29use ark_relations::r1cs::ConstraintMatrices;
30use ark_serialize::{CanonicalDeserialize, SerializationError};
31use ark_std::log2;
32use byteorder::{LittleEndian, ReadBytesExt};
33
34use std::{
35 collections::HashMap,
36 io::{Read, Result as IoResult, Seek, SeekFrom},
37};
38
39use ark_bn254::{Bn254, Fq, Fq2, Fr, G1Affine, G2Affine};
40use ark_groth16::{ProvingKey, VerifyingKey};
41use num_traits::Zero;
42
43#[derive(Clone, Debug)]
44struct Section {
45 position: u64,
46 #[allow(dead_code)]
47 size: usize,
48}
49
50/// Reads a SnarkJS ZKey file into an Arkworks ProvingKey.
51pub fn read_zkey<R: Read + Seek>(
52 reader: &mut R,
53) -> IoResult<(ProvingKey<Bn254>, ConstraintMatrices<Fr>)> {
54 let mut binfile = BinFile::new(reader)?;
55 let proving_key = binfile.proving_key()?;
56 let matrices = binfile.matrices()?;
57 Ok((proving_key, matrices))
58}
59
60#[derive(Debug)]
61struct BinFile<'a, R> {
62 #[allow(dead_code)]
63 ftype: String,
64 #[allow(dead_code)]
65 version: u32,
66 sections: HashMap<u32, Vec<Section>>,
67 reader: &'a mut R,
68}
69
70impl<'a, R: Read + Seek> BinFile<'a, R> {
71 fn new(reader: &'a mut R) -> IoResult<Self> {
72 let mut magic = [0u8; 4];
73 reader.read_exact(&mut magic)?;
74
75 let version = reader.read_u32::<LittleEndian>()?;
76
77 let num_sections = reader.read_u32::<LittleEndian>()?;
78
79 let mut sections = HashMap::new();
80 for _ in 0..num_sections {
81 let section_id = reader.read_u32::<LittleEndian>()?;
82 let section_length = reader.read_u64::<LittleEndian>()?;
83
84 let section = sections.entry(section_id).or_insert_with(Vec::new);
85 section.push(Section {
86 position: reader.stream_position()?,
87 size: section_length as usize,
88 });
89
90 reader.seek(SeekFrom::Current(section_length as i64))?;
91 }
92
93 Ok(Self {
94 ftype: std::str::from_utf8(&magic[..]).unwrap().to_string(),
95 version,
96 sections,
97 reader,
98 })
99 }
100
101 fn proving_key(&mut self) -> IoResult<ProvingKey<Bn254>> {
102 let header = self.groth_header()?;
103 let ic = self.ic(header.n_public)?;
104
105 let a_query = self.a_query(header.n_vars)?;
106 let b_g1_query = self.b_g1_query(header.n_vars)?;
107 let b_g2_query = self.b_g2_query(header.n_vars)?;
108 let l_query = self.l_query(header.n_vars - header.n_public - 1)?;
109 let h_query = self.h_query(header.domain_size as usize)?;
110
111 let vk = VerifyingKey::<Bn254> {
112 alpha_g1: header.verifying_key.alpha_g1,
113 beta_g2: header.verifying_key.beta_g2,
114 gamma_g2: header.verifying_key.gamma_g2,
115 delta_g2: header.verifying_key.delta_g2,
116 gamma_abc_g1: ic,
117 };
118
119 let pk = ProvingKey::<Bn254> {
120 vk,
121 beta_g1: header.verifying_key.beta_g1,
122 delta_g1: header.verifying_key.delta_g1,
123 a_query,
124 b_g1_query,
125 b_g2_query,
126 h_query,
127 l_query,
128 };
129
130 Ok(pk)
131 }
132
133 fn get_section(&self, id: u32) -> Section {
134 self.sections.get(&id).unwrap()[0].clone()
135 }
136
137 fn groth_header(&mut self) -> IoResult<HeaderGroth> {
138 let section = self.get_section(2);
139 let header = HeaderGroth::new(&mut self.reader, §ion)?;
140 Ok(header)
141 }
142
143 fn ic(&mut self, n_public: usize) -> IoResult<Vec<G1Affine>> {
144 // the range is non-inclusive so we do +1 to get all inputs
145 self.g1_section(n_public + 1, 3)
146 }
147
148 /// Returns the [`ConstraintMatrices`] corresponding to the zkey
149 pub fn matrices(&mut self) -> IoResult<ConstraintMatrices<Fr>> {
150 let header = self.groth_header()?;
151
152 let section = self.get_section(4);
153 self.reader.seek(SeekFrom::Start(section.position))?;
154 let num_coeffs: u32 = self.reader.read_u32::<LittleEndian>()?;
155
156 // insantiate AB
157 let mut matrices = vec![vec![vec![]; header.domain_size as usize]; 2];
158 let mut max_constraint_index = 0;
159 for _ in 0..num_coeffs {
160 let matrix: u32 = self.reader.read_u32::<LittleEndian>()?;
161 let constraint: u32 = self.reader.read_u32::<LittleEndian>()?;
162 let signal: u32 = self.reader.read_u32::<LittleEndian>()?;
163
164 let value: Fr = deserialize_field_fr(&mut self.reader)?;
165 max_constraint_index = std::cmp::max(max_constraint_index, constraint);
166 matrices[matrix as usize][constraint as usize].push((value, signal as usize));
167 }
168
169 let num_constraints = max_constraint_index as usize - header.n_public;
170 // Remove the public input constraints, Arkworks adds them later
171 matrices.iter_mut().for_each(|m| {
172 m.truncate(num_constraints);
173 });
174 // This is taken from Arkworks' to_matrices() function
175 let a = matrices[0].clone();
176 let b = matrices[1].clone();
177 let a_num_non_zero: usize = a.iter().map(|lc| lc.len()).sum();
178 let b_num_non_zero: usize = b.iter().map(|lc| lc.len()).sum();
179 let matrices = ConstraintMatrices {
180 num_instance_variables: header.n_public + 1,
181 num_witness_variables: header.n_vars - header.n_public,
182 num_constraints,
183
184 a_num_non_zero,
185 b_num_non_zero,
186 c_num_non_zero: 0,
187
188 a,
189 b,
190 c: vec![],
191 };
192
193 Ok(matrices)
194 }
195
196 fn a_query(&mut self, n_vars: usize) -> IoResult<Vec<G1Affine>> {
197 self.g1_section(n_vars, 5)
198 }
199
200 fn b_g1_query(&mut self, n_vars: usize) -> IoResult<Vec<G1Affine>> {
201 self.g1_section(n_vars, 6)
202 }
203
204 fn b_g2_query(&mut self, n_vars: usize) -> IoResult<Vec<G2Affine>> {
205 self.g2_section(n_vars, 7)
206 }
207
208 fn l_query(&mut self, n_vars: usize) -> IoResult<Vec<G1Affine>> {
209 self.g1_section(n_vars, 8)
210 }
211
212 fn h_query(&mut self, n_vars: usize) -> IoResult<Vec<G1Affine>> {
213 self.g1_section(n_vars, 9)
214 }
215
216 fn g1_section(&mut self, num: usize, section_id: usize) -> IoResult<Vec<G1Affine>> {
217 let section = self.get_section(section_id as u32);
218 self.reader.seek(SeekFrom::Start(section.position))?;
219 deserialize_g1_vec(self.reader, num as u32)
220 }
221
222 fn g2_section(&mut self, num: usize, section_id: usize) -> IoResult<Vec<G2Affine>> {
223 let section = self.get_section(section_id as u32);
224 self.reader.seek(SeekFrom::Start(section.position))?;
225 deserialize_g2_vec(self.reader, num as u32)
226 }
227}
228
229#[derive(Default, Clone, Debug, CanonicalDeserialize)]
230pub struct ZVerifyingKey {
231 alpha_g1: G1Affine,
232 beta_g1: G1Affine,
233 beta_g2: G2Affine,
234 gamma_g2: G2Affine,
235 delta_g1: G1Affine,
236 delta_g2: G2Affine,
237}
238
239impl ZVerifyingKey {
240 fn new<R: Read>(reader: &mut R) -> IoResult<Self> {
241 let alpha_g1 = deserialize_g1(reader)?;
242 let beta_g1 = deserialize_g1(reader)?;
243 let beta_g2 = deserialize_g2(reader)?;
244 let gamma_g2 = deserialize_g2(reader)?;
245 let delta_g1 = deserialize_g1(reader)?;
246 let delta_g2 = deserialize_g2(reader)?;
247
248 Ok(Self {
249 alpha_g1,
250 beta_g1,
251 beta_g2,
252 gamma_g2,
253 delta_g1,
254 delta_g2,
255 })
256 }
257}
258
259#[derive(Clone, Debug)]
260struct HeaderGroth {
261 #[allow(dead_code)]
262 n8q: u32,
263 #[allow(dead_code)]
264 q: BigInteger256,
265 #[allow(dead_code)]
266 n8r: u32,
267 #[allow(dead_code)]
268 r: BigInteger256,
269
270 n_vars: usize,
271 n_public: usize,
272
273 domain_size: u32,
274 #[allow(dead_code)]
275 power: u32,
276
277 verifying_key: ZVerifyingKey,
278}
279
280impl HeaderGroth {
281 fn new<R: Read + Seek>(reader: &mut R, section: &Section) -> IoResult<Self> {
282 reader.seek(SeekFrom::Start(section.position))?;
283 Self::read(reader)
284 }
285
286 fn read<R: Read>(mut reader: &mut R) -> IoResult<Self> {
287 // TODO: Impl From<u32> in Arkworks
288 let n8q: u32 = FromBytes::read(&mut reader)?;
289 // group order r of Bn254
290 let q = BigInteger256::read(&mut reader)?;
291
292 let n8r: u32 = FromBytes::read(&mut reader)?;
293 // Prime field modulus
294 let r = BigInteger256::read(&mut reader)?;
295
296 let n_vars = u32::read(&mut reader)? as usize;
297 let n_public = u32::read(&mut reader)? as usize;
298
299 let domain_size: u32 = FromBytes::read(&mut reader)?;
300 let power = log2(domain_size as usize);
301
302 let verifying_key = ZVerifyingKey::new(&mut reader)?;
303
304 Ok(Self {
305 n8q,
306 q,
307 n8r,
308 r,
309 n_vars,
310 n_public,
311 domain_size,
312 power,
313 verifying_key,
314 })
315 }
316}
317
318// need to divide by R, since snarkjs outputs the zkey with coefficients
319// multiplieid by R^2
320fn deserialize_field_fr<R: Read>(reader: &mut R) -> IoResult<Fr> {
321 let bigint = BigInteger256::read(reader)?;
322 Ok(Fr::new(Fr::new(bigint).into_repr()))
323}
324
325// skips the multiplication by R because Circom points are already in Montgomery form
326fn deserialize_field<R: Read>(reader: &mut R) -> IoResult<Fq> {
327 let bigint = BigInteger256::read(reader)?;
328 // if you use ark_ff::PrimeField::from_repr it multiplies by R
329 Ok(Fq::new(bigint))
330}
331
332pub fn deserialize_field2<R: Read>(reader: &mut R) -> IoResult<Fq2> {
333 let c0 = deserialize_field(reader)?;
334 let c1 = deserialize_field(reader)?;
335 Ok(Fq2::new(c0, c1))
336}
337
338fn deserialize_g1<R: Read>(reader: &mut R) -> IoResult<G1Affine> {
339 let x = deserialize_field(reader)?;
340 let y = deserialize_field(reader)?;
341 let infinity = x.is_zero() && y.is_zero();
342 Ok(G1Affine::new(x, y, infinity))
343}
344
345fn deserialize_g2<R: Read>(reader: &mut R) -> IoResult<G2Affine> {
346 let f1 = deserialize_field2(reader)?;
347 let f2 = deserialize_field2(reader)?;
348 let infinity = f1.is_zero() && f2.is_zero();
349 Ok(G2Affine::new(f1, f2, infinity))
350}
351
352fn deserialize_g1_vec<R: Read>(reader: &mut R, n_vars: u32) -> IoResult<Vec<G1Affine>> {
353 (0..n_vars).map(|_| deserialize_g1(reader)).collect()
354}
355
356fn deserialize_g2_vec<R: Read>(reader: &mut R, n_vars: u32) -> IoResult<Vec<G2Affine>> {
357 (0..n_vars).map(|_| deserialize_g2(reader)).collect()
358}
359
360#[cfg(test)]
361mod tests {
362 use super::*;
363 use ark_bn254::{G1Projective, G2Projective};
364 use num_bigint::BigUint;
365 use serde_json::Value;
366 use std::fs::File;
367
368 use crate::witness::WitnessCalculator;
369 use crate::{circom::CircomReduction, CircomBuilder, CircomConfig};
370 use ark_groth16::{
371 create_proof_with_reduction_and_matrices, create_random_proof_with_reduction as prove,
372 prepare_verifying_key, verify_proof,
373 };
374 use ark_std::rand::thread_rng;
375 use num_traits::{One, Zero};
376 use std::str::FromStr;
377
378 use std::convert::TryFrom;
379
380 fn fq_from_str(s: &str) -> Fq {
381 BigInteger256::try_from(BigUint::from_str(s).unwrap())
382 .unwrap()
383 .into()
384 }
385
386 // Circom snarkjs code:
387 // console.log(curve.G1.F.one)
388 fn fq_buf() -> Vec<u8> {
389 vec![
390 157, 13, 143, 197, 141, 67, 93, 211, 61, 11, 199, 245, 40, 235, 120, 10, 44, 70, 121,
391 120, 111, 163, 110, 102, 47, 223, 7, 154, 193, 119, 10, 14,
392 ]
393 }
394
395 // Circom snarkjs code:
396 // const buff = new Uint8Array(curve.G1.F.n8*2);
397 // curve.G1.toRprLEM(buff, 0, curve.G1.one);
398 // console.dir( buff, { 'maxArrayLength': null })
399 fn g1_buf() -> Vec<u8> {
400 vec![
401 157, 13, 143, 197, 141, 67, 93, 211, 61, 11, 199, 245, 40, 235, 120, 10, 44, 70, 121,
402 120, 111, 163, 110, 102, 47, 223, 7, 154, 193, 119, 10, 14, 58, 27, 30, 139, 27, 135,
403 186, 166, 123, 22, 142, 235, 81, 214, 241, 20, 88, 140, 242, 240, 222, 70, 221, 204,
404 94, 190, 15, 52, 131, 239, 20, 28,
405 ]
406 }
407
408 // Circom snarkjs code:
409 // const buff = new Uint8Array(curve.G2.F.n8*2);
410 // curve.G2.toRprLEM(buff, 0, curve.G2.one);
411 // console.dir( buff, { 'maxArrayLength': null })
412 fn g2_buf() -> Vec<u8> {
413 vec![
414 38, 32, 188, 2, 209, 181, 131, 142, 114, 1, 123, 73, 53, 25, 235, 220, 223, 26, 129,
415 151, 71, 38, 184, 251, 59, 80, 150, 175, 65, 56, 87, 25, 64, 97, 76, 168, 125, 115,
416 180, 175, 196, 216, 2, 88, 90, 221, 67, 96, 134, 47, 160, 82, 252, 80, 233, 9, 107,
417 123, 234, 58, 131, 240, 254, 20, 246, 233, 107, 136, 157, 250, 157, 97, 120, 155, 158,
418 245, 151, 210, 127, 254, 254, 125, 27, 35, 98, 26, 158, 255, 6, 66, 158, 174, 235, 126,
419 253, 40, 238, 86, 24, 199, 86, 91, 9, 100, 187, 60, 125, 50, 34, 249, 87, 220, 118, 16,
420 53, 51, 190, 53, 249, 85, 130, 100, 253, 147, 230, 160, 164, 13,
421 ]
422 }
423
424 // Circom logs in Projective coordinates: console.log(curve.G1.one)
425 fn g1_one() -> G1Affine {
426 let x = Fq::one();
427 let y = Fq::one() + Fq::one();
428 let z = Fq::one();
429 G1Affine::from(G1Projective::new(x, y, z))
430 }
431
432 // Circom logs in Projective coordinates: console.log(curve.G2.one)
433 fn g2_one() -> G2Affine {
434 let x = Fq2::new(
435 fq_from_str(
436 "10857046999023057135944570762232829481370756359578518086990519993285655852781",
437 ),
438 fq_from_str(
439 "11559732032986387107991004021392285783925812861821192530917403151452391805634",
440 ),
441 );
442
443 let y = Fq2::new(
444 fq_from_str(
445 "8495653923123431417604973247489272438418190587263600148770280649306958101930",
446 ),
447 fq_from_str(
448 "4082367875863433681332203403145435568316851327593401208105741076214120093531",
449 ),
450 );
451 let z = Fq2::new(Fq::one(), Fq::zero());
452 G2Affine::from(G2Projective::new(x, y, z))
453 }
454
455 #[test]
456 fn can_deser_fq() {
457 let buf = fq_buf();
458 let fq = deserialize_field(&mut &buf[..]).unwrap();
459 assert_eq!(fq, Fq::one());
460 }
461
462 #[test]
463 fn can_deser_g1() {
464 let buf = g1_buf();
465 assert_eq!(buf.len(), 64);
466 let g1 = deserialize_g1(&mut &buf[..]).unwrap();
467 let expected = g1_one();
468 assert_eq!(g1, expected);
469 }
470
471 #[test]
472 fn can_deser_g1_vec() {
473 let n_vars = 10;
474 let buf = vec![g1_buf(); n_vars]
475 .iter()
476 .cloned()
477 .flatten()
478 .collect::<Vec<_>>();
479 let expected = vec![g1_one(); n_vars];
480
481 let de = deserialize_g1_vec(&mut &buf[..], n_vars as u32).unwrap();
482 assert_eq!(expected, de);
483 }
484
485 #[test]
486 fn can_deser_g2() {
487 let buf = g2_buf();
488 assert_eq!(buf.len(), 128);
489 let g2 = deserialize_g2(&mut &buf[..]).unwrap();
490
491 let expected = g2_one();
492 assert_eq!(g2, expected);
493 }
494
495 #[test]
496 fn can_deser_g2_vec() {
497 let n_vars = 10;
498 let buf = vec![g2_buf(); n_vars]
499 .iter()
500 .cloned()
501 .flatten()
502 .collect::<Vec<_>>();
503 let expected = vec![g2_one(); n_vars];
504
505 let de = deserialize_g2_vec(&mut &buf[..], n_vars as u32).unwrap();
506 assert_eq!(expected, de);
507 }
508
509 #[test]
510 fn header() {
511 // `circom --r1cs` using the below file:
512 //
513 // template Multiplier() {
514 // signal private input a;
515 // signal private input b;
516 // signal output c;
517 //
518 // c <== a*b;
519 // }
520 //
521 // component main = Multiplier();
522 //
523 // Then:
524 // `snarkjs zkey new circuit.r1cs powersOfTau28_hez_final_10.ptau test.zkey`
525 let path = "./test-vectors/test.zkey";
526 let mut file = File::open(path).unwrap();
527 let mut binfile = BinFile::new(&mut file).unwrap();
528 let header = binfile.groth_header().unwrap();
529 assert_eq!(header.n_vars, 4);
530 assert_eq!(header.n_public, 1);
531 assert_eq!(header.domain_size, 4);
532 assert_eq!(header.power, 2);
533 }
534
535 #[test]
536 fn deser_key() {
537 let path = "./test-vectors/test.zkey";
538 let mut file = File::open(path).unwrap();
539 let (params, _matrices) = read_zkey(&mut file).unwrap();
540
541 // Check IC
542 let expected = vec![
543 deserialize_g1(
544 &mut &[
545 11, 205, 205, 176, 2, 105, 129, 243, 153, 58, 137, 89, 61, 95, 99, 161, 133,
546 201, 153, 192, 119, 19, 113, 136, 43, 105, 47, 206, 166, 55, 81, 22, 154, 77,
547 58, 119, 28, 230, 160, 206, 134, 98, 4, 115, 112, 184, 46, 117, 61, 180, 103,
548 138, 141, 202, 110, 252, 199, 252, 141, 211, 5, 46, 244, 10,
549 ][..],
550 )
551 .unwrap(),
552 deserialize_g1(
553 &mut &[
554 118, 135, 198, 156, 63, 190, 210, 98, 194, 59, 169, 168, 204, 168, 76, 208,
555 109, 170, 24, 193, 57, 31, 184, 88, 234, 218, 118, 58, 107, 129, 90, 36, 230,
556 98, 62, 243, 3, 55, 68, 227, 117, 64, 188, 81, 81, 247, 161, 68, 68, 210, 142,
557 191, 174, 43, 110, 194, 253, 128, 217, 4, 54, 196, 111, 43,
558 ][..],
559 )
560 .unwrap(),
561 ];
562 assert_eq!(expected, params.vk.gamma_abc_g1);
563
564 // Check A Query
565 let expected = vec![
566 deserialize_g1(
567 &mut &[
568 240, 165, 110, 187, 72, 39, 218, 59, 128, 85, 50, 174, 229, 1, 86, 58, 125,
569 244, 145, 205, 248, 253, 120, 2, 165, 140, 154, 55, 220, 253, 14, 19, 212, 106,
570 59, 19, 125, 198, 202, 4, 59, 74, 14, 62, 20, 248, 219, 47, 234, 205, 54, 183,
571 33, 119, 165, 84, 46, 75, 39, 17, 229, 42, 192, 2,
572 ][..],
573 )
574 .unwrap(),
575 deserialize_g1(
576 &mut &[
577 93, 53, 177, 82, 50, 5, 123, 116, 91, 35, 14, 196, 43, 180, 54, 15, 88, 144,
578 197, 105, 57, 167, 54, 5, 188, 109, 17, 89, 9, 223, 80, 1, 39, 193, 211, 168,
579 203, 119, 169, 105, 17, 156, 53, 106, 11, 102, 44, 92, 123, 220, 158, 240, 97,
580 253, 30, 121, 4, 236, 171, 23, 100, 34, 133, 11,
581 ][..],
582 )
583 .unwrap(),
584 deserialize_g1(
585 &mut &[
586 177, 47, 21, 237, 244, 73, 76, 98, 80, 10, 10, 142, 80, 145, 40, 254, 100, 214,
587 103, 33, 38, 84, 238, 248, 252, 181, 75, 32, 109, 16, 93, 23, 135, 157, 206,
588 122, 107, 105, 202, 164, 197, 124, 242, 100, 70, 108, 9, 180, 224, 102, 250,
589 149, 130, 14, 133, 185, 132, 189, 193, 230, 180, 143, 156, 30,
590 ][..],
591 )
592 .unwrap(),
593 deserialize_g1(
594 &mut &[
595 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
596 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
597 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
598 ][..],
599 )
600 .unwrap(),
601 ];
602 assert_eq!(expected, params.a_query);
603
604 // B G1 Query
605 let expected = vec![
606 deserialize_g1(
607 &mut &[
608 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
609 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
610 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
611 ][..],
612 )
613 .unwrap(),
614 deserialize_g1(
615 &mut &[
616 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
617 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
618 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
619 ][..],
620 )
621 .unwrap(),
622 deserialize_g1(
623 &mut &[
624 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
625 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
626 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
627 ][..],
628 )
629 .unwrap(),
630 deserialize_g1(
631 &mut &[
632 177, 47, 21, 237, 244, 73, 76, 98, 80, 10, 10, 142, 80, 145, 40, 254, 100, 214,
633 103, 33, 38, 84, 238, 248, 252, 181, 75, 32, 109, 16, 93, 23, 192, 95, 174, 93,
634 171, 34, 86, 151, 199, 77, 127, 3, 75, 254, 119, 227, 124, 241, 134, 235, 51,
635 55, 203, 254, 164, 226, 111, 250, 189, 190, 199, 17,
636 ][..],
637 )
638 .unwrap(),
639 ];
640 assert_eq!(expected, params.b_g1_query);
641
642 // B G2 Query
643 let expected = vec![
644 deserialize_g2(
645 &mut &[
646 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
647 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
648 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
649 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
650 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
651 ][..],
652 )
653 .unwrap(),
654 deserialize_g2(
655 &mut &[
656 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
657 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
658 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
659 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
660 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
661 ][..],
662 )
663 .unwrap(),
664 deserialize_g2(
665 &mut &[
666 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
667 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
668 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
669 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
670 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
671 ][..],
672 )
673 .unwrap(),
674 deserialize_g2(
675 &mut &[
676 240, 25, 157, 232, 164, 49, 152, 204, 244, 190, 178, 178, 29, 133, 205, 175,
677 172, 28, 12, 123, 139, 202, 196, 13, 67, 165, 204, 42, 74, 40, 6, 36, 112, 104,
678 61, 67, 107, 112, 72, 41, 213, 210, 249, 75, 89, 144, 144, 34, 177, 228, 18,
679 70, 80, 195, 124, 82, 40, 122, 91, 21, 198, 100, 154, 1, 16, 235, 41, 4, 176,
680 106, 9, 113, 141, 251, 100, 233, 188, 128, 194, 173, 0, 100, 206, 110, 53, 223,
681 163, 47, 166, 235, 25, 12, 151, 238, 45, 0, 78, 210, 56, 53, 57, 212, 67, 189,
682 253, 132, 62, 62, 116, 20, 235, 15, 245, 113, 30, 182, 33, 127, 203, 231, 124,
683 149, 74, 223, 39, 190, 217, 41,
684 ][..],
685 )
686 .unwrap(),
687 ];
688 assert_eq!(expected, params.b_g2_query);
689
690 // Check L Query
691 let expected = vec![
692 deserialize_g1(
693 &mut &[
694 146, 142, 29, 235, 9, 162, 84, 255, 6, 119, 86, 214, 154, 18, 12, 190, 202, 19,
695 168, 45, 29, 76, 174, 130, 6, 59, 146, 15, 229, 82, 81, 40, 50, 25, 124, 247,
696 129, 12, 147, 35, 108, 119, 178, 116, 238, 145, 33, 184, 74, 201, 128, 41, 151,
697 6, 60, 84, 156, 225, 200, 14, 240, 171, 128, 20,
698 ][..],
699 )
700 .unwrap(),
701 deserialize_g1(
702 &mut &[
703 26, 32, 112, 226, 161, 84, 188, 236, 141, 226, 119, 169, 235, 218, 253, 176,
704 157, 184, 108, 243, 73, 122, 239, 217, 39, 190, 239, 105, 147, 190, 80, 47,
705 211, 68, 155, 212, 139, 173, 229, 160, 123, 117, 243, 110, 162, 188, 217, 206,
706 102, 19, 36, 189, 87, 183, 113, 8, 164, 133, 43, 142, 138, 109, 66, 33,
707 ][..],
708 )
709 .unwrap(),
710 ];
711 assert_eq!(expected, params.l_query);
712
713 // Check H Query
714 let expected = vec![
715 deserialize_g1(
716 &mut &[
717 21, 76, 104, 34, 28, 236, 135, 204, 218, 16, 160, 115, 185, 44, 19, 62, 43, 24,
718 57, 99, 207, 105, 10, 139, 195, 60, 17, 57, 85, 244, 167, 10, 166, 166, 165,
719 55, 38, 75, 116, 116, 182, 87, 217, 112, 28, 237, 239, 123, 231, 180, 122, 109,
720 77, 116, 88, 67, 102, 48, 80, 214, 137, 47, 94, 30,
721 ][..],
722 )
723 .unwrap(),
724 deserialize_g1(
725 &mut &[
726 144, 175, 205, 119, 119, 192, 11, 10, 148, 224, 87, 161, 157, 231, 101, 208,
727 55, 15, 13, 16, 24, 59, 9, 22, 63, 215, 255, 30, 77, 188, 71, 37, 84, 227, 59,
728 29, 159, 116, 101, 93, 212, 220, 159, 141, 204, 107, 131, 87, 174, 149, 175,
729 72, 199, 109, 64, 109, 180, 150, 160, 249, 246, 33, 212, 29,
730 ][..],
731 )
732 .unwrap(),
733 deserialize_g1(
734 &mut &[
735 129, 169, 52, 179, 66, 88, 123, 199, 222, 69, 24, 17, 219, 235, 118, 195, 156,
736 210, 14, 21, 76, 155, 178, 210, 223, 4, 233, 5, 8, 18, 156, 24, 82, 68, 183,
737 186, 7, 126, 2, 201, 207, 207, 74, 45, 44, 199, 16, 165, 25, 65, 157, 199, 90,
738 159, 12, 150, 250, 17, 177, 193, 244, 93, 230, 41,
739 ][..],
740 )
741 .unwrap(),
742 deserialize_g1(
743 &mut &[
744 207, 61, 229, 214, 21, 61, 103, 165, 93, 145, 54, 138, 143, 214, 5, 83, 183,
745 22, 174, 87, 108, 59, 99, 96, 19, 20, 25, 139, 114, 238, 198, 40, 182, 88, 1,
746 255, 206, 132, 156, 165, 178, 171, 0, 226, 179, 30, 192, 4, 79, 198, 69, 43,
747 145, 133, 116, 86, 36, 144, 190, 119, 79, 241, 76, 16,
748 ][..],
749 )
750 .unwrap(),
751 ];
752 assert_eq!(expected, params.h_query);
753 }
754
755 #[test]
756 fn deser_vk() {
757 let path = "./test-vectors/test.zkey";
758 let mut file = File::open(path).unwrap();
759 let (params, _matrices) = read_zkey(&mut file).unwrap();
760
761 let json = std::fs::read_to_string("./test-vectors/verification_key.json").unwrap();
762 let json: Value = serde_json::from_str(&json).unwrap();
763
764 assert_eq!(json_to_g1(&json, "vk_alpha_1"), params.vk.alpha_g1);
765 assert_eq!(json_to_g2(&json, "vk_beta_2"), params.vk.beta_g2);
766 assert_eq!(json_to_g2(&json, "vk_gamma_2"), params.vk.gamma_g2);
767 assert_eq!(json_to_g2(&json, "vk_delta_2"), params.vk.delta_g2);
768 assert_eq!(json_to_g1_vec(&json, "IC"), params.vk.gamma_abc_g1);
769 }
770
771 fn json_to_g1(json: &Value, key: &str) -> G1Affine {
772 let els: Vec<String> = json
773 .get(key)
774 .unwrap()
775 .as_array()
776 .unwrap()
777 .iter()
778 .map(|i| i.as_str().unwrap().to_string())
779 .collect();
780 G1Affine::from(G1Projective::new(
781 fq_from_str(&els[0]),
782 fq_from_str(&els[1]),
783 fq_from_str(&els[2]),
784 ))
785 }
786
787 fn json_to_g1_vec(json: &Value, key: &str) -> Vec<G1Affine> {
788 let els: Vec<Vec<String>> = json
789 .get(key)
790 .unwrap()
791 .as_array()
792 .unwrap()
793 .iter()
794 .map(|i| {
795 i.as_array()
796 .unwrap()
797 .iter()
798 .map(|x| x.as_str().unwrap().to_string())
799 .collect::<Vec<String>>()
800 })
801 .collect();
802
803 els.iter()
804 .map(|coords| {
805 G1Affine::from(G1Projective::new(
806 fq_from_str(&coords[0]),
807 fq_from_str(&coords[1]),
808 fq_from_str(&coords[2]),
809 ))
810 })
811 .collect()
812 }
813
814 fn json_to_g2(json: &Value, key: &str) -> G2Affine {
815 let els: Vec<Vec<String>> = json
816 .get(key)
817 .unwrap()
818 .as_array()
819 .unwrap()
820 .iter()
821 .map(|i| {
822 i.as_array()
823 .unwrap()
824 .iter()
825 .map(|x| x.as_str().unwrap().to_string())
826 .collect::<Vec<String>>()
827 })
828 .collect();
829
830 let x = Fq2::new(fq_from_str(&els[0][0]), fq_from_str(&els[0][1]));
831 let y = Fq2::new(fq_from_str(&els[1][0]), fq_from_str(&els[1][1]));
832 let z = Fq2::new(fq_from_str(&els[2][0]), fq_from_str(&els[2][1]));
833 G2Affine::from(G2Projective::new(x, y, z))
834 }
835
836 #[test]
837 fn verify_proof_with_zkey_with_r1cs() {
838 let path = "./test-vectors/test.zkey";
839 let mut file = File::open(path).unwrap();
840 let (params, _matrices) = read_zkey(&mut file).unwrap(); // binfile.proving_key().unwrap();
841
842 let cfg = CircomConfig::<Bn254>::new(
843 "./test-vectors/mycircuit.wasm",
844 "./test-vectors/mycircuit.r1cs",
845 )
846 .unwrap();
847 let mut builder = CircomBuilder::new(cfg);
848 builder.push_input("a", 3);
849 builder.push_input("b", 11);
850
851 let circom = builder.build().unwrap();
852
853 let inputs = circom.get_public_inputs().unwrap();
854
855 let mut rng = thread_rng();
856 let proof = prove::<_, _, _, CircomReduction>(circom, ¶ms, &mut rng).unwrap();
857
858 let pvk = prepare_verifying_key(¶ms.vk);
859
860 let verified = verify_proof(&pvk, &proof, &inputs).unwrap();
861
862 assert!(verified);
863 }
864
865 #[test]
866 fn verify_proof_with_zkey_without_r1cs() {
867 let path = "./test-vectors/test.zkey";
868 let mut file = File::open(path).unwrap();
869 let (params, matrices) = read_zkey(&mut file).unwrap();
870
871 let mut wtns = WitnessCalculator::new("./test-vectors/mycircuit.wasm").unwrap();
872 let mut inputs: HashMap<String, Vec<num_bigint::BigInt>> = HashMap::new();
873 let values = inputs.entry("a".to_string()).or_insert_with(Vec::new);
874 values.push(3.into());
875
876 let values = inputs.entry("b".to_string()).or_insert_with(Vec::new);
877 values.push(11.into());
878
879 let mut rng = thread_rng();
880 use ark_std::UniformRand;
881 let num_inputs = matrices.num_instance_variables;
882 let num_constraints = matrices.num_constraints;
883 let rng = &mut rng;
884
885 let r = ark_bn254::Fr::rand(rng);
886 let s = ark_bn254::Fr::rand(rng);
887
888 let full_assignment = wtns
889 .calculate_witness_element::<Bn254, _>(inputs, false)
890 .unwrap();
891 let proof = create_proof_with_reduction_and_matrices::<_, CircomReduction>(
892 ¶ms,
893 r,
894 s,
895 &matrices,
896 num_inputs,
897 num_constraints,
898 full_assignment.as_slice(),
899 )
900 .unwrap();
901
902 let pvk = prepare_verifying_key(¶ms.vk);
903 let inputs = &full_assignment[1..num_inputs];
904 let verified = verify_proof(&pvk, &proof, inputs).unwrap();
905
906 assert!(verified);
907 }
908}