1use core::hash::Hash;
2
3use crate::ff::{FromUniformBytes, PrimeField};
4#[cfg(not(feature = "halo2-axiom"))]
5use crate::halo2_proofs::arithmetic::CurveAffine;
6use crate::halo2_proofs::circuit::Value;
7#[cfg(feature = "halo2-axiom")]
8pub use crate::halo2_proofs::halo2curves::CurveAffineExt;
9
10use num_bigint::BigInt;
11use num_bigint::BigUint;
12use num_bigint::Sign;
13use num_traits::Signed;
14use num_traits::{One, Zero};
15
16pub mod halo2;
18#[cfg(any(test, feature = "test-utils"))]
19pub mod testing;
20
21#[cfg(feature = "halo2-axiom")]
23pub trait BigPrimeField: ScalarField {
24 fn from_u64_digits(val: &[u64]) -> Self;
31}
32#[cfg(feature = "halo2-axiom")]
33impl<F> BigPrimeField for F
34where
35 F: ScalarField + From<[u64; 4]>, {
37 #[inline(always)]
38 fn from_u64_digits(val: &[u64]) -> Self {
39 debug_assert!(val.len() <= 4);
40 let mut raw = [0u64; 4];
41 raw[..val.len()].copy_from_slice(val);
42 Self::from(raw)
43 }
44}
45
46pub trait ScalarField: PrimeField + FromUniformBytes<64> + From<bool> + Hash + Ord {
50 fn to_u64_limbs(self, num_limbs: usize, bit_len: usize) -> Vec<u64>;
56
57 fn to_bytes_le(&self) -> Vec<u8>;
59
60 fn from_bytes_le(bytes: &[u8]) -> Self {
65 let mut repr = Self::Repr::default();
66 repr.as_mut()[..bytes.len()].copy_from_slice(bytes);
67 Self::from_repr(repr).unwrap()
68 }
69
70 fn get_lower_32(&self) -> u32 {
72 let bytes = self.to_bytes_le();
73 let mut lower_32 = 0u32;
74 for (i, byte) in bytes.into_iter().enumerate().take(4) {
75 lower_32 |= (byte as u32) << (i * 8);
76 }
77 lower_32
78 }
79
80 fn get_lower_64(&self) -> u64 {
82 let bytes = self.to_bytes_le();
83 let mut lower_64 = 0u64;
84 for (i, byte) in bytes.into_iter().enumerate().take(8) {
85 lower_64 |= (byte as u64) << (i * 8);
86 }
87 lower_64
88 }
89}
90#[cfg(feature = "halo2-pse")]
96pub trait BigPrimeField: PrimeField<Repr = [u8; 32]> + ScalarField {}
97#[cfg(feature = "halo2-pse")]
98impl<F: PrimeField<Repr = [u8; 32]> + ScalarField> BigPrimeField for F {}
99
100#[inline(always)]
107pub(crate) fn decompose_u64_digits_to_limbs(
108 e: impl IntoIterator<Item = u64>,
109 number_of_limbs: usize,
110 bit_len: usize,
111) -> Vec<u64> {
112 debug_assert!(bit_len < 64);
113
114 let mut e = e.into_iter();
115 let mask: u64 = (1u64 << bit_len) - 1u64;
117 let mut u64_digit = e.next().unwrap_or(0);
118 let mut rem = 64;
119
120 (0..number_of_limbs)
122 .map(|_| match rem.cmp(&bit_len) {
123 core::cmp::Ordering::Greater => {
126 let limb = u64_digit & mask;
127 u64_digit >>= bit_len;
128 rem -= bit_len;
129 limb
130 }
131 core::cmp::Ordering::Equal => {
134 let limb = u64_digit & mask;
135 u64_digit = e.next().unwrap_or(0);
136 rem = 64;
137 limb
138 }
139 core::cmp::Ordering::Less => {
142 let mut limb = u64_digit;
143 u64_digit = e.next().unwrap_or(0);
144 limb |= (u64_digit & ((1u64 << (bit_len - rem)) - 1u64)) << rem;
145 u64_digit >>= bit_len - rem;
146 rem += 64 - bit_len;
147 limb
148 }
149 })
150 .collect()
151}
152
153pub const fn bit_length(x: u64) -> usize {
155 (u64::BITS - x.leading_zeros()) as usize
156}
157
158pub fn log2_ceil(x: u64) -> usize {
162 (u64::BITS - x.leading_zeros()) as usize - usize::from(x.is_power_of_two())
163}
164
165pub fn modulus<F: BigPrimeField>() -> BigUint {
167 fe_to_biguint(&-F::ONE) + 1u64
168}
169
170pub fn power_of_two<F: BigPrimeField>(n: usize) -> F {
173 biguint_to_fe(&(BigUint::one() << n))
174}
175
176pub fn biguint_to_fe<F: BigPrimeField>(e: &BigUint) -> F {
182 #[cfg(feature = "halo2-axiom")]
183 {
184 F::from_u64_digits(&e.to_u64_digits())
185 }
186
187 #[cfg(feature = "halo2-pse")]
188 {
189 let bytes = e.to_bytes_le();
190 F::from_bytes_le(&bytes)
191 }
192}
193
194pub fn bigint_to_fe<F: BigPrimeField>(e: &BigInt) -> F {
200 #[cfg(feature = "halo2-axiom")]
201 {
202 let (sign, digits) = e.to_u64_digits();
203 if sign == Sign::Minus {
204 -F::from_u64_digits(&digits)
205 } else {
206 F::from_u64_digits(&digits)
207 }
208 }
209 #[cfg(feature = "halo2-pse")]
210 {
211 let (sign, bytes) = e.to_bytes_le();
212 let f_abs = F::from_bytes_le(&bytes);
213 if sign == Sign::Minus {
214 -f_abs
215 } else {
216 f_abs
217 }
218 }
219}
220
221pub fn fe_to_biguint<F: ScalarField>(fe: &F) -> BigUint {
224 BigUint::from_bytes_le(fe.to_bytes_le().as_ref())
225}
226
227pub fn fe_to_bigint<F: BigPrimeField>(fe: &F) -> BigInt {
233 let modulus = modulus::<F>();
235 let e = fe_to_biguint(fe);
236 if e <= &modulus / 2u32 {
237 BigInt::from_biguint(Sign::Plus, e)
238 } else {
239 BigInt::from_biguint(Sign::Minus, modulus - e)
240 }
241}
242
243pub fn decompose<F: BigPrimeField>(e: &F, number_of_limbs: usize, bit_len: usize) -> Vec<F> {
250 if bit_len > 64 {
251 decompose_biguint(&fe_to_biguint(e), number_of_limbs, bit_len)
252 } else {
253 decompose_fe_to_u64_limbs(e, number_of_limbs, bit_len).into_iter().map(F::from).collect()
254 }
255}
256
257pub fn decompose_fe_to_u64_limbs<F: ScalarField>(
264 e: &F,
265 number_of_limbs: usize,
266 bit_len: usize,
267) -> Vec<u64> {
268 #[cfg(feature = "halo2-axiom")]
269 {
270 e.to_u64_limbs(number_of_limbs, bit_len)
271 }
272
273 #[cfg(feature = "halo2-pse")]
274 {
275 decompose_u64_digits_to_limbs(fe_to_biguint(e).iter_u64_digits(), number_of_limbs, bit_len)
276 }
277}
278
279pub fn decompose_biguint<F: BigPrimeField>(
288 e: &BigUint,
289 num_limbs: usize,
290 bit_len: usize,
291) -> Vec<F> {
292 debug_assert!((64..128).contains(&bit_len));
294 let mut e = e.iter_u64_digits();
295
296 let mut limb0 = e.next().unwrap_or(0) as u128;
298 let mut rem = bit_len - 64;
299 let mut u64_digit = e.next().unwrap_or(0);
300 limb0 |= ((u64_digit & ((1u64 << rem) - 1u64)) as u128) << 64u32;
302 u64_digit >>= rem;
303 rem = 64 - rem;
304
305 core::iter::once(F::from_u128(limb0))
307 .chain((1..num_limbs).map(|_| {
308 let mut limb = u64_digit as u128;
309 let mut bits = rem;
310 u64_digit = e.next().unwrap_or(0);
311 if bit_len >= 64 + bits {
312 limb |= (u64_digit as u128) << bits;
313 u64_digit = e.next().unwrap_or(0);
314 bits += 64;
315 }
316 rem = bit_len - bits;
317 limb |= ((u64_digit & ((1u64 << rem) - 1u64)) as u128) << bits;
318 u64_digit >>= rem;
319 rem = 64 - rem;
320 F::from_u128(limb)
321 }))
322 .collect()
323}
324
325pub fn decompose_bigint<F: BigPrimeField>(e: &BigInt, num_limbs: usize, bit_len: usize) -> Vec<F> {
332 if e.is_negative() {
333 decompose_biguint::<F>(e.magnitude(), num_limbs, bit_len).into_iter().map(|x| -x).collect()
334 } else {
335 decompose_biguint(e.magnitude(), num_limbs, bit_len)
336 }
337}
338
339pub fn decompose_bigint_option<F: BigPrimeField>(
346 value: Value<&BigInt>,
347 number_of_limbs: usize,
348 bit_len: usize,
349) -> Vec<Value<F>> {
350 value.map(|e| decompose_bigint(e, number_of_limbs, bit_len)).transpose_vec(number_of_limbs)
351}
352
353pub fn value_to_option<V>(value: Value<V>) -> Option<V> {
357 let mut v = None;
358 value.map(|val| {
359 v = Some(val);
360 });
361 v
362}
363
364pub fn compose(input: Vec<BigUint>, bit_len: usize) -> BigUint {
370 input.iter().rev().fold(BigUint::zero(), |acc, val| (acc << bit_len) + val)
371}
372
373#[cfg(feature = "halo2-pse")]
375pub trait CurveAffineExt: CurveAffine {
376 fn into_coordinates(self) -> (Self::Base, Self::Base) {
378 let coordinates = self.coordinates().unwrap();
379 (*coordinates.x(), *coordinates.y())
380 }
381}
382#[cfg(feature = "halo2-pse")]
383impl<C: CurveAffine> CurveAffineExt for C {}
384
385mod scalar_field_impls {
386 use super::{decompose_u64_digits_to_limbs, ScalarField};
387 #[cfg(feature = "halo2-pse")]
388 use crate::ff::PrimeField;
389 use crate::halo2_proofs::halo2curves::{
390 bn256::{Fq as bn254Fq, Fr as bn254Fr},
391 secp256k1::{Fp as secpFp, Fq as secpFq},
392 };
393
394 #[cfg(feature = "halo2-axiom")]
397 #[macro_export]
398 macro_rules! impl_scalar_field {
399 ($field:ident) => {
400 impl ScalarField for $field {
401 #[inline(always)]
402 fn to_u64_limbs(self, num_limbs: usize, bit_len: usize) -> Vec<u64> {
403 let tmp: [u64; 4] = self.into();
405 decompose_u64_digits_to_limbs(tmp, num_limbs, bit_len)
406 }
407
408 #[inline(always)]
409 fn to_bytes_le(&self) -> Vec<u8> {
410 let tmp: [u64; 4] = (*self).into();
411 tmp.iter().flat_map(|x| x.to_le_bytes()).collect()
412 }
413
414 #[inline(always)]
415 fn get_lower_32(&self) -> u32 {
416 let tmp: [u64; 4] = (*self).into();
417 tmp[0] as u32
418 }
419
420 #[inline(always)]
421 fn get_lower_64(&self) -> u64 {
422 let tmp: [u64; 4] = (*self).into();
423 tmp[0]
424 }
425 }
426 };
427 }
428
429 #[cfg(feature = "halo2-pse")]
432 #[macro_export]
433 macro_rules! impl_scalar_field {
434 ($field:ident) => {
435 impl ScalarField for $field {
436 #[inline(always)]
437 fn to_u64_limbs(self, num_limbs: usize, bit_len: usize) -> Vec<u64> {
438 let bytes = self.to_repr();
439 let digits = (0..4)
440 .map(|i| u64::from_le_bytes(bytes[i * 8..(i + 1) * 8].try_into().unwrap()));
441 decompose_u64_digits_to_limbs(digits, num_limbs, bit_len)
442 }
443
444 #[inline(always)]
445 fn to_bytes_le(&self) -> Vec<u8> {
446 self.to_repr().to_vec()
447 }
448 }
449 };
450 }
451
452 impl_scalar_field!(bn254Fr);
453 impl_scalar_field!(bn254Fq);
454 impl_scalar_field!(secpFp);
455 impl_scalar_field!(secpFq);
456}
457
458pub mod fs {
460 use std::{
461 env::var,
462 fs::{self, File},
463 io::{BufReader, BufWriter},
464 };
465
466 use crate::halo2_proofs::{
467 halo2curves::{
468 bn256::{Bn256, G1Affine},
469 CurveAffine,
470 },
471 poly::{
472 commitment::{Params, ParamsProver},
473 kzg::commitment::ParamsKZG,
474 },
475 };
476 use rand_chacha::{rand_core::SeedableRng, ChaCha20Rng};
477
478 pub fn read_params(k: u32) -> ParamsKZG<Bn256> {
481 let dir = var("PARAMS_DIR").unwrap_or_else(|_| "./params".to_string());
482 ParamsKZG::<Bn256>::read(&mut BufReader::new(
483 File::open(format!("{dir}/kzg_bn254_{k}.srs").as_str())
484 .expect("Params file does not exist"),
485 ))
486 .unwrap()
487 }
488
489 pub fn read_or_create_srs<'a, C: CurveAffine, P: ParamsProver<'a, C>>(
493 k: u32,
494 setup: impl Fn(u32) -> P,
495 ) -> P {
496 let dir = var("PARAMS_DIR").unwrap_or_else(|_| "./params".to_string());
497 let path = format!("{dir}/kzg_bn254_{k}.srs");
498 match File::open(path.as_str()) {
499 Ok(f) => {
500 #[cfg(feature = "display")]
501 println!("read params from {path}");
502 let mut reader = BufReader::new(f);
503 P::read(&mut reader).unwrap()
504 }
505 Err(_) => {
506 #[cfg(feature = "display")]
507 println!("creating params for {k}");
508 fs::create_dir_all(dir).unwrap();
509 let params = setup(k);
510 params.write(&mut BufWriter::new(File::create(path).unwrap())).unwrap();
511 params
512 }
513 }
514 }
515
516 pub fn gen_srs(k: u32) -> ParamsKZG<Bn256> {
519 read_or_create_srs::<G1Affine, _>(k, |k| {
520 ParamsKZG::<Bn256>::setup(k, ChaCha20Rng::from_seed(Default::default()))
521 })
522 }
523}
524
525#[cfg(test)]
526mod tests {
527 use crate::halo2_proofs::halo2curves::bn256::Fr;
528 use num_bigint::RandomBits;
529 use rand::{
530 rngs::{OsRng, StdRng},
531 Rng, SeedableRng,
532 };
533 use std::ops::Shl;
534
535 use super::*;
536
537 #[test]
538 fn test_signed_roundtrip() {
539 use crate::halo2_proofs::halo2curves::bn256::Fr;
540 assert_eq!(fe_to_bigint(&bigint_to_fe::<Fr>(&-BigInt::one())), -BigInt::one());
541 }
542
543 #[test]
544 fn test_decompose_biguint() {
545 let mut rng = OsRng;
546 const MAX_LIMBS: u64 = 5;
547 for bit_len in 64..128usize {
548 for num_limbs in 1..=MAX_LIMBS {
549 for _ in 0..10_000usize {
550 let mut e: BigUint = rng.sample(RandomBits::new(num_limbs * bit_len as u64));
551 let limbs = decompose_biguint::<Fr>(&e, num_limbs as usize, bit_len);
552
553 let limbs2 = {
554 let mut limbs = vec![];
555 let mask = BigUint::one().shl(bit_len) - 1usize;
556 for _ in 0..num_limbs {
557 let limb = &e & &mask;
558 let mut bytes_le = limb.to_bytes_le();
559 bytes_le.resize(32, 0u8);
560 limbs.push(Fr::from_bytes(&bytes_le.try_into().unwrap()).unwrap());
561 e >>= bit_len;
562 }
563 limbs
564 };
565 assert_eq!(limbs, limbs2);
566 }
567 }
568 }
569 }
570
571 #[test]
572 fn test_decompose_u64_digits_to_limbs() {
573 let mut rng = OsRng;
574 const MAX_LIMBS: u64 = 5;
575 for bit_len in 0..64usize {
576 for num_limbs in 1..=MAX_LIMBS {
577 for _ in 0..10_000usize {
578 let mut e: BigUint = rng.sample(RandomBits::new(num_limbs * bit_len as u64));
579 let limbs = decompose_u64_digits_to_limbs(
580 e.to_u64_digits(),
581 num_limbs as usize,
582 bit_len,
583 );
584 let limbs2 = {
585 let mut limbs = vec![];
586 let mask = BigUint::one().shl(bit_len) - 1usize;
587 for _ in 0..num_limbs {
588 let limb = &e & &mask;
589 limbs.push(u64::try_from(limb).unwrap());
590 e >>= bit_len;
591 }
592 limbs
593 };
594 assert_eq!(limbs, limbs2);
595 }
596 }
597 }
598 }
599
600 #[test]
601 fn test_log2_ceil_zero() {
602 assert_eq!(log2_ceil(0), 0);
603 }
604
605 #[test]
606 fn test_get_lower_32() {
607 let mut rng = StdRng::seed_from_u64(0);
608 for _ in 0..10_000usize {
609 let e: u32 = rng.gen_range(0..u32::MAX);
610 assert_eq!(Fr::from(e as u64).get_lower_32(), e);
611 }
612 assert_eq!(Fr::from((1u64 << 32_i32) + 1).get_lower_32(), 1);
613 }
614
615 #[test]
616 fn test_get_lower_64() {
617 let mut rng = StdRng::seed_from_u64(0);
618 for _ in 0..10_000usize {
619 let e: u64 = rng.gen_range(0..u64::MAX);
620 assert_eq!(Fr::from(e).get_lower_64(), e);
621 }
622 }
623}