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
98#[inline(always)]
105pub(crate) fn decompose_u64_digits_to_limbs(
106 e: impl IntoIterator<Item = u64>,
107 number_of_limbs: usize,
108 bit_len: usize,
109) -> Vec<u64> {
110 debug_assert!(bit_len < 64);
111
112 let mut e = e.into_iter();
113 let mask: u64 = (1u64 << bit_len) - 1u64;
115 let mut u64_digit = e.next().unwrap_or(0);
116 let mut rem = 64;
117
118 (0..number_of_limbs)
120 .map(|_| match rem.cmp(&bit_len) {
121 core::cmp::Ordering::Greater => {
124 let limb = u64_digit & mask;
125 u64_digit >>= bit_len;
126 rem -= bit_len;
127 limb
128 }
129 core::cmp::Ordering::Equal => {
132 let limb = u64_digit & mask;
133 u64_digit = e.next().unwrap_or(0);
134 rem = 64;
135 limb
136 }
137 core::cmp::Ordering::Less => {
140 let mut limb = u64_digit;
141 u64_digit = e.next().unwrap_or(0);
142 limb |= (u64_digit & ((1u64 << (bit_len - rem)) - 1u64)) << rem;
143 u64_digit >>= bit_len - rem;
144 rem += 64 - bit_len;
145 limb
146 }
147 })
148 .collect()
149}
150
151pub const fn bit_length(x: u64) -> usize {
153 (u64::BITS - x.leading_zeros()) as usize
154}
155
156pub fn log2_ceil(x: u64) -> usize {
160 (u64::BITS - x.leading_zeros()) as usize - usize::from(x.is_power_of_two())
161}
162
163pub fn modulus<F: BigPrimeField>() -> BigUint {
165 fe_to_biguint(&-F::ONE) + 1u64
166}
167
168pub fn power_of_two<F: BigPrimeField>(n: usize) -> F {
171 biguint_to_fe(&(BigUint::one() << n))
172}
173
174pub fn biguint_to_fe<F: BigPrimeField>(e: &BigUint) -> F {
180 #[cfg(feature = "halo2-axiom")]
181 {
182 F::from_u64_digits(&e.to_u64_digits())
183 }
184
185 #[cfg(feature = "halo2-pse")]
186 {
187 let bytes = e.to_bytes_le();
188 F::from_bytes_le(&bytes)
189 }
190}
191
192pub fn bigint_to_fe<F: BigPrimeField>(e: &BigInt) -> F {
198 #[cfg(feature = "halo2-axiom")]
199 {
200 let (sign, digits) = e.to_u64_digits();
201 if sign == Sign::Minus {
202 -F::from_u64_digits(&digits)
203 } else {
204 F::from_u64_digits(&digits)
205 }
206 }
207 #[cfg(feature = "halo2-pse")]
208 {
209 let (sign, bytes) = e.to_bytes_le();
210 let f_abs = F::from_bytes_le(&bytes);
211 if sign == Sign::Minus {
212 -f_abs
213 } else {
214 f_abs
215 }
216 }
217}
218
219pub fn fe_to_biguint<F: ScalarField>(fe: &F) -> BigUint {
222 BigUint::from_bytes_le(fe.to_bytes_le().as_ref())
223}
224
225pub fn fe_to_bigint<F: BigPrimeField>(fe: &F) -> BigInt {
231 let modulus = modulus::<F>();
233 let e = fe_to_biguint(fe);
234 if e <= &modulus / 2u32 {
235 BigInt::from_biguint(Sign::Plus, e)
236 } else {
237 BigInt::from_biguint(Sign::Minus, modulus - e)
238 }
239}
240
241pub fn decompose<F: BigPrimeField>(e: &F, number_of_limbs: usize, bit_len: usize) -> Vec<F> {
248 if bit_len > 64 {
249 decompose_biguint(&fe_to_biguint(e), number_of_limbs, bit_len)
250 } else {
251 decompose_fe_to_u64_limbs(e, number_of_limbs, bit_len).into_iter().map(F::from).collect()
252 }
253}
254
255pub fn decompose_fe_to_u64_limbs<F: ScalarField>(
262 e: &F,
263 number_of_limbs: usize,
264 bit_len: usize,
265) -> Vec<u64> {
266 #[cfg(feature = "halo2-axiom")]
267 {
268 e.to_u64_limbs(number_of_limbs, bit_len)
269 }
270
271 #[cfg(feature = "halo2-pse")]
272 {
273 decompose_u64_digits_to_limbs(fe_to_biguint(e).iter_u64_digits(), number_of_limbs, bit_len)
274 }
275}
276
277pub fn decompose_biguint<F: BigPrimeField>(
286 e: &BigUint,
287 num_limbs: usize,
288 bit_len: usize,
289) -> Vec<F> {
290 debug_assert!((64..128).contains(&bit_len));
292 let mut e = e.iter_u64_digits();
293
294 let mut limb0 = e.next().unwrap_or(0) as u128;
296 let mut rem = bit_len - 64;
297 let mut u64_digit = e.next().unwrap_or(0);
298 limb0 |= ((u64_digit & ((1u64 << rem) - 1u64)) as u128) << 64u32;
300 u64_digit >>= rem;
301 rem = 64 - rem;
302
303 core::iter::once(F::from_u128(limb0))
305 .chain((1..num_limbs).map(|_| {
306 let mut limb = u64_digit as u128;
307 let mut bits = rem;
308 u64_digit = e.next().unwrap_or(0);
309 if bit_len >= 64 + bits {
310 limb |= (u64_digit as u128) << bits;
311 u64_digit = e.next().unwrap_or(0);
312 bits += 64;
313 }
314 rem = bit_len - bits;
315 limb |= ((u64_digit & ((1u64 << rem) - 1u64)) as u128) << bits;
316 u64_digit >>= rem;
317 rem = 64 - rem;
318 F::from_u128(limb)
319 }))
320 .collect()
321}
322
323pub fn decompose_bigint<F: BigPrimeField>(e: &BigInt, num_limbs: usize, bit_len: usize) -> Vec<F> {
330 if e.is_negative() {
331 decompose_biguint::<F>(e.magnitude(), num_limbs, bit_len).into_iter().map(|x| -x).collect()
332 } else {
333 decompose_biguint(e.magnitude(), num_limbs, bit_len)
334 }
335}
336
337pub fn decompose_bigint_option<F: BigPrimeField>(
344 value: Value<&BigInt>,
345 number_of_limbs: usize,
346 bit_len: usize,
347) -> Vec<Value<F>> {
348 value.map(|e| decompose_bigint(e, number_of_limbs, bit_len)).transpose_vec(number_of_limbs)
349}
350
351pub fn value_to_option<V>(value: Value<V>) -> Option<V> {
355 let mut v = None;
356 value.map(|val| {
357 v = Some(val);
358 });
359 v
360}
361
362pub fn compose(input: Vec<BigUint>, bit_len: usize) -> BigUint {
368 input.iter().rev().fold(BigUint::zero(), |acc, val| (acc << bit_len) + val)
369}
370
371#[cfg(feature = "halo2-pse")]
373pub trait CurveAffineExt: CurveAffine {
374 fn into_coordinates(self) -> (Self::Base, Self::Base) {
376 let coordinates = self.coordinates().unwrap();
377 (*coordinates.x(), *coordinates.y())
378 }
379}
380#[cfg(feature = "halo2-pse")]
381impl<C: CurveAffine> CurveAffineExt for C {}
382
383mod scalar_field_impls {
384 use super::{decompose_u64_digits_to_limbs, ScalarField};
385 #[cfg(feature = "halo2-pse")]
386 use crate::ff::PrimeField;
387 use crate::halo2_proofs::halo2curves::{
388 bn256::{Fq as bn254Fq, Fr as bn254Fr},
389 secp256k1::{Fp as secpFp, Fq as secpFq},
390 };
391
392 #[cfg(feature = "halo2-axiom")]
395 #[macro_export]
396 macro_rules! impl_scalar_field {
397 ($field:ident) => {
398 impl ScalarField for $field {
399 #[inline(always)]
400 fn to_u64_limbs(self, num_limbs: usize, bit_len: usize) -> Vec<u64> {
401 let tmp: [u64; 4] = self.into();
403 decompose_u64_digits_to_limbs(tmp, num_limbs, bit_len)
404 }
405
406 #[inline(always)]
407 fn to_bytes_le(&self) -> Vec<u8> {
408 let tmp: [u64; 4] = (*self).into();
409 tmp.iter().flat_map(|x| x.to_le_bytes()).collect()
410 }
411
412 #[inline(always)]
413 fn get_lower_32(&self) -> u32 {
414 let tmp: [u64; 4] = (*self).into();
415 tmp[0] as u32
416 }
417
418 #[inline(always)]
419 fn get_lower_64(&self) -> u64 {
420 let tmp: [u64; 4] = (*self).into();
421 tmp[0]
422 }
423 }
424 };
425 }
426
427 #[cfg(feature = "halo2-pse")]
430 #[macro_export]
431 macro_rules! impl_scalar_field {
432 ($field:ident) => {
433 impl ScalarField for $field {
434 #[inline(always)]
435 fn to_u64_limbs(self, num_limbs: usize, bit_len: usize) -> Vec<u64> {
436 let bytes = self.to_repr();
437 let digits = (0..4)
438 .map(|i| u64::from_le_bytes(bytes[i * 8..(i + 1) * 8].try_into().unwrap()));
439 decompose_u64_digits_to_limbs(digits, num_limbs, bit_len)
440 }
441
442 #[inline(always)]
443 fn to_bytes_le(&self) -> Vec<u8> {
444 self.to_repr().to_vec()
445 }
446 }
447 };
448 }
449
450 impl_scalar_field!(bn254Fr);
451 impl_scalar_field!(bn254Fq);
452 impl_scalar_field!(secpFp);
453 impl_scalar_field!(secpFq);
454}
455
456pub mod fs {
458 use std::{
459 env::var,
460 fs::{self, File},
461 io::{BufReader, BufWriter},
462 };
463
464 use crate::halo2_proofs::{
465 halo2curves::{
466 bn256::{Bn256, G1Affine},
467 CurveAffine,
468 },
469 poly::{
470 commitment::{Params, ParamsProver},
471 kzg::commitment::ParamsKZG,
472 },
473 };
474 use rand_chacha::{rand_core::SeedableRng, ChaCha20Rng};
475
476 pub fn read_params(k: u32) -> ParamsKZG<Bn256> {
479 let dir = var("PARAMS_DIR").unwrap_or_else(|_| "./params".to_string());
480 ParamsKZG::<Bn256>::read(&mut BufReader::new(
481 File::open(format!("{dir}/kzg_bn254_{k}.srs").as_str())
482 .expect("Params file does not exist"),
483 ))
484 .unwrap()
485 }
486
487 pub fn read_or_create_srs<'a, C: CurveAffine, P: ParamsProver<'a, C>>(
491 k: u32,
492 setup: impl Fn(u32) -> P,
493 ) -> P {
494 let dir = var("PARAMS_DIR").unwrap_or_else(|_| "./params".to_string());
495 let path = format!("{dir}/kzg_bn254_{k}.srs");
496 match File::open(path.as_str()) {
497 Ok(f) => {
498 #[cfg(feature = "display")]
499 println!("read params from {path}");
500 let mut reader = BufReader::new(f);
501 P::read(&mut reader).unwrap()
502 }
503 Err(_) => {
504 #[cfg(feature = "display")]
505 println!("creating params for {k}");
506 fs::create_dir_all(dir).unwrap();
507 let params = setup(k);
508 params.write(&mut BufWriter::new(File::create(path).unwrap())).unwrap();
509 params
510 }
511 }
512 }
513
514 pub fn gen_srs(k: u32) -> ParamsKZG<Bn256> {
517 read_or_create_srs::<G1Affine, _>(k, |k| {
518 ParamsKZG::<Bn256>::setup(k, ChaCha20Rng::from_seed(Default::default()))
519 })
520 }
521}
522
523#[cfg(test)]
524mod tests {
525 use crate::halo2_proofs::halo2curves::bn256::Fr;
526 use num_bigint::RandomBits;
527 use rand::{
528 rngs::{OsRng, StdRng},
529 Rng, SeedableRng,
530 };
531 use std::ops::Shl;
532
533 use super::*;
534
535 #[test]
536 fn test_signed_roundtrip() {
537 use crate::halo2_proofs::halo2curves::bn256::Fr;
538 assert_eq!(fe_to_bigint(&bigint_to_fe::<Fr>(&-BigInt::one())), -BigInt::one());
539 }
540
541 #[test]
542 fn test_decompose_biguint() {
543 let mut rng = OsRng;
544 const MAX_LIMBS: u64 = 5;
545 for bit_len in 64..128usize {
546 for num_limbs in 1..=MAX_LIMBS {
547 for _ in 0..10_000usize {
548 let mut e: BigUint = rng.sample(RandomBits::new(num_limbs * bit_len as u64));
549 let limbs = decompose_biguint::<Fr>(&e, num_limbs as usize, bit_len);
550
551 let limbs2 = {
552 let mut limbs = vec![];
553 let mask = BigUint::one().shl(bit_len) - 1usize;
554 for _ in 0..num_limbs {
555 let limb = &e & &mask;
556 let mut bytes_le = limb.to_bytes_le();
557 bytes_le.resize(32, 0u8);
558 limbs.push(Fr::from_bytes(&bytes_le.try_into().unwrap()).unwrap());
559 e >>= bit_len;
560 }
561 limbs
562 };
563 assert_eq!(limbs, limbs2);
564 }
565 }
566 }
567 }
568
569 #[test]
570 fn test_decompose_u64_digits_to_limbs() {
571 let mut rng = OsRng;
572 const MAX_LIMBS: u64 = 5;
573 for bit_len in 0..64usize {
574 for num_limbs in 1..=MAX_LIMBS {
575 for _ in 0..10_000usize {
576 let mut e: BigUint = rng.sample(RandomBits::new(num_limbs * bit_len as u64));
577 let limbs = decompose_u64_digits_to_limbs(
578 e.to_u64_digits(),
579 num_limbs as usize,
580 bit_len,
581 );
582 let limbs2 = {
583 let mut limbs = vec![];
584 let mask = BigUint::one().shl(bit_len) - 1usize;
585 for _ in 0..num_limbs {
586 let limb = &e & &mask;
587 limbs.push(u64::try_from(limb).unwrap());
588 e >>= bit_len;
589 }
590 limbs
591 };
592 assert_eq!(limbs, limbs2);
593 }
594 }
595 }
596 }
597
598 #[test]
599 fn test_log2_ceil_zero() {
600 assert_eq!(log2_ceil(0), 0);
601 }
602
603 #[test]
604 fn test_get_lower_32() {
605 let mut rng = StdRng::seed_from_u64(0);
606 for _ in 0..10_000usize {
607 let e: u32 = rng.gen_range(0..u32::MAX);
608 assert_eq!(Fr::from(e as u64).get_lower_32(), e);
609 }
610 assert_eq!(Fr::from((1u64 << 32_i32) + 1).get_lower_32(), 1);
611 }
612
613 #[test]
614 fn test_get_lower_64() {
615 let mut rng = StdRng::seed_from_u64(0);
616 for _ in 0..10_000usize {
617 let e: u64 = rng.gen_range(0..u64::MAX);
618 assert_eq!(Fr::from(e).get_lower_64(), e);
619 }
620 }
621}