Skip to main content

midnight_zk_stdlib/
lib.rs

1// This file is part of MIDNIGHT-ZK.
2// Copyright (C) Midnight Foundation
3// SPDX-License-Identifier: Apache-2.0
4// Licensed under the Apache License, Version 2.0 (the "License");
5// You may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7// http://www.apache.org/licenses/LICENSE-2.0
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14#![doc = include_str!("../README.md")]
15//!
16//! ## Implementation Details
17//!
18//! This library uses a fixed configuration, meaning that regardless of what one
19//! uses, it will always consist of the same columns, lookups, permutation
20//! enabled columns, or gates. The motivation for this is twofold:
21//!
22//! * It facilitates recursion (we always aggregate circuits that have the same
23//!   verification logic).
24//!
25//! * We could optimise the verifier, who can store part of the circuit
26//!   description in memory and does not need to reproduce it everytime it
27//!   receives a new proof.
28
29mod 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
128// Type aliases, for readability.
129type 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
150/// Byte size of a serialized BLS12-381 G1 commitment (compressed).
151const COMMITMENT_BYTE_SIZE: usize = 48;
152
153/// Byte size of a serialized BLS12-381 scalar.
154const SCALAR_BYTE_SIZE: usize = 32;
155
156/// Architecture of the standard library. Specifies what chips need to be
157/// configured.
158#[derive(Clone, Copy, Debug, Eq, PartialEq, Encode, Decode)]
159pub struct ZkStdLibArch {
160    /// Enable the Jubjub chip?
161    pub jubjub: bool,
162
163    /// Enable the Poseidon chip?
164    pub poseidon: bool,
165
166    /// Enable the SHA256 chip?
167    pub sha2_256: bool,
168
169    /// Enable the SHA512 chip?
170    pub sha2_512: bool,
171
172    /// Enable the Keccak chip? (third-party implementation)
173    ///
174    /// Note: is configured using the same columns and tables as sha3_256,
175    /// meaning enabling either of the two, or both, requires the same
176    /// configuration resources.
177    pub keccak_256: bool,
178
179    /// Enable the Sha3 chip? (third-party implementation)
180    ///
181    /// Note: is configured using the same columns and tables as keccak_256,
182    /// meaning enabling either of the two, or both, requires the same
183    /// configuration resources.
184    pub sha3_256: bool,
185
186    /// Enable the Blake2b chip? (third-party implementation)
187    pub blake2b: bool,
188
189    /// Enable the Secp256k1 chip?
190    pub secp256k1: bool,
191
192    /// Enable the P256 chip?
193    pub p256: bool,
194
195    /// Enable BLS12-381 chip?
196    pub bls12_381: bool,
197
198    /// Enable Curve25519 chip?
199    pub curve25519: bool,
200
201    /// Enable base64 chip?
202    pub base64: bool,
203
204    /// Enable scanner chip (automaton-based parsing and substring checks)?
205    pub automaton: bool,
206
207    /// Number of parallel lookups for range checks.
208    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    /// Writes the ZKStd architecture to a buffer.
234    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    /// Reads the ZkStd architecture from a buffer.
242    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    /// Reads the ZkStdArchitecture from a buffer where a MidnightVK was
257    /// serialized. This enables the reader to know the architecture without
258    /// the need of deserializing the full verifying key.
259    pub fn read_from_serialized_vk<R: io::Read>(reader: &mut R) -> io::Result<Self> {
260        // The current serialization of the verifying key places the architecture at
261        // the beginning.
262        Self::read(reader)
263    }
264}
265
266#[derive(Debug, Clone)]
267/// Configured chips for [ZkStdLib].
268pub 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    // Configuration of external libraries.
286    keccak_sha3_config: Option<PackedConfig>,
287    blake2b_config: Option<Blake2bConfig>,
288}
289
290/// The `ZkStdLib` exposes all tools that are used in circuit generation.
291#[derive(Clone, Debug)]
292#[allow(clippy::type_complexity)]
293pub struct ZkStdLib {
294    // Internal chips and gadgets.
295    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    // Third-party chips.
317    keccak_sha3_chip: Option<KeccakSha3Wrapper<F>>,
318    blake2b_chip: Option<Blake2bWrapper<F>>,
319
320    // Flags that indicate if certain chips have been used. This way we can load the tables only
321    // when necessary (thus reducing the min_k in some cases).
322    // Such a usage flag has to be added and updated correctly for each new chip using tables.
323    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    /// Creates a new [ZkStdLib] given its config.
337    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    /// Configure [ZkStdLib] from scratch.
445    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    /// Native EccChip.
709    pub fn jubjub(&self) -> &EccChip<C> {
710        self.jubjub_chip.as_ref().expect("ZkStdLibArch must enable jubjub")
711    }
712
713    /// Gadget for performing in-circuit big-unsigned integer operations.
714    pub fn biguint(&self) -> &BigUintGadget<F, NG> {
715        &self.biguint_gadget
716    }
717
718    /// Gadget for performing map and non-map checks
719    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    /// Chip for performing in-circuit operations over the Secp256k1 curve, its
726    /// scalar field or its base field.
727    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    /// Chip for performing in-circuit operations over the P256 curve, its
735    /// scalar field or its base field.
736    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    /// Chip for performing in-circuit operations over the BLS12-381 curve, its
744    /// scalar field or its base field.
745    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    /// Chip for performing in-circuit operations over Curve25519.
753    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    /// Chip for performing in-circuit base64 decoding.
761    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    /// Gadget for column-free parsing helpers (fetch_bytes, date_to_int, etc.).
769    /// Always available (no arch flag needed).
770    pub fn parser(&self) -> &ParserGadget<F, NG> {
771        &self.parser_gadget
772    }
773
774    /// Chip for various scanning functions based on lookups. This includes
775    /// automaton-based parsing ([`ScannerChip::parse`]) and substring checks
776    /// ([`ScannerChip::check_subsequence`], [`ScannerChip::check_bytes`]).
777    ///
778    /// Returns the scanner chip for automaton-based parsing and substring
779    /// checks. The static automaton table is loaded automatically when
780    /// `parse` is called with a `Static(..)` variant.
781    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    /// Chip for performing in-circuit verification of proofs
787    /// (generated with Poseidon as the Fiat-Shamir transcript hash).
788    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    /// Assert that a given assigned bit is true.
796    ///
797    /// ```
798    /// # midnight_zk_stdlib::run_test_stdlib!(chip, layouter, 13, {
799    /// let input: AssignedBit<F> = chip.assign_fixed(layouter, true)?;
800    /// chip.assert_true(layouter, &input)?;
801    /// # });
802    /// ```
803    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    /// Assert that a given assigned bit is false
812    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    /// Returns `1` iff `x < y`.
821    ///
822    /// ```
823    /// # midnight_zk_stdlib::run_test_stdlib!(chip, layouter, 13, {
824    /// let x: AssignedNative<F> = chip.assign_fixed(layouter, F::from(127))?;
825    /// let y: AssignedNative<F> = chip.assign_fixed(layouter, F::from(212))?;
826    /// let condition = chip.lower_than(layouter, &x, &y, 8)?;
827    ///
828    /// chip.assert_true(layouter, &condition)?;
829    /// # });
830    /// ```
831    ///
832    /// # Unsatisfiable Circuit
833    ///
834    /// If `x` or `y` are not in the range `[0, 2^n)`.
835    ///
836    /// ```should_panic
837    /// # midnight_zk_stdlib::run_test_stdlib!(chip, layouter, 13, {
838    /// let x: AssignedNative<F> = chip.assign_fixed(layouter, F::from(127))?;
839    /// let y: AssignedNative<F> = chip.assign_fixed(layouter, F::from(212))?;
840    /// let _condition = chip.lower_than(layouter, &x, &y, 7)?;
841    /// # });
842    /// ```
843    ///
844    /// Setting `n > (F::NUM_BITS - 1) / 2` will result in a compile-time
845    /// error.
846    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    /// Poseidon hash from a slice of native values into a native value.
859    ///
860    /// ```
861    /// # midnight_zk_stdlib::run_test_stdlib!(chip, layouter, 13, {
862    /// let x: AssignedNative<F> = chip.assign_fixed(layouter, F::from(127))?;
863    /// let y: AssignedNative<F> = chip.assign_fixed(layouter, F::from(212))?;
864    ///
865    /// let _hash = chip.poseidon(layouter, &[x, y])?;
866    /// # });
867    /// ```
868    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    /// Poseidon hash over a payload whose element count can vary between
880    /// proofs.
881    ///
882    /// Unlike [`poseidon`](Self::poseidon), which takes a plain slice whose
883    /// length is structurally fixed in the circuit (the same for every proof),
884    /// this variant takes an [`AssignedVector`]: a specialized structure for
885    /// carrying data of varying length, up to a maximum capacity of `M`
886    /// elements.
887    ///
888    /// `M` must be a multiple of 2 (the Poseidon absorption rate).
889    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    /// Hashes a slice of assigned values into `(x, y)` coordinates which are
905    /// guaranteed to be in the curve `C`. For usage, see [HashToCurveGadget].
906    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    /// SHA2-256.
918    /// Takes as input a slice of assigned bytes and returns the assigned
919    /// input/output in bytes.
920    /// We assume the field uses little endian encoding.
921    /// ```
922    /// # midnight_zk_stdlib::run_test_stdlib!(chip, layouter, 13, {
923    /// let input = chip.assign_many(
924    ///     layouter,
925    ///     &[
926    ///         Value::known(13),
927    ///         Value::known(226),
928    ///         Value::known(119),
929    ///         Value::known(5),
930    ///     ],
931    /// )?;
932    ///
933    /// let _hash = chip.sha2_256(layouter, &input)?;
934    /// # });
935    /// ```
936    pub fn sha2_256(
937        &self,
938        layouter: &mut impl Layouter<F>,
939        input: &[AssignedByte<F>], // F -> decompose_bytes -> hash
940    ) -> 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    /// SHA-256 hash over a payload whose byte count can vary between proofs.
949    ///
950    /// Unlike [`sha2_256`](Self::sha2_256), which takes a plain slice whose
951    /// length is structurally fixed in the circuit (the same for every proof),
952    /// this variant takes an [`AssignedVector`]: a specialized structure for
953    /// carrying data of varying length, up to a maximum capacity of `M` bytes.
954    ///
955    /// `M` must be a multiple of 64 (the SHA-256 block size).
956    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    /// SHA2-512 hash.
973    pub fn sha2_512(
974        &self,
975        layouter: &mut impl Layouter<F>,
976        input: &[AssignedByte<F>], // F -> decompose_bytes -> hash
977    ) -> 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    /// SHA3-256 hash (third-party implementation).
986    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    /// Keccak-256 hash (third-party implementation).
1000    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    /// Blake2b hash with a 256-bit output, unkeyed (third-party
1014    /// implementation).
1015    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    /// Blake2b hash with a 512-bit output, unkeyed (third-party
1026    /// implementation).
1027    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/// Circuit structure which is used to create any circuit that can be compiled
1452/// into keys using the ZK standard library.
1453#[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    /// A MidnightCircuit with unknown instance-witness for the given relation.
1465    /// `k` is the log2 of the circuit size (i.e. the circuit has `2^k` rows).
1466    /// If `k` is `None`, the optimal value is computed automatically.
1467    pub fn from_relation(relation: &'a R, k: Option<u32>) -> Self {
1468        MidnightCircuit::new(relation, Value::unknown(), Value::unknown(), k)
1469    }
1470
1471    /// Creates a new MidnightCircuit for the given relation.
1472    /// `k` is the log2 of the circuit size (i.e. the circuit has `2^k` rows).
1473    /// If `k` is `None`, the optimal value is computed automatically.
1474    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    /// Returns the log2 of the circuit size.
1492    pub fn k(&self) -> u32 {
1493        self.k
1494    }
1495
1496    /// Takes the circuit error stashed during synthesis, if any.
1497    pub fn take_error(&self) -> Option<R::Error> {
1498        self.circuit_error.take()
1499    }
1500}
1501
1502/// A verifier key of a Midnight circuit.
1503#[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    /// Writes a verifying key to a buffer.
1513    ///
1514    /// Depending on the `format`:
1515    /// - `Processed`: Takes less space, but more time to read.
1516    /// - `RawBytes`: Takes more space, but faster to read.
1517    ///
1518    /// Using `RawBytesUnchecked` will have the same effect as `RawBytes`,
1519    /// but it is not recommended.
1520    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    /// Reads a verification key from a buffer.
1531    ///
1532    /// The `format` must match the one that was used when writing the key.
1533    /// If the key was written with `RawBytes`, it can be read with `RawBytes`
1534    /// or `RawBytesUnchecked` (which is faster).
1535    ///
1536    /// # WARNING
1537    /// Use `RawBytesUnchecked` only if you trust the party who wrote the key.
1538    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    /// The size of the domain associated to this verifying key.
1563    pub fn k(&self) -> u8 {
1564        self.k
1565    }
1566
1567    /// The underlying midnight-proofs verifying key.
1568    pub fn vk(
1569        &self,
1570    ) -> &VerifyingKey<midnight_curves::Fq, KZGCommitmentScheme<midnight_curves::Bls12>> {
1571        &self.vk
1572    }
1573}
1574
1575/// A proving key of a Midnight circuit.
1576#[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    /// Writes a proving key to a buffer.
1585    ///
1586    /// Depending on the `format`:
1587    /// - `Processed`: Takes less space, but more time to read.
1588    /// - `RawBytes`: Takes more space, but faster to read.
1589    ///
1590    /// Using `RawBytesUnchecked` will have the same effect as `RawBytes`,
1591    /// but it is not recommended.
1592    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    /// Reads a proving key from a buffer.
1601    ///
1602    /// The `format` must match the one that was used when writing the key.
1603    /// If the key was written with `RawBytes`, it can be read with `RawBytes`
1604    /// or `RawBytesUnchecked` (which is faster).
1605    ///
1606    /// # WARNING
1607    /// Use `RawBytesUnchecked` only if you trust the party who wrote the key.
1608    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    /// The size of the domain associated to this proving key.
1632    pub fn k(&self) -> u8 {
1633        self.k
1634    }
1635
1636    /// The underlying midnight-proofs proving key.
1637    pub fn pk(
1638        &self,
1639    ) -> &ProvingKey<midnight_curves::Fq, KZGCommitmentScheme<midnight_curves::Bls12>> {
1640        &self.pk
1641    }
1642}
1643
1644/// Helper trait, used to abstract the circuit developer from Halo2's
1645/// boilerplate.
1646///
1647/// `Relation` has a default implementation for loading only the tables
1648/// needed for the requested chips. The developer needs to implement the
1649/// function [Relation::circuit], which essentially contains the
1650/// statement of the proof we are creating.
1651///
1652/// # Important note
1653///
1654/// The API provided here guarantees that the number of public inputs
1655/// used during verification matches the number of public inputs (as raw
1656/// scalars) declared in [Relation::circuit] through the
1657/// [PublicInputInstructions] interface. Proof verification will fail if
1658/// this requirement is not met.
1659///
1660/// # Example
1661///
1662/// ```
1663/// # use midnight_circuits::{
1664/// #     instructions::{AssignmentInstructions, PublicInputInstructions},
1665/// #     types::{AssignedByte, Instantiable},
1666/// # };
1667/// # use midnight_zk_stdlib::{utils::plonk_api::filecoin_srs, Relation, ZkStdLib, ZkStdLibArch};
1668/// # use midnight_proofs::{
1669/// #     circuit::{Layouter, Value},
1670/// #     plonk::Error,
1671/// # };
1672/// # use rand::{rngs::OsRng, Rng, SeedableRng};
1673/// # use rand_chacha::ChaCha8Rng;
1674/// # use sha2::Digest;
1675/// #
1676/// type F = midnight_curves::Fq;
1677///
1678/// #[derive(Clone, Default)]
1679/// struct ShaPreImageCircuit;
1680///
1681/// impl Relation for ShaPreImageCircuit {
1682///     // When defining a circuit, one must clearly state the instance and the witness
1683///     // of the underlying NP-relation.
1684///     type Instance = [u8; 32];
1685///     type Witness = [u8; 24]; // 192 = 24 * 8
1686///     type Error = Error;
1687///
1688///     // We must specify how the instance is converted into raw field elements to
1689///     // be process by the prover/verifier. The order here must be consistent with
1690///     // the order in which public inputs are constrained/assigned in [circuit].
1691///     fn format_instance(instance: &Self::Instance) -> Result<Vec<F>, Error> {
1692///         Ok(instance.iter().flat_map(AssignedByte::<F>::as_public_input).collect())
1693///     }
1694///
1695///     // Define the logic of the NP-relation being proved.
1696///     fn circuit(
1697///         &self,
1698///         std_lib: &ZkStdLib,
1699///         layouter: &mut impl Layouter<F>,
1700///         _instance: Value<Self::Instance>,
1701///         witness: Value<Self::Witness>,
1702///     ) -> Result<(), Error> {
1703///         let assigned_input = std_lib.assign_many(layouter, &witness.transpose_array())?;
1704///         let output = std_lib.sha2_256(layouter, &assigned_input)?;
1705///         output.iter().try_for_each(|b| std_lib.constrain_as_public_input(layouter, b))
1706///     }
1707///
1708///     fn used_chips(&self) -> ZkStdLibArch {
1709///         ZkStdLibArch {
1710///             sha2_256: true,
1711///             ..ZkStdLibArch::default()
1712///         }
1713///     }
1714///
1715///     fn write_relation<W: std::io::Write>(&self, _writer: &mut W) -> std::io::Result<()> {
1716///         Ok(())
1717///     }
1718///
1719///     fn read_relation<R: std::io::Read>(_reader: &mut R) -> std::io::Result<Self> {
1720///         Ok(ShaPreImageCircuit)
1721///     }
1722/// }
1723///
1724/// const K: u32 = 13;
1725/// let mut srs = filecoin_srs(K);
1726///
1727/// let relation = ShaPreImageCircuit;
1728///
1729/// let vk = midnight_zk_stdlib::setup_vk(&srs, &relation);
1730/// let pk = midnight_zk_stdlib::setup_pk(&relation, &vk);
1731///
1732/// let mut rng = ChaCha8Rng::from_entropy();
1733/// let witness: [u8; 24] = core::array::from_fn(|_| rng.gen());
1734/// let instance = sha2::Sha256::digest(witness).into();
1735///
1736/// let proof = midnight_zk_stdlib::prove::<ShaPreImageCircuit, blake2b_simd::State>(
1737///     &srs, &pk, &relation, &instance, witness, OsRng,
1738/// )
1739/// .expect("Proof generation should not fail");
1740///
1741/// assert!(
1742///     midnight_zk_stdlib::verify::<ShaPreImageCircuit, blake2b_simd::State>(
1743///         &srs.verifier_params(),
1744///         &vk,
1745///         &instance,
1746///         None,
1747///         &proof
1748///     )
1749///     .is_ok()
1750/// )
1751/// ```
1752pub trait Relation: Clone {
1753    /// The instance of the NP-relation described by this circuit.
1754    type Instance: Clone;
1755
1756    /// The witness of the NP-relation described by this circuit.
1757    type Witness: Clone;
1758
1759    /// The error type returned by [Self::circuit] and [Self::format_instance].
1760    type Error: From<plonk::Error>;
1761
1762    /// Produces a vector of field elements in PLONK format representing the
1763    /// given [Self::Instance].
1764    fn format_instance(instance: &Self::Instance) -> Result<Vec<F>, Self::Error>;
1765
1766    /// Produces a vector of field elements in PLONK format representing the
1767    /// data inside the committed instance.
1768    fn format_committed_instances(_witness: &Self::Witness) -> Vec<F> {
1769        vec![]
1770    }
1771
1772    /// Defines the circuit's logic.
1773    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    /// Specifies what chips are enabled in the standard library. A chip needs
1782    /// to be enabled if it is used in [Self::circuit], but it can also be
1783    /// enabled even if it is not used (possibly to share the same architecture
1784    /// with other circuits).
1785    ///
1786    /// The blanket implementation enables none of them.
1787    fn used_chips(&self) -> ZkStdLibArch {
1788        ZkStdLibArch::default()
1789    }
1790
1791    /// Writes a relation to a buffer.
1792    fn write_relation<W: io::Write>(&self, writer: &mut W) -> io::Result<()>;
1793
1794    /// Reads a relation from a buffer.
1795    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    // FIXME: this could be parametrised by MidnightCircuit.
1802    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        // After the circuit function has been called, we can update the expected
1846        // number of raw public inputs in [Self] (via a RefCell). This number will
1847        // be stored in the MidnightVK so that we can make sure it matches the number of
1848        // public inputs provided during verification.
1849        *self.nb_public_inputs.borrow_mut() =
1850            Some(zk_std_lib.native_gadget.native_chip.nb_public_inputs());
1851
1852        // We load the tables at the end, once we have figured out what chips/gadgets
1853        // were actually used.
1854        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
1896/// Generates a verifying key for a `MidnightCircuit<R>` circuit.
1897///
1898/// The log2 of the circuit size (`k`) is derived from the SRS parameters.
1899/// For optimal performance, downsize the SRS to the circuit's optimal `k`
1900/// beforehand (see [optimal_k]). Otherwise, the circuit will use the full
1901/// size of the SRS, which may be unnecessarily large.
1902pub 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    // During the call to [setup_vk] the circuit RefCell on public inputs has been
1911    // mutated with the correct value. The following [unwrap] is safe here.
1912    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
1922/// Generates a proving key for a `MidnightCircuit<R>` circuit.
1923pub 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
1938/// Produces a proof of relation `R` for the given instance (using the given
1939/// proving key and witness).
1940pub 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
1971/// Verifies the given proof of relation `R` with respect to the given instance.
1972/// Returns `Ok(())` if the proof is valid.
1973pub 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
1998/// Verifies a batch of proofs with respect to their corresponding vk.
1999/// This method does not need to know the `Relation` the proofs are associated
2000/// to and, indeed, it can verify proofs from different `Relation`s.
2001/// For that, this function does not take `instance`s, but public inputs
2002/// in raw format (`Vec<F>`).
2003///
2004/// Returns `Ok(())` if all proofs are valid.
2005pub 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    // TODO: For the moment, committed instances are not supported.
2018    let n = vks.len();
2019    if pis.len() != n || proofs.len() != n {
2020        // TODO: have richer types in halo2
2021        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                // TODO: We could batch here proofs with the same vk.
2042                &[&[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    // Phase 4: add scaled guards sequentially.
2065    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    // TODO: Have richer error types
2072    acc_guard.verify(params_verifier).map_err(|_| Error::Opening)
2073}
2074
2075/// Cost model of the given relation for the given `k`.
2076/// `k` is the log2 of the circuit size. If `None`, the optimal value is
2077/// computed automatically.
2078pub 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
2083/// Finds the optimal `k` (log2 of the circuit size) for the given relation.
2084/// Tries different values of `k` (9..=25) and picks the smallest one where
2085/// the circuit fits. The pow2range table uses `max_bit_len = k - 1`.
2086pub 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        // Stop when the pow2range table (2^k rows) becomes the bottleneck.
2097        if model.rows < (1 << k) {
2098            break;
2099        }
2100    }
2101
2102    best_k
2103}