conversion to decimal string; mulAdd

This commit is contained in:
Balazs Komuves 2026-01-25 19:45:51 +01:00
parent 1786565415
commit 92881234bf
No known key found for this signature in database
GPG Key ID: F63B7AEF18435562
3 changed files with 115 additions and 2 deletions

View File

@ -100,7 +100,7 @@ impl<const N: usize> BigInt<N> {
buf
}
pub fn from_be_bytes(buf : &[u8; 4*N]) -> BigInt<N> {
pub fn from_be_bytes(buf: &[u8; 4*N]) -> BigInt<N> {
let mut ws: [u32; N] = [0; N];
for i in 0..N {
let k = 4*i;
@ -113,8 +113,38 @@ impl<const N: usize> BigInt<N> {
}
//------------------------------------
// decimal printing
pub fn truncate1(big : &BigInt<{N+1}>) -> BigInt<N> {
pub fn divmod_small(big: &BigInt<N>, modulus: u32) -> (BigInt<N> , u32) {
let u64_modulus: u64 = modulus as u64;
let mut carry: u32 = 0;
let mut qs: [u32; N] = [0; N];
for i in 0..N {
let x: u64 = ((carry as u64) << 32) + (big.0[N-1-i] as u64);
qs[N-1-i] = (x / u64_modulus) as u32;
carry = (x % u64_modulus) as u32;
}
(BigInt(qs), carry)
}
pub fn to_decimal_string(input: &BigInt<N>) -> String {
let mut digits: Vec<u8> = Vec::new();
let mut big: BigInt<N> = input.clone();
while( !BigInt::is_zero(&big) ) {
let (q,r) = BigInt::divmod_small(&big, 10);
digits.push( 48 + (r as u8) );
big = q;
}
if digits.len() == 0 {
digits.push( 48 );
}
digits.reverse();
str::from_utf8(&digits).unwrap().to_string()
}
//------------------------------------
pub fn truncate1(big: &BigInt<{N+1}>) -> BigInt<N> {
// let small: [u32; N] = &big.limbs[0..N];
let mut small: [u32; N] = [0; N];
for i in 0..N { small[i] = big.0[i]; }
@ -343,6 +373,66 @@ impl<const N: usize> BigInt<N> {
BigInt::multiply(big1,big2)
}
// x*y + z
#[inline(always)]
pub fn mulAdd(big1: &BigInt<N>, big2: &BigInt<N>, big3: &BigInt<N>) -> BigInt<{N+N}> {
// first compute the product
let mut product : [u32; N+N] = [0; N+N];
let mut state : [u32; N] = [0; N];
for j in 0..N {
let (scaled,carry) = BigInt::scaleAdd( big2.0[j], &big1, &BigInt(state) );
product[j] = scaled.0[0];
for i in 1..N { state[i-1] = scaled.0[i] }
state[N-1] = carry;
}
for i in 0..N {
product[i+N] = state[i]
}
// then add the third number
let mut carry: bool = false;
for i in 0..N {
let (z,c) = addCarry32( product[i] , big3.0[i] , carry );
carry = c;
product[i] = z;
}
// continue carrying
for i in N..(N+N) {
let (z,c) = addCarry32( product[i] , 0 , carry );
carry = c;
product[i] = z;
}
BigInt(product)
}
// x*y + (z << 256)
#[inline(always)]
pub fn mulAddShifted(big1: &BigInt<N>, big2: &BigInt<N>, big3: &BigInt<N>) -> BigInt<{N+N}> {
// first compute the product
let mut product : [u32; N+N] = [0; N+N];
let mut state : [u32; N] = [0; N];
for j in 0..N {
let (scaled,carry) = BigInt::scaleAdd( big2.0[j], &big1, &BigInt(state) );
product[j] = scaled.0[0];
for i in 1..N { state[i-1] = scaled.0[i] }
state[N-1] = carry;
}
for i in 0..N {
product[i+N] = state[i]
}
// then add the third number, shifted
let mut carry: bool = false;
for i in 0..N {
let (z,c) = addCarry32( product[i+N] , big3.0[i] , carry );
carry = c;
product[i+N] = z;
}
BigInt(product)
}
// TODO: optimize this?!
pub fn sqr_naive(big: &BigInt<N>) -> BigInt<{N+N}> {
BigInt::multiply(big,big)

View File

@ -93,6 +93,10 @@ impl Felt {
Felt(Mont::convert_to_big(&mont))
}
pub fn to_decimal_string(input: &Felt) -> String {
BigInt::to_decimal_string(&input.0)
}
//------------------------------------
pub fn zero() -> Felt {

View File

@ -43,6 +43,9 @@ impl Mont {
BigInt::is_lt_prime(&mont.0)
}
//------------------------------------
// to/from bytes
// note: this exports the Montgomery representation!
pub fn to_le_bytes(mont: &Mont) -> [u8; 32] {
BigInt::to_le_bytes(&mont.0)
@ -65,6 +68,10 @@ impl Mont {
Mont(big)
}
pub fn to_decimal_string(input: &Mont) -> String {
BigInt::to_decimal_string(&Mont::convert_to_big(&input))
}
//------------------------------------
#[inline(always)]
@ -109,6 +116,9 @@ impl Mont {
Mont::add(&mont, &mont)
}
//------------------------------------
// reduction and multiplication
// the Montgomery reduction algorithm
// <https://en.wikipedia.org/wiki/Montgomery_modular_multiplication#Montgomery_arithmetic_on_multiprecision_integers>
fn redc_safe(input: BigInt<16>) -> Big {
@ -188,6 +198,15 @@ impl Mont {
Mont(Mont::redc(large))
}
// x*y + z
pub fn mulAdd(mont1: &Mont, mont2: &Mont, mont3: &Mont) -> Mont {
let large = BigInt::mulAddShifted(&mont1.0, &mont2.0, &mont3.0);
Mont(Mont::redc(large))
}
//------------------------------------
// conversions
// this does conversion from the standard representation
// we assume the input is in the range `[0..p-1]`
pub fn unsafe_convert_from_big(input: &Big) -> Mont {