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