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 = 2;
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
232#[derive(Decode)]
236struct ZkStdLibArchV1 {
237 jubjub: bool,
238 poseidon: bool,
239 sha2_256: bool,
240 sha2_512: bool,
241 keccak_256: bool,
242 sha3_256: bool,
243 blake2b: bool,
244 secp256k1: bool,
245 bls12_381: bool,
246 base64: bool,
247 automaton: bool,
248 nr_pow2range_cols: u8,
249}
250
251impl From<ZkStdLibArchV1> for ZkStdLibArch {
252 fn from(v1: ZkStdLibArchV1) -> Self {
253 ZkStdLibArch {
254 jubjub: v1.jubjub,
255 poseidon: v1.poseidon,
256 sha2_256: v1.sha2_256,
257 sha2_512: v1.sha2_512,
258 keccak_256: v1.keccak_256,
259 sha3_256: v1.sha3_256,
260 blake2b: v1.blake2b,
261 secp256k1: v1.secp256k1,
262 p256: false,
263 bls12_381: v1.bls12_381,
264 curve25519: false,
265 base64: v1.base64,
266 automaton: v1.automaton,
267 nr_pow2range_cols: v1.nr_pow2range_cols,
268 }
269 }
270}
271
272impl ZkStdLibArch {
273 pub fn write<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
275 writer.write_all(&ZKSTD_VERSION.to_le_bytes())?;
276 bincode::encode_into_std_write(self, writer, standard())
277 .map(|_| ())
278 .map_err(io::Error::other)
279 }
280
281 pub fn read<R: io::Read>(reader: &mut R) -> io::Result<Self> {
283 let mut version = [0u8; 4];
284 reader.read_exact(&mut version)?;
285 let version = u32::from_le_bytes(version);
286 match version {
287 1 => bincode::decode_from_std_read::<ZkStdLibArchV1, _, _>(reader, standard())
288 .map(ZkStdLibArch::from)
289 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)),
290 2 => bincode::decode_from_std_read(reader, standard())
291 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)),
292 _ => Err(io::Error::new(
293 io::ErrorKind::InvalidData,
294 format!("Unsupported ZKStd version: {}", version),
295 )),
296 }
297 }
298
299 pub fn read_from_serialized_vk<R: io::Read>(reader: &mut R) -> io::Result<Self> {
303 Self::read(reader)
306 }
307}
308
309#[derive(Debug, Clone)]
310pub struct ZkStdLibConfig {
312 native_config: NativeConfig,
313 core_decomposition_config: P2RDecompositionConfig,
314 jubjub_config: Option<EccConfig>,
315 sha2_256_config: Option<Sha256Config>,
316 sha2_512_config: Option<Sha512Config>,
317 poseidon_config: Option<PoseidonConfig<midnight_curves::Fq>>,
318 secp256k1_scalar_config: Option<FieldChipConfig>,
319 secp256k1_config: Option<ForeignWeierstrassEccConfig<K256>>,
320 p256_scalar_config: Option<FieldChipConfig>,
321 p256_config: Option<ForeignWeierstrassEccConfig<P256>>,
322 bls12_381_config: Option<ForeignWeierstrassEccConfig<midnight_curves::G1Projective>>,
323 curve25519_scalar_config: Option<FieldChipConfig>,
324 curve25519_config: Option<ForeignEdwardsEccConfig<Curve25519>>,
325 base64_config: Option<Base64Config>,
326 scanner_config: Option<ScannerConfig>,
327
328 keccak_sha3_config: Option<PackedConfig>,
330 blake2b_config: Option<Blake2bConfig>,
331}
332
333#[derive(Clone, Debug)]
335#[allow(clippy::type_complexity)]
336pub struct ZkStdLib {
337 native_gadget: NG,
339 core_decomposition_chip: P2RDecompositionChip<F>,
340 jubjub_chip: Option<EccChip<C>>,
341 sha2_256_chip: Option<Sha256Chip<F>>,
342 varlen_sha2_256_gadget: Option<VarLenSha256Gadget<F>>,
343 sha2_512_chip: Option<Sha512Chip<F>>,
344 poseidon_gadget: Option<PoseidonChip<F>>,
345 varlen_poseidon_gadget: Option<VarLenPoseidonGadget<F>>,
346 htc_gadget: Option<HashToCurveGadget<F, C, AssignedNative<F>, PoseidonChip<F>, EccChip<C>>>,
347 map_gadget: Option<MapGadget<F, NG, PoseidonChip<F>>>,
348 biguint_gadget: BigUintGadget<F, NG>,
349 secp256k1_chip: Option<Secp256k1Chip>,
350 p256_chip: Option<P256Chip>,
351 bls12_381_chip: Option<Bls12381Chip>,
352 curve25519_chip: Option<Curve25519Chip>,
353 base64_chip: Option<Base64Chip<F>>,
354 parser_gadget: ParserGadget<F, NG>,
355 scanner_chip: Option<ScannerChip<F>>,
356 vector_gadget: VectorGadget<F>,
357 verifier_gadget: Option<VerifierGadget<BlstrsEmulation>>,
358
359 keccak_sha3_chip: Option<KeccakSha3Wrapper<F>>,
361 blake2b_chip: Option<Blake2bWrapper<F>>,
362
363 used_sha2_256: Rc<RefCell<bool>>,
367 used_sha2_512: Rc<RefCell<bool>>,
368 used_secp256k1: Rc<RefCell<bool>>,
369 used_p256: Rc<RefCell<bool>>,
370 used_bls12_381: Rc<RefCell<bool>>,
371 used_curve25519: Rc<RefCell<bool>>,
372 used_base64: Rc<RefCell<bool>>,
373 used_scanner: Rc<RefCell<bool>>,
374 used_keccak_or_sha3: Rc<RefCell<bool>>,
375 used_blake2b: Rc<RefCell<bool>>,
376}
377
378impl ZkStdLib {
379 pub fn new(config: &ZkStdLibConfig, max_bit_len: usize) -> Self {
381 let native_chip = NativeChip::new(&config.native_config, &());
382 let core_decomposition_chip =
383 P2RDecompositionChip::new(&config.core_decomposition_config, &max_bit_len);
384 let native_gadget = NativeGadget::new(core_decomposition_chip.clone(), native_chip.clone());
385 let jubjub_chip = (config.jubjub_config.as_ref())
386 .map(|jubjub_config| EccChip::new(jubjub_config, &native_gadget));
387 let sha2_256_chip = (config.sha2_256_config.as_ref())
388 .map(|sha256_config| Sha256Chip::new(sha256_config, &native_gadget));
389 let varlen_sha2_256_gadget = sha2_256_chip.as_ref().map(VarLenSha256Gadget::new);
390 let sha2_512_chip = (config.sha2_512_config.as_ref())
391 .map(|sha512_config| Sha512Chip::new(sha512_config, &native_gadget));
392 let poseidon_gadget = (config.poseidon_config.as_ref())
393 .map(|poseidon_config| PoseidonChip::new(poseidon_config, &native_chip));
394 let varlen_poseidon_gadget = (poseidon_gadget.as_ref())
395 .map(|poseidon| VarLenPoseidonGadget::new(poseidon, &native_gadget));
396 let htc_gadget = (jubjub_chip.as_ref())
397 .zip(poseidon_gadget.as_ref())
398 .map(|(ecc_chip, poseidon_gadget)| HashToCurveGadget::new(poseidon_gadget, ecc_chip));
399 let biguint_gadget = BigUintGadget::new(&native_gadget);
400 let map_gadget = poseidon_gadget
401 .as_ref()
402 .map(|poseidon_gadget| MapGadget::new(&native_gadget, poseidon_gadget));
403 let secp256k1_scalar_chip = (config.secp256k1_scalar_config.as_ref())
404 .map(|scalar_config| FieldChip::new(scalar_config, &native_gadget));
405 let secp256k1_chip = (config.secp256k1_config.as_ref())
406 .zip(secp256k1_scalar_chip.as_ref())
407 .map(|(curve_config, scalar_chip)| {
408 ForeignWeierstrassEccChip::new(curve_config, &native_gadget, scalar_chip)
409 });
410 let p256_scalar_chip = (config.p256_scalar_config.as_ref())
411 .map(|scalar_config| FieldChip::new(scalar_config, &native_gadget));
412 let p256_chip = (config.p256_config.as_ref()).zip(p256_scalar_chip.as_ref()).map(
413 |(curve_config, scalar_chip)| {
414 ForeignWeierstrassEccChip::new(curve_config, &native_gadget, scalar_chip)
415 },
416 );
417 let bls12_381_chip = (config.bls12_381_config.as_ref()).map(|curve_config| {
418 ForeignWeierstrassEccChip::new(curve_config, &native_gadget, &native_gadget)
419 });
420 let curve25519_scalar_chip = (config.curve25519_scalar_config.as_ref())
421 .map(|scalar_config| FieldChip::new(scalar_config, &native_gadget));
422 let curve25519_chip = (config.curve25519_config.as_ref())
423 .zip(curve25519_scalar_chip.as_ref())
424 .map(|(curve_config, scalar_chip)| {
425 ForeignEdwardsEccChip::new(curve_config, &native_gadget, scalar_chip)
426 });
427
428 let base64_chip = (config.base64_config.as_ref())
429 .map(|base64_config| Base64Chip::new(base64_config, &native_gadget));
430
431 let parser_gadget = ParserGadget::new(&native_gadget);
432 let scanner_chip =
433 config.scanner_config.as_ref().map(|c| ScannerChip::new(c, &native_gadget));
434 let vector_gadget = VectorGadget::new(&native_gadget);
435
436 let verifier_gadget = bls12_381_chip.as_ref().zip(poseidon_gadget.as_ref()).map(
437 |(curve_chip, sponge_chip)| {
438 VerifierGadget::<BlstrsEmulation>::new(curve_chip, &native_gadget, sponge_chip)
439 },
440 );
441
442 let keccak_sha3_chip = config
443 .keccak_sha3_config
444 .as_ref()
445 .map(|sha3_config| KeccakSha3Wrapper::new(sha3_config, &native_gadget));
446 let blake2b_chip = config
447 .blake2b_config
448 .as_ref()
449 .map(|blake2b_config| Blake2bWrapper::new(blake2b_config, &native_gadget));
450
451 Self {
452 native_gadget,
453 core_decomposition_chip,
454 jubjub_chip,
455 sha2_256_chip,
456 varlen_sha2_256_gadget,
457 sha2_512_chip,
458 poseidon_gadget,
459 varlen_poseidon_gadget,
460 map_gadget,
461 htc_gadget,
462 biguint_gadget,
463 secp256k1_chip,
464 p256_chip,
465 bls12_381_chip,
466 curve25519_chip,
467 base64_chip,
468 parser_gadget,
469 scanner_chip,
470 vector_gadget,
471 verifier_gadget,
472 keccak_sha3_chip,
473 blake2b_chip,
474 used_sha2_256: Rc::new(RefCell::new(false)),
475 used_sha2_512: Rc::new(RefCell::new(false)),
476 used_secp256k1: Rc::new(RefCell::new(false)),
477 used_p256: Rc::new(RefCell::new(false)),
478 used_bls12_381: Rc::new(RefCell::new(false)),
479 used_curve25519: Rc::new(RefCell::new(false)),
480 used_base64: Rc::new(RefCell::new(false)),
481 used_scanner: Rc::new(RefCell::new(false)),
482 used_keccak_or_sha3: Rc::new(RefCell::new(false)),
483 used_blake2b: Rc::new(RefCell::new(false)),
484 }
485 }
486
487 pub fn configure(
489 meta: &mut ConstraintSystem<F>,
490 (arch, max_bit_len): (ZkStdLibArch, u8),
491 ) -> ZkStdLibConfig {
492 let nb_advice_cols = [
493 NB_ARITH_COLS,
494 arch.nr_pow2range_cols as usize,
495 arch.jubjub as usize * NB_EDWARDS_COLS,
496 arch.poseidon as usize * NB_POSEIDON_ADVICE_COLS,
497 arch.sha2_256 as usize * NB_SHA256_ADVICE_COLS,
498 arch.sha2_512 as usize * NB_SHA512_ADVICE_COLS,
499 arch.secp256k1 as usize
500 * max(
501 nb_field_chip_columns::<F, k256_mod::Fq, MEP>(),
502 nb_foreign_ecc_chip_columns::<F, K256, MEP, k256_mod::Fq>(),
503 ),
504 arch.p256 as usize
505 * max(
506 nb_field_chip_columns::<F, p256_mod::Fq, MEP>(),
507 nb_foreign_ecc_chip_columns::<F, P256, MEP, p256_mod::Fq>(),
508 ),
509 arch.bls12_381 as usize
510 * max(
511 nb_field_chip_columns::<F, midnight_curves::Fp, MEP>(),
512 nb_foreign_ecc_chip_columns::<
513 F,
514 midnight_curves::G1Projective,
515 MEP,
516 midnight_curves::Fp,
517 >(),
518 ),
519 arch.curve25519 as usize
520 * max(
521 nb_field_chip_columns::<F, curve25519_mod::Scalar, MEP>(),
522 nb_foreign_edwards_chip_columns::<F, Curve25519, MEP>(),
523 ),
524 arch.base64 as usize * NB_BASE64_ADVICE_COLS,
525 arch.automaton as usize * NB_SCANNER_ADVICE_COLS,
526 (arch.keccak_256 || arch.sha3_256) as usize * PACKED_ADVICE_COLS,
527 arch.blake2b as usize * NB_BLAKE2B_ADVICE_COLS,
528 ]
529 .into_iter()
530 .max()
531 .unwrap_or(0);
532
533 let nb_fixed_cols = [
534 NB_ARITH_FIXED_COLS,
535 arch.poseidon as usize * NB_POSEIDON_FIXED_COLS,
536 arch.sha2_256 as usize * NB_SHA256_FIXED_COLS,
537 arch.sha2_512 as usize * NB_SHA512_FIXED_COLS,
538 (arch.keccak_256 || arch.sha3_256) as usize * PACKED_FIXED_COLS,
539 arch.automaton as usize * NB_SCANNER_FIXED_COLS,
540 ]
541 .into_iter()
542 .max()
543 .unwrap_or(0);
544
545 let advice_columns = (0..nb_advice_cols).map(|_| meta.advice_column()).collect::<Vec<_>>();
546 let fixed_columns = (0..nb_fixed_cols).map(|_| meta.fixed_column()).collect::<Vec<_>>();
547 let committed_instance_column = meta.instance_column();
548 let instance_column = meta.instance_column();
549
550 let native_config = NativeChip::configure(
551 meta,
552 &(
553 advice_columns[..NB_ARITH_COLS].try_into().unwrap(),
554 fixed_columns[..NB_ARITH_FIXED_COLS].try_into().unwrap(),
555 [committed_instance_column, instance_column],
556 ),
557 );
558
559 let nb_parallel_range_checks = arch.nr_pow2range_cols as usize;
560 let max_bit_len = max_bit_len as u32;
561
562 let pow2range_config =
563 Pow2RangeChip::configure(meta, &advice_columns[1..=arch.nr_pow2range_cols as usize]);
564
565 let core_decomposition_config =
566 P2RDecompositionChip::configure(meta, &(native_config.clone(), pow2range_config));
567
568 let jubjub_config = arch.jubjub.then(|| {
569 EccChip::<C>::configure(meta, &advice_columns[..NB_EDWARDS_COLS].try_into().unwrap())
570 });
571
572 let sha2_256_config = arch.sha2_256.then(|| {
573 Sha256Chip::configure(
574 meta,
575 &(
576 advice_columns[..NB_SHA256_ADVICE_COLS].try_into().unwrap(),
577 fixed_columns[..NB_SHA256_FIXED_COLS].try_into().unwrap(),
578 ),
579 )
580 });
581
582 let sha2_512_config = arch.sha2_512.then(|| {
583 Sha512Chip::configure(
584 meta,
585 &(
586 advice_columns[..NB_SHA512_ADVICE_COLS].try_into().unwrap(),
587 fixed_columns[..NB_SHA512_FIXED_COLS].try_into().unwrap(),
588 ),
589 )
590 });
591
592 let poseidon_config = arch.poseidon.then(|| {
593 PoseidonChip::configure(
594 meta,
595 &(
596 advice_columns[..NB_POSEIDON_ADVICE_COLS].try_into().unwrap(),
597 fixed_columns[..NB_POSEIDON_FIXED_COLS].try_into().unwrap(),
598 ),
599 )
600 });
601
602 let secp256k1_scalar_config = arch.secp256k1.then(|| {
603 Secp256k1ScalarChip::configure(
604 meta,
605 &advice_columns,
606 nb_parallel_range_checks,
607 max_bit_len,
608 )
609 });
610
611 let secp256k1_config = arch.secp256k1.then(|| {
612 let base_config = Secp256k1BaseChip::configure(
613 meta,
614 &advice_columns,
615 nb_parallel_range_checks,
616 max_bit_len,
617 );
618 Secp256k1Chip::configure(
619 meta,
620 &base_config,
621 &advice_columns,
622 nb_parallel_range_checks,
623 max_bit_len,
624 )
625 });
626
627 let p256_scalar_config = arch.p256.then(|| {
628 P256ScalarChip::configure(meta, &advice_columns, nb_parallel_range_checks, max_bit_len)
629 });
630
631 let p256_config = arch.p256.then(|| {
632 let base_config = P256BaseChip::configure(
633 meta,
634 &advice_columns,
635 nb_parallel_range_checks,
636 max_bit_len,
637 );
638 P256Chip::configure(
639 meta,
640 &base_config,
641 &advice_columns,
642 nb_parallel_range_checks,
643 max_bit_len,
644 )
645 });
646
647 let bls12_381_config = arch.bls12_381.then(|| {
648 let base_config = Bls12381BaseChip::configure(
649 meta,
650 &advice_columns,
651 nb_parallel_range_checks,
652 max_bit_len,
653 );
654 Bls12381Chip::configure(
655 meta,
656 &base_config,
657 &advice_columns,
658 nb_parallel_range_checks,
659 max_bit_len,
660 )
661 });
662
663 let curve25519_scalar_config = arch.curve25519.then(|| {
664 Curve25519ScalarChip::configure(
665 meta,
666 &advice_columns,
667 nb_parallel_range_checks,
668 max_bit_len,
669 )
670 });
671
672 let curve25519_config = arch.curve25519.then(|| {
673 let base_config = Curve25519BaseChip::configure(
674 meta,
675 &advice_columns,
676 nb_parallel_range_checks,
677 max_bit_len,
678 );
679 Curve25519Chip::configure(
680 meta,
681 &base_config,
682 &advice_columns,
683 &fixed_columns,
684 nb_parallel_range_checks,
685 max_bit_len,
686 )
687 });
688
689 let base64_config = arch.base64.then(|| {
690 Base64Chip::configure(
691 meta,
692 advice_columns[..NB_BASE64_ADVICE_COLS].try_into().unwrap(),
693 )
694 });
695
696 let scanner_config = arch.automaton.then(|| {
697 ScannerChip::configure(
698 meta,
699 &(
700 advice_columns[..NB_SCANNER_ADVICE_COLS].try_into().unwrap(),
701 fixed_columns[0],
702 parsing::spec_library(),
703 ),
704 )
705 });
706
707 let constant_column =
708 (arch.keccak_256 || arch.sha3_256 || arch.blake2b).then(|| meta.fixed_column());
709
710 let keccak_sha3_config = (arch.keccak_256 || arch.sha3_256).then(|| {
711 PackedChip::configure(
712 meta,
713 constant_column.unwrap(),
714 advice_columns[..PACKED_ADVICE_COLS].try_into().unwrap(),
715 fixed_columns[..PACKED_FIXED_COLS].try_into().unwrap(),
716 )
717 });
718
719 let blake2b_config = arch.blake2b.then(|| {
720 Blake2bChip::configure(
721 meta,
722 constant_column.unwrap(),
723 advice_columns[0],
724 advice_columns[1..NB_BLAKE2B_ADVICE_COLS].try_into().unwrap(),
725 )
726 });
727
728 ZkStdLibConfig {
729 native_config,
730 core_decomposition_config,
731 jubjub_config,
732 sha2_256_config,
733 sha2_512_config,
734 poseidon_config,
735 secp256k1_scalar_config,
736 secp256k1_config,
737 p256_scalar_config,
738 p256_config,
739 bls12_381_config,
740 curve25519_scalar_config,
741 curve25519_config,
742 base64_config,
743 scanner_config,
744 keccak_sha3_config,
745 blake2b_config,
746 }
747 }
748}
749
750impl ZkStdLib {
751 pub fn jubjub(&self) -> &EccChip<C> {
753 self.jubjub_chip.as_ref().expect("ZkStdLibArch must enable jubjub")
754 }
755
756 pub fn biguint(&self) -> &BigUintGadget<F, NG> {
758 &self.biguint_gadget
759 }
760
761 pub fn map_gadget(&self) -> &MapGadget<F, NG, PoseidonChip<F>> {
763 self.map_gadget
764 .as_ref()
765 .unwrap_or_else(|| panic!("ZkStdLibArch must enable poseidon"))
766 }
767
768 pub fn secp256k1(&self) -> &Secp256k1Chip {
771 *self.used_secp256k1.borrow_mut() = true;
772 self.secp256k1_chip
773 .as_ref()
774 .unwrap_or_else(|| panic!("ZkStdLibArch must enable secp256k1"))
775 }
776
777 pub fn p256(&self) -> &P256Chip {
780 *self.used_p256.borrow_mut() = true;
781 self.p256_chip
782 .as_ref()
783 .unwrap_or_else(|| panic!("ZkStdLibArch must enable p256"))
784 }
785
786 pub fn bls12_381(&self) -> &Bls12381Chip {
789 *self.used_bls12_381.borrow_mut() = true;
790 self.bls12_381_chip
791 .as_ref()
792 .unwrap_or_else(|| panic!("ZkStdLibArch must enable bls12_381"))
793 }
794
795 pub fn curve25519(&self) -> &Curve25519Chip {
797 *self.used_curve25519.borrow_mut() = true;
798 self.curve25519_chip
799 .as_ref()
800 .unwrap_or_else(|| panic!("ZkStdLibArch must enable curve25519"))
801 }
802
803 pub fn base64(&self) -> &Base64Chip<F> {
805 *self.used_base64.borrow_mut() = true;
806 self.base64_chip
807 .as_ref()
808 .unwrap_or_else(|| panic!("ZkStdLibArch must enable base64"))
809 }
810
811 pub fn parser(&self) -> &ParserGadget<F, NG> {
814 &self.parser_gadget
815 }
816
817 pub fn scanner(&self) -> &ScannerChip<F> {
825 *self.used_scanner.borrow_mut() = true;
826 (self.scanner_chip.as_ref()).unwrap_or_else(|| panic!("ZkStdLibArch must enable automaton"))
827 }
828
829 pub fn verifier(&self) -> &VerifierGadget<BlstrsEmulation> {
832 *self.used_bls12_381.borrow_mut() = true;
833 self.verifier_gadget
834 .as_ref()
835 .unwrap_or_else(|| panic!("ZkStdLibArch must enable bls12_381 & poseidon"))
836 }
837
838 pub fn assert_true(
847 &self,
848 layouter: &mut impl Layouter<F>,
849 input: &AssignedBit<F>,
850 ) -> Result<(), Error> {
851 self.native_gadget.assert_equal_to_fixed(layouter, input, true)
852 }
853
854 pub fn assert_false(
856 &self,
857 layouter: &mut impl Layouter<F>,
858 input: &AssignedBit<F>,
859 ) -> Result<(), Error> {
860 self.native_gadget.assert_equal_to_fixed(layouter, input, false)
861 }
862
863 pub fn lower_than(
890 &self,
891 layouter: &mut impl Layouter<F>,
892 x: &AssignedNative<F>,
893 y: &AssignedNative<F>,
894 n: u32,
895 ) -> Result<AssignedBit<F>, Error> {
896 let bounded_x = self.native_gadget.bounded_of_element(layouter, n as usize, x)?;
897 let bounded_y = self.native_gadget.bounded_of_element(layouter, n as usize, y)?;
898 self.native_gadget.lower_than(layouter, &bounded_x, &bounded_y)
899 }
900
901 pub fn poseidon(
912 &self,
913 layouter: &mut impl Layouter<F>,
914 input: &[AssignedNative<F>],
915 ) -> Result<AssignedNative<F>, Error> {
916 self.poseidon_gadget
917 .as_ref()
918 .unwrap_or_else(|| panic!("ZkStdLibArch must enable poseidon"))
919 .hash(layouter, input)
920 }
921
922 pub fn poseidon_varlen<const M: usize>(
933 &self,
934 layouter: &mut impl Layouter<F>,
935 input: &AssignedVector<F, AssignedNative<F>, M, RATE>,
936 ) -> Result<AssignedNative<F>, Error> {
937 assert!(
938 M.is_multiple_of(RATE),
939 "poseidon_varlen only supports assigned vector whose maxlen M is a multiple of {RATE} (here M = {M})"
940 );
941 self.varlen_poseidon_gadget
942 .as_ref()
943 .unwrap_or_else(|| panic!("ZkStdLibArch must enable poseidon"))
944 .poseidon_varlen(layouter, input)
945 }
946
947 pub fn hash_to_curve(
950 &self,
951 layouter: &mut impl Layouter<F>,
952 inputs: &[AssignedNative<F>],
953 ) -> Result<AssignedNativePoint<C>, Error> {
954 self.htc_gadget
955 .as_ref()
956 .unwrap_or_else(|| panic!("ZkStdLibArch must enable poseidon and jubjub"))
957 .hash_to_curve(layouter, inputs)
958 }
959
960 pub fn sha2_256(
980 &self,
981 layouter: &mut impl Layouter<F>,
982 input: &[AssignedByte<F>], ) -> Result<[AssignedByte<F>; 32], Error> {
984 *self.used_sha2_256.borrow_mut() = true;
985 self.sha2_256_chip
986 .as_ref()
987 .expect("ZkStdLibArch must enable sha256")
988 .hash(layouter, input)
989 }
990
991 pub fn sha2_256_varlen<const M: usize>(
1000 &self,
1001 layouter: &mut impl Layouter<F>,
1002 input: &AssignedVector<F, AssignedByte<F>, M, 64>,
1003 ) -> Result<[AssignedByte<F>; 32], Error> {
1004 *self.used_sha2_256.borrow_mut() = true;
1005 assert!(
1006 M.is_multiple_of(64),
1007 "sha2_256_varlen only supports assigned vector whose maxlen M is a multiple of 64 (here M = {M})"
1008 );
1009 self.varlen_sha2_256_gadget
1010 .as_ref()
1011 .expect("ZkStdLibArch must enable sha256")
1012 .varhash(layouter, input)
1013 }
1014
1015 pub fn sha2_512(
1017 &self,
1018 layouter: &mut impl Layouter<F>,
1019 input: &[AssignedByte<F>], ) -> Result<[AssignedByte<F>; 64], Error> {
1021 *self.used_sha2_512.borrow_mut() = true;
1022 self.sha2_512_chip
1023 .as_ref()
1024 .expect("ZkStdLibArch must enable sha512")
1025 .hash(layouter, input)
1026 }
1027
1028 pub fn sha3_256(
1030 &self,
1031 layouter: &mut impl Layouter<F>,
1032 input: &[AssignedByte<F>],
1033 ) -> Result<[AssignedByte<Fq>; 32], Error> {
1034 *self.used_keccak_or_sha3.borrow_mut() = true;
1035 let chip = self
1036 .keccak_sha3_chip
1037 .as_ref()
1038 .expect("ZkStdLibArch must enable sha3 (or keccak)");
1039 chip.sha3_256_digest(layouter, input)
1040 }
1041
1042 pub fn keccak_256(
1044 &self,
1045 layouter: &mut impl Layouter<F>,
1046 input: &[AssignedByte<F>],
1047 ) -> Result<[AssignedByte<Fq>; 32], Error> {
1048 *self.used_keccak_or_sha3.borrow_mut() = true;
1049 let chip = self
1050 .keccak_sha3_chip
1051 .as_ref()
1052 .expect("ZkStdLibArch must enable keccak (or sha3)");
1053 chip.keccak_256_digest(layouter, input)
1054 }
1055
1056 pub fn blake2b_256(
1059 &self,
1060 layouter: &mut impl Layouter<F>,
1061 input: &[AssignedByte<F>],
1062 ) -> Result<[AssignedByte<F>; 32], Error> {
1063 *self.used_blake2b.borrow_mut() = true;
1064 let chip = self.blake2b_chip.as_ref().expect("ZkStdLibArch must enable blake2b");
1065 chip.blake2b_256_digest(layouter, input)
1066 }
1067
1068 pub fn blake2b_512(
1071 &self,
1072 layouter: &mut impl Layouter<F>,
1073 input: &[AssignedByte<F>],
1074 ) -> Result<[AssignedByte<F>; 64], Error> {
1075 *self.used_blake2b.borrow_mut() = true;
1076 let chip = self.blake2b_chip.as_ref().expect("ZkStdLibArch must enable blake2b");
1077 chip.blake2b_512_digest(layouter, input)
1078 }
1079}
1080
1081impl<T> AssignmentInstructions<F, T> for ZkStdLib
1082where
1083 T: InnerValue,
1084 T::Element: Clone,
1085 NG: AssignmentInstructions<F, T>,
1086{
1087 fn assign(
1088 &self,
1089 layouter: &mut impl Layouter<F>,
1090 value: Value<T::Element>,
1091 ) -> Result<T, Error> {
1092 self.native_gadget.assign(layouter, value)
1093 }
1094
1095 fn assign_fixed(
1096 &self,
1097 layouter: &mut impl Layouter<F>,
1098 constant: T::Element,
1099 ) -> Result<T, Error> {
1100 self.native_gadget.assign_fixed(layouter, constant)
1101 }
1102
1103 fn assign_many(
1104 &self,
1105 layouter: &mut impl Layouter<F>,
1106 values: &[Value<T::Element>],
1107 ) -> Result<Vec<T>, Error> {
1108 self.native_gadget.assign_many(layouter, values)
1109 }
1110}
1111
1112impl<T> PublicInputInstructions<F, T> for ZkStdLib
1113where
1114 T: Instantiable<F>,
1115 T::Element: Clone,
1116 NG: PublicInputInstructions<F, T>,
1117{
1118 fn as_public_input(
1119 &self,
1120 layouter: &mut impl Layouter<F>,
1121 assigned: &T,
1122 ) -> Result<Vec<AssignedNative<F>>, Error> {
1123 self.native_gadget.as_public_input(layouter, assigned)
1124 }
1125
1126 fn constrain_as_public_input(
1127 &self,
1128 layouter: &mut impl Layouter<F>,
1129 assigned: &T,
1130 ) -> Result<(), Error> {
1131 self.native_gadget.constrain_as_public_input(layouter, assigned)
1132 }
1133
1134 fn assign_as_public_input(
1135 &self,
1136 layouter: &mut impl Layouter<F>,
1137 value: Value<<T>::Element>,
1138 ) -> Result<T, Error> {
1139 self.native_gadget.assign_as_public_input(layouter, value)
1140 }
1141}
1142
1143impl<T> CommittedInstanceInstructions<F, T> for ZkStdLib
1144where
1145 F: PrimeField,
1146 T: Instantiable<F>,
1147 NG: CommittedInstanceInstructions<F, T>,
1148{
1149 fn constrain_as_committed_public_input(
1150 &self,
1151 layouter: &mut impl Layouter<F>,
1152 assigned: &T,
1153 ) -> Result<(), Error> {
1154 self.native_gadget.constrain_as_committed_public_input(layouter, assigned)
1155 }
1156}
1157
1158impl<T> AssertionInstructions<F, T> for ZkStdLib
1159where
1160 T: InnerValue,
1161 NG: AssertionInstructions<F, T>,
1162{
1163 fn assert_equal(&self, layouter: &mut impl Layouter<F>, x: &T, y: &T) -> Result<(), Error> {
1164 self.native_gadget.assert_equal(layouter, x, y)
1165 }
1166
1167 fn assert_not_equal(&self, layouter: &mut impl Layouter<F>, x: &T, y: &T) -> Result<(), Error> {
1168 self.native_gadget.assert_not_equal(layouter, x, y)
1169 }
1170
1171 fn assert_equal_to_fixed(
1172 &self,
1173 layouter: &mut impl Layouter<F>,
1174 x: &T,
1175 constant: T::Element,
1176 ) -> Result<(), Error> {
1177 self.native_gadget.assert_equal_to_fixed(layouter, x, constant)
1178 }
1179
1180 fn assert_not_equal_to_fixed(
1181 &self,
1182 layouter: &mut impl Layouter<F>,
1183 x: &T,
1184 constant: T::Element,
1185 ) -> Result<(), Error> {
1186 self.native_gadget.assert_not_equal_to_fixed(layouter, x, constant)
1187 }
1188}
1189
1190impl<T> EqualityInstructions<F, T> for ZkStdLib
1191where
1192 T: InnerValue,
1193 NG: EqualityInstructions<F, T>,
1194{
1195 fn is_equal(
1196 &self,
1197 layouter: &mut impl Layouter<F>,
1198 x: &T,
1199 y: &T,
1200 ) -> Result<AssignedBit<F>, Error> {
1201 self.native_gadget.is_equal(layouter, x, y)
1202 }
1203
1204 fn is_not_equal(
1205 &self,
1206 layouter: &mut impl Layouter<F>,
1207 x: &T,
1208 y: &T,
1209 ) -> Result<AssignedBit<F>, Error> {
1210 self.native_gadget.is_not_equal(layouter, x, y)
1211 }
1212
1213 fn is_equal_to_fixed(
1214 &self,
1215 layouter: &mut impl Layouter<F>,
1216 x: &T,
1217 constant: T::Element,
1218 ) -> Result<AssignedBit<F>, Error> {
1219 self.native_gadget.is_equal_to_fixed(layouter, x, constant)
1220 }
1221
1222 fn is_not_equal_to_fixed(
1223 &self,
1224 layouter: &mut impl Layouter<F>,
1225 x: &T,
1226 constant: T::Element,
1227 ) -> Result<AssignedBit<F>, Error> {
1228 self.native_gadget.is_not_equal_to_fixed(layouter, x, constant)
1229 }
1230}
1231
1232impl<T1, T2> ConversionInstructions<F, T1, T2> for ZkStdLib
1233where
1234 T1: InnerValue,
1235 T2: InnerValue,
1236 NG: ConversionInstructions<F, T1, T2>,
1237{
1238 fn convert_value(&self, x: &T1::Element) -> Option<T2::Element> {
1239 ConversionInstructions::<_, T1, T2>::convert_value(&self.native_gadget, x)
1240 }
1241
1242 fn convert(&self, layouter: &mut impl Layouter<F>, x: &T1) -> Result<T2, Error> {
1243 self.native_gadget.convert(layouter, x)
1244 }
1245}
1246
1247impl CanonicityInstructions<F, AssignedNative<F>> for ZkStdLib {
1248 fn le_bits_lower_than(
1249 &self,
1250 layouter: &mut impl Layouter<F>,
1251 bits: &[AssignedBit<F>],
1252 bound: BigUint,
1253 ) -> Result<AssignedBit<F>, Error> {
1254 self.native_gadget.le_bits_lower_than(layouter, bits, bound)
1255 }
1256
1257 fn le_bits_geq_than(
1258 &self,
1259 layouter: &mut impl Layouter<F>,
1260 bits: &[AssignedBit<F>],
1261 bound: BigUint,
1262 ) -> Result<AssignedBit<F>, Error> {
1263 self.native_gadget.le_bits_geq_than(layouter, bits, bound)
1264 }
1265}
1266
1267impl DecompositionInstructions<F, AssignedNative<F>> for ZkStdLib {
1268 fn assigned_to_le_bits(
1269 &self,
1270 layouter: &mut impl Layouter<F>,
1271 x: &AssignedNative<F>,
1272 nb_bits: Option<usize>,
1273 enforce_canonical: bool,
1274 ) -> Result<Vec<AssignedBit<F>>, Error> {
1275 self.native_gadget.assigned_to_le_bits(layouter, x, nb_bits, enforce_canonical)
1276 }
1277
1278 fn assigned_to_le_bytes(
1279 &self,
1280 layouter: &mut impl Layouter<F>,
1281 x: &AssignedNative<F>,
1282 nb_bytes: Option<usize>,
1283 ) -> Result<Vec<AssignedByte<F>>, Error> {
1284 self.native_gadget.assigned_to_le_bytes(layouter, x, nb_bytes)
1285 }
1286
1287 fn assigned_to_le_chunks(
1288 &self,
1289 layouter: &mut impl Layouter<F>,
1290 x: &AssignedNative<F>,
1291 nb_bits_per_chunk: usize,
1292 nb_chunks: Option<usize>,
1293 ) -> Result<Vec<AssignedNative<F>>, Error> {
1294 self.native_gadget
1295 .assigned_to_le_chunks(layouter, x, nb_bits_per_chunk, nb_chunks)
1296 }
1297
1298 fn sgn0(
1299 &self,
1300 layouter: &mut impl Layouter<F>,
1301 x: &AssignedNative<F>,
1302 ) -> Result<AssignedBit<F>, Error> {
1303 self.native_gadget.sgn0(layouter, x)
1304 }
1305}
1306
1307impl ArithInstructions<F, AssignedNative<F>> for ZkStdLib {
1308 fn linear_combination(
1309 &self,
1310 layouter: &mut impl Layouter<F>,
1311 terms: &[(F, AssignedNative<F>)],
1312 constant: F,
1313 ) -> Result<AssignedNative<F>, Error> {
1314 self.native_gadget.linear_combination(layouter, terms, constant)
1315 }
1316
1317 fn mul(
1318 &self,
1319 layouter: &mut impl Layouter<F>,
1320 x: &AssignedNative<F>,
1321 y: &AssignedNative<F>,
1322 multiplying_constant: Option<F>,
1323 ) -> Result<AssignedNative<F>, Error> {
1324 self.native_gadget.mul(layouter, x, y, multiplying_constant)
1325 }
1326
1327 fn div(
1328 &self,
1329 layouter: &mut impl Layouter<F>,
1330 x: &AssignedNative<F>,
1331 y: &AssignedNative<F>,
1332 ) -> Result<AssignedNative<F>, Error> {
1333 self.native_gadget.div(layouter, x, y)
1334 }
1335
1336 fn inv(
1337 &self,
1338 layouter: &mut impl Layouter<F>,
1339 x: &AssignedNative<F>,
1340 ) -> Result<AssignedNative<F>, Error> {
1341 self.native_gadget.inv(layouter, x)
1342 }
1343
1344 fn inv0(
1345 &self,
1346 layouter: &mut impl Layouter<F>,
1347 x: &AssignedNative<F>,
1348 ) -> Result<AssignedNative<F>, Error> {
1349 self.native_gadget.inv0(layouter, x)
1350 }
1351}
1352
1353impl ZeroInstructions<F, AssignedNative<F>> for ZkStdLib {}
1354
1355impl<Assigned> ControlFlowInstructions<F, Assigned> for ZkStdLib
1356where
1357 Assigned: InnerValue,
1358 NG: ControlFlowInstructions<F, Assigned>,
1359{
1360 fn select(
1361 &self,
1362 layouter: &mut impl Layouter<F>,
1363 cond: &AssignedBit<F>,
1364 x: &Assigned,
1365 y: &Assigned,
1366 ) -> Result<Assigned, Error> {
1367 self.native_gadget.select(layouter, cond, x, y)
1368 }
1369
1370 fn cond_swap(
1371 &self,
1372 layouter: &mut impl Layouter<F>,
1373 cond: &AssignedBit<F>,
1374 x: &Assigned,
1375 y: &Assigned,
1376 ) -> Result<(Assigned, Assigned), Error> {
1377 self.native_gadget.cond_swap(layouter, cond, x, y)
1378 }
1379}
1380
1381impl FieldInstructions<F, AssignedNative<F>> for ZkStdLib {
1382 fn order(&self) -> BigUint {
1383 self.native_gadget.order()
1384 }
1385}
1386
1387impl RangeCheckInstructions<F, AssignedNative<F>> for ZkStdLib {
1388 fn assign_lower_than_fixed(
1389 &self,
1390 layouter: &mut impl Layouter<F>,
1391 value: Value<F>,
1392 bound: &BigUint,
1393 ) -> Result<AssignedNative<F>, Error> {
1394 self.native_gadget.assign_lower_than_fixed(layouter, value, bound)
1395 }
1396
1397 fn assert_lower_than_fixed(
1398 &self,
1399 layouter: &mut impl Layouter<F>,
1400 x: &AssignedNative<F>,
1401 bound: &BigUint,
1402 ) -> Result<(), Error> {
1403 self.native_gadget.assert_lower_than_fixed(layouter, x, bound)
1404 }
1405}
1406
1407impl DivisionInstructions<F, AssignedNative<F>> for ZkStdLib {}
1408
1409impl BinaryInstructions<F> for ZkStdLib {
1410 fn and(
1411 &self,
1412 layouter: &mut impl Layouter<F>,
1413 bits: &[AssignedBit<F>],
1414 ) -> Result<AssignedBit<F>, Error> {
1415 self.native_gadget.and(layouter, bits)
1416 }
1417
1418 fn or(
1419 &self,
1420 layouter: &mut impl Layouter<F>,
1421 bits: &[AssignedBit<F>],
1422 ) -> Result<AssignedBit<F>, Error> {
1423 self.native_gadget.or(layouter, bits)
1424 }
1425
1426 fn xor(
1427 &self,
1428 layouter: &mut impl Layouter<F>,
1429 bits: &[AssignedBit<F>],
1430 ) -> Result<AssignedBit<F>, Error> {
1431 self.native_gadget.xor(layouter, bits)
1432 }
1433
1434 fn not(
1435 &self,
1436 layouter: &mut impl Layouter<F>,
1437 bit: &AssignedBit<F>,
1438 ) -> Result<AssignedBit<F>, Error> {
1439 self.native_gadget.not(layouter, bit)
1440 }
1441}
1442
1443impl BitwiseInstructions<F, AssignedNative<F>> for ZkStdLib {}
1444
1445impl<const M: usize, const A: usize, T> VectorInstructions<F, T, M, A> for ZkStdLib
1446where
1447 T: Vectorizable,
1448 T::Element: Copy,
1449 NG: AssignmentInstructions<F, T> + ControlFlowInstructions<F, T>,
1450{
1451 fn trim_beginning(
1452 &self,
1453 layouter: &mut impl Layouter<F>,
1454 input: &AssignedVector<F, T, M, A>,
1455 n_elems: usize,
1456 ) -> Result<AssignedVector<F, T, M, A>, Error> {
1457 self.vector_gadget.trim_beginning(layouter, input, n_elems)
1458 }
1459
1460 fn padding_flag(
1461 &self,
1462 layouter: &mut impl Layouter<F>,
1463 input: &AssignedVector<F, T, M, A>,
1464 ) -> Result<(Box<[AssignedBit<F>; M]>, VectorBounds<F>), Error> {
1465 self.vector_gadget.padding_flag(layouter, input)
1466 }
1467
1468 fn get_limits(
1469 &self,
1470 layouter: &mut impl Layouter<F>,
1471 input: &AssignedVector<F, T, M, A>,
1472 ) -> Result<VectorBounds<F>, Error> {
1473 self.vector_gadget.get_limits(layouter, input)
1474 }
1475
1476 fn resize<const L: usize>(
1477 &self,
1478 layouter: &mut impl Layouter<F>,
1479 input: AssignedVector<F, T, M, A>,
1480 ) -> Result<AssignedVector<F, T, L, A>, Error> {
1481 self.vector_gadget.resize(layouter, input)
1482 }
1483
1484 fn assign_with_filler(
1485 &self,
1486 layouter: &mut impl Layouter<F>,
1487 value: Value<Vec<<T>::Element>>,
1488 filler: Option<<T>::Element>,
1489 ) -> Result<AssignedVector<F, T, M, A>, Error> {
1490 self.vector_gadget.assign_with_filler(layouter, value, filler)
1491 }
1492}
1493
1494#[derive(Clone, Debug)]
1497pub struct MidnightCircuit<'a, R: Relation> {
1498 relation: &'a R,
1499 k: u32,
1500 instance: Value<R::Instance>,
1501 witness: Value<R::Witness>,
1502 nb_public_inputs: Rc<RefCell<Option<usize>>>,
1503 circuit_error: Rc<RefCell<Option<R::Error>>>,
1504}
1505
1506impl<'a, R: Relation> MidnightCircuit<'a, R> {
1507 pub fn from_relation(relation: &'a R, k: Option<u32>) -> Self {
1511 MidnightCircuit::new(relation, Value::unknown(), Value::unknown(), k)
1512 }
1513
1514 pub fn new(
1518 relation: &'a R,
1519 instance: Value<R::Instance>,
1520 witness: Value<R::Witness>,
1521 k: Option<u32>,
1522 ) -> Self {
1523 let k = k.unwrap_or_else(|| optimal_k(relation));
1524 MidnightCircuit {
1525 relation,
1526 k,
1527 instance,
1528 witness,
1529 nb_public_inputs: Rc::new(RefCell::new(None)),
1530 circuit_error: Rc::new(RefCell::new(None)),
1531 }
1532 }
1533
1534 pub fn k(&self) -> u32 {
1536 self.k
1537 }
1538
1539 pub fn take_error(&self) -> Option<R::Error> {
1541 self.circuit_error.take()
1542 }
1543}
1544
1545#[derive(Clone, Debug)]
1547pub struct MidnightVK {
1548 architecture: ZkStdLibArch,
1549 k: u8,
1550 nb_public_inputs: usize,
1551 vk: VerifyingKey<midnight_curves::Fq, KZGCommitmentScheme<midnight_curves::Bls12>>,
1552}
1553
1554impl MidnightVK {
1555 pub fn write<W: io::Write>(&self, writer: &mut W, format: SerdeFormat) -> io::Result<()> {
1564 self.architecture.write(writer)?;
1565
1566 writer.write_all(&[self.k])?;
1567
1568 writer.write_all(&(self.nb_public_inputs as u32).to_le_bytes())?;
1569
1570 self.vk.write(writer, format)
1571 }
1572
1573 pub fn read<R: io::Read>(reader: &mut R, format: SerdeFormat) -> io::Result<Self> {
1582 let architecture = ZkStdLibArch::read(reader)?;
1583
1584 let mut byte = [0u8; 1];
1585 reader.read_exact(&mut byte)?;
1586 let k = byte[0];
1587
1588 let mut bytes = [0u8; 4];
1589 reader.read_exact(&mut bytes)?;
1590 let nb_public_inputs = u32::from_le_bytes(bytes) as usize;
1591
1592 let mut cs = ConstraintSystem::default();
1593 let _config = ZkStdLib::configure(&mut cs, (architecture, k - 1));
1594
1595 let vk = VerifyingKey::read_from_cs::<R>(reader, format, cs)?;
1596
1597 Ok(MidnightVK {
1598 architecture,
1599 k,
1600 nb_public_inputs,
1601 vk,
1602 })
1603 }
1604
1605 pub fn k(&self) -> u8 {
1607 self.k
1608 }
1609
1610 pub fn vk(
1612 &self,
1613 ) -> &VerifyingKey<midnight_curves::Fq, KZGCommitmentScheme<midnight_curves::Bls12>> {
1614 &self.vk
1615 }
1616}
1617
1618#[derive(Clone, Debug)]
1620pub struct MidnightPK<R: Relation> {
1621 k: u8,
1622 relation: R,
1623 pk: ProvingKey<midnight_curves::Fq, KZGCommitmentScheme<midnight_curves::Bls12>>,
1624}
1625
1626impl<Rel: Relation> MidnightPK<Rel> {
1627 pub fn write<W: io::Write>(&self, writer: &mut W, format: SerdeFormat) -> io::Result<()> {
1636 writer.write_all(&[self.k])?;
1637
1638 Rel::write_relation(&self.relation, writer)?;
1639
1640 self.pk.write(writer, format)
1641 }
1642
1643 pub fn read<R: io::Read>(reader: &mut R, format: SerdeFormat) -> io::Result<Self> {
1652 let mut byte = [0u8; 1];
1653
1654 reader.read_exact(&mut byte)?;
1655 let k = byte[0];
1656
1657 let relation = Rel::read_relation(reader)?;
1658
1659 let pk = ProvingKey::read::<R, MidnightCircuit<Rel>>(
1660 reader,
1661 format,
1662 MidnightCircuit::new(
1663 &relation,
1664 Value::unknown(),
1665 Value::unknown(),
1666 Some(k as u32),
1667 )
1668 .params(),
1669 )?;
1670
1671 Ok(MidnightPK { k, relation, pk })
1672 }
1673
1674 pub fn k(&self) -> u8 {
1676 self.k
1677 }
1678
1679 pub fn pk(
1681 &self,
1682 ) -> &ProvingKey<midnight_curves::Fq, KZGCommitmentScheme<midnight_curves::Bls12>> {
1683 &self.pk
1684 }
1685}
1686
1687pub trait Relation: Clone {
1796 type Instance: Clone;
1798
1799 type Witness: Clone;
1801
1802 type Error: From<plonk::Error>;
1804
1805 fn format_instance(instance: &Self::Instance) -> Result<Vec<F>, Self::Error>;
1808
1809 fn format_committed_instances(_witness: &Self::Witness) -> Vec<F> {
1812 vec![]
1813 }
1814
1815 fn circuit(
1817 &self,
1818 std_lib: &ZkStdLib,
1819 layouter: &mut impl Layouter<F>,
1820 instance: Value<Self::Instance>,
1821 witness: Value<Self::Witness>,
1822 ) -> Result<(), Self::Error>;
1823
1824 fn used_chips(&self) -> ZkStdLibArch {
1831 ZkStdLibArch::default()
1832 }
1833
1834 fn write_relation<W: io::Write>(&self, writer: &mut W) -> io::Result<()>;
1836
1837 fn read_relation<R: io::Read>(reader: &mut R) -> io::Result<Self>;
1839}
1840
1841impl<R: Relation> Circuit<F> for MidnightCircuit<'_, R> {
1842 type Config = ZkStdLibConfig;
1843
1844 type FloorPlanner = SimpleFloorPlanner;
1846
1847 type Params = (ZkStdLibArch, u8);
1848
1849 fn without_witnesses(&self) -> Self {
1850 unreachable!()
1851 }
1852
1853 fn params(&self) -> Self::Params {
1854 (self.relation.used_chips(), (self.k - 1) as u8)
1855 }
1856
1857 fn configure_with_params(
1858 meta: &mut ConstraintSystem<F>,
1859 params: (ZkStdLibArch, u8),
1860 ) -> Self::Config {
1861 ZkStdLib::configure(meta, params)
1862 }
1863
1864 fn configure(meta: &mut ConstraintSystem<F>) -> Self::Config {
1865 ZkStdLib::configure(meta, (ZkStdLibArch::default(), 8))
1866 }
1867
1868 fn synthesize(
1869 &self,
1870 config: Self::Config,
1871 mut layouter: impl Layouter<F>,
1872 ) -> Result<(), Error> {
1873 let max_bit_len = (self.k - 1) as usize;
1874 let zk_std_lib = ZkStdLib::new(&config, max_bit_len);
1875
1876 self.relation
1877 .circuit(
1878 &zk_std_lib,
1879 &mut layouter.namespace(|| "Running logic circuit"),
1880 self.instance.clone(),
1881 self.witness.clone(),
1882 )
1883 .map_err(|e| {
1884 *self.circuit_error.borrow_mut() = Some(e);
1885 Error::Synthesis("Relation::circuit error".into())
1886 })?;
1887
1888 *self.nb_public_inputs.borrow_mut() =
1893 Some(zk_std_lib.native_gadget.native_chip.nb_public_inputs());
1894
1895 zk_std_lib.core_decomposition_chip.load(&mut layouter)?;
1898
1899 if let Some(sha256_chip) = zk_std_lib.sha2_256_chip {
1900 if *zk_std_lib.used_sha2_256.borrow() {
1901 sha256_chip.load(&mut layouter)?;
1902 }
1903 }
1904
1905 if let Some(sha512_chip) = zk_std_lib.sha2_512_chip {
1906 if *zk_std_lib.used_sha2_512.borrow() {
1907 sha512_chip.load(&mut layouter)?;
1908 }
1909 }
1910
1911 if let Some(b64_chip) = zk_std_lib.base64_chip {
1912 if *zk_std_lib.used_base64.borrow() {
1913 b64_chip.load(&mut layouter)?;
1914 }
1915 }
1916
1917 if let Some(scanner_chip) = zk_std_lib.scanner_chip {
1918 if *zk_std_lib.used_scanner.borrow() {
1919 scanner_chip.load(&mut layouter)?;
1920 }
1921 }
1922
1923 if let Some(keccak_sha3_chip) = zk_std_lib.keccak_sha3_chip {
1924 if *zk_std_lib.used_keccak_or_sha3.borrow() {
1925 keccak_sha3_chip.load(&mut layouter)?;
1926 }
1927 }
1928
1929 if let Some(blake2b_chip) = zk_std_lib.blake2b_chip {
1930 if *zk_std_lib.used_blake2b.borrow() {
1931 blake2b_chip.load(&mut layouter)?;
1932 }
1933 }
1934
1935 Ok(())
1936 }
1937}
1938
1939pub fn setup_vk<R: Relation>(
1946 params: &ParamsKZG<midnight_curves::Bls12>,
1947 relation: &R,
1948) -> MidnightVK {
1949 let k = params.max_k();
1950 let circuit = MidnightCircuit::from_relation(relation, Some(k));
1951 let vk = keygen_vk_with_k(params, &circuit, k).expect("keygen_vk should not fail");
1952
1953 let nb_public_inputs = circuit.nb_public_inputs.clone().borrow().unwrap();
1956
1957 MidnightVK {
1958 architecture: relation.used_chips(),
1959 k: circuit.k as u8,
1960 nb_public_inputs,
1961 vk,
1962 }
1963}
1964
1965pub fn setup_pk<R: Relation>(relation: &R, vk: &MidnightVK) -> MidnightPK<R> {
1967 let circuit = MidnightCircuit::new(
1968 relation,
1969 Value::unknown(),
1970 Value::unknown(),
1971 Some(vk.k() as u32),
1972 );
1973 let pk = BlstPLONK::<MidnightCircuit<R>>::setup_pk(&circuit, &vk.vk);
1974 MidnightPK {
1975 k: vk.k(),
1976 relation: relation.clone(),
1977 pk,
1978 }
1979}
1980
1981pub fn prove<R: Relation, H: TranscriptHash>(
1984 params: &ParamsKZG<midnight_curves::Bls12>,
1985 pk: &MidnightPK<R>,
1986 relation: &R,
1987 instance: &R::Instance,
1988 witness: R::Witness,
1989 rng: impl RngCore + CryptoRng,
1990) -> Result<Vec<u8>, R::Error>
1991where
1992 G1Projective: Hashable<H>,
1993 F: Hashable<H> + Sampleable<H>,
1994{
1995 let pi = R::format_instance(instance)?;
1996 let com_inst = R::format_committed_instances(&witness);
1997 let circuit = MidnightCircuit::new(
1998 relation,
1999 Value::known(instance.clone()),
2000 Value::known(witness),
2001 Some(pk.k as u32),
2002 );
2003 BlstPLONK::<MidnightCircuit<R>>::prove::<H>(
2004 params,
2005 &pk.pk,
2006 &circuit,
2007 1,
2008 &[com_inst.as_slice(), &pi],
2009 rng,
2010 )
2011 .map_err(|e| circuit.take_error().unwrap_or_else(|| e.into()))
2012}
2013
2014pub fn verify<R: Relation, H: TranscriptHash>(
2017 params_verifier: &ParamsVerifierKZG<midnight_curves::Bls12>,
2018 vk: &MidnightVK,
2019 instance: &R::Instance,
2020 committed_instance: Option<G1Affine>,
2021 proof: &[u8],
2022) -> Result<(), R::Error>
2023where
2024 G1Projective: Hashable<H>,
2025 F: Hashable<H> + Sampleable<H>,
2026{
2027 let pi = R::format_instance(instance)?;
2028 let committed_pi = committed_instance.unwrap_or(G1Affine::identity());
2029 if pi.len() != vk.nb_public_inputs {
2030 return Err(Error::InvalidInstances.into());
2031 }
2032 Ok(BlstPLONK::<MidnightCircuit<R>>::verify::<H>(
2033 params_verifier,
2034 &vk.vk,
2035 &[committed_pi],
2036 &[&pi],
2037 proof,
2038 )?)
2039}
2040
2041pub fn batch_verify<H: TranscriptHash + Send + Sync>(
2049 params_verifier: &ParamsVerifierKZG<midnight_curves::Bls12>,
2050 vks: &[MidnightVK],
2051 pis: &[Vec<F>],
2052 proofs: &[Vec<u8>],
2053) -> Result<(), Error>
2054where
2055 G1Projective: Hashable<H>,
2056 F: Hashable<H> + Sampleable<H>,
2057{
2058 use rayon::prelude::*;
2059
2060 let n = vks.len();
2062 if pis.len() != n || proofs.len() != n {
2063 return Err(Error::InvalidInstances);
2065 }
2066
2067 let prepared: Vec<(_, F)> = vks
2068 .par_iter()
2069 .zip(pis.par_iter())
2070 .zip(proofs.par_iter())
2071 .map(|((vk, pi), proof)| {
2072 if pi.len() != vk.nb_public_inputs {
2073 return Err(Error::InvalidInstances);
2074 }
2075
2076 let mut transcript = CircuitTranscript::init_from_bytes(proof);
2077 let dual_msm = prepare::<
2078 midnight_curves::Fq,
2079 KZGCommitmentScheme<midnight_curves::Bls12>,
2080 CircuitTranscript<H>,
2081 >(
2082 &vk.vk,
2083 &[&[midnight_curves::G1Projective::identity()]],
2084 &[&[pi]],
2086 &mut transcript,
2087 )?;
2088 let summary: F = transcript.squeeze_challenge();
2089 transcript.assert_empty().map_err(|_| Error::Opening)?;
2090 Ok((dual_msm, summary))
2091 })
2092 .collect::<Result<Vec<_>, Error>>()?;
2093
2094 let mut r_transcript = CircuitTranscript::init();
2095 let mut guards = Vec::with_capacity(n);
2096 for (guard, summary) in prepared {
2097 r_transcript.common(&summary)?;
2098 guards.push(guard);
2099 }
2100 let r: F = r_transcript.squeeze_challenge();
2101
2102 let n_guards = guards.len();
2103 let powers: Vec<F> =
2104 std::iter::successors(Some(F::ONE), |p| Some(*p * r)).take(n_guards).collect();
2105 guards.par_iter_mut().enumerate().for_each(|(i, guard)| guard.scale(powers[i]));
2106
2107 let Some(mut acc_guard) = guards.pop() else {
2109 return Ok(());
2110 };
2111 for guard in guards {
2112 acc_guard.add_msm(guard);
2113 }
2114 acc_guard.verify(params_verifier).map_err(|_| Error::Opening)
2116}
2117
2118pub fn cost_model<R: Relation>(relation: &R, k: Option<u32>) -> CircuitModel {
2122 let circuit = MidnightCircuit::from_relation(relation, k);
2123 circuit_model::<_, COMMITMENT_BYTE_SIZE, SCALAR_BYTE_SIZE>(&circuit)
2124}
2125
2126pub fn optimal_k<R: Relation>(relation: &R) -> u32 {
2130 let mut best_k = u32::MAX;
2131
2132 for k in 9..=25 {
2133 let model = cost_model(relation, Some(k));
2134
2135 if model.k < best_k {
2136 best_k = model.k;
2137 }
2138
2139 if model.rows < (1 << k) {
2141 break;
2142 }
2143 }
2144
2145 best_k
2146}