midnight_circuits/field/foreign/params.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//! Foreign-field arithmetic parameters for different emulation scenarios.
15//!
16//! All the emulation parameters from this file were generated using
17//! [scripts/foreign_params_gen.py].
18
19use std::{fmt::Debug, ops::Rem};
20
21#[cfg(feature = "dev-curves")]
22use midnight_curves::bn256;
23use midnight_curves::{k256, p256};
24use num_bigint::{BigInt, BigInt as BI, ToBigInt};
25use num_traits::{One, Signed};
26
27use crate::{ecc::curves::CircuitCurve, CircuitField};
28
29/// Trait for configuring a (foreign) FieldChip. These parameters need to be
30/// manually optimized for each emulation of field K over native field F.
31/// These parameters were generated with our script:
32/// `scripts/foreign_params_gen.py`.
33pub trait FieldEmulationParams<F: CircuitField, K: CircuitField>:
34 Default + Clone + Debug + PartialEq + Eq
35{
36 /// The logarithm in base 2 (bit length) of the base in which we represent
37 /// integers modulo the emulated modulus.
38 /// The actual base is 2 powered to this constant.
39 const LOG2_BASE: u32;
40
41 /// The number of limbs used to represent a emulated field element.
42 /// It must hold base^NB_LIMBS >= emulated_modulus.
43 const NB_LIMBS: u32;
44
45 /// Vector of powers of the base, used for the foreign-field identities.
46 /// The i-th element must be congruent to base^i modulo the emulated
47 /// modulus.
48 fn base_powers() -> Vec<BI> {
49 let two = BI::from(2);
50 let m = &K::modulus().to_bigint().unwrap();
51 (0..Self::NB_LIMBS)
52 .map(|i| two.pow(Self::LOG2_BASE * i).rem(m))
53 .collect::<Vec<_>>()
54 }
55
56 /// Vector of powers of the base, used for the foreign-field identities.
57 /// The (i * nb_limbs + j)-th element must be congruent to base^(i+j) modulo
58 /// the emulated modulus.
59 fn double_base_powers() -> Vec<BI> {
60 let two = BI::from(2);
61 let m = &K::modulus().to_bigint().unwrap();
62 (0..Self::NB_LIMBS)
63 .flat_map(|i| {
64 (0..Self::NB_LIMBS)
65 .map(|j| two.pow(Self::LOG2_BASE * (i + j)).rem(m))
66 .collect::<Vec<_>>()
67 })
68 .collect::<Vec<_>>()
69 }
70
71 /// Auxiliary moduli used in the identities. They should be as large as
72 /// possible, to maximize their contribution to the lcm bound.
73 /// On the other hand, they cannot be excessively large, in order to
74 /// guarantee no wrap-around (modulo the native modulus) in the equations.
75 fn moduli() -> Vec<BI>;
76
77 /// A bound on the maximum size of the absolute value of limb bounds for
78 /// non-well-formed emulated field elements. If such bound is exceeded, the
79 /// normalization function can no longer be applied.
80 /// We set this value to be base^2 by default. This value is guaranteed to
81 /// be supported with the same moduli as those used for the multiplication
82 /// gate. Another good choice for this value would be the largest possible
83 /// value that allows us to implement the normalization gate with only
84 /// one extra auxiliary modulus.
85 fn max_limb_bound() -> BI {
86 BI::from(2).pow(2 * Self::LOG2_BASE)
87 }
88
89 /// Log2 of the limb size of range-checks. This value is different and
90 /// independent of base, the size of ModArith limbs.
91 const RC_LIMB_SIZE: u32;
92}
93
94/// Sanity checks on the parameters for the FieldChip to be sound.
95pub(crate) fn check_params<F, K, P>()
96where
97 F: CircuitField,
98 K: CircuitField,
99 P: FieldEmulationParams<F, K>,
100{
101 let m = &K::modulus().to_bigint().unwrap();
102 let base = BI::from(2).pow(P::LOG2_BASE);
103 let nb_limbs = P::NB_LIMBS;
104
105 // The integer represented by limbs [x0, ..., x_{n-1}] is 1 + sum_i base^i xi
106
107 assert!(*m > BI::one());
108 assert!(base > BI::one());
109
110 // Assert that we can encode any integer in [Z_m] with [nb_limbs] limbs of size
111 // [base].
112 assert!(BI::pow(&base, nb_limbs) >= *m);
113
114 let base_powers = P::base_powers();
115 let double_base_powers = P::double_base_powers();
116
117 assert_eq!(base_powers.len(), nb_limbs as usize);
118 assert_eq!(double_base_powers.len(), (nb_limbs * nb_limbs) as usize);
119
120 let expected_powers = (0..nb_limbs).map(|i| BI::pow(&base, i).rem(m));
121 let expected_double_powers = (0..nb_limbs)
122 .flat_map(|i| (0..nb_limbs).map(|j| BI::pow(&base, i + j).rem(m)).collect::<Vec<_>>());
123
124 // Check that the powers in ModAP are congruent to the expected powers modulo m.
125 base_powers
126 .iter()
127 .chain(double_base_powers.iter())
128 .zip(expected_powers.chain(expected_double_powers))
129 .for_each(|(b, e)| {
130 // The assertion on the base powers being negative can be removed if we
131 // generalize the way upper-bounds are computed. ATM they are simply computed by
132 // considering the integer represented with all limbs set to (base-1).
133 assert!(!BI::is_negative(b));
134 assert_eq!(b.rem(m), e.rem(m))
135 });
136}
137
138/// MultiEmulationParams.
139#[derive(Clone, Default, Debug, PartialEq, Eq)]
140pub struct MultiEmulationParams {}
141
142/// Implement FieldEmulationParams for any curve that can emulate itself through
143/// MultiEmulationParams.
144impl<C: CircuitCurve + Default> FieldEmulationParams<C::ScalarField, C::Base> for C
145where
146 MultiEmulationParams: FieldEmulationParams<C::ScalarField, C::Base>,
147{
148 const LOG2_BASE: u32 = MultiEmulationParams::LOG2_BASE;
149
150 const NB_LIMBS: u32 = MultiEmulationParams::NB_LIMBS;
151
152 fn moduli() -> Vec<BigInt> {
153 MultiEmulationParams::moduli()
154 }
155
156 const RC_LIMB_SIZE: u32 = MultiEmulationParams::RC_LIMB_SIZE;
157}
158
159/*
160====================================================
161Emulated: Secp256k1's Base field
162
163Native fields supported:
164 - BN254's Scalar field
165 - BLS12-381's Scalar field
166====================================================
167*/
168
169/// Secp256k1's Base field over BN254's Scalar field.
170#[cfg(feature = "dev-curves")]
171impl FieldEmulationParams<bn256::Fr, k256::Fp> for MultiEmulationParams {
172 const LOG2_BASE: u32 = 64;
173 const NB_LIMBS: u32 = 4;
174 fn moduli() -> Vec<BigInt> {
175 vec![BigInt::from(2).pow(128)]
176 }
177 const RC_LIMB_SIZE: u32 = 16;
178}
179
180/// Secp256k1's Base field over BLS12-381's Scalar field.
181impl FieldEmulationParams<midnight_curves::Fq, k256::Fp> for MultiEmulationParams {
182 const LOG2_BASE: u32 = 64;
183 const NB_LIMBS: u32 = 4;
184 fn moduli() -> Vec<BigInt> {
185 vec![BigInt::from(2).pow(128)]
186 }
187 const RC_LIMB_SIZE: u32 = 16;
188}
189
190/*
191====================================================
192Emulated: Secp256k1's Scalar field
193
194Native fields supported:
195 - BN254's Scalar field
196 - BLS12-381's Scalar field
197====================================================
198*/
199
200/// Secp256k1's Scalar field over BN254's Scalar field.
201#[cfg(feature = "dev-curves")]
202impl FieldEmulationParams<bn256::Fr, k256::Fq> for MultiEmulationParams {
203 const LOG2_BASE: u32 = 52;
204 const NB_LIMBS: u32 = 5;
205 fn moduli() -> Vec<BigInt> {
206 vec![BigInt::from(2).pow(141)]
207 }
208 const RC_LIMB_SIZE: u32 = 14;
209}
210
211/// Secp256k1's Scalar field over BLS12-381's Scalar field.
212impl FieldEmulationParams<midnight_curves::Fq, k256::Fq> for MultiEmulationParams {
213 const LOG2_BASE: u32 = 64;
214 const NB_LIMBS: u32 = 4;
215 fn moduli() -> Vec<BigInt> {
216 vec![
217 BigInt::from(2).pow(118),
218 BigInt::from(2).pow(118) - BigInt::one(),
219 ]
220 }
221 const RC_LIMB_SIZE: u32 = 17;
222}
223
224/*
225====================================================
226Emulated: Secp256r1's Base field
227
228Native fields supported:
229 - BLS12-381's Scalar field
230====================================================
231*/
232
233/// Secp256r1's Base field over BLS12-381's Scalar field.
234impl FieldEmulationParams<midnight_curves::Fq, p256::Fp> for MultiEmulationParams {
235 const LOG2_BASE: u32 = 64;
236 const NB_LIMBS: u32 = 4;
237 fn moduli() -> Vec<BigInt> {
238 vec![
239 BigInt::from(2).pow(122),
240 BigInt::from(2).pow(122) - BigInt::from(507376),
241 ]
242 }
243 const RC_LIMB_SIZE: u32 = 17;
244}
245
246/*
247====================================================
248Emulated: Secp256r1's Scalar field
249
250Native fields supported:
251 - BLS12-381's Scalar field
252====================================================
253*/
254
255/// Secp256r1's Scalar field over BLS12-381's Scalar field.
256impl FieldEmulationParams<midnight_curves::Fq, p256::Fq> for MultiEmulationParams {
257 const LOG2_BASE: u32 = 64;
258 const NB_LIMBS: u32 = 4;
259 fn moduli() -> Vec<BigInt> {
260 vec![
261 BigInt::from(2).pow(118),
262 BigInt::from(2).pow(118) - BigInt::one(),
263 ]
264 }
265 const RC_LIMB_SIZE: u32 = 17;
266}
267
268/*
269====================================================
270Emulated: BLS12-381's Base field
271
272Native fields supported:
273 - BLS12-381's Scalar field
274====================================================
275*/
276
277/// BLS12-381's Base field over BLS12-381's Scalar field.
278impl FieldEmulationParams<midnight_curves::Fq, midnight_curves::Fp> for MultiEmulationParams {
279 const LOG2_BASE: u32 = 56;
280 const NB_LIMBS: u32 = 7;
281 fn moduli() -> Vec<BigInt> {
282 vec![
283 BigInt::from(2).pow(134),
284 BigInt::from(2).pow(134) - BigInt::from(1),
285 ]
286 }
287 const RC_LIMB_SIZE: u32 = 15;
288}
289
290/*
291====================================================
292Emulated: BN254's Base field
293
294Native fields supported:
295 - BLS12-381's Scalar field
296 - BN254's Scalar field
297====================================================
298*/
299
300/// BN254's Base field over BLS12-381's Scalar field.
301#[cfg(feature = "dev-curves")]
302impl FieldEmulationParams<midnight_curves::Fq, bn256::Fq> for MultiEmulationParams {
303 const LOG2_BASE: u32 = 52;
304 const NB_LIMBS: u32 = 5;
305 fn moduli() -> Vec<BigInt> {
306 vec![BigInt::from(2).pow(142)]
307 }
308 const RC_LIMB_SIZE: u32 = 14;
309}
310
311/// BN254's Base field over BN254's Scalar field.
312#[cfg(feature = "dev-curves")]
313impl FieldEmulationParams<bn256::Fr, bn256::Fq> for MultiEmulationParams {
314 const LOG2_BASE: u32 = 52;
315 const NB_LIMBS: u32 = 5;
316 fn moduli() -> Vec<BigInt> {
317 vec![BigInt::from(2).pow(141)]
318 }
319 const RC_LIMB_SIZE: u32 = 14;
320}
321
322/*
323====================================================
324Emulated: BLS12-381's Scalar field
325
326Native fields supported:
327 - BLS12-381's Scalar field (for tests only)
328====================================================
329*/
330
331/// BLS12-381's Scalar field over BLS12-381's Scalar field.
332impl FieldEmulationParams<midnight_curves::Fq, midnight_curves::Fq> for MultiEmulationParams {
333 const LOG2_BASE: u32 = 52;
334 const NB_LIMBS: u32 = 5;
335 fn moduli() -> Vec<BigInt> {
336 vec![BigInt::from(2).pow(142)]
337 }
338 const RC_LIMB_SIZE: u32 = 14;
339}
340
341/*
342====================================================
343Emulated: Curve25519's Base field
344
345Native fields supported:
346 - BLS12-381's Scalar field
347====================================================
348*/
349
350/// Curve25519's Base field over BLS12-381's Scalar field.
351impl FieldEmulationParams<midnight_curves::Fq, midnight_curves::curve25519::Fp>
352 for MultiEmulationParams
353{
354 const LOG2_BASE: u32 = 64;
355 const NB_LIMBS: u32 = 4;
356 fn moduli() -> Vec<BigInt> {
357 vec![BigInt::from(2).pow(128)]
358 }
359 const RC_LIMB_SIZE: u32 = 16;
360}
361
362/*
363====================================================
364Emulated: Curve25519's Scalar field
365
366Native fields supported:
367 - BLS12-381's Scalar field
368====================================================
369*/
370
371/// Curve25519's Scalar field over BLS12-381's Scalar field.
372impl FieldEmulationParams<midnight_curves::Fq, midnight_curves::curve25519::Scalar>
373 for MultiEmulationParams
374{
375 const LOG2_BASE: u32 = 51;
376 const NB_LIMBS: u32 = 5;
377 fn moduli() -> Vec<BigInt> {
378 vec![BigInt::from(2).pow(146)]
379 }
380 const RC_LIMB_SIZE: u32 = 17;
381}