1#![doc = include_str!("../README.md")]
15mod external;
30pub mod utils;
31
32use std::{cell::RefCell, cmp::max, convert::TryInto, fmt::Debug, io, rc::Rc};
33
34use bincode::{config::standard, Decode, Encode};
35use blake2b::blake2b::{
36 blake2b_chip::{Blake2bChip, Blake2bConfig},
37 NB_BLAKE2B_ADVICE_COLS,
38};
39use ff::{Field, PrimeField};
40use group::{prime::PrimeCurveAffine, Group};
41use keccak_sha3::packed_chip::{PackedChip, PackedConfig, PACKED_ADVICE_COLS, PACKED_FIXED_COLS};
42use midnight_circuits::{
43 biguint::biguint_gadget::BigUintGadget,
44 ecc::{
45 foreign::{
46 edwards_chip::{
47 nb_foreign_edwards_chip_columns, ForeignEdwardsEccChip, ForeignEdwardsEccConfig,
48 },
49 weierstrass_chip::{
50 nb_foreign_ecc_chip_columns, ForeignWeierstrassEccChip, ForeignWeierstrassEccConfig,
51 },
52 },
53 hash_to_curve::HashToCurveGadget,
54 native::{EccChip, EccConfig, NB_EDWARDS_COLS},
55 },
56 field::{
57 decomposition::{
58 chip::{P2RDecompositionChip, P2RDecompositionConfig},
59 pow2range::Pow2RangeChip,
60 },
61 foreign::{
62 nb_field_chip_columns, params::MultiEmulationParams as MEP, FieldChip, FieldChipConfig,
63 },
64 native::{NB_ARITH_COLS, NB_ARITH_FIXED_COLS},
65 NativeChip, NativeConfig, NativeGadget,
66 },
67 hash::{
68 poseidon::{
69 constants::RATE, PoseidonChip, PoseidonConfig, VarLenPoseidonGadget,
70 NB_POSEIDON_ADVICE_COLS, NB_POSEIDON_FIXED_COLS,
71 },
72 sha256::{
73 Sha256Chip, Sha256Config, VarLenSha256Gadget, NB_SHA256_ADVICE_COLS,
74 NB_SHA256_FIXED_COLS,
75 },
76 sha512::{Sha512Chip, Sha512Config, NB_SHA512_ADVICE_COLS, NB_SHA512_FIXED_COLS},
77 },
78 instructions::{
79 hash::VarHashInstructions, public_input::CommittedInstanceInstructions,
80 vector::VectorBounds, *,
81 },
82 map::map_gadget::MapGadget,
83 parsing::{
84 self,
85 scanner::{ScannerChip, ScannerConfig, NB_SCANNER_ADVICE_COLS, NB_SCANNER_FIXED_COLS},
86 Base64Chip, Base64Config, ParserGadget, NB_BASE64_ADVICE_COLS,
87 },
88 types::{
89 AssignedBit, AssignedByte, AssignedNative, AssignedNativePoint, ComposableChip, InnerValue,
90 Instantiable,
91 },
92 vec::{vector_gadget::VectorGadget, AssignedVector, Vectorizable},
93 verifier::{BlstrsEmulation, VerifierGadget},
94};
95use midnight_curves::{
96 curve25519::{self as curve25519_mod, Curve25519},
97 k256::{self as k256_mod, K256},
98 p256::{self as p256_mod, P256},
99 Fq, G1Affine, G1Projective,
100};
101use midnight_proofs::{
102 circuit::{Layouter, SimpleFloorPlanner, Value},
103 dev::cost_model::{circuit_model, CircuitModel},
104 plonk::{
105 self, keygen_vk_with_k, prepare, Circuit, ConstraintSystem, Error, ProvingKey, VerifyingKey,
106 },
107 poly::{
108 commitment::{Guard, Params},
109 kzg::{
110 params::{ParamsKZG, ParamsVerifierKZG},
111 KZGCommitmentScheme,
112 },
113 },
114 transcript::{CircuitTranscript, Hashable, Sampleable, Transcript, TranscriptHash},
115 utils::SerdeFormat,
116};
117use num_bigint::BigUint;
118use rand::{CryptoRng, RngCore};
119
120use crate::{
121 external::{blake2b::Blake2bWrapper, keccak_sha3::KeccakSha3Wrapper},
122 utils::plonk_api::BlstPLONK,
123};
124
125type C = midnight_curves::JubjubExtended;
126type F = midnight_curves::Fq;
127
128type NG = NativeGadget<F, P2RDecompositionChip<F>, NativeChip<F>>;
130type Secp256k1BaseChip = FieldChip<F, k256_mod::Fp, MEP, NG>;
131type Secp256k1ScalarChip = FieldChip<F, k256_mod::Fq, MEP, NG>;
132type Secp256k1Chip = ForeignWeierstrassEccChip<F, K256, MEP, Secp256k1ScalarChip, NG>;
133type P256BaseChip = FieldChip<F, p256_mod::Fp, MEP, NG>;
134type P256ScalarChip = FieldChip<F, p256_mod::Fq, MEP, NG>;
135type P256Chip = ForeignWeierstrassEccChip<F, P256, MEP, P256ScalarChip, NG>;
136type Bls12381BaseChip = FieldChip<F, midnight_curves::Fp, MEP, NG>;
137type Bls12381Chip = ForeignWeierstrassEccChip<
138 F,
139 midnight_curves::G1Projective,
140 midnight_curves::G1Projective,
141 NG,
142 NG,
143>;
144type Curve25519BaseChip = FieldChip<F, curve25519_mod::Fp, MEP, NG>;
145type Curve25519ScalarChip = FieldChip<F, curve25519_mod::Scalar, MEP, NG>;
146type Curve25519Chip = ForeignEdwardsEccChip<F, Curve25519, MEP, Curve25519ScalarChip, NG>;
147
148const ZKSTD_VERSION: u32 = 1;
149
150const COMMITMENT_BYTE_SIZE: usize = 48;
152
153const SCALAR_BYTE_SIZE: usize = 32;
155
156#[derive(Clone, Copy, Debug, Eq, PartialEq, Encode, Decode)]
159pub struct ZkStdLibArch {
160 pub jubjub: bool,
162
163 pub poseidon: bool,
165
166 pub sha2_256: bool,
168
169 pub sha2_512: bool,
171
172 pub keccak_256: bool,
178
179 pub sha3_256: bool,
185
186 pub blake2b: bool,
188
189 pub secp256k1: bool,
191
192 pub p256: bool,
194
195 pub bls12_381: bool,
197
198 pub curve25519: bool,
200
201 pub base64: bool,
203
204 pub automaton: bool,
206
207 pub nr_pow2range_cols: u8,
209}
210
211impl Default for ZkStdLibArch {
212 fn default() -> Self {
213 ZkStdLibArch {
214 jubjub: false,
215 poseidon: false,
216 sha2_256: false,
217 sha2_512: false,
218 sha3_256: false,
219 keccak_256: false,
220 blake2b: false,
221 secp256k1: false,
222 p256: false,
223 bls12_381: false,
224 curve25519: false,
225 base64: false,
226 automaton: false,
227 nr_pow2range_cols: 1,
228 }
229 }
230}
231
232impl ZkStdLibArch {
233 pub fn write<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
235 writer.write_all(&ZKSTD_VERSION.to_le_bytes())?;
236 bincode::encode_into_std_write(self, writer, standard())
237 .map(|_| ())
238 .map_err(io::Error::other)
239 }
240
241 pub fn read<R: io::Read>(reader: &mut R) -> io::Result<Self> {
243 let mut version = [0u8; 4];
244 reader.read_exact(&mut version)?;
245 let version = u32::from_le_bytes(version);
246 match version {
247 1 => bincode::decode_from_std_read(reader, standard())
248 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)),
249 _ => Err(io::Error::new(
250 io::ErrorKind::InvalidData,
251 format!("Unsupported ZKStd version: {}", version),
252 )),
253 }
254 }
255
256 pub fn read_from_serialized_vk<R: io::Read>(reader: &mut R) -> io::Result<Self> {
260 Self::read(reader)
263 }
264}
265
266#[derive(Debug, Clone)]
267pub struct ZkStdLibConfig {
269 native_config: NativeConfig,
270 core_decomposition_config: P2RDecompositionConfig,
271 jubjub_config: Option<EccConfig>,
272 sha2_256_config: Option<Sha256Config>,
273 sha2_512_config: Option<Sha512Config>,
274 poseidon_config: Option<PoseidonConfig<midnight_curves::Fq>>,
275 secp256k1_scalar_config: Option<FieldChipConfig>,
276 secp256k1_config: Option<ForeignWeierstrassEccConfig<K256>>,
277 p256_scalar_config: Option<FieldChipConfig>,
278 p256_config: Option<ForeignWeierstrassEccConfig<P256>>,
279 bls12_381_config: Option<ForeignWeierstrassEccConfig<midnight_curves::G1Projective>>,
280 curve25519_scalar_config: Option<FieldChipConfig>,
281 curve25519_config: Option<ForeignEdwardsEccConfig<Curve25519>>,
282 base64_config: Option<Base64Config>,
283 scanner_config: Option<ScannerConfig>,
284
285 keccak_sha3_config: Option<PackedConfig>,
287 blake2b_config: Option<Blake2bConfig>,
288}
289
290#[derive(Clone, Debug)]
292#[allow(clippy::type_complexity)]
293pub struct ZkStdLib {
294 native_gadget: NG,
296 core_decomposition_chip: P2RDecompositionChip<F>,
297 jubjub_chip: Option<EccChip<C>>,
298 sha2_256_chip: Option<Sha256Chip<F>>,
299 varlen_sha2_256_gadget: Option<VarLenSha256Gadget<F>>,
300 sha2_512_chip: Option<Sha512Chip<F>>,
301 poseidon_gadget: Option<PoseidonChip<F>>,
302 varlen_poseidon_gadget: Option<VarLenPoseidonGadget<F>>,
303 htc_gadget: Option<HashToCurveGadget<F, C, AssignedNative<F>, PoseidonChip<F>, EccChip<C>>>,
304 map_gadget: Option<MapGadget<F, NG, PoseidonChip<F>>>,
305 biguint_gadget: BigUintGadget<F, NG>,
306 secp256k1_chip: Option<Secp256k1Chip>,
307 p256_chip: Option<P256Chip>,
308 bls12_381_chip: Option<Bls12381Chip>,
309 curve25519_chip: Option<Curve25519Chip>,
310 base64_chip: Option<Base64Chip<F>>,
311 parser_gadget: ParserGadget<F, NG>,
312 scanner_chip: Option<ScannerChip<F>>,
313 vector_gadget: VectorGadget<F>,
314 verifier_gadget: Option<VerifierGadget<BlstrsEmulation>>,
315
316 keccak_sha3_chip: Option<KeccakSha3Wrapper<F>>,
318 blake2b_chip: Option<Blake2bWrapper<F>>,
319
320 used_sha2_256: Rc<RefCell<bool>>,
324 used_sha2_512: Rc<RefCell<bool>>,
325 used_secp256k1: Rc<RefCell<bool>>,
326 used_p256: Rc<RefCell<bool>>,
327 used_bls12_381: Rc<RefCell<bool>>,
328 used_curve25519: Rc<RefCell<bool>>,
329 used_base64: Rc<RefCell<bool>>,
330 used_scanner: Rc<RefCell<bool>>,
331 used_keccak_or_sha3: Rc<RefCell<bool>>,
332 used_blake2b: Rc<RefCell<bool>>,
333}
334
335impl ZkStdLib {
336 pub fn new(config: &ZkStdLibConfig, max_bit_len: usize) -> Self {
338 let native_chip = NativeChip::new(&config.native_config, &());
339 let core_decomposition_chip =
340 P2RDecompositionChip::new(&config.core_decomposition_config, &max_bit_len);
341 let native_gadget = NativeGadget::new(core_decomposition_chip.clone(), native_chip.clone());
342 let jubjub_chip = (config.jubjub_config.as_ref())
343 .map(|jubjub_config| EccChip::new(jubjub_config, &native_gadget));
344 let sha2_256_chip = (config.sha2_256_config.as_ref())
345 .map(|sha256_config| Sha256Chip::new(sha256_config, &native_gadget));
346 let varlen_sha2_256_gadget = sha2_256_chip.as_ref().map(VarLenSha256Gadget::new);
347 let sha2_512_chip = (config.sha2_512_config.as_ref())
348 .map(|sha512_config| Sha512Chip::new(sha512_config, &native_gadget));
349 let poseidon_gadget = (config.poseidon_config.as_ref())
350 .map(|poseidon_config| PoseidonChip::new(poseidon_config, &native_chip));
351 let varlen_poseidon_gadget = (poseidon_gadget.as_ref())
352 .map(|poseidon| VarLenPoseidonGadget::new(poseidon, &native_gadget));
353 let htc_gadget = (jubjub_chip.as_ref())
354 .zip(poseidon_gadget.as_ref())
355 .map(|(ecc_chip, poseidon_gadget)| HashToCurveGadget::new(poseidon_gadget, ecc_chip));
356 let biguint_gadget = BigUintGadget::new(&native_gadget);
357 let map_gadget = poseidon_gadget
358 .as_ref()
359 .map(|poseidon_gadget| MapGadget::new(&native_gadget, poseidon_gadget));
360 let secp256k1_scalar_chip = (config.secp256k1_scalar_config.as_ref())
361 .map(|scalar_config| FieldChip::new(scalar_config, &native_gadget));
362 let secp256k1_chip = (config.secp256k1_config.as_ref())
363 .zip(secp256k1_scalar_chip.as_ref())
364 .map(|(curve_config, scalar_chip)| {
365 ForeignWeierstrassEccChip::new(curve_config, &native_gadget, scalar_chip)
366 });
367 let p256_scalar_chip = (config.p256_scalar_config.as_ref())
368 .map(|scalar_config| FieldChip::new(scalar_config, &native_gadget));
369 let p256_chip = (config.p256_config.as_ref()).zip(p256_scalar_chip.as_ref()).map(
370 |(curve_config, scalar_chip)| {
371 ForeignWeierstrassEccChip::new(curve_config, &native_gadget, scalar_chip)
372 },
373 );
374 let bls12_381_chip = (config.bls12_381_config.as_ref()).map(|curve_config| {
375 ForeignWeierstrassEccChip::new(curve_config, &native_gadget, &native_gadget)
376 });
377 let curve25519_scalar_chip = (config.curve25519_scalar_config.as_ref())
378 .map(|scalar_config| FieldChip::new(scalar_config, &native_gadget));
379 let curve25519_chip = (config.curve25519_config.as_ref())
380 .zip(curve25519_scalar_chip.as_ref())
381 .map(|(curve_config, scalar_chip)| {
382 ForeignEdwardsEccChip::new(curve_config, &native_gadget, scalar_chip)
383 });
384
385 let base64_chip = (config.base64_config.as_ref())
386 .map(|base64_config| Base64Chip::new(base64_config, &native_gadget));
387
388 let parser_gadget = ParserGadget::new(&native_gadget);
389 let scanner_chip =
390 config.scanner_config.as_ref().map(|c| ScannerChip::new(c, &native_gadget));
391 let vector_gadget = VectorGadget::new(&native_gadget);
392
393 let verifier_gadget = bls12_381_chip.as_ref().zip(poseidon_gadget.as_ref()).map(
394 |(curve_chip, sponge_chip)| {
395 VerifierGadget::<BlstrsEmulation>::new(curve_chip, &native_gadget, sponge_chip)
396 },
397 );
398
399 let keccak_sha3_chip = config
400 .keccak_sha3_config
401 .as_ref()
402 .map(|sha3_config| KeccakSha3Wrapper::new(sha3_config, &native_gadget));
403 let blake2b_chip = config
404 .blake2b_config
405 .as_ref()
406 .map(|blake2b_config| Blake2bWrapper::new(blake2b_config, &native_gadget));
407
408 Self {
409 native_gadget,
410 core_decomposition_chip,
411 jubjub_chip,
412 sha2_256_chip,
413 varlen_sha2_256_gadget,
414 sha2_512_chip,
415 poseidon_gadget,
416 varlen_poseidon_gadget,
417 map_gadget,
418 htc_gadget,
419 biguint_gadget,
420 secp256k1_chip,
421 p256_chip,
422 bls12_381_chip,
423 curve25519_chip,
424 base64_chip,
425 parser_gadget,
426 scanner_chip,
427 vector_gadget,
428 verifier_gadget,
429 keccak_sha3_chip,
430 blake2b_chip,
431 used_sha2_256: Rc::new(RefCell::new(false)),
432 used_sha2_512: Rc::new(RefCell::new(false)),
433 used_secp256k1: Rc::new(RefCell::new(false)),
434 used_p256: Rc::new(RefCell::new(false)),
435 used_bls12_381: Rc::new(RefCell::new(false)),
436 used_curve25519: Rc::new(RefCell::new(false)),
437 used_base64: Rc::new(RefCell::new(false)),
438 used_scanner: Rc::new(RefCell::new(false)),
439 used_keccak_or_sha3: Rc::new(RefCell::new(false)),
440 used_blake2b: Rc::new(RefCell::new(false)),
441 }
442 }
443
444 pub fn configure(
446 meta: &mut ConstraintSystem<F>,
447 (arch, max_bit_len): (ZkStdLibArch, u8),
448 ) -> ZkStdLibConfig {
449 let nb_advice_cols = [
450 NB_ARITH_COLS,
451 arch.nr_pow2range_cols as usize,
452 arch.jubjub as usize * NB_EDWARDS_COLS,
453 arch.poseidon as usize * NB_POSEIDON_ADVICE_COLS,
454 arch.sha2_256 as usize * NB_SHA256_ADVICE_COLS,
455 arch.sha2_512 as usize * NB_SHA512_ADVICE_COLS,
456 arch.secp256k1 as usize
457 * max(
458 nb_field_chip_columns::<F, k256_mod::Fq, MEP>(),
459 nb_foreign_ecc_chip_columns::<F, K256, MEP, k256_mod::Fq>(),
460 ),
461 arch.p256 as usize
462 * max(
463 nb_field_chip_columns::<F, p256_mod::Fq, MEP>(),
464 nb_foreign_ecc_chip_columns::<F, P256, MEP, p256_mod::Fq>(),
465 ),
466 arch.bls12_381 as usize
467 * max(
468 nb_field_chip_columns::<F, midnight_curves::Fp, MEP>(),
469 nb_foreign_ecc_chip_columns::<
470 F,
471 midnight_curves::G1Projective,
472 MEP,
473 midnight_curves::Fp,
474 >(),
475 ),
476 arch.curve25519 as usize
477 * max(
478 nb_field_chip_columns::<F, curve25519_mod::Scalar, MEP>(),
479 nb_foreign_edwards_chip_columns::<F, Curve25519, MEP>(),
480 ),
481 arch.base64 as usize * NB_BASE64_ADVICE_COLS,
482 arch.automaton as usize * NB_SCANNER_ADVICE_COLS,
483 (arch.keccak_256 || arch.sha3_256) as usize * PACKED_ADVICE_COLS,
484 arch.blake2b as usize * NB_BLAKE2B_ADVICE_COLS,
485 ]
486 .into_iter()
487 .max()
488 .unwrap_or(0);
489
490 let nb_fixed_cols = [
491 NB_ARITH_FIXED_COLS,
492 arch.poseidon as usize * NB_POSEIDON_FIXED_COLS,
493 arch.sha2_256 as usize * NB_SHA256_FIXED_COLS,
494 arch.sha2_512 as usize * NB_SHA512_FIXED_COLS,
495 (arch.keccak_256 || arch.sha3_256) as usize * PACKED_FIXED_COLS,
496 arch.automaton as usize * NB_SCANNER_FIXED_COLS,
497 ]
498 .into_iter()
499 .max()
500 .unwrap_or(0);
501
502 let advice_columns = (0..nb_advice_cols).map(|_| meta.advice_column()).collect::<Vec<_>>();
503 let fixed_columns = (0..nb_fixed_cols).map(|_| meta.fixed_column()).collect::<Vec<_>>();
504 let committed_instance_column = meta.instance_column();
505 let instance_column = meta.instance_column();
506
507 let native_config = NativeChip::configure(
508 meta,
509 &(
510 advice_columns[..NB_ARITH_COLS].try_into().unwrap(),
511 fixed_columns[..NB_ARITH_FIXED_COLS].try_into().unwrap(),
512 [committed_instance_column, instance_column],
513 ),
514 );
515
516 let nb_parallel_range_checks = arch.nr_pow2range_cols as usize;
517 let max_bit_len = max_bit_len as u32;
518
519 let pow2range_config =
520 Pow2RangeChip::configure(meta, &advice_columns[1..=arch.nr_pow2range_cols as usize]);
521
522 let core_decomposition_config =
523 P2RDecompositionChip::configure(meta, &(native_config.clone(), pow2range_config));
524
525 let jubjub_config = arch.jubjub.then(|| {
526 EccChip::<C>::configure(meta, &advice_columns[..NB_EDWARDS_COLS].try_into().unwrap())
527 });
528
529 let sha2_256_config = arch.sha2_256.then(|| {
530 Sha256Chip::configure(
531 meta,
532 &(
533 advice_columns[..NB_SHA256_ADVICE_COLS].try_into().unwrap(),
534 fixed_columns[..NB_SHA256_FIXED_COLS].try_into().unwrap(),
535 ),
536 )
537 });
538
539 let sha2_512_config = arch.sha2_512.then(|| {
540 Sha512Chip::configure(
541 meta,
542 &(
543 advice_columns[..NB_SHA512_ADVICE_COLS].try_into().unwrap(),
544 fixed_columns[..NB_SHA512_FIXED_COLS].try_into().unwrap(),
545 ),
546 )
547 });
548
549 let poseidon_config = arch.poseidon.then(|| {
550 PoseidonChip::configure(
551 meta,
552 &(
553 advice_columns[..NB_POSEIDON_ADVICE_COLS].try_into().unwrap(),
554 fixed_columns[..NB_POSEIDON_FIXED_COLS].try_into().unwrap(),
555 ),
556 )
557 });
558
559 let secp256k1_scalar_config = arch.secp256k1.then(|| {
560 Secp256k1ScalarChip::configure(
561 meta,
562 &advice_columns,
563 nb_parallel_range_checks,
564 max_bit_len,
565 )
566 });
567
568 let secp256k1_config = arch.secp256k1.then(|| {
569 let base_config = Secp256k1BaseChip::configure(
570 meta,
571 &advice_columns,
572 nb_parallel_range_checks,
573 max_bit_len,
574 );
575 Secp256k1Chip::configure(
576 meta,
577 &base_config,
578 &advice_columns,
579 nb_parallel_range_checks,
580 max_bit_len,
581 )
582 });
583
584 let p256_scalar_config = arch.p256.then(|| {
585 P256ScalarChip::configure(meta, &advice_columns, nb_parallel_range_checks, max_bit_len)
586 });
587
588 let p256_config = arch.p256.then(|| {
589 let base_config = P256BaseChip::configure(
590 meta,
591 &advice_columns,
592 nb_parallel_range_checks,
593 max_bit_len,
594 );
595 P256Chip::configure(
596 meta,
597 &base_config,
598 &advice_columns,
599 nb_parallel_range_checks,
600 max_bit_len,
601 )
602 });
603
604 let bls12_381_config = arch.bls12_381.then(|| {
605 let base_config = Bls12381BaseChip::configure(
606 meta,
607 &advice_columns,
608 nb_parallel_range_checks,
609 max_bit_len,
610 );
611 Bls12381Chip::configure(
612 meta,
613 &base_config,
614 &advice_columns,
615 nb_parallel_range_checks,
616 max_bit_len,
617 )
618 });
619
620 let curve25519_scalar_config = arch.curve25519.then(|| {
621 Curve25519ScalarChip::configure(
622 meta,
623 &advice_columns,
624 nb_parallel_range_checks,
625 max_bit_len,
626 )
627 });
628
629 let curve25519_config = arch.curve25519.then(|| {
630 let base_config = Curve25519BaseChip::configure(
631 meta,
632 &advice_columns,
633 nb_parallel_range_checks,
634 max_bit_len,
635 );
636 Curve25519Chip::configure(
637 meta,
638 &base_config,
639 &advice_columns,
640 &fixed_columns,
641 nb_parallel_range_checks,
642 max_bit_len,
643 )
644 });
645
646 let base64_config = arch.base64.then(|| {
647 Base64Chip::configure(
648 meta,
649 advice_columns[..NB_BASE64_ADVICE_COLS].try_into().unwrap(),
650 )
651 });
652
653 let scanner_config = arch.automaton.then(|| {
654 ScannerChip::configure(
655 meta,
656 &(
657 advice_columns[..NB_SCANNER_ADVICE_COLS].try_into().unwrap(),
658 fixed_columns[0],
659 parsing::spec_library(),
660 ),
661 )
662 });
663
664 let constant_column =
665 (arch.keccak_256 || arch.sha3_256 || arch.blake2b).then(|| meta.fixed_column());
666
667 let keccak_sha3_config = (arch.keccak_256 || arch.sha3_256).then(|| {
668 PackedChip::configure(
669 meta,
670 constant_column.unwrap(),
671 advice_columns[..PACKED_ADVICE_COLS].try_into().unwrap(),
672 fixed_columns[..PACKED_FIXED_COLS].try_into().unwrap(),
673 )
674 });
675
676 let blake2b_config = arch.blake2b.then(|| {
677 Blake2bChip::configure(
678 meta,
679 constant_column.unwrap(),
680 advice_columns[0],
681 advice_columns[1..NB_BLAKE2B_ADVICE_COLS].try_into().unwrap(),
682 )
683 });
684
685 ZkStdLibConfig {
686 native_config,
687 core_decomposition_config,
688 jubjub_config,
689 sha2_256_config,
690 sha2_512_config,
691 poseidon_config,
692 secp256k1_scalar_config,
693 secp256k1_config,
694 p256_scalar_config,
695 p256_config,
696 bls12_381_config,
697 curve25519_scalar_config,
698 curve25519_config,
699 base64_config,
700 scanner_config,
701 keccak_sha3_config,
702 blake2b_config,
703 }
704 }
705}
706
707impl ZkStdLib {
708 pub fn jubjub(&self) -> &EccChip<C> {
710 self.jubjub_chip.as_ref().expect("ZkStdLibArch must enable jubjub")
711 }
712
713 pub fn biguint(&self) -> &BigUintGadget<F, NG> {
715 &self.biguint_gadget
716 }
717
718 pub fn map_gadget(&self) -> &MapGadget<F, NG, PoseidonChip<F>> {
720 self.map_gadget
721 .as_ref()
722 .unwrap_or_else(|| panic!("ZkStdLibArch must enable poseidon"))
723 }
724
725 pub fn secp256k1(&self) -> &Secp256k1Chip {
728 *self.used_secp256k1.borrow_mut() = true;
729 self.secp256k1_chip
730 .as_ref()
731 .unwrap_or_else(|| panic!("ZkStdLibArch must enable secp256k1"))
732 }
733
734 pub fn p256(&self) -> &P256Chip {
737 *self.used_p256.borrow_mut() = true;
738 self.p256_chip
739 .as_ref()
740 .unwrap_or_else(|| panic!("ZkStdLibArch must enable p256"))
741 }
742
743 pub fn bls12_381(&self) -> &Bls12381Chip {
746 *self.used_bls12_381.borrow_mut() = true;
747 self.bls12_381_chip
748 .as_ref()
749 .unwrap_or_else(|| panic!("ZkStdLibArch must enable bls12_381"))
750 }
751
752 pub fn curve25519(&self) -> &Curve25519Chip {
754 *self.used_curve25519.borrow_mut() = true;
755 self.curve25519_chip
756 .as_ref()
757 .unwrap_or_else(|| panic!("ZkStdLibArch must enable curve25519"))
758 }
759
760 pub fn base64(&self) -> &Base64Chip<F> {
762 *self.used_base64.borrow_mut() = true;
763 self.base64_chip
764 .as_ref()
765 .unwrap_or_else(|| panic!("ZkStdLibArch must enable base64"))
766 }
767
768 pub fn parser(&self) -> &ParserGadget<F, NG> {
771 &self.parser_gadget
772 }
773
774 pub fn scanner(&self) -> &ScannerChip<F> {
782 *self.used_scanner.borrow_mut() = true;
783 (self.scanner_chip.as_ref()).unwrap_or_else(|| panic!("ZkStdLibArch must enable automaton"))
784 }
785
786 pub fn verifier(&self) -> &VerifierGadget<BlstrsEmulation> {
789 *self.used_bls12_381.borrow_mut() = true;
790 self.verifier_gadget
791 .as_ref()
792 .unwrap_or_else(|| panic!("ZkStdLibArch must enable bls12_381 & poseidon"))
793 }
794
795 pub fn assert_true(
804 &self,
805 layouter: &mut impl Layouter<F>,
806 input: &AssignedBit<F>,
807 ) -> Result<(), Error> {
808 self.native_gadget.assert_equal_to_fixed(layouter, input, true)
809 }
810
811 pub fn assert_false(
813 &self,
814 layouter: &mut impl Layouter<F>,
815 input: &AssignedBit<F>,
816 ) -> Result<(), Error> {
817 self.native_gadget.assert_equal_to_fixed(layouter, input, false)
818 }
819
820 pub fn lower_than(
847 &self,
848 layouter: &mut impl Layouter<F>,
849 x: &AssignedNative<F>,
850 y: &AssignedNative<F>,
851 n: u32,
852 ) -> Result<AssignedBit<F>, Error> {
853 let bounded_x = self.native_gadget.bounded_of_element(layouter, n as usize, x)?;
854 let bounded_y = self.native_gadget.bounded_of_element(layouter, n as usize, y)?;
855 self.native_gadget.lower_than(layouter, &bounded_x, &bounded_y)
856 }
857
858 pub fn poseidon(
869 &self,
870 layouter: &mut impl Layouter<F>,
871 input: &[AssignedNative<F>],
872 ) -> Result<AssignedNative<F>, Error> {
873 self.poseidon_gadget
874 .as_ref()
875 .unwrap_or_else(|| panic!("ZkStdLibArch must enable poseidon"))
876 .hash(layouter, input)
877 }
878
879 pub fn poseidon_varlen<const M: usize>(
890 &self,
891 layouter: &mut impl Layouter<F>,
892 input: &AssignedVector<F, AssignedNative<F>, M, RATE>,
893 ) -> Result<AssignedNative<F>, Error> {
894 assert!(
895 M.is_multiple_of(RATE),
896 "poseidon_varlen only supports assigned vector whose maxlen M is a multiple of {RATE} (here M = {M})"
897 );
898 self.varlen_poseidon_gadget
899 .as_ref()
900 .unwrap_or_else(|| panic!("ZkStdLibArch must enable poseidon"))
901 .poseidon_varlen(layouter, input)
902 }
903
904 pub fn hash_to_curve(
907 &self,
908 layouter: &mut impl Layouter<F>,
909 inputs: &[AssignedNative<F>],
910 ) -> Result<AssignedNativePoint<C>, Error> {
911 self.htc_gadget
912 .as_ref()
913 .unwrap_or_else(|| panic!("ZkStdLibArch must enable poseidon and jubjub"))
914 .hash_to_curve(layouter, inputs)
915 }
916
917 pub fn sha2_256(
937 &self,
938 layouter: &mut impl Layouter<F>,
939 input: &[AssignedByte<F>], ) -> Result<[AssignedByte<F>; 32], Error> {
941 *self.used_sha2_256.borrow_mut() = true;
942 self.sha2_256_chip
943 .as_ref()
944 .expect("ZkStdLibArch must enable sha256")
945 .hash(layouter, input)
946 }
947
948 pub fn sha2_256_varlen<const M: usize>(
957 &self,
958 layouter: &mut impl Layouter<F>,
959 input: &AssignedVector<F, AssignedByte<F>, M, 64>,
960 ) -> Result<[AssignedByte<F>; 32], Error> {
961 *self.used_sha2_256.borrow_mut() = true;
962 assert!(
963 M.is_multiple_of(64),
964 "sha2_256_varlen only supports assigned vector whose maxlen M is a multiple of 64 (here M = {M})"
965 );
966 self.varlen_sha2_256_gadget
967 .as_ref()
968 .expect("ZkStdLibArch must enable sha256")
969 .varhash(layouter, input)
970 }
971
972 pub fn sha2_512(
974 &self,
975 layouter: &mut impl Layouter<F>,
976 input: &[AssignedByte<F>], ) -> Result<[AssignedByte<F>; 64], Error> {
978 *self.used_sha2_512.borrow_mut() = true;
979 self.sha2_512_chip
980 .as_ref()
981 .expect("ZkStdLibArch must enable sha512")
982 .hash(layouter, input)
983 }
984
985 pub fn sha3_256(
987 &self,
988 layouter: &mut impl Layouter<F>,
989 input: &[AssignedByte<F>],
990 ) -> Result<[AssignedByte<Fq>; 32], Error> {
991 *self.used_keccak_or_sha3.borrow_mut() = true;
992 let chip = self
993 .keccak_sha3_chip
994 .as_ref()
995 .expect("ZkStdLibArch must enable sha3 (or keccak)");
996 chip.sha3_256_digest(layouter, input)
997 }
998
999 pub fn keccak_256(
1001 &self,
1002 layouter: &mut impl Layouter<F>,
1003 input: &[AssignedByte<F>],
1004 ) -> Result<[AssignedByte<Fq>; 32], Error> {
1005 *self.used_keccak_or_sha3.borrow_mut() = true;
1006 let chip = self
1007 .keccak_sha3_chip
1008 .as_ref()
1009 .expect("ZkStdLibArch must enable keccak (or sha3)");
1010 chip.keccak_256_digest(layouter, input)
1011 }
1012
1013 pub fn blake2b_256(
1016 &self,
1017 layouter: &mut impl Layouter<F>,
1018 input: &[AssignedByte<F>],
1019 ) -> Result<[AssignedByte<F>; 32], Error> {
1020 *self.used_blake2b.borrow_mut() = true;
1021 let chip = self.blake2b_chip.as_ref().expect("ZkStdLibArch must enable blake2b");
1022 chip.blake2b_256_digest(layouter, input)
1023 }
1024
1025 pub fn blake2b_512(
1028 &self,
1029 layouter: &mut impl Layouter<F>,
1030 input: &[AssignedByte<F>],
1031 ) -> Result<[AssignedByte<F>; 64], Error> {
1032 *self.used_blake2b.borrow_mut() = true;
1033 let chip = self.blake2b_chip.as_ref().expect("ZkStdLibArch must enable blake2b");
1034 chip.blake2b_512_digest(layouter, input)
1035 }
1036}
1037
1038impl<T> AssignmentInstructions<F, T> for ZkStdLib
1039where
1040 T: InnerValue,
1041 T::Element: Clone,
1042 NG: AssignmentInstructions<F, T>,
1043{
1044 fn assign(
1045 &self,
1046 layouter: &mut impl Layouter<F>,
1047 value: Value<T::Element>,
1048 ) -> Result<T, Error> {
1049 self.native_gadget.assign(layouter, value)
1050 }
1051
1052 fn assign_fixed(
1053 &self,
1054 layouter: &mut impl Layouter<F>,
1055 constant: T::Element,
1056 ) -> Result<T, Error> {
1057 self.native_gadget.assign_fixed(layouter, constant)
1058 }
1059
1060 fn assign_many(
1061 &self,
1062 layouter: &mut impl Layouter<F>,
1063 values: &[Value<T::Element>],
1064 ) -> Result<Vec<T>, Error> {
1065 self.native_gadget.assign_many(layouter, values)
1066 }
1067}
1068
1069impl<T> PublicInputInstructions<F, T> for ZkStdLib
1070where
1071 T: Instantiable<F>,
1072 T::Element: Clone,
1073 NG: PublicInputInstructions<F, T>,
1074{
1075 fn as_public_input(
1076 &self,
1077 layouter: &mut impl Layouter<F>,
1078 assigned: &T,
1079 ) -> Result<Vec<AssignedNative<F>>, Error> {
1080 self.native_gadget.as_public_input(layouter, assigned)
1081 }
1082
1083 fn constrain_as_public_input(
1084 &self,
1085 layouter: &mut impl Layouter<F>,
1086 assigned: &T,
1087 ) -> Result<(), Error> {
1088 self.native_gadget.constrain_as_public_input(layouter, assigned)
1089 }
1090
1091 fn assign_as_public_input(
1092 &self,
1093 layouter: &mut impl Layouter<F>,
1094 value: Value<<T>::Element>,
1095 ) -> Result<T, Error> {
1096 self.native_gadget.assign_as_public_input(layouter, value)
1097 }
1098}
1099
1100impl<T> CommittedInstanceInstructions<F, T> for ZkStdLib
1101where
1102 F: PrimeField,
1103 T: Instantiable<F>,
1104 NG: CommittedInstanceInstructions<F, T>,
1105{
1106 fn constrain_as_committed_public_input(
1107 &self,
1108 layouter: &mut impl Layouter<F>,
1109 assigned: &T,
1110 ) -> Result<(), Error> {
1111 self.native_gadget.constrain_as_committed_public_input(layouter, assigned)
1112 }
1113}
1114
1115impl<T> AssertionInstructions<F, T> for ZkStdLib
1116where
1117 T: InnerValue,
1118 NG: AssertionInstructions<F, T>,
1119{
1120 fn assert_equal(&self, layouter: &mut impl Layouter<F>, x: &T, y: &T) -> Result<(), Error> {
1121 self.native_gadget.assert_equal(layouter, x, y)
1122 }
1123
1124 fn assert_not_equal(&self, layouter: &mut impl Layouter<F>, x: &T, y: &T) -> Result<(), Error> {
1125 self.native_gadget.assert_not_equal(layouter, x, y)
1126 }
1127
1128 fn assert_equal_to_fixed(
1129 &self,
1130 layouter: &mut impl Layouter<F>,
1131 x: &T,
1132 constant: T::Element,
1133 ) -> Result<(), Error> {
1134 self.native_gadget.assert_equal_to_fixed(layouter, x, constant)
1135 }
1136
1137 fn assert_not_equal_to_fixed(
1138 &self,
1139 layouter: &mut impl Layouter<F>,
1140 x: &T,
1141 constant: T::Element,
1142 ) -> Result<(), Error> {
1143 self.native_gadget.assert_not_equal_to_fixed(layouter, x, constant)
1144 }
1145}
1146
1147impl<T> EqualityInstructions<F, T> for ZkStdLib
1148where
1149 T: InnerValue,
1150 NG: EqualityInstructions<F, T>,
1151{
1152 fn is_equal(
1153 &self,
1154 layouter: &mut impl Layouter<F>,
1155 x: &T,
1156 y: &T,
1157 ) -> Result<AssignedBit<F>, Error> {
1158 self.native_gadget.is_equal(layouter, x, y)
1159 }
1160
1161 fn is_not_equal(
1162 &self,
1163 layouter: &mut impl Layouter<F>,
1164 x: &T,
1165 y: &T,
1166 ) -> Result<AssignedBit<F>, Error> {
1167 self.native_gadget.is_not_equal(layouter, x, y)
1168 }
1169
1170 fn is_equal_to_fixed(
1171 &self,
1172 layouter: &mut impl Layouter<F>,
1173 x: &T,
1174 constant: T::Element,
1175 ) -> Result<AssignedBit<F>, Error> {
1176 self.native_gadget.is_equal_to_fixed(layouter, x, constant)
1177 }
1178
1179 fn is_not_equal_to_fixed(
1180 &self,
1181 layouter: &mut impl Layouter<F>,
1182 x: &T,
1183 constant: T::Element,
1184 ) -> Result<AssignedBit<F>, Error> {
1185 self.native_gadget.is_not_equal_to_fixed(layouter, x, constant)
1186 }
1187}
1188
1189impl<T1, T2> ConversionInstructions<F, T1, T2> for ZkStdLib
1190where
1191 T1: InnerValue,
1192 T2: InnerValue,
1193 NG: ConversionInstructions<F, T1, T2>,
1194{
1195 fn convert_value(&self, x: &T1::Element) -> Option<T2::Element> {
1196 ConversionInstructions::<_, T1, T2>::convert_value(&self.native_gadget, x)
1197 }
1198
1199 fn convert(&self, layouter: &mut impl Layouter<F>, x: &T1) -> Result<T2, Error> {
1200 self.native_gadget.convert(layouter, x)
1201 }
1202}
1203
1204impl CanonicityInstructions<F, AssignedNative<F>> for ZkStdLib {
1205 fn le_bits_lower_than(
1206 &self,
1207 layouter: &mut impl Layouter<F>,
1208 bits: &[AssignedBit<F>],
1209 bound: BigUint,
1210 ) -> Result<AssignedBit<F>, Error> {
1211 self.native_gadget.le_bits_lower_than(layouter, bits, bound)
1212 }
1213
1214 fn le_bits_geq_than(
1215 &self,
1216 layouter: &mut impl Layouter<F>,
1217 bits: &[AssignedBit<F>],
1218 bound: BigUint,
1219 ) -> Result<AssignedBit<F>, Error> {
1220 self.native_gadget.le_bits_geq_than(layouter, bits, bound)
1221 }
1222}
1223
1224impl DecompositionInstructions<F, AssignedNative<F>> for ZkStdLib {
1225 fn assigned_to_le_bits(
1226 &self,
1227 layouter: &mut impl Layouter<F>,
1228 x: &AssignedNative<F>,
1229 nb_bits: Option<usize>,
1230 enforce_canonical: bool,
1231 ) -> Result<Vec<AssignedBit<F>>, Error> {
1232 self.native_gadget.assigned_to_le_bits(layouter, x, nb_bits, enforce_canonical)
1233 }
1234
1235 fn assigned_to_le_bytes(
1236 &self,
1237 layouter: &mut impl Layouter<F>,
1238 x: &AssignedNative<F>,
1239 nb_bytes: Option<usize>,
1240 ) -> Result<Vec<AssignedByte<F>>, Error> {
1241 self.native_gadget.assigned_to_le_bytes(layouter, x, nb_bytes)
1242 }
1243
1244 fn assigned_to_le_chunks(
1245 &self,
1246 layouter: &mut impl Layouter<F>,
1247 x: &AssignedNative<F>,
1248 nb_bits_per_chunk: usize,
1249 nb_chunks: Option<usize>,
1250 ) -> Result<Vec<AssignedNative<F>>, Error> {
1251 self.native_gadget
1252 .assigned_to_le_chunks(layouter, x, nb_bits_per_chunk, nb_chunks)
1253 }
1254
1255 fn sgn0(
1256 &self,
1257 layouter: &mut impl Layouter<F>,
1258 x: &AssignedNative<F>,
1259 ) -> Result<AssignedBit<F>, Error> {
1260 self.native_gadget.sgn0(layouter, x)
1261 }
1262}
1263
1264impl ArithInstructions<F, AssignedNative<F>> for ZkStdLib {
1265 fn linear_combination(
1266 &self,
1267 layouter: &mut impl Layouter<F>,
1268 terms: &[(F, AssignedNative<F>)],
1269 constant: F,
1270 ) -> Result<AssignedNative<F>, Error> {
1271 self.native_gadget.linear_combination(layouter, terms, constant)
1272 }
1273
1274 fn mul(
1275 &self,
1276 layouter: &mut impl Layouter<F>,
1277 x: &AssignedNative<F>,
1278 y: &AssignedNative<F>,
1279 multiplying_constant: Option<F>,
1280 ) -> Result<AssignedNative<F>, Error> {
1281 self.native_gadget.mul(layouter, x, y, multiplying_constant)
1282 }
1283
1284 fn div(
1285 &self,
1286 layouter: &mut impl Layouter<F>,
1287 x: &AssignedNative<F>,
1288 y: &AssignedNative<F>,
1289 ) -> Result<AssignedNative<F>, Error> {
1290 self.native_gadget.div(layouter, x, y)
1291 }
1292
1293 fn inv(
1294 &self,
1295 layouter: &mut impl Layouter<F>,
1296 x: &AssignedNative<F>,
1297 ) -> Result<AssignedNative<F>, Error> {
1298 self.native_gadget.inv(layouter, x)
1299 }
1300
1301 fn inv0(
1302 &self,
1303 layouter: &mut impl Layouter<F>,
1304 x: &AssignedNative<F>,
1305 ) -> Result<AssignedNative<F>, Error> {
1306 self.native_gadget.inv0(layouter, x)
1307 }
1308}
1309
1310impl ZeroInstructions<F, AssignedNative<F>> for ZkStdLib {}
1311
1312impl<Assigned> ControlFlowInstructions<F, Assigned> for ZkStdLib
1313where
1314 Assigned: InnerValue,
1315 NG: ControlFlowInstructions<F, Assigned>,
1316{
1317 fn select(
1318 &self,
1319 layouter: &mut impl Layouter<F>,
1320 cond: &AssignedBit<F>,
1321 x: &Assigned,
1322 y: &Assigned,
1323 ) -> Result<Assigned, Error> {
1324 self.native_gadget.select(layouter, cond, x, y)
1325 }
1326
1327 fn cond_swap(
1328 &self,
1329 layouter: &mut impl Layouter<F>,
1330 cond: &AssignedBit<F>,
1331 x: &Assigned,
1332 y: &Assigned,
1333 ) -> Result<(Assigned, Assigned), Error> {
1334 self.native_gadget.cond_swap(layouter, cond, x, y)
1335 }
1336}
1337
1338impl FieldInstructions<F, AssignedNative<F>> for ZkStdLib {
1339 fn order(&self) -> BigUint {
1340 self.native_gadget.order()
1341 }
1342}
1343
1344impl RangeCheckInstructions<F, AssignedNative<F>> for ZkStdLib {
1345 fn assign_lower_than_fixed(
1346 &self,
1347 layouter: &mut impl Layouter<F>,
1348 value: Value<F>,
1349 bound: &BigUint,
1350 ) -> Result<AssignedNative<F>, Error> {
1351 self.native_gadget.assign_lower_than_fixed(layouter, value, bound)
1352 }
1353
1354 fn assert_lower_than_fixed(
1355 &self,
1356 layouter: &mut impl Layouter<F>,
1357 x: &AssignedNative<F>,
1358 bound: &BigUint,
1359 ) -> Result<(), Error> {
1360 self.native_gadget.assert_lower_than_fixed(layouter, x, bound)
1361 }
1362}
1363
1364impl DivisionInstructions<F, AssignedNative<F>> for ZkStdLib {}
1365
1366impl BinaryInstructions<F> for ZkStdLib {
1367 fn and(
1368 &self,
1369 layouter: &mut impl Layouter<F>,
1370 bits: &[AssignedBit<F>],
1371 ) -> Result<AssignedBit<F>, Error> {
1372 self.native_gadget.and(layouter, bits)
1373 }
1374
1375 fn or(
1376 &self,
1377 layouter: &mut impl Layouter<F>,
1378 bits: &[AssignedBit<F>],
1379 ) -> Result<AssignedBit<F>, Error> {
1380 self.native_gadget.or(layouter, bits)
1381 }
1382
1383 fn xor(
1384 &self,
1385 layouter: &mut impl Layouter<F>,
1386 bits: &[AssignedBit<F>],
1387 ) -> Result<AssignedBit<F>, Error> {
1388 self.native_gadget.xor(layouter, bits)
1389 }
1390
1391 fn not(
1392 &self,
1393 layouter: &mut impl Layouter<F>,
1394 bit: &AssignedBit<F>,
1395 ) -> Result<AssignedBit<F>, Error> {
1396 self.native_gadget.not(layouter, bit)
1397 }
1398}
1399
1400impl BitwiseInstructions<F, AssignedNative<F>> for ZkStdLib {}
1401
1402impl<const M: usize, const A: usize, T> VectorInstructions<F, T, M, A> for ZkStdLib
1403where
1404 T: Vectorizable,
1405 T::Element: Copy,
1406 NG: AssignmentInstructions<F, T> + ControlFlowInstructions<F, T>,
1407{
1408 fn trim_beginning(
1409 &self,
1410 layouter: &mut impl Layouter<F>,
1411 input: &AssignedVector<F, T, M, A>,
1412 n_elems: usize,
1413 ) -> Result<AssignedVector<F, T, M, A>, Error> {
1414 self.vector_gadget.trim_beginning(layouter, input, n_elems)
1415 }
1416
1417 fn padding_flag(
1418 &self,
1419 layouter: &mut impl Layouter<F>,
1420 input: &AssignedVector<F, T, M, A>,
1421 ) -> Result<(Box<[AssignedBit<F>; M]>, VectorBounds<F>), Error> {
1422 self.vector_gadget.padding_flag(layouter, input)
1423 }
1424
1425 fn get_limits(
1426 &self,
1427 layouter: &mut impl Layouter<F>,
1428 input: &AssignedVector<F, T, M, A>,
1429 ) -> Result<VectorBounds<F>, Error> {
1430 self.vector_gadget.get_limits(layouter, input)
1431 }
1432
1433 fn resize<const L: usize>(
1434 &self,
1435 layouter: &mut impl Layouter<F>,
1436 input: AssignedVector<F, T, M, A>,
1437 ) -> Result<AssignedVector<F, T, L, A>, Error> {
1438 self.vector_gadget.resize(layouter, input)
1439 }
1440
1441 fn assign_with_filler(
1442 &self,
1443 layouter: &mut impl Layouter<F>,
1444 value: Value<Vec<<T>::Element>>,
1445 filler: Option<<T>::Element>,
1446 ) -> Result<AssignedVector<F, T, M, A>, Error> {
1447 self.vector_gadget.assign_with_filler(layouter, value, filler)
1448 }
1449}
1450
1451#[derive(Clone, Debug)]
1454pub struct MidnightCircuit<'a, R: Relation> {
1455 relation: &'a R,
1456 k: u32,
1457 instance: Value<R::Instance>,
1458 witness: Value<R::Witness>,
1459 nb_public_inputs: Rc<RefCell<Option<usize>>>,
1460 circuit_error: Rc<RefCell<Option<R::Error>>>,
1461}
1462
1463impl<'a, R: Relation> MidnightCircuit<'a, R> {
1464 pub fn from_relation(relation: &'a R, k: Option<u32>) -> Self {
1468 MidnightCircuit::new(relation, Value::unknown(), Value::unknown(), k)
1469 }
1470
1471 pub fn new(
1475 relation: &'a R,
1476 instance: Value<R::Instance>,
1477 witness: Value<R::Witness>,
1478 k: Option<u32>,
1479 ) -> Self {
1480 let k = k.unwrap_or_else(|| optimal_k(relation));
1481 MidnightCircuit {
1482 relation,
1483 k,
1484 instance,
1485 witness,
1486 nb_public_inputs: Rc::new(RefCell::new(None)),
1487 circuit_error: Rc::new(RefCell::new(None)),
1488 }
1489 }
1490
1491 pub fn k(&self) -> u32 {
1493 self.k
1494 }
1495
1496 pub fn take_error(&self) -> Option<R::Error> {
1498 self.circuit_error.take()
1499 }
1500}
1501
1502#[derive(Clone, Debug)]
1504pub struct MidnightVK {
1505 architecture: ZkStdLibArch,
1506 k: u8,
1507 nb_public_inputs: usize,
1508 vk: VerifyingKey<midnight_curves::Fq, KZGCommitmentScheme<midnight_curves::Bls12>>,
1509}
1510
1511impl MidnightVK {
1512 pub fn write<W: io::Write>(&self, writer: &mut W, format: SerdeFormat) -> io::Result<()> {
1521 self.architecture.write(writer)?;
1522
1523 writer.write_all(&[self.k])?;
1524
1525 writer.write_all(&(self.nb_public_inputs as u32).to_le_bytes())?;
1526
1527 self.vk.write(writer, format)
1528 }
1529
1530 pub fn read<R: io::Read>(reader: &mut R, format: SerdeFormat) -> io::Result<Self> {
1539 let architecture = ZkStdLibArch::read(reader)?;
1540
1541 let mut byte = [0u8; 1];
1542 reader.read_exact(&mut byte)?;
1543 let k = byte[0];
1544
1545 let mut bytes = [0u8; 4];
1546 reader.read_exact(&mut bytes)?;
1547 let nb_public_inputs = u32::from_le_bytes(bytes) as usize;
1548
1549 let mut cs = ConstraintSystem::default();
1550 let _config = ZkStdLib::configure(&mut cs, (architecture, k - 1));
1551
1552 let vk = VerifyingKey::read_from_cs::<R>(reader, format, cs)?;
1553
1554 Ok(MidnightVK {
1555 architecture,
1556 k,
1557 nb_public_inputs,
1558 vk,
1559 })
1560 }
1561
1562 pub fn k(&self) -> u8 {
1564 self.k
1565 }
1566
1567 pub fn vk(
1569 &self,
1570 ) -> &VerifyingKey<midnight_curves::Fq, KZGCommitmentScheme<midnight_curves::Bls12>> {
1571 &self.vk
1572 }
1573}
1574
1575#[derive(Clone, Debug)]
1577pub struct MidnightPK<R: Relation> {
1578 k: u8,
1579 relation: R,
1580 pk: ProvingKey<midnight_curves::Fq, KZGCommitmentScheme<midnight_curves::Bls12>>,
1581}
1582
1583impl<Rel: Relation> MidnightPK<Rel> {
1584 pub fn write<W: io::Write>(&self, writer: &mut W, format: SerdeFormat) -> io::Result<()> {
1593 writer.write_all(&[self.k])?;
1594
1595 Rel::write_relation(&self.relation, writer)?;
1596
1597 self.pk.write(writer, format)
1598 }
1599
1600 pub fn read<R: io::Read>(reader: &mut R, format: SerdeFormat) -> io::Result<Self> {
1609 let mut byte = [0u8; 1];
1610
1611 reader.read_exact(&mut byte)?;
1612 let k = byte[0];
1613
1614 let relation = Rel::read_relation(reader)?;
1615
1616 let pk = ProvingKey::read::<R, MidnightCircuit<Rel>>(
1617 reader,
1618 format,
1619 MidnightCircuit::new(
1620 &relation,
1621 Value::unknown(),
1622 Value::unknown(),
1623 Some(k as u32),
1624 )
1625 .params(),
1626 )?;
1627
1628 Ok(MidnightPK { k, relation, pk })
1629 }
1630
1631 pub fn k(&self) -> u8 {
1633 self.k
1634 }
1635
1636 pub fn pk(
1638 &self,
1639 ) -> &ProvingKey<midnight_curves::Fq, KZGCommitmentScheme<midnight_curves::Bls12>> {
1640 &self.pk
1641 }
1642}
1643
1644pub trait Relation: Clone {
1753 type Instance: Clone;
1755
1756 type Witness: Clone;
1758
1759 type Error: From<plonk::Error>;
1761
1762 fn format_instance(instance: &Self::Instance) -> Result<Vec<F>, Self::Error>;
1765
1766 fn format_committed_instances(_witness: &Self::Witness) -> Vec<F> {
1769 vec![]
1770 }
1771
1772 fn circuit(
1774 &self,
1775 std_lib: &ZkStdLib,
1776 layouter: &mut impl Layouter<F>,
1777 instance: Value<Self::Instance>,
1778 witness: Value<Self::Witness>,
1779 ) -> Result<(), Self::Error>;
1780
1781 fn used_chips(&self) -> ZkStdLibArch {
1788 ZkStdLibArch::default()
1789 }
1790
1791 fn write_relation<W: io::Write>(&self, writer: &mut W) -> io::Result<()>;
1793
1794 fn read_relation<R: io::Read>(reader: &mut R) -> io::Result<Self>;
1796}
1797
1798impl<R: Relation> Circuit<F> for MidnightCircuit<'_, R> {
1799 type Config = ZkStdLibConfig;
1800
1801 type FloorPlanner = SimpleFloorPlanner;
1803
1804 type Params = (ZkStdLibArch, u8);
1805
1806 fn without_witnesses(&self) -> Self {
1807 unreachable!()
1808 }
1809
1810 fn params(&self) -> Self::Params {
1811 (self.relation.used_chips(), (self.k - 1) as u8)
1812 }
1813
1814 fn configure_with_params(
1815 meta: &mut ConstraintSystem<F>,
1816 params: (ZkStdLibArch, u8),
1817 ) -> Self::Config {
1818 ZkStdLib::configure(meta, params)
1819 }
1820
1821 fn configure(meta: &mut ConstraintSystem<F>) -> Self::Config {
1822 ZkStdLib::configure(meta, (ZkStdLibArch::default(), 8))
1823 }
1824
1825 fn synthesize(
1826 &self,
1827 config: Self::Config,
1828 mut layouter: impl Layouter<F>,
1829 ) -> Result<(), Error> {
1830 let max_bit_len = (self.k - 1) as usize;
1831 let zk_std_lib = ZkStdLib::new(&config, max_bit_len);
1832
1833 self.relation
1834 .circuit(
1835 &zk_std_lib,
1836 &mut layouter.namespace(|| "Running logic circuit"),
1837 self.instance.clone(),
1838 self.witness.clone(),
1839 )
1840 .map_err(|e| {
1841 *self.circuit_error.borrow_mut() = Some(e);
1842 Error::Synthesis("Relation::circuit error".into())
1843 })?;
1844
1845 *self.nb_public_inputs.borrow_mut() =
1850 Some(zk_std_lib.native_gadget.native_chip.nb_public_inputs());
1851
1852 zk_std_lib.core_decomposition_chip.load(&mut layouter)?;
1855
1856 if let Some(sha256_chip) = zk_std_lib.sha2_256_chip {
1857 if *zk_std_lib.used_sha2_256.borrow() {
1858 sha256_chip.load(&mut layouter)?;
1859 }
1860 }
1861
1862 if let Some(sha512_chip) = zk_std_lib.sha2_512_chip {
1863 if *zk_std_lib.used_sha2_512.borrow() {
1864 sha512_chip.load(&mut layouter)?;
1865 }
1866 }
1867
1868 if let Some(b64_chip) = zk_std_lib.base64_chip {
1869 if *zk_std_lib.used_base64.borrow() {
1870 b64_chip.load(&mut layouter)?;
1871 }
1872 }
1873
1874 if let Some(scanner_chip) = zk_std_lib.scanner_chip {
1875 if *zk_std_lib.used_scanner.borrow() {
1876 scanner_chip.load(&mut layouter)?;
1877 }
1878 }
1879
1880 if let Some(keccak_sha3_chip) = zk_std_lib.keccak_sha3_chip {
1881 if *zk_std_lib.used_keccak_or_sha3.borrow() {
1882 keccak_sha3_chip.load(&mut layouter)?;
1883 }
1884 }
1885
1886 if let Some(blake2b_chip) = zk_std_lib.blake2b_chip {
1887 if *zk_std_lib.used_blake2b.borrow() {
1888 blake2b_chip.load(&mut layouter)?;
1889 }
1890 }
1891
1892 Ok(())
1893 }
1894}
1895
1896pub fn setup_vk<R: Relation>(
1903 params: &ParamsKZG<midnight_curves::Bls12>,
1904 relation: &R,
1905) -> MidnightVK {
1906 let k = params.max_k();
1907 let circuit = MidnightCircuit::from_relation(relation, Some(k));
1908 let vk = keygen_vk_with_k(params, &circuit, k).expect("keygen_vk should not fail");
1909
1910 let nb_public_inputs = circuit.nb_public_inputs.clone().borrow().unwrap();
1913
1914 MidnightVK {
1915 architecture: relation.used_chips(),
1916 k: circuit.k as u8,
1917 nb_public_inputs,
1918 vk,
1919 }
1920}
1921
1922pub fn setup_pk<R: Relation>(relation: &R, vk: &MidnightVK) -> MidnightPK<R> {
1924 let circuit = MidnightCircuit::new(
1925 relation,
1926 Value::unknown(),
1927 Value::unknown(),
1928 Some(vk.k() as u32),
1929 );
1930 let pk = BlstPLONK::<MidnightCircuit<R>>::setup_pk(&circuit, &vk.vk);
1931 MidnightPK {
1932 k: vk.k(),
1933 relation: relation.clone(),
1934 pk,
1935 }
1936}
1937
1938pub fn prove<R: Relation, H: TranscriptHash>(
1941 params: &ParamsKZG<midnight_curves::Bls12>,
1942 pk: &MidnightPK<R>,
1943 relation: &R,
1944 instance: &R::Instance,
1945 witness: R::Witness,
1946 rng: impl RngCore + CryptoRng,
1947) -> Result<Vec<u8>, R::Error>
1948where
1949 G1Projective: Hashable<H>,
1950 F: Hashable<H> + Sampleable<H>,
1951{
1952 let pi = R::format_instance(instance)?;
1953 let com_inst = R::format_committed_instances(&witness);
1954 let circuit = MidnightCircuit::new(
1955 relation,
1956 Value::known(instance.clone()),
1957 Value::known(witness),
1958 Some(pk.k as u32),
1959 );
1960 BlstPLONK::<MidnightCircuit<R>>::prove::<H>(
1961 params,
1962 &pk.pk,
1963 &circuit,
1964 1,
1965 &[com_inst.as_slice(), &pi],
1966 rng,
1967 )
1968 .map_err(|e| circuit.take_error().unwrap_or_else(|| e.into()))
1969}
1970
1971pub fn verify<R: Relation, H: TranscriptHash>(
1974 params_verifier: &ParamsVerifierKZG<midnight_curves::Bls12>,
1975 vk: &MidnightVK,
1976 instance: &R::Instance,
1977 committed_instance: Option<G1Affine>,
1978 proof: &[u8],
1979) -> Result<(), R::Error>
1980where
1981 G1Projective: Hashable<H>,
1982 F: Hashable<H> + Sampleable<H>,
1983{
1984 let pi = R::format_instance(instance)?;
1985 let committed_pi = committed_instance.unwrap_or(G1Affine::identity());
1986 if pi.len() != vk.nb_public_inputs {
1987 return Err(Error::InvalidInstances.into());
1988 }
1989 Ok(BlstPLONK::<MidnightCircuit<R>>::verify::<H>(
1990 params_verifier,
1991 &vk.vk,
1992 &[committed_pi],
1993 &[&pi],
1994 proof,
1995 )?)
1996}
1997
1998pub fn batch_verify<H: TranscriptHash + Send + Sync>(
2006 params_verifier: &ParamsVerifierKZG<midnight_curves::Bls12>,
2007 vks: &[MidnightVK],
2008 pis: &[Vec<F>],
2009 proofs: &[Vec<u8>],
2010) -> Result<(), Error>
2011where
2012 G1Projective: Hashable<H>,
2013 F: Hashable<H> + Sampleable<H>,
2014{
2015 use rayon::prelude::*;
2016
2017 let n = vks.len();
2019 if pis.len() != n || proofs.len() != n {
2020 return Err(Error::InvalidInstances);
2022 }
2023
2024 let prepared: Vec<(_, F)> = vks
2025 .par_iter()
2026 .zip(pis.par_iter())
2027 .zip(proofs.par_iter())
2028 .map(|((vk, pi), proof)| {
2029 if pi.len() != vk.nb_public_inputs {
2030 return Err(Error::InvalidInstances);
2031 }
2032
2033 let mut transcript = CircuitTranscript::init_from_bytes(proof);
2034 let dual_msm = prepare::<
2035 midnight_curves::Fq,
2036 KZGCommitmentScheme<midnight_curves::Bls12>,
2037 CircuitTranscript<H>,
2038 >(
2039 &vk.vk,
2040 &[&[midnight_curves::G1Projective::identity()]],
2041 &[&[pi]],
2043 &mut transcript,
2044 )?;
2045 let summary: F = transcript.squeeze_challenge();
2046 transcript.assert_empty().map_err(|_| Error::Opening)?;
2047 Ok((dual_msm, summary))
2048 })
2049 .collect::<Result<Vec<_>, Error>>()?;
2050
2051 let mut r_transcript = CircuitTranscript::init();
2052 let mut guards = Vec::with_capacity(n);
2053 for (guard, summary) in prepared {
2054 r_transcript.common(&summary)?;
2055 guards.push(guard);
2056 }
2057 let r: F = r_transcript.squeeze_challenge();
2058
2059 let n_guards = guards.len();
2060 let powers: Vec<F> =
2061 std::iter::successors(Some(F::ONE), |p| Some(*p * r)).take(n_guards).collect();
2062 guards.par_iter_mut().enumerate().for_each(|(i, guard)| guard.scale(powers[i]));
2063
2064 let Some(mut acc_guard) = guards.pop() else {
2066 return Ok(());
2067 };
2068 for guard in guards {
2069 acc_guard.add_msm(guard);
2070 }
2071 acc_guard.verify(params_verifier).map_err(|_| Error::Opening)
2073}
2074
2075pub fn cost_model<R: Relation>(relation: &R, k: Option<u32>) -> CircuitModel {
2079 let circuit = MidnightCircuit::from_relation(relation, k);
2080 circuit_model::<_, COMMITMENT_BYTE_SIZE, SCALAR_BYTE_SIZE>(&circuit)
2081}
2082
2083pub fn optimal_k<R: Relation>(relation: &R) -> u32 {
2087 let mut best_k = u32::MAX;
2088
2089 for k in 9..=25 {
2090 let model = cost_model(relation, Some(k));
2091
2092 if model.k < best_k {
2093 best_k = model.k;
2094 }
2095
2096 if model.rows < (1 << k) {
2098 break;
2099 }
2100 }
2101
2102 best_k
2103}