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().cloned()
486 .collect::<Vec<_>>();
487 let expected = vec![g1_one(); n_vars];
488
489 let de = deserialize_g1_vec(&mut &buf[..], n_vars as u32).unwrap();
490 assert_eq!(expected, de);
491 }
492
493 #[test]
494 fn can_deser_g2() {
495 let buf = g2_buf();
496 assert_eq!(buf.len(), 128);
497 let g2 = deserialize_g2(&mut &buf[..]).unwrap();
498
499 let expected = g2_one();
500 assert_eq!(g2, expected);
501 }
502
503 #[test]
504 fn can_deser_g2_vec() {
505 let n_vars = 10;
506 let buf = vec![g2_buf(); n_vars]
507 .iter()
508 .flatten().cloned()
509 .collect::<Vec<_>>();
510 let expected = vec![g2_one(); n_vars];
511
512 let de = deserialize_g2_vec(&mut &buf[..], n_vars as u32).unwrap();
513 assert_eq!(expected, de);
514 }
515
516 #[test]
517 fn header() {
518 // `circom --r1cs` using the below file:
519 //
520 // template Multiplier() {
521 // signal private input a;
522 // signal private input b;
523 // signal output c;
524 //
525 // c <== a*b;
526 // }
527 //
528 // component main = Multiplier();
529 //
530 // Then:
531 // `snarkjs zkey new circuit.r1cs powersOfTau28_hez_final_10.ptau test.zkey`
532 let path = "./test-vectors/test.zkey";
533 let mut file = File::open(path).unwrap();
534 let mut binfile = BinFile::new(&mut file).unwrap();
535 let header = binfile.groth_header().unwrap();
536 assert_eq!(header.n_vars, 4);
537 assert_eq!(header.n_public, 1);
538 assert_eq!(header.domain_size, 4);
539 assert_eq!(header.power, 2);
540 }
541
542 #[test]
543 fn deser_key() {
544 let path = "./test-vectors/test.zkey";
545 let mut file = File::open(path).unwrap();
546 let (params, _matrices) = read_zkey(&mut file).unwrap();
547
548 // Check IC
549 let expected = vec![
550 deserialize_g1(
551 &mut &[
552 11, 205, 205, 176, 2, 105, 129, 243, 153, 58, 137, 89, 61, 95, 99, 161, 133,
553 201, 153, 192, 119, 19, 113, 136, 43, 105, 47, 206, 166, 55, 81, 22, 154, 77,
554 58, 119, 28, 230, 160, 206, 134, 98, 4, 115, 112, 184, 46, 117, 61, 180, 103,
555 138, 141, 202, 110, 252, 199, 252, 141, 211, 5, 46, 244, 10,
556 ][..],
557 )
558 .unwrap(),
559 deserialize_g1(
560 &mut &[
561 118, 135, 198, 156, 63, 190, 210, 98, 194, 59, 169, 168, 204, 168, 76, 208,
562 109, 170, 24, 193, 57, 31, 184, 88, 234, 218, 118, 58, 107, 129, 90, 36, 230,
563 98, 62, 243, 3, 55, 68, 227, 117, 64, 188, 81, 81, 247, 161, 68, 68, 210, 142,
564 191, 174, 43, 110, 194, 253, 128, 217, 4, 54, 196, 111, 43,
565 ][..],
566 )
567 .unwrap(),
568 ];
569 assert_eq!(expected, params.vk.gamma_abc_g1);
570
571 // Check A Query
572 let expected = vec![
573 deserialize_g1(
574 &mut &[
575 240, 165, 110, 187, 72, 39, 218, 59, 128, 85, 50, 174, 229, 1, 86, 58, 125,
576 244, 145, 205, 248, 253, 120, 2, 165, 140, 154, 55, 220, 253, 14, 19, 212, 106,
577 59, 19, 125, 198, 202, 4, 59, 74, 14, 62, 20, 248, 219, 47, 234, 205, 54, 183,
578 33, 119, 165, 84, 46, 75, 39, 17, 229, 42, 192, 2,
579 ][..],
580 )
581 .unwrap(),
582 deserialize_g1(
583 &mut &[
584 93, 53, 177, 82, 50, 5, 123, 116, 91, 35, 14, 196, 43, 180, 54, 15, 88, 144,
585 197, 105, 57, 167, 54, 5, 188, 109, 17, 89, 9, 223, 80, 1, 39, 193, 211, 168,
586 203, 119, 169, 105, 17, 156, 53, 106, 11, 102, 44, 92, 123, 220, 158, 240, 97,
587 253, 30, 121, 4, 236, 171, 23, 100, 34, 133, 11,
588 ][..],
589 )
590 .unwrap(),
591 deserialize_g1(
592 &mut &[
593 177, 47, 21, 237, 244, 73, 76, 98, 80, 10, 10, 142, 80, 145, 40, 254, 100, 214,
594 103, 33, 38, 84, 238, 248, 252, 181, 75, 32, 109, 16, 93, 23, 135, 157, 206,
595 122, 107, 105, 202, 164, 197, 124, 242, 100, 70, 108, 9, 180, 224, 102, 250,
596 149, 130, 14, 133, 185, 132, 189, 193, 230, 180, 143, 156, 30,
597 ][..],
598 )
599 .unwrap(),
600 deserialize_g1(
601 &mut &[
602 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,
603 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,
604 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
605 ][..],
606 )
607 .unwrap(),
608 ];
609 assert_eq!(expected, params.a_query);
610
611 // B G1 Query
612 let expected = vec![
613 deserialize_g1(
614 &mut &[
615 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,
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,
618 ][..],
619 )
620 .unwrap(),
621 deserialize_g1(
622 &mut &[
623 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,
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,
626 ][..],
627 )
628 .unwrap(),
629 deserialize_g1(
630 &mut &[
631 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,
632 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,
633 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
634 ][..],
635 )
636 .unwrap(),
637 deserialize_g1(
638 &mut &[
639 177, 47, 21, 237, 244, 73, 76, 98, 80, 10, 10, 142, 80, 145, 40, 254, 100, 214,
640 103, 33, 38, 84, 238, 248, 252, 181, 75, 32, 109, 16, 93, 23, 192, 95, 174, 93,
641 171, 34, 86, 151, 199, 77, 127, 3, 75, 254, 119, 227, 124, 241, 134, 235, 51,
642 55, 203, 254, 164, 226, 111, 250, 189, 190, 199, 17,
643 ][..],
644 )
645 .unwrap(),
646 ];
647 assert_eq!(expected, params.b_g1_query);
648
649 // B G2 Query
650 let expected = vec![
651 deserialize_g2(
652 &mut &[
653 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,
654 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,
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,
658 ][..],
659 )
660 .unwrap(),
661 deserialize_g2(
662 &mut &[
663 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,
664 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,
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,
668 ][..],
669 )
670 .unwrap(),
671 deserialize_g2(
672 &mut &[
673 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,
674 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,
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,
678 ][..],
679 )
680 .unwrap(),
681 deserialize_g2(
682 &mut &[
683 240, 25, 157, 232, 164, 49, 152, 204, 244, 190, 178, 178, 29, 133, 205, 175,
684 172, 28, 12, 123, 139, 202, 196, 13, 67, 165, 204, 42, 74, 40, 6, 36, 112, 104,
685 61, 67, 107, 112, 72, 41, 213, 210, 249, 75, 89, 144, 144, 34, 177, 228, 18,
686 70, 80, 195, 124, 82, 40, 122, 91, 21, 198, 100, 154, 1, 16, 235, 41, 4, 176,
687 106, 9, 113, 141, 251, 100, 233, 188, 128, 194, 173, 0, 100, 206, 110, 53, 223,
688 163, 47, 166, 235, 25, 12, 151, 238, 45, 0, 78, 210, 56, 53, 57, 212, 67, 189,
689 253, 132, 62, 62, 116, 20, 235, 15, 245, 113, 30, 182, 33, 127, 203, 231, 124,
690 149, 74, 223, 39, 190, 217, 41,
691 ][..],
692 )
693 .unwrap(),
694 ];
695 assert_eq!(expected, params.b_g2_query);
696
697 // Check L Query
698 let expected = vec![
699 deserialize_g1(
700 &mut &[
701 146, 142, 29, 235, 9, 162, 84, 255, 6, 119, 86, 214, 154, 18, 12, 190, 202, 19,
702 168, 45, 29, 76, 174, 130, 6, 59, 146, 15, 229, 82, 81, 40, 50, 25, 124, 247,
703 129, 12, 147, 35, 108, 119, 178, 116, 238, 145, 33, 184, 74, 201, 128, 41, 151,
704 6, 60, 84, 156, 225, 200, 14, 240, 171, 128, 20,
705 ][..],
706 )
707 .unwrap(),
708 deserialize_g1(
709 &mut &[
710 26, 32, 112, 226, 161, 84, 188, 236, 141, 226, 119, 169, 235, 218, 253, 176,
711 157, 184, 108, 243, 73, 122, 239, 217, 39, 190, 239, 105, 147, 190, 80, 47,
712 211, 68, 155, 212, 139, 173, 229, 160, 123, 117, 243, 110, 162, 188, 217, 206,
713 102, 19, 36, 189, 87, 183, 113, 8, 164, 133, 43, 142, 138, 109, 66, 33,
714 ][..],
715 )
716 .unwrap(),
717 ];
718 assert_eq!(expected, params.l_query);
719
720 // Check H Query
721 let expected = vec![
722 deserialize_g1(
723 &mut &[
724 21, 76, 104, 34, 28, 236, 135, 204, 218, 16, 160, 115, 185, 44, 19, 62, 43, 24,
725 57, 99, 207, 105, 10, 139, 195, 60, 17, 57, 85, 244, 167, 10, 166, 166, 165,
726 55, 38, 75, 116, 116, 182, 87, 217, 112, 28, 237, 239, 123, 231, 180, 122, 109,
727 77, 116, 88, 67, 102, 48, 80, 214, 137, 47, 94, 30,
728 ][..],
729 )
730 .unwrap(),
731 deserialize_g1(
732 &mut &[
733 144, 175, 205, 119, 119, 192, 11, 10, 148, 224, 87, 161, 157, 231, 101, 208,
734 55, 15, 13, 16, 24, 59, 9, 22, 63, 215, 255, 30, 77, 188, 71, 37, 84, 227, 59,
735 29, 159, 116, 101, 93, 212, 220, 159, 141, 204, 107, 131, 87, 174, 149, 175,
736 72, 199, 109, 64, 109, 180, 150, 160, 249, 246, 33, 212, 29,
737 ][..],
738 )
739 .unwrap(),
740 deserialize_g1(
741 &mut &[
742 129, 169, 52, 179, 66, 88, 123, 199, 222, 69, 24, 17, 219, 235, 118, 195, 156,
743 210, 14, 21, 76, 155, 178, 210, 223, 4, 233, 5, 8, 18, 156, 24, 82, 68, 183,
744 186, 7, 126, 2, 201, 207, 207, 74, 45, 44, 199, 16, 165, 25, 65, 157, 199, 90,
745 159, 12, 150, 250, 17, 177, 193, 244, 93, 230, 41,
746 ][..],
747 )
748 .unwrap(),
749 deserialize_g1(
750 &mut &[
751 207, 61, 229, 214, 21, 61, 103, 165, 93, 145, 54, 138, 143, 214, 5, 83, 183,
752 22, 174, 87, 108, 59, 99, 96, 19, 20, 25, 139, 114, 238, 198, 40, 182, 88, 1,
753 255, 206, 132, 156, 165, 178, 171, 0, 226, 179, 30, 192, 4, 79, 198, 69, 43,
754 145, 133, 116, 86, 36, 144, 190, 119, 79, 241, 76, 16,
755 ][..],
756 )
757 .unwrap(),
758 ];
759 assert_eq!(expected, params.h_query);
760 }
761
762 #[test]
763 fn deser_vk() {
764 let path = "./test-vectors/test.zkey";
765 let mut file = File::open(path).unwrap();
766 let (params, _matrices) = read_zkey(&mut file).unwrap();
767
768 let json = std::fs::read_to_string("./test-vectors/verification_key.json").unwrap();
769 let json: Value = serde_json::from_str(&json).unwrap();
770
771 assert_eq!(json_to_g1(&json, "vk_alpha_1"), params.vk.alpha_g1);
772 assert_eq!(json_to_g2(&json, "vk_beta_2"), params.vk.beta_g2);
773 assert_eq!(json_to_g2(&json, "vk_gamma_2"), params.vk.gamma_g2);
774 assert_eq!(json_to_g2(&json, "vk_delta_2"), params.vk.delta_g2);
775 assert_eq!(json_to_g1_vec(&json, "IC"), params.vk.gamma_abc_g1);
776 }
777
778 fn json_to_g1(json: &Value, key: &str) -> G1Affine {
779 let els: Vec<String> = json
780 .get(key)
781 .unwrap()
782 .as_array()
783 .unwrap()
784 .iter()
785 .map(|i| i.as_str().unwrap().to_string())
786 .collect();
787 G1Affine::from(G1Projective::new(
788 fq_from_str(&els[0]),
789 fq_from_str(&els[1]),
790 fq_from_str(&els[2]),
791 ))
792 }
793
794 fn json_to_g1_vec(json: &Value, key: &str) -> Vec<G1Affine> {
795 let els: Vec<Vec<String>> = json
796 .get(key)
797 .unwrap()
798 .as_array()
799 .unwrap()
800 .iter()
801 .map(|i| {
802 i.as_array()
803 .unwrap()
804 .iter()
805 .map(|x| x.as_str().unwrap().to_string())
806 .collect::<Vec<String>>()
807 })
808 .collect();
809
810 els.iter()
811 .map(|coords| {
812 G1Affine::from(G1Projective::new(
813 fq_from_str(&coords[0]),
814 fq_from_str(&coords[1]),
815 fq_from_str(&coords[2]),
816 ))
817 })
818 .collect()
819 }
820
821 fn json_to_g2(json: &Value, key: &str) -> G2Affine {
822 let els: Vec<Vec<String>> = json
823 .get(key)
824 .unwrap()
825 .as_array()
826 .unwrap()
827 .iter()
828 .map(|i| {
829 i.as_array()
830 .unwrap()
831 .iter()
832 .map(|x| x.as_str().unwrap().to_string())
833 .collect::<Vec<String>>()
834 })
835 .collect();
836
837 let x = Fq2::new(fq_from_str(&els[0][0]), fq_from_str(&els[0][1]));
838 let y = Fq2::new(fq_from_str(&els[1][0]), fq_from_str(&els[1][1]));
839 let z = Fq2::new(fq_from_str(&els[2][0]), fq_from_str(&els[2][1]));
840 G2Affine::from(G2Projective::new(x, y, z))
841 }
842
843 #[test]
844 fn verify_proof_with_zkey_with_r1cs() {
845 let path = "./test-vectors/test.zkey";
846 let mut file = File::open(path).unwrap();
847 let (params, _matrices) = read_zkey(&mut file).unwrap(); // binfile.proving_key().unwrap();
848
849 let cfg = CircomConfig::<Bn254>::new(
850 "./test-vectors/mycircuit.wasm",
851 "./test-vectors/mycircuit.r1cs",
852 )
853 .unwrap();
854 let mut builder = CircomBuilder::new(cfg);
855 builder.push_input("a", 3);
856 builder.push_input("b", 11);
857
858 let circom = builder.build().unwrap();
859
860 let inputs = circom.get_public_inputs().unwrap();
861
862 let mut rng = thread_rng();
863 let proof = Groth16::<Bn254, CircomReduction>::prove(¶ms, circom, &mut rng).unwrap();
864
865 let pvk = Groth16::<Bn254>::process_vk(¶ms.vk).unwrap();
866
867 let verified = Groth16::<Bn254>::verify_with_processed_vk(&pvk, &inputs, &proof).unwrap();
868
869 assert!(verified);
870 }
871
872 #[test]
873 fn verify_proof_with_zkey_without_r1cs() {
874 let path = "./test-vectors/test.zkey";
875 let mut file = File::open(path).unwrap();
876 let (params, matrices) = read_zkey(&mut file).unwrap();
877
878 let mut wtns = WitnessCalculator::new("./test-vectors/mycircuit.wasm").unwrap();
879 let mut inputs: HashMap<String, Vec<num_bigint::BigInt>> = HashMap::new();
880 let values = inputs.entry("a".to_string()).or_insert_with(Vec::new);
881 values.push(3.into());
882
883 let values = inputs.entry("b".to_string()).or_insert_with(Vec::new);
884 values.push(11.into());
885
886 let mut rng = thread_rng();
887 use ark_std::UniformRand;
888 let num_inputs = matrices.num_instance_variables;
889 let num_constraints = matrices.num_constraints;
890 let rng = &mut rng;
891
892 let r = ark_bn254::Fr::rand(rng);
893 let s = ark_bn254::Fr::rand(rng);
894
895 let full_assignment = wtns
896 .calculate_witness_element::<Bn254, _>(inputs, false)
897 .unwrap();
898 let proof = Groth16::<Bn254, CircomReduction>::create_proof_with_reduction_and_matrices(
899 ¶ms,
900 r,
901 s,
902 &matrices,
903 num_inputs,
904 num_constraints,
905 full_assignment.as_slice(),
906 )
907 .unwrap();
908
909 let pvk = Groth16::<Bn254>::process_vk(¶ms.vk).unwrap();
910 let inputs = &full_assignment[1..num_inputs];
911 let verified = Groth16::<Bn254>::verify_with_processed_vk(&pvk, inputs, &proof).unwrap();
912
913 assert!(verified);
914 }
915}