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