diff --git a/src/bn254/bigint.rs b/src/bn254/bigint.rs index 096a1e7..96729b7 100644 --- a/src/bn254/bigint.rs +++ b/src/bn254/bigint.rs @@ -100,7 +100,7 @@ impl BigInt { buf } - pub fn from_be_bytes(buf : &[u8; 4*N]) -> BigInt { + pub fn from_be_bytes(buf: &[u8; 4*N]) -> BigInt { let mut ws: [u32; N] = [0; N]; for i in 0..N { let k = 4*i; @@ -113,8 +113,38 @@ impl BigInt { } //------------------------------------ + // decimal printing - pub fn truncate1(big : &BigInt<{N+1}>) -> BigInt { + pub fn divmod_small(big: &BigInt, modulus: u32) -> (BigInt , 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) -> String { + let mut digits: Vec = Vec::new(); + let mut big: BigInt = 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 { // 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 BigInt { BigInt::multiply(big1,big2) } + // x*y + z + #[inline(always)] + pub fn mulAdd(big1: &BigInt, big2: &BigInt, big3: &BigInt) -> 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, big2: &BigInt, big3: &BigInt) -> 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) -> BigInt<{N+N}> { BigInt::multiply(big,big) diff --git a/src/bn254/field.rs b/src/bn254/field.rs index fe4d0cd..b701eff 100644 --- a/src/bn254/field.rs +++ b/src/bn254/field.rs @@ -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 { diff --git a/src/bn254/montgomery.rs b/src/bn254/montgomery.rs index 77ee094..a22ef97 100644 --- a/src/bn254/montgomery.rs +++ b/src/bn254/montgomery.rs @@ -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 // 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 {