Skip to content
This repository was archived by the owner on Dec 8, 2025. It is now read-only.

Commit f42a8ec

Browse files
committed
Add new field implementation: 32x9 to be used in webnode
o1-labs/proof-systems#2638
1 parent 33a1de2 commit f42a8ec

File tree

18 files changed

+1662
-105
lines changed

18 files changed

+1662
-105
lines changed

ec/src/models/bw6/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ use crate::{
22
models::{ModelParameters, SWModelParameters},
33
PairingEngine,
44
};
5-
use ark_ff::fields::{
5+
use ark_ff::{fields::{
66
fp3::Fp3Parameters,
77
fp6_2over3::{Fp6, Fp6Parameters},
88
BitIteratorBE, Field, PrimeField, SquareRootField,
9-
};
9+
}, BigInteger};
1010
use num_traits::One;
1111

1212
use core::marker::PhantomData;
@@ -68,7 +68,7 @@ impl<P: BW6Parameters> BW6<P> {
6868
}
6969

7070
fn exp_by_x(mut f: Fp6<P::Fp6Params>) -> Fp6<P::Fp6Params> {
71-
f = f.cyclotomic_exp(&P::X);
71+
f = f.cyclotomic_exp(&P::X.to_64x4());
7272
if P::X_IS_NEGATIVE {
7373
f.conjugate();
7474
}

ec/src/models/mnt4/mod.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use ark_ff::BigInteger;
2+
13
use {
24
crate::{
35
models::{ModelParameters, SWModelParameters},
@@ -179,11 +181,11 @@ impl<P: MNT4Parameters> MNT4<P> {
179181
let mut elt_q = *elt;
180182
elt_q.frobenius_map(1);
181183

182-
let w1_part = elt_q.cyclotomic_exp(&P::FINAL_EXPONENT_LAST_CHUNK_1);
184+
let w1_part = elt_q.cyclotomic_exp(&P::FINAL_EXPONENT_LAST_CHUNK_1.to_64x4());
183185
let w0_part = if P::FINAL_EXPONENT_LAST_CHUNK_W0_IS_NEG {
184-
elt_inv_clone.cyclotomic_exp(&P::FINAL_EXPONENT_LAST_CHUNK_ABS_OF_W0)
186+
elt_inv_clone.cyclotomic_exp(&P::FINAL_EXPONENT_LAST_CHUNK_ABS_OF_W0.to_64x4())
185187
} else {
186-
elt_clone.cyclotomic_exp(&P::FINAL_EXPONENT_LAST_CHUNK_ABS_OF_W0)
188+
elt_clone.cyclotomic_exp(&P::FINAL_EXPONENT_LAST_CHUNK_ABS_OF_W0.to_64x4())
187189
};
188190

189191
w1_part * &w0_part

ec/src/models/mnt6/mod.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use ark_ff::BigInteger;
2+
13
use {
24
crate::{
35
models::{ModelParameters, SWModelParameters},
@@ -185,11 +187,11 @@ impl<P: MNT6Parameters> MNT6<P> {
185187
let mut elt_q = *elt;
186188
elt_q.frobenius_map(1);
187189

188-
let w1_part = elt_q.cyclotomic_exp(&P::FINAL_EXPONENT_LAST_CHUNK_1);
190+
let w1_part = elt_q.cyclotomic_exp(&P::FINAL_EXPONENT_LAST_CHUNK_1.to_64x4());
189191
let w0_part = if P::FINAL_EXPONENT_LAST_CHUNK_W0_IS_NEG {
190-
elt_inv_clone.cyclotomic_exp(&P::FINAL_EXPONENT_LAST_CHUNK_ABS_OF_W0)
192+
elt_inv_clone.cyclotomic_exp(&P::FINAL_EXPONENT_LAST_CHUNK_ABS_OF_W0.to_64x4())
191193
} else {
192-
elt_clone.cyclotomic_exp(&P::FINAL_EXPONENT_LAST_CHUNK_ABS_OF_W0)
194+
elt_clone.cyclotomic_exp(&P::FINAL_EXPONENT_LAST_CHUNK_ABS_OF_W0.to_64x4())
193195
};
194196

195197
w1_part * &w0_part

ec/src/models/short_weierstrass_jacobian.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,7 @@ use ark_std::{
1111
};
1212

1313
use ark_ff::{
14-
bytes::{FromBytes, ToBytes},
15-
fields::{BitIteratorBE, Field, PrimeField, SquareRootField},
16-
ToConstraintField, UniformRand,
14+
bytes::{FromBytes, ToBytes}, fields::{BitIteratorBE, Field, PrimeField, SquareRootField}, BigInteger, ToConstraintField, UniformRand
1715
};
1816

1917
use crate::{models::SWModelParameters as Parameters, AffineCurve, ProjectiveCurve};
@@ -223,7 +221,8 @@ impl<P: Parameters> AffineCurve for GroupAffine<P> {
223221

224222
#[inline]
225223
fn mul<S: Into<<Self::ScalarField as PrimeField>::BigInt>>(&self, by: S) -> GroupProjective<P> {
226-
let bits = BitIteratorBE::new(by.into());
224+
let inner: <Self::ScalarField as PrimeField>::BigInt = by.into();
225+
let bits = ark_ff::BitIteratorBE::new(inner.to_64x4());
227226
self.mul_bits(bits)
228227
}
229228

@@ -714,7 +713,7 @@ impl<'a, P: Parameters> SubAssign<&'a Self> for GroupProjective<P> {
714713

715714
impl<P: Parameters> MulAssign<P::ScalarField> for GroupProjective<P> {
716715
fn mul_assign(&mut self, other: P::ScalarField) {
717-
*self = self.mul(other.into_repr())
716+
*self = self.mul(other.into_repr().to_64x4())
718717
}
719718
}
720719

ec/src/models/twisted_edwards_extended.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,7 @@ use num_traits::{One, Zero};
2121
use zeroize::Zeroize;
2222

2323
use ark_ff::{
24-
bytes::{FromBytes, ToBytes},
25-
fields::{BitIteratorBE, Field, PrimeField, SquareRootField},
26-
ToConstraintField, UniformRand,
24+
bytes::{FromBytes, ToBytes}, fields::{BitIteratorBE, Field, PrimeField, SquareRootField}, BigInteger, ToConstraintField, UniformRand
2725
};
2826

2927
#[cfg(feature = "parallel")]
@@ -138,7 +136,8 @@ impl<P: Parameters> AffineCurve for GroupAffine<P> {
138136
}
139137

140138
fn mul<S: Into<<Self::ScalarField as PrimeField>::BigInt>>(&self, by: S) -> GroupProjective<P> {
141-
self.mul_bits(BitIteratorBE::new(by.into()))
139+
let inner: <Self::ScalarField as PrimeField>::BigInt = by.into();
140+
self.mul_bits(ark_ff::BitIteratorBE::new(inner.to_64x4()))
142141
}
143142

144143
fn from_random_bytes(bytes: &[u8]) -> Option<Self> {
@@ -610,7 +609,7 @@ impl<'a, P: Parameters> SubAssign<&'a Self> for GroupProjective<P> {
610609

611610
impl<P: Parameters> MulAssign<P::ScalarField> for GroupProjective<P> {
612611
fn mul_assign(&mut self, other: P::ScalarField) {
613-
*self = self.mul(other.into_repr())
612+
*self = self.mul(other.into_repr().to_64x4())
614613
}
615614
}
616615

ec/src/msm/variable_base.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ impl VariableBaseMSM {
5454
scalar.divn(w_start as u32);
5555

5656
// We mod the remaining bits by 2^{window size}, thus taking `c` bits.
57-
let scalar = scalar.as_ref()[0] % (1 << c);
57+
let scalar = scalar.to_64x4()[0] % (1 << c);
5858

5959
// If the scalar is non-zero, we update the corresponding
6060
// bucket.

ff/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,7 @@ default = []
3333
std = [ "ark-std/std", "ark-serialize/std" ]
3434
parallel = [ "std", "rayon", "ark-std/parallel" ]
3535
asm = []
36+
32x9 = []
37+
38+
[lints.rust]
39+
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(use_asm)'] }

ff/src/biginteger/arithmetic.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#![allow(unused)]
12
use ark_std::vec::Vec;
23

34
/// Make 4 u64 multiplications, instead of 1 u128

ff/src/biginteger/macros.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,43 @@
11
macro_rules! bigint_impl {
22
($name:ident, $num_limbs:expr) => {
33
#[derive(Copy, Clone, PartialEq, Eq, Debug, Default, Hash, Zeroize)]
4-
pub struct $name(pub [u64; $num_limbs]);
4+
pub struct $name(pub(crate) [u64; $num_limbs]);
55

66
impl $name {
77
pub const fn new(value: [u64; $num_limbs]) -> Self {
88
$name(value)
99
}
10+
11+
pub const fn to_64x4(&self) -> [u64; $num_limbs] {
12+
self.0
13+
}
14+
15+
pub const fn from_64x4(value: [u64; $num_limbs]) -> Self {
16+
$name(value)
17+
}
18+
19+
#[ark_ff_asm::unroll_for_loops]
20+
pub fn assign_bits_and(&mut self, other: &Self) {
21+
for i in 0..$num_limbs {
22+
self.0[i] |= other.0[i]
23+
}
24+
}
25+
26+
pub fn to_native(&self) -> [u64; $num_limbs] {
27+
self.0
28+
}
1029
}
1130

1231
impl BigInteger for $name {
1332
const NUM_LIMBS: usize = $num_limbs;
1433

34+
fn to_64x4(&self) -> [u64; 4] {
35+
self.0
36+
}
37+
fn from_64x4(value: [u64; 4]) -> Self {
38+
$name(value)
39+
}
40+
1541
#[inline]
1642
#[ark_ff_asm::unroll_for_loops]
1743
fn add_nocarry(&mut self, other: &Self) -> bool {

ff/src/biginteger/mod.rs

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
use crate::{
2-
bytes::{FromBytes, ToBytes},
3-
fields::{BitIteratorBE, BitIteratorLE},
4-
UniformRand,
2+
bytes::{FromBytes, ToBytes}, fields::{BitIteratorBE, BitIteratorLE}, UniformRand
53
};
64
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, SerializationError};
75
use ark_std::rand::{
@@ -31,14 +29,17 @@ pub fn signed_mod_reduction(n: u64, modulus: u64) -> i64 {
3129
}
3230
}
3331

34-
bigint_impl!(BigInteger64, 1);
35-
bigint_impl!(BigInteger128, 2);
36-
bigint_impl!(BigInteger256, 4);
37-
bigint_impl!(BigInteger320, 5);
38-
bigint_impl!(BigInteger384, 6);
39-
bigint_impl!(BigInteger448, 7);
40-
bigint_impl!(BigInteger768, 12);
41-
bigint_impl!(BigInteger832, 13);
32+
pub mod native_bigint {
33+
use super::*;
34+
bigint_impl!(BigInteger256, 4);
35+
}
36+
pub mod webnode;
37+
38+
#[cfg(not(any(target_family = "wasm", feature = "32x9")))]
39+
pub use native_bigint::*;
40+
41+
#[cfg(any(target_family = "wasm", feature = "32x9"))]
42+
pub use webnode::*;
4243

4344
#[cfg(test)]
4445
mod tests;
@@ -63,15 +64,16 @@ pub trait BigInteger:
6364
+ 'static
6465
+ UniformRand
6566
+ Zeroize
66-
+ AsMut<[u64]>
67-
+ AsRef<[u64]>
6867
+ From<u64>
6968
+ TryFrom<BigUint>
7069
+ Into<BigUint>
7170
{
7271
/// Number of limbs.
7372
const NUM_LIMBS: usize;
7473

74+
fn to_64x4(&self) -> [u64; 4];
75+
fn from_64x4(value: [u64; 4]) -> Self;
76+
7577
/// Add another representation to this one, returning the carry bit.
7678
fn add_nocarry(&mut self, other: &Self) -> bool;
7779

@@ -119,13 +121,13 @@ pub trait BigInteger:
119121
/// Returns the bit representation in a big endian boolean array,
120122
/// with leading zeroes.
121123
fn to_bits_be(&self) -> Vec<bool> {
122-
BitIteratorBE::new(self).collect::<Vec<_>>()
124+
BitIteratorBE::new(self.to_64x4()).collect::<Vec<_>>()
123125
}
124126

125127
/// Returns the bit representation in a little endian boolean array,
126128
/// with trailing zeroes.
127129
fn to_bits_le(&self) -> Vec<bool> {
128-
BitIteratorLE::new(self).collect::<Vec<_>>()
130+
BitIteratorLE::new(self.to_64x4()).collect::<Vec<_>>()
129131
}
130132

131133
/// Returns the byte representation in a big endian byte array,
@@ -143,11 +145,12 @@ pub trait BigInteger:
143145
if w >= 2 && w < 64 {
144146
let mut res = vec![];
145147
let mut e = *self;
148+
let e64 = self.to_64x4();
146149

147150
while !e.is_zero() {
148151
let z: i64;
149152
if e.is_odd() {
150-
z = signed_mod_reduction(e.as_ref()[0], 1 << w);
153+
z = signed_mod_reduction(e64.as_ref()[0], 1 << w);
151154
if z >= 0 {
152155
e.sub_noborrow(&Self::from(z as u64));
153156
} else {

0 commit comments

Comments
 (0)