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