diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ae4b8f448..32c1a450a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,6 +14,7 @@ jobs: runs-on: ubuntu-latest-16-cores steps: - uses: actions/checkout@v3 + - uses: foundry-rs/setup-snfoundry@v3 - uses: software-mansion/setup-scarb@v1 - run: scarb fmt --check - run: scarb build diff --git a/.gitignore b/.gitignore index bd757b3dd..4f53a819c 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ target .idea/ node_modules/ +*.snfoundry_cache diff --git a/crates/utils/Scarb.toml b/crates/utils/Scarb.toml index f8c95dc92..189538b4f 100644 --- a/crates/utils/Scarb.toml +++ b/crates/utils/Scarb.toml @@ -13,3 +13,7 @@ fmt.workspace = true [dev-dependencies] cairo_test.workspace = true + +[scripts] +test = "snforge test --max-n-steps 4294967295" +test-profiling = "snforge test --max-n-steps 4294967295 --build-profile" diff --git a/crates/utils/src/crypto/modexp/arith.cairo b/crates/utils/src/crypto/modexp/arith.cairo index 33de0383c..d08bbffee 100644 --- a/crates/utils/src/crypto/modexp/arith.cairo +++ b/crates/utils/src/crypto/modexp/arith.cairo @@ -608,3 +608,1943 @@ fn in_place_mul_sub(ref a: Felt252Vec, ref x: Felt252Vec, y: Word) - // Return the borrow. WORD_MAX - offset_carry } + + +#[cfg(test)] +mod tests { + use alexandria_data_structures::vec::VecTrait; + use alexandria_data_structures::vec::{Felt252Vec, Felt252VecImpl}; + use core::result::ResultTrait; + use core::traits::Into; + use integer::u128_wrapping_sub; + + use utils::crypto::modexp::arith::{ + mod_inv, monsq, monpro, compute_r_mod_n, in_place_shl, in_place_shr, big_wrapping_pow, + big_wrapping_mul, big_sq, borrowing_sub, shifted_carrying_mul + }; + use utils::crypto::modexp::mpnat::tests::{mp_nat_to_u128}; + use utils::crypto::modexp::mpnat::{ + MPNat, MPNatTrait, WORD_MAX, DOUBLE_WORD_MAX, BASE, Word, DoubleWord, WORD_BYTES + }; + use utils::helpers::{Felt252VecTrait, ToBytes}; + use utils::helpers::{U128Trait}; + use utils::math::{WrappingMul, WrappingBitshift, WrappingExponentiation}; + + // the tests are taken from + // [aurora-engine](https://github.com/aurora-is-near/aurora-engine/blob/1213f2c7c035aa523601fced8f75bef61b4728ab/engine-modexp/src/arith.rs#L401) + + fn check_monsq(x: u128, n: u128) { + let mut a = MPNatTrait::from_big_endian(x.to_be_bytes_padded()); + let mut m = MPNatTrait::from_big_endian(n.to_be_bytes_padded()); + let n_prime = WORD_MAX - mod_inv(m.digits[0]) + 1; + + let mut output = Felt252VecImpl::new(); + output.expand(2 * m.digits.len() + 1).unwrap(); + + monsq(ref a, ref m, n_prime, ref output); + let mut result = MPNat { digits: output }; + + let mut output = Felt252VecImpl::new(); + output.expand(m.digits.len() + 2).unwrap(); + let mut tmp = MPNat { digits: a.digits.duplicate() }; + monpro(ref a, ref tmp, ref m, n_prime, ref output); + + let mut expected = MPNat { digits: output }; + + assert!(result.digits.equal_remove_trailing_zeroes(ref expected.digits)); + } + + fn check_monpro(x: u128, y: u128, n: u128, ref expected: MPNat) { + let mut a = MPNatTrait::from_big_endian(x.to_be_bytes_padded()); + let mut b = MPNatTrait::from_big_endian(y.to_be_bytes_padded()); + let mut m = MPNatTrait::from_big_endian(n.to_be_bytes()); + let n_prime = WORD_MAX - mod_inv(m.digits[0]) + 1; + + let mut output = Felt252VecImpl::new(); + output.expand(m.digits.len() + 2).unwrap(); + monpro(ref a, ref b, ref m, n_prime, ref output); + let mut result = MPNat { digits: output }; + + assert!(result.digits.equal_remove_trailing_zeroes(ref expected.digits)); + } + + + fn check_r_mod_n(n: u128, ref expected: MPNat) { + let mut x = MPNatTrait::from_big_endian(n.to_be_bytes_padded()); + let mut out: Felt252Vec = Felt252VecImpl::new(); + out.expand(x.digits.len()).unwrap(); + compute_r_mod_n(ref x, ref out); + let mut result = MPNat { digits: out }; + assert!(result.digits.equal_remove_trailing_zeroes(ref expected.digits)); + } + + fn check_in_place_shl(n: u128, shift: u32) { + let mut x = MPNatTrait::from_big_endian(n.to_be_bytes_padded()); + in_place_shl(ref x.digits, shift); + let mut result = mp_nat_to_u128(ref x); + + let mask = u128_wrapping_sub(BASE.wrapping_pow(x.digits.len().into()), 1); + assert_eq!(result, n.wrapping_shl(shift.into()) & mask); + } + + fn check_in_place_shr(n: u128, shift: u32) { + let mut x = MPNatTrait::from_big_endian(n.to_be_bytes_padded()); + in_place_shr(ref x.digits, shift); + let mut result = mp_nat_to_u128(ref x); + + assert_eq!(result, n.wrapping_shr(shift.into())); + } + + fn check_mod_inv(n: Word) { + let n_inv = mod_inv(n); + assert_eq!(n.wrapping_mul(n_inv), 1); + } + + fn check_big_wrapping_pow(a: u128, b: u32, expected_bytes: Span) { + let mut x = MPNatTrait::from_big_endian(a.to_be_bytes_padded()); + let mut y = b.to_be_bytes_padded(); + + let mut scratch = Felt252VecImpl::new(); + scratch.expand(1 + (expected_bytes.len() / WORD_BYTES)).unwrap(); + + let mut result = big_wrapping_pow(ref x, y, ref scratch); + + let mut expected = MPNatTrait::from_big_endian(expected_bytes); + assert!(result.digits.equal_remove_trailing_zeroes(ref expected.digits)); + } + + fn check_big_wrapping_mul(a: u128, b: u128, output_digits: usize, ref expected: MPNat) { + let mut x = MPNatTrait::from_big_endian(a.to_be_bytes_padded()); + let mut y = MPNatTrait::from_big_endian(b.to_be_bytes_padded()); + + let mut out = Felt252VecImpl::new(); + out.expand(output_digits).unwrap(); + + big_wrapping_mul(ref x, ref y, ref out); + let mut result = MPNat { digits: out }; + + assert!(result.digits.equal_remove_trailing_zeroes(ref expected.digits)); + } + + fn check_big_sq(a: u128, ref expected: MPNat) { + let mut x = MPNatTrait::from_big_endian(a.to_be_bytes_padded()); + let mut out = Felt252VecImpl::new(); + out.expand(2 * x.digits.len() + 1).unwrap(); + + big_sq(ref x, ref out); + + let mut result = MPNat { digits: out }; + assert!(result.digits.equal_remove_trailing_zeroes(ref expected.digits)); + } + + #[test] + fn test_monsq_alpha() { + let mut x = Felt252VecImpl::new(); + x.push(0xf72fc634c83435bc); + x.push(0xa6b0ce70ac511873); + let mut x = MPNat { digits: x }; + + let mut y = Felt252VecImpl::new(); + y.push(0xf3e77eceb2ecfce5); + y.push(0xc4550871a1cfc67a); + let mut y = MPNat { digits: y }; + + let n_prime = 0xa51080a4eb8b9f13; + let mut scratch = Felt252VecImpl::new(); + scratch.expand(5).unwrap(); + + monsq(ref x, ref y, n_prime, ref scratch); + } + + + #[test] + fn test_monsq_0() { + check_monsq(1, 31); + } + + #[test] + fn test_monsq_1() { + check_monsq(6, 31); + } + + #[test] + fn test_monsq_2() { + // This example is intentionally chosen because 5 * 5 = 25 = 0 mod 25, + // therefore it requires the final subtraction step in the algorithm. + check_monsq(5, 25); + } + + #[test] + fn test_monsq_3() { + check_monsq(0x1FFF_FFFF_FFFF_FFF0, 0x1FFF_FFFF_FFFF_FFF1); + } + + #[test] + fn test_monsq_4() { + check_monsq(0x16FF_221F_CB7D, 0x011E_842B_6BAA_5017_EBF2_8293); + } + + #[test] + fn test_monsq_5() { + check_monsq(0x0A2D_63F5_CFF9, 0x1F3B_3BD9_43EF); + } + + #[test] + fn test_monsq_6() { + check_monsq(0xa6b0ce71a380dea7c83435bc, 0xc4550871a1cfc67af3e77eceb2ecfce5,); + } + + #[test] + fn test_monpro_0() { + let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); + expected_digits.push(2); + let mut expected = MPNat { digits: expected_digits }; + + check_monpro(1, 1, 31, ref expected); + } + + #[test] + fn test_monpro_1() { + let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); + expected_digits.push(22); + let mut expected = MPNat { digits: expected_digits }; + + check_monpro(6, 7, 31, ref expected); + } + + #[test] + fn test_monpro_2() { + let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); + expected_digits.push(0); + let mut expected = MPNat { digits: expected_digits }; + + // This example is intentionally chosen because 5 * 7 = 35 = 0 mod 35, + // therefore it requires the final subtraction step in the algorithm. + check_monpro(5, 7, 35, ref expected); + } + + #[test] + fn test_monpro_3() { + let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); + expected_digits.push(384307168202282284); + + let mut expected = MPNat { digits: expected_digits }; + + // This example is intentionally chosen because 5 * 7 = 35 = 0 mod 35, + // therefore it requires the final subtraction step in the algorithm. + check_monpro(0x1FFF_FFFF_FFFF_FFF0, 0x1234, 0x1FFF_FFFF_FFFF_FFF1, ref expected); + } + + #[test] + fn test_monpro_4() { + let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); + expected_digits.push(0); + let mut expected = MPNat { digits: expected_digits }; + + // This example is intentionally chosen because 5 * 7 = 35 = 0 mod 35, + // therefore it requires the final subtraction step in the algorithm. + check_monpro( + 0x16FF_221F_CB7D, 0x0C75_8535_434F, 0x011E_842B_6BAA_5017_EBF2_8293, ref expected + ); + } + + #[test] + fn test_monpro_5() { + let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); + expected_digits.push(4425093052866); + let mut expected = MPNat { digits: expected_digits }; + + // This example is intentionally chosen because 5 * 7 = 35 = 0 mod 35, + // therefore it requires the final subtraction step in the algorithm. + check_monpro(0x0A2D_63F5_CFF9, 0x1B21_FF3C_FA8E, 0x1F3B_3BD9_43EF, ref expected); + } + + #[test] + fn test_r_mod_n_0() { + let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); + expected_digits.push(1); + let mut expected = MPNat { digits: expected_digits }; + + check_r_mod_n(0x01_00_00_00_01, ref expected); + } + + #[test] + fn test_r_mod_n_1() { + let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); + expected_digits.push(549722259457); + let mut expected = MPNat { digits: expected_digits }; + + check_r_mod_n(0x80_00_00_00_01, ref expected); + } + + #[test] + fn test_r_mod_n_2() { + let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); + expected_digits.push(1); + let mut expected = MPNat { digits: expected_digits }; + + check_r_mod_n(0xFFFF_FFFF_FFFF_FFFF, ref expected); + } + + #[test] + fn test_r_mod_n_3() { + let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); + expected_digits.push(1); + let mut expected = MPNat { digits: expected_digits }; + + check_r_mod_n(0x0001_0000_0000_0000_0001, ref expected); + } + + #[test] + fn test_r_mod_n_4() { + let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); + expected_digits.push(18446181123756130305); + expected_digits.push(32767); + + let mut expected = MPNat { digits: expected_digits }; + + check_r_mod_n(0x8000_0000_0000_0000_0001, ref expected); + } + + #[test] + fn test_r_mod_n_5() { + let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); + expected_digits.push(3491005389787767287); + expected_digits.push(2668502225); + + let mut expected = MPNat { digits: expected_digits }; + + check_r_mod_n(0xbf2d_c9a3_82c5_6e85_b033_7651, ref expected); + } + + #[test] + fn test_r_mod_n_6() { + let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); + expected_digits.push(4294967296); + + let mut expected = MPNat { digits: expected_digits }; + + check_r_mod_n(0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF, ref expected); + } + + #[test] + fn test_in_place_shl() { + check_in_place_shl(0, 0); + check_in_place_shl(1, 10); + check_in_place_shl(WORD_MAX.into(), 5); + check_in_place_shl(DOUBLE_WORD_MAX.into(), 16); + } + + #[test] + fn test_in_place_shr() { + check_in_place_shr(0, 0); + check_in_place_shr(1, 10); + check_in_place_shr(0x1234_5678, 10); + check_in_place_shr(WORD_MAX.into(), 5); + check_in_place_shr(DOUBLE_WORD_MAX, 16); + } + + #[test] + #[available_gas(10000000000000)] + fn test_mod_inv_0() { + let mut i = 1; + loop { + if i == 1025 { + break; + }; + + check_mod_inv(2 * i - 1); + i += 1; + } + } + + #[test] + #[available_gas(10000000000000)] + fn test_mod_inv_1() { + let mut i = 0; + loop { + if i == 1025 { + break; + }; + + check_mod_inv(0xFF_FF_FF_FF - 2 * i); + i += 1; + } + } + + #[test] + fn test_big_wrapping_pow_0() { + let expected_bytes: Span = array![1].span(); + check_big_wrapping_pow(1, 1, expected_bytes); + } + + #[test] + fn test_big_wrapping_pow_1() { + let expected_bytes: Span = array![100].span(); + + check_big_wrapping_pow(10, 2, expected_bytes); + } + + #[test] + fn test_big_wrapping_pow_2() { + let expected_bytes: Span = array![1, 0, 0, 0, 0].span(); + + check_big_wrapping_pow(2, 32, expected_bytes); + } + + #[test] + fn test_big_wrapping_pow_3() { + let expected_bytes: Span = array![1, 0, 0, 0, 0, 0, 0, 0, 0].span(); + check_big_wrapping_pow(2, 64, expected_bytes); + } + + #[test] + #[available_gas(10000000000000)] + fn test_big_wrapping_pow_4() { + let expected_bytes: Span = array![ + 3, + 218, + 116, + 252, + 230, + 21, + 167, + 46, + 59, + 185, + 199, + 194, + 149, + 140, + 133, + 157, + 60, + 102, + 160, + 27, + 104, + 79, + 16, + 104, + 20, + 104, + 116, + 207, + 214, + 100, + 237, + 159, + 0, + 245, + 249, + 156, + 52, + 33, + 217, + 113, + 130, + 6, + 65, + 78, + 49, + 141, + 141, + 160, + 29, + 125, + 168, + 236, + 88, + 174, + 146, + 81, + 137, + 165, + 242, + 90, + 251, + 115, + 144, + 169, + 141, + 66, + 207, + 230, + 56, + 199, + 140, + 109, + 7, + 99, + 35, + 155, + 88, + 29, + 90, + 192, + 55, + 127, + 112, + 26, + 176, + 181, + 13, + 72, + 107, + 209, + 1, + 210, + 88, + 233, + 185, + 87, + 108, + 122, + 168, + 137, + 255, + 36, + 201, + 185, + 31, + 36, + 51, + 208, + 64, + 154, + 113, + 233, + 71, + 95, + 35, + 253, + 0, + 3, + 159, + 183, + 10, + 83, + 233, + 88, + 96, + 19, + 104, + 229, + 132, + 73, + 219, + 152, + 126, + 215, + 249, + 46, + 110, + 157, + 234, + 2, + 100, + 178, + 150, + 110, + 217, + 246, + 128, + 219, + 121, + 21, + 234, + 55, + 101, + 81, + 207, + 191, + 200, + 201, + 2, + 40, + 13, + 80, + 107, + 226, + 143, + 164, + 254, + 91, + 54, + 46, + 254, + 7, + 14, + 136, + 149, + 194, + 6, + 191, + 14, + 49, + 140, + 193, + 40, + 1, + 138, + 165, + 82, + 34, + 33, + 169, + 41, + 136, + 130, + 47, + 84, + 173, + 58, + 121, + 192, + 247, + 98, + 237, + 165, + 215, + 161, + 198, + 87, + 228, + 76, + 160, + 66, + 78, + 169, + 139, + 234, + 169, + 83, + 15, + 16, + 192, + 170, + 71, + 227, + 232, + 116, + 189, + 81, + 64, + 104, + 182, + 129, + 203, + 191, + 210, + 151, + 132, + 254, + 239, + 19, + 138, + 49, + 113, + 140, + 77, + 38, + 49, + 117, + 127, + 203, + 123, + 127, + 49, + 32, + 61, + 108, + 120, + 133, + 119, + 8, + 232, + 84, + 57, + 103, + 197, + 160, + 65, + 191, + 82, + 253, + 60, + 191, + 209, + 63, + 176, + 43, + 33, + 54, + 75, + 17, + 73, + 222, + 198, + 80, + 5, + 14, + 50, + 117, + 156, + 77, + 147, + 190, + 230, + 143, + 47, + 149, + 180, + 203, + 144, + 202, + 102, + 231, + 2, + 91, + 22, + 101, + 178, + 211, + 233, + 109, + 156, + 72, + 151, + 199, + 189, + 90, + 76, + 21, + 112, + 21, + 2, + 44, + 96, + 42, + 141, + 217, + 142, + 23, + 75, + 248, + 209, + 26, + 3, + 198, + 103, + 227, + 103, + 140, + 99, + 75, + 211, + 152, + 109, + 19, + 72, + 6, + 116, + 67, + 70, + 32, + 45, + 5, + 113, + 179, + 252, + 2, + 202, + 115, + 244, + 68, + 128, + 156, + 233, + 227, + 211, + 5, + 146, + 147, + 186, + 34, + 3, + 105, + 147, + 64, + 79, + 172, + 141, + 14, + 60, + 69, + 249, + 169, + 76, + 252, + 84, + 151, + 49, + 81, + 246, + 185, + 181, + 181, + 226, + 28, + 152, + 30, + 47, + 248, + 103, + 21, + 184, + 140, + 193, + 112, + 139, + 250, + 206, + 35, + 180, + 122, + 32, + 151, + 105, + 30, + 193, + 68, + 232, + 170, + 174, + 254, + 143, + 29, + 165, + 194, + 14, + 164, + 35, + 25, + 250, + 86, + 76, + 213, + 159, + 21, + 0, + 212, + 146, + 21, + 8, + 180, + 73, + 250, + 116, + 137, + 221, + 20, + 22, + 146, + 169, + 120, + 166, + 229, + 226, + 136, + 201, + 177, + 49, + 21, + 228, + 191, + 246, + 26, + 36, + 183, + 175, + 137, + 71, + 4, + 46, + 235, + 197, + 99, + 0, + 142, + 97, + 184, + 34, + 84, + 254, + 41, + 95, + 198, + 178, + 48, + 105, + 215, + 72, + 155, + 238, + 51, + 164, + 52, + 179, + 126, + 254, + 100, + 35, + 236, + 63, + 215, + 238, + 217, + 239, + 229, + 160, + 192, + 33, + 82, + 165, + 81, + 149, + 186, + 53, + 109, + 184, + 187, + 186, + 8, + 43, + 249, + 20, + 37, + 255, + 241, + 18, + 61, + 97, + 229, + 29, + 201, + 144, + 92, + 202, + 215, + 161, + 165, + 133, + 89, + 180, + 246, + 37, + 16, + 133, + 226, + 209, + 23, + 61, + 241, + 25, + 9, + 150, + 154, + 150, + 133, + 210, + 62, + 115, + 34, + 201, + 187, + 217, + 3, + 82, + 102, + 174, + 233, + 33, + 31, + 7, + 4, + 88, + 70, + 173, + 157, + 111, + 96, + 102, + 223, + 157, + 224, + 158, + 235, + 191, + 55, + 219, + 218, + 146, + 233, + 242, + 250, + 170, + 100, + 68, + 37, + 56, + 251, + 109, + 112, + 217, + 209, + 46, + 229, + 198, + 198, + 156, + 198, + 70, + 76, + 131, + 79, + 40, + 25, + 176, + 21, + 43, + 31, + 121, + 204, + 225, + 128, + 182, + 191, + 148, + 72, + 22, + 112, + 63, + 223, + 182, + 155, + 177, + 183, + 72, + 111, + 6, + 196, + 250, + 189, + 45, + 97, + 182, + 14, + 219, + 189, + 50, + 226, + 91, + 1, + 86, + 95, + 131, + 120, + 224, + 0, + 71, + 28, + 151, + 69, + 24, + 93, + 82, + 237, + 136, + 103, + 90, + 247, + 173, + 204, + 121, + 199, + 17, + 164, + 80, + 49, + 183, + 10, + 200, + 235, + 56, + 72, + 72, + 147, + 150, + 223, + 110, + 165, + 60, + 13, + 251, + 42, + 193, + 78, + 212, + 166, + 178, + 103, + 19, + 35, + 69, + 10, + 137, + 62, + 13, + 90, + 203, + 126, + 203, + 207, + 190, + 184, + 89, + 118, + 186, + 203, + 6, + 115, + 158, + 168, + 35, + 206, + 227, + 48, + 221, + 252, + 190, + 166, + 249, + 96, + 92, + 244, + 77, + 213, + 119, + 44, + 207, + 17, + 16, + 118, + 104, + 106, + 188, + 205, + 5, + 240, + 14, + 181, + 227, + 4, + 11, + 32, + 91, + 224, + 78, + 175, + 49, + 19, + 12, + 233, + 131, + 141, + 47, + 32, + 14, + 195, + 214, + 77, + 158, + 39, + 114, + 167, + 37, + 16, + 249, + 73, + 167, + 230, + 165, + 19, + 4, + 199, + 227, + 251, + 184, + 131, + 137, + 74, + 176, + 116, + 35, + 182, + 121, + 62, + 114, + 64, + 163, + 84, + 208, + 111, + 56, + 191, + 88, + 130, + 64, + 64, + 181, + 162, + 53, + 34, + 16, + 179, + 155, + 137, + 138, + 101, + 121, + 73, + 234, + 189, + 100, + 141, + 122, + 123, + 79, + 200, + 90, + 208, + 83, + 253, + 124, + 125, + 116, + 72, + 138, + 63, + 42, + 144, + 200, + 73, + 233, + 113, + 143, + 85, + 140, + 16, + 240, + 230, + 42, + 114, + 137, + 193, + 10, + 129, + 124, + 193, + 104, + 177, + 55, + 156, + 173, + 135, + 168, + 217, + 1, + 46, + 41, + 132, + 17, + 222, + 178, + 226, + 24, + 108, + 117, + 199, + 171, + 232, + 129, + 82, + 225, + 214, + 105, + 94, + 188, + 72, + 62, + 91, + 193, + 188, + 18, + 33, + 131, + 18, + 194, + 70, + 151, + 187, + 42, + 5, + 62, + 85, + 38, + 134, + 252, + 183, + 227, + 120, + 19, + 152, + 243, + 235, + 114, + 208, + 78, + 57, + 113, + 217, + 182, + 125, + 195, + 64, + 229, + 232, + 54, + 118, + 11, + 119, + 163, + 235, + 12, + 67, + 90, + 246, + 76, + 219, + 200, + 124, + 234, + 41, + 172, + 31, + 167, + 213, + 127, + 100, + 163, + 72, + 44, + 107, + 171, + 229, + 189, + 68, + 201, + 244, + 154, + 27, + 172, + 228, + 234, + 192, + 156, + 127, + 170, + 9, + 78, + 166, + 249, + 154, + 178, + 179, + 172, + 220, + 205, + 220, + 60, + 86, + 98, + 134, + 60, + 134, + 89, + 244, + 187, + 231, + 128, + 6, + 109, + 152, + 251, + 44, + 208, + 238, + 169, + 71, + 51, + 192, + 242, + 57, + 8, + 62, + 206, + 94, + 94, + 25, + 220, + 160, + 175, + 35, + 113, + 66, + 42, + 134, + 241, + 57, + 253, + 44, + 244, + 163, + 158, + 152, + 147, + 79, + 142, + 190, + 139, + 222, + 202, + 216, + 220, + 47, + 179, + 207, + 199, + 104, + 1, + 21, + 106, + 142, + 188, + 105, + 247, + 111, + 202, + 78, + 145, + 66, + 216, + 222, + 96, + 138, + 133, + 28, + 235, + 204, + 100, + 183, + 232, + 65, + 138, + 196, + 133, + 23, + 154, + 0, + 187, + 252, + 32, + 106, + 76, + 94, + 129, + 173, + 13, + 79, + 167, + 103, + 54, + 51, + 102, + 224, + 231, + 159, + 127, + 54, + 131, + 122, + 65, + 83, + 195, + 9, + 175, + 45, + 179, + 32, + 118, + 230, + 101, + 85, + 13, + 85, + 234, + 26, + 16, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + .span(); + check_big_wrapping_pow(2766, 844, expected_bytes); + } + + #[test] + fn test_big_wrapping_mul_0() { + let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); + expected_digits.push(0); + + let mut expected = MPNat { digits: expected_digits }; + + check_big_wrapping_mul(0, 0, 1, ref expected); + } + + + #[test] + fn test_big_wrapping_mul_1() { + let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); + expected_digits.push(1); + + let mut expected = MPNat { digits: expected_digits }; + + check_big_wrapping_mul(1, 1, 1, ref expected); + } + + #[test] + fn test_big_wrapping_mul_2() { + let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); + expected_digits.push(42); + + let mut expected = MPNat { digits: expected_digits }; + + check_big_wrapping_mul(7, 6, 1, ref expected); + } + + #[test] + fn test_big_wrapping_mul_3() { + let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); + expected_digits.push(1); + expected_digits.push(18446744073709551614); + + let mut expected = MPNat { digits: expected_digits }; + + check_big_wrapping_mul(WORD_MAX.into(), WORD_MAX.into(), 2, ref expected); + } + + #[test] + fn test_big_wrapping_mul_4() { + let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); + expected_digits.push(1); + + let mut expected = MPNat { digits: expected_digits }; + + check_big_wrapping_mul(WORD_MAX.into(), WORD_MAX.into(), 1, ref expected); + } + + #[test] + fn test_big_wrapping_mul_5() { + let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); + expected_digits.push(42); + + let mut expected = MPNat { digits: expected_digits }; + + check_big_wrapping_mul(DOUBLE_WORD_MAX - 5, DOUBLE_WORD_MAX - 6, 2, ref expected); + } + + #[test] + fn test_big_wrapping_mul_6() { + let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); + expected_digits.push(6727192404480162174); + expected_digits.push(3070707315540124665); + + let mut expected = MPNat { digits: expected_digits }; + + check_big_wrapping_mul(0xa945_aa5e_429a_6d1a, 0x4072_d45d_3355_237b, 3, ref expected); + } + + #[test] + fn test_big_wrapping_mul_7() { + let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); + expected_digits.push(2063196614268007784); + expected_digits.push(7048986299143829482); + expected_digits.push(14065833420641261004); + + let mut expected = MPNat { digits: expected_digits }; + + check_big_wrapping_mul( + 0x8ae1_5515_fc92_b1c0_b473_8ce8_6bbf_7218, + 0x43e9_8b77_1f7c_aa93_6c4c_85e9_7fd0_504f, + 3, + ref expected + ); + } + + #[test] + fn test_big_sq_0() { + let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); + expected_digits.push(0); + + let mut expected = MPNat { digits: expected_digits }; + + check_big_sq(0, ref expected); + } + + #[test] + fn test_big_sq_1() { + let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); + expected_digits.push(1); + + let mut expected = MPNat { digits: expected_digits }; + + check_big_sq(1, ref expected); + } + + #[test] + fn test_big_sq_2() { + let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); + expected_digits.push(1); + expected_digits.push(18446744073709551614); + + let mut expected = MPNat { digits: expected_digits }; + + check_big_sq(WORD_MAX.into(), ref expected); + } + + #[test] + fn test_big_sq_3() { + let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); + expected_digits.push(4); + expected_digits.push(18446744073709551608); + expected_digits.push(3); + + let mut expected = MPNat { digits: expected_digits }; + + check_big_sq(2 * WORD_MAX.into(), ref expected); + } + + #[test] + fn test_big_sq_4() { + let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); + expected_digits.push(0); + + let mut expected = MPNat { digits: expected_digits }; + + check_big_sq(0, ref expected); + } + + #[test] + fn test_big_sq_5() { + let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); + expected_digits.push(2532367871917050473); + expected_digits.push(16327525306720758713); + expected_digits.push(15087745550001425684); + expected_digits.push(5708046406239628566); + + let mut expected = MPNat { digits: expected_digits }; + + check_big_sq(0x8e67904953db9a2bf6da64bf8bda866d, ref expected); + } + + + #[test] + fn test_big_sq_6() { + let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); + expected_digits.push(15092604974397072849); + expected_digits.push(3791921091882282235); + expected_digits.push(12594445234582458012); + expected_digits.push(7165619740963215273); + + let mut expected = MPNat { digits: expected_digits }; + + check_big_sq(0x9f8dc1c3fc0bf50fe75ac3bbc03124c9, ref expected); + } + + #[test] + fn test_big_sq_7() { + let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); + expected_digits.push(5163998055150312593); + expected_digits.push(8460506958278925118); + expected_digits.push(17089393176389340230); + expected_digits.push(6902937458884066534); + + let mut expected = MPNat { digits: expected_digits }; + + check_big_sq(0x9c9a17378f3d064e5eaa80eeb3850cd7, ref expected); + } + + + #[test] + fn test_big_sq_8() { + let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); + expected_digits.push(2009857620356723108); + expected_digits.push(5657228334642978155); + expected_digits.push(88889113116670247); + expected_digits.push(12075559273075793199); + + let mut expected = MPNat { digits: expected_digits }; + + check_big_sq(0xcf2025cee03025d247ad190e9366d926, ref expected); + } + + #[test] + fn test_big_sq_9() { + let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); + expected_digits.push(1); + expected_digits.push(0); + expected_digits.push(18446744073709551614); + expected_digits.push(18446744073709551615); + + let mut expected = MPNat { digits: expected_digits }; + + check_big_sq(DOUBLE_WORD_MAX, ref expected); + } + + // Test for addition overflows in the big_sq inner loop */ + #[test] + fn test_big_sq_10() { + let mut x = MPNatTrait::from_big_endian( + array![ + 0xff, + 0xff, + 0xff, + 0xff, + 0x80, + 0x00, + 0x00, + 0x00, + 0x80, + 0x00, + 0x00, + 0x00, + 0x40, + 0x00, + 0x00, + 0x00, + 0xff, + 0xff, + 0xff, + 0xff, + 0x80, + 0x00, + 0x00, + 0x00, + ] + .span() + ); + + let mut out = Felt252VecImpl::new(); + out.expand(2 * x.digits.len() + 1).unwrap(); + + big_sq(ref x, ref out); + let mut result = MPNat { digits: out }; + + let mut expected = MPNatTrait::from_big_endian( + array![ + 0xff, + 0xff, + 0xff, + 0xff, + 0x00, + 0x00, + 0x00, + 0x01, + 0x40, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x01, + 0xff, + 0xff, + 0xff, + 0xfe, + 0x40, + 0x00, + 0x00, + 0x01, + 0x90, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0xbf, + 0xff, + 0xff, + 0xff, + 0x00, + 0x00, + 0x00, + 0x00, + 0x40, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + ] + .span() + ); + + assert!(result.digits.equal_remove_trailing_zeroes(ref expected.digits)); + } + + #[test] + fn test_borrowing_sub() { + assert_eq!(borrowing_sub(0, 0, false), (0, false)); + assert_eq!(borrowing_sub(1, 0, false), (1, false)); + assert_eq!(borrowing_sub(47, 5, false), (42, false)); + assert_eq!(borrowing_sub(101, 7, true), (93, false)); + assert_eq!(borrowing_sub(0x00_00_01_00, 0x00_00_02_00, false), (WORD_MAX - 0xFF, true)); + assert_eq!(borrowing_sub(0x00_00_01_00, 0x00_00_10_00, true), (WORD_MAX - 0x0F_00, true)); + } + + + #[test] + fn test_shifted_carrying_mul() { + assert_eq!(shifted_carrying_mul(0, 0, 0, 0), (0, 0)); + assert_eq!(shifted_carrying_mul(0, 6, 7, 0), (42, 0)); + assert_eq!(shifted_carrying_mul(0, 6, 7, 8), (50, 0)); + assert_eq!(shifted_carrying_mul(5, 6, 7, 8), (55, 0)); + assert_eq!( + shifted_carrying_mul( + WORD_MAX - 0x11, WORD_MAX - 0x1234, WORD_MAX - 0xABCD, WORD_MAX - 0xFF + ), + (0x0C_38_0C_94, WORD_MAX - 0xBE00) + ); + assert_eq!( + shifted_carrying_mul(WORD_MAX, WORD_MAX, WORD_MAX, WORD_MAX), (WORD_MAX, WORD_MAX) + ); + } +} diff --git a/crates/utils/src/crypto/modexp/mpnat.cairo b/crates/utils/src/crypto/modexp/mpnat.cairo index 15cc4f48d..de35c28ef 100644 --- a/crates/utils/src/crypto/modexp/mpnat.cairo +++ b/crates/utils/src/crypto/modexp/mpnat.cairo @@ -683,3 +683,367 @@ impl MPNatTraitImpl of MPNatTrait { } } } + +#[cfg(test)] +mod tests { + use alexandria_data_structures::vec::VecTrait; + use alexandria_data_structures::vec::{Felt252Vec, Felt252VecImpl}; + use core::result::ResultTrait; + use core::traits::Into; + + use utils::crypto::modexp::arith::{ + mod_inv, monsq, monpro, compute_r_mod_n, in_place_shl, in_place_shr, big_wrapping_pow, + big_wrapping_mul, big_sq, borrowing_sub, shifted_carrying_mul + }; + use utils::crypto::modexp::mpnat::{ + MPNat, MPNatTrait, WORD_MAX, DOUBLE_WORD_MAX, Word, DoubleWord, WORD_BYTES + }; + use utils::helpers::{Felt252VecTrait, ToBytes, FromBytes}; + use utils::math::{Bitshift, WrappingBitshift}; + + // the tests are taken from + // [aurora-engine](https://github.com/aurora-is-near/aurora-engine/blob/1213f2c7c035aa523601fced8f75bef61b4728ab/engine-modexp/src/mpnat.rs#L825) + + pub fn mp_nat_to_u128(ref x: MPNat) -> u128 { + let result = x.digits.to_le_bytes(); + let mut i: usize = 0; + loop { + if i == result.len() { + break; + }; + + i += 1; + }; + result.from_le_bytes().unwrap() + } + + fn check_modpow_even(base: u128, exp: u128, modulus: u128, expected: u128) { + let mut x = MPNatTrait::from_big_endian(base.to_be_bytes()); + let mut m = MPNatTrait::from_big_endian(modulus.to_be_bytes()); + let mut result = x.modpow(exp.to_be_bytes_padded(), ref m); + let result = mp_nat_to_u128(ref result); + assert_eq!(result, expected); + } + + fn check_modpow_with_power_of_two(base: u128, exp: u128, modulus: u128, expected: u128) { + let mut x = MPNatTrait::from_big_endian(base.to_be_bytes()); + let mut m = MPNatTrait::from_big_endian(modulus.to_be_bytes()); + let mut result = x.modpow_with_power_of_two(exp.to_be_bytes(), ref m); + let result = mp_nat_to_u128(ref result); + assert_eq!(result, expected); + } + + fn check_modpow_montgomery(base: u128, exp: u128, modulus: u128, expected: u128) { + let mut x = MPNatTrait::from_big_endian(base.to_be_bytes()); + let mut m = MPNatTrait::from_big_endian(modulus.to_be_bytes()); + let mut result = x.modpow_montgomery(exp.to_be_bytes(), ref m); + let result = mp_nat_to_u128(ref result); + assert_eq!(result, expected, "({base} ^ {exp}) % {modulus} failed check_modpow_montgomery"); + } + + fn check_sub_to_same_size(a: u128, n: u128) { + let mut x = MPNatTrait::from_big_endian(a.to_be_bytes()); + let mut y = MPNatTrait::from_big_endian(n.to_be_bytes()); + x.sub_to_same_size(ref y); + + assert!(x.digits.len() <= y.digits.len()); + let result = mp_nat_to_u128(ref x); + assert_eq!(result % n, a % n, "{a} % {n} failed sub_to_same_size check"); + } + + + fn check_is_odd(n: u128) { + let mut mp = MPNatTrait::from_big_endian(n.to_be_bytes()); + assert_eq!(mp.is_odd(), n % 2 == 1, "{n} failed is_odd test"); + } + + fn check_is_p2(n: u128, expected_result: bool) { + let mut mp = MPNatTrait::from_big_endian(n.to_be_bytes()); + assert_eq!(mp.is_power_of_two(), expected_result, "{n} failed is_power_of_two test"); + } + + #[test] + #[available_gas(100000000000000)] + fn test_modpow_even() { + check_modpow_even(3, 5, 500, 243); + check_modpow_even(3, 5, 20, 3); + check_modpow_even( + 0x2ff4f4df4c518867207c84b57a77aa50, + 0xca83c2925d17c577c9a03598b6f360, + 0xf863d4f17a5405d84814f54c92f803c8, + 0x8d216c9a1fb275ed18eb340ed43cacc0, + ); + check_modpow_even( + 0x13881e1614244c56d15ac01096b070e7, + 0x336df5b4567cbe4c093271dc151e6c72, + 0x7540f399a0b6c220f1fc60d2451a1ff0, + 0x1251d64c552e8f831f5b841d2811f9c1, + ); + check_modpow_even( + 0x774d5b2494a449d8f22b22ea542d4ddf, + 0xd2f602e1688f271853e7794503c2837e, + 0xa80d20ebf75f92192159197b60f36e8e, + 0x3fbbba42489b27fc271fb39f54aae2e1, + ); + check_modpow_even( + 0x756e409cc3583a6b68ae27ccd9eb3d50, + 0x16dafb38a334288954d038bedbddc970, + 0x1f9b2237f09413d1fc44edf9bd02b8bc, + 0x9347445ac61536a402723cd07a3f5a4, + ); + check_modpow_even( + 0x6dcb8405e2cc4dcebee3e2b14861b47d, + 0xe6c1e5251d6d5deb8dddd0198481d671, + 0xe34a31d814536e8b9ff6cc5300000000, + 0xaa86af638386880334694967564d0c3d, + ); + check_modpow_even( + 0x9c12fe4a1a97d17c1e4573247a43b0e5, + 0x466f3e0a2e8846b8c48ecbf612b96412, + 0x710d7b9d5718acff0000000000000000, + 0x569bf65929e71cd10a553a8623bdfc99, + ); + check_modpow_even( + 0x6d018fdeaa408222cb10ff2c36124dcf, + 0x8e35fc05d490bb138f73c2bc284a67a7, + 0x6c237160750d78400000000000000000, + 0x3fe14e11392c6c6be8efe956c965d5af, + ); + } + + #[test] + fn test_modpow_with_power_of_two() { + check_modpow_with_power_of_two(3, 2, 1.wrapping_shl(30), 9); + check_modpow_with_power_of_two(3, 5, 1.wrapping_shl(30), 243); + check_modpow_with_power_of_two(3, 1_000_000, 1.wrapping_shl(30), 641836289); + check_modpow_with_power_of_two(3, 1_000_000, 1.wrapping_shl(31), 1715578113); + check_modpow_with_power_of_two(3, 1_000_000, 1.wrapping_shl(32), 3863061761); + check_modpow_with_power_of_two( + 0xabcd_ef01_2345_6789_1111, 0x1234_5678_90ab_cdef, 1.wrapping_shl(5), 17, + ); + check_modpow_with_power_of_two( + 0x3f47_9dc0_d5b9_6003, + 0xa180_e045_e314_8581, + 1.wrapping_shl(118), + 0x0028_3d19_e6cc_b8a0_e050_6abb_b9b1_1a03, + ); + } + + #[test] + #[available_gas(100000000000000)] + fn test_modpow_montgomery() { + check_modpow_montgomery(3, 5, 0x9346_9d50_1f74_d1c1, 243); + check_modpow_montgomery(3, 5, 19, 15); + check_modpow_montgomery( + 0x5c4b74ec760dfb021499f5c5e3c69222, + 0x62b2a34b21cf4cc036e880b3fb59fe09, + 0x7b799c4502cd69bde8bb12601ce3ff15, + 0x10c9d9071d0b86d6a59264d2f461200, + ); + check_modpow_montgomery( + 0xadb5ce8589030e3a9112123f4558f69c, + 0xb002827068f05b84a87431a70fb763ab, + 0xc4550871a1cfc67af3e77eceb2ecfce5, + 0x7cb78c0e1c1b43f6412e9d1155ea96d2, + ); + check_modpow_montgomery( + 0x26eb51a5d9bf15a536b6e3c67867b492, + 0xddf007944a79bf55806003220a58cc6, + 0xc96275a80c694a62330872b2690f8773, + 0x23b75090ead913def3a1e0bde863eda7, + ); + check_modpow_montgomery( + 0xb93fa81979e597f548c78f2ecb6800f3, + 0x5fad650044963a271898d644984cb9f0, + 0xbeb60d6bd0439ea39d447214a4f8d3ab, + 0x354e63e6a5e007014acd3e5ea88dc3ad, + ); + check_modpow_montgomery( + 0x1993163e4f578869d04949bc005c878f, + 0x8cb960f846475690259514af46868cf5, + 0x52e104dc72423b534d8e49d878f29e3b, + 0x2aa756846258d5cfa6a3f8b9b181a11c, + ); + } + + #[test] + fn test_sub_to_same_size() { + check_sub_to_same_size(0x10_00_00_00_00, 0xFF_00_00_00); + check_sub_to_same_size(0x10_00_00_00_00, 0x01_00_00_00); + check_sub_to_same_size(0x35_00_00_00_00, 0x01_00_00_00); + check_sub_to_same_size(0xEF_00_00_00_00_00_00, 0x02_FF_FF_FF); + + let n = 10; + let a = 57 + 2 * n + 0x1234_0000_0000 * n + 0x000b_0000_0000_0000_0000 * n; + check_sub_to_same_size(a, n); + + // Test that borrow equals self_most_sig at end of sub_to_same_size */ + { + let mut x = MPNatTrait::from_big_endian( + array![ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0xae, + 0x5f, + 0xf0, + 0x8b, + 0xfc, + 0x02, + 0x71, + 0xa4, + 0xfe, + 0xe0, + 0x49, + 0x02, + 0xc9, + 0xd9, + 0x12, + 0x61, + 0x8e, + 0xf5, + 0x02, + 0x2c, + 0xa0, + 0x00, + 0x00, + 0x00, + ] + .span() + ); + let mut y = MPNatTrait::from_big_endian( + array![ + 0xae, + 0x5f, + 0xf0, + 0x8b, + 0xfc, + 0x02, + 0x71, + 0xa4, + 0xfe, + 0xe0, + 0x49, + 0x0f, + 0x70, + 0x00, + 0x00, + 0x00, + ] + .span() + ); + x.sub_to_same_size(ref y); + } + + // Additional test for sub_to_same_size q_hat/r_hat adjustment logic */ + { + let mut x = MPNatTrait::from_big_endian( + array![ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0xff, + 0xff, + 0xff, + 0xff, + 0x00, + 0x00, + 0x00, + 0x00, + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + ] + .span() + ); + let mut y = MPNatTrait::from_big_endian( + array![ + 0xff, + 0xff, + 0xff, + 0xff, + 0x00, + 0x00, + 0x00, + 0x00, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0x00, + 0x00, + 0x00, + ] + .span() + ); + x.sub_to_same_size(ref y); + } + } + + #[test] + #[available_gas(100000000000000)] + fn test_mp_nat_is_odd() { + let mut n = 0; + loop { + if n == 1025 { + break; + }; + check_is_odd(n); + + n += 1; + }; + + let mut n = 0xFF_FF_FF_FF_00_00_00_00; + + loop { + if n == 0xFF_FF_FF_FF_00_00_04_01 { + break; + } + + check_is_odd(n); + n += 1; + }; + } + + #[test] + fn test_mp_nat_is_power_of_two() { + check_is_p2(0, false); + check_is_p2(1, true); + check_is_p2(1327, false); + check_is_p2((1.shl(1)) + (1.shl(35)), false); + check_is_p2(1.shl(1), true); + check_is_p2(1.shl(2), true); + check_is_p2(1.shl(3), true); + check_is_p2(1.shl(4), true); + check_is_p2(1.shl(5), true); + check_is_p2(1.shl(31), true); + check_is_p2(1.shl(32), true); + check_is_p2(1.shl(64), true); + check_is_p2(1.shl(65), true); + check_is_p2(1.shl(127), true); + } +} diff --git a/crates/utils/src/lib.cairo b/crates/utils/src/lib.cairo index d0edbfe64..da4c7eead 100644 --- a/crates/utils/src/lib.cairo +++ b/crates/utils/src/lib.cairo @@ -15,7 +15,6 @@ mod serialization; mod set; mod storage; -#[cfg(target: 'test')] mod test_data; mod traits; diff --git a/crates/utils/src/math.cairo b/crates/utils/src/math.cairo index a41784249..43478712e 100644 --- a/crates/utils/src/math.cairo +++ b/crates/utils/src/math.cairo @@ -460,14 +460,6 @@ mod tests { assert(0_u256.pow(123456) == 0, '0^n should be 0'); } - #[test] - #[available_gas(2000000)] - #[should_panic(expected: ('Out of gas',))] - fn test_wrapping_slow_pow_runs_out_of_gas() { - let exp = 3_u256.wrapping_fpow(10); - 3_u256.wrapping_spow(exp); - } - #[test] fn test_wrapping_fast_pow() { let exp = 3_u256.wrapping_fpow(10); diff --git a/crates/utils/tests/lib.cairo b/crates/utils/tests/lib.cairo deleted file mode 100644 index c20ca6fef..000000000 --- a/crates/utils/tests/lib.cairo +++ /dev/null @@ -1 +0,0 @@ -mod test_modexp; diff --git a/crates/utils/tests/test_modexp.cairo b/crates/utils/tests/test_modexp.cairo deleted file mode 100644 index 351554425..000000000 --- a/crates/utils/tests/test_modexp.cairo +++ /dev/null @@ -1,2 +0,0 @@ -mod test_arith; -mod test_mpnat; diff --git a/crates/utils/tests/test_modexp/test_arith.cairo b/crates/utils/tests/test_modexp/test_arith.cairo deleted file mode 100644 index bbb30755e..000000000 --- a/crates/utils/tests/test_modexp/test_arith.cairo +++ /dev/null @@ -1,1931 +0,0 @@ -use alexandria_data_structures::vec::VecTrait; -use alexandria_data_structures::vec::{Felt252Vec, Felt252VecImpl}; -use core::result::ResultTrait; -use core::traits::Into; -use integer::u128_wrapping_sub; - -use utils::crypto::modexp::arith::{ - mod_inv, monsq, monpro, compute_r_mod_n, in_place_shl, in_place_shr, big_wrapping_pow, - big_wrapping_mul, big_sq, borrowing_sub, shifted_carrying_mul -}; -use utils::crypto::modexp::mpnat::{ - MPNat, MPNatTrait, WORD_MAX, DOUBLE_WORD_MAX, BASE, Word, DoubleWord, WORD_BYTES -}; -use utils::helpers::{Felt252VecTrait, ToBytes}; -use utils::helpers::{U128Trait}; -use utils::math::{WrappingMul, WrappingBitshift, WrappingExponentiation}; -use utils_tests::test_modexp::test_mpnat::{mp_nat_to_u128}; - -// the tests are taken from -// [aurora-engine](https://github.com/aurora-is-near/aurora-engine/blob/1213f2c7c035aa523601fced8f75bef61b4728ab/engine-modexp/src/arith.rs#L401) - -fn check_monsq(x: u128, n: u128) { - let mut a = MPNatTrait::from_big_endian(x.to_be_bytes_padded()); - let mut m = MPNatTrait::from_big_endian(n.to_be_bytes_padded()); - let n_prime = WORD_MAX - mod_inv(m.digits[0]) + 1; - - let mut output = Felt252VecImpl::new(); - output.expand(2 * m.digits.len() + 1).unwrap(); - - monsq(ref a, ref m, n_prime, ref output); - let mut result = MPNat { digits: output }; - - let mut output = Felt252VecImpl::new(); - output.expand(m.digits.len() + 2).unwrap(); - let mut tmp = MPNat { digits: a.digits.duplicate() }; - monpro(ref a, ref tmp, ref m, n_prime, ref output); - - let mut expected = MPNat { digits: output }; - - assert!(result.digits.equal_remove_trailing_zeroes(ref expected.digits)); -} - -fn check_monpro(x: u128, y: u128, n: u128, ref expected: MPNat) { - let mut a = MPNatTrait::from_big_endian(x.to_be_bytes_padded()); - let mut b = MPNatTrait::from_big_endian(y.to_be_bytes_padded()); - let mut m = MPNatTrait::from_big_endian(n.to_be_bytes()); - let n_prime = WORD_MAX - mod_inv(m.digits[0]) + 1; - - let mut output = Felt252VecImpl::new(); - output.expand(m.digits.len() + 2).unwrap(); - monpro(ref a, ref b, ref m, n_prime, ref output); - let mut result = MPNat { digits: output }; - - assert!(result.digits.equal_remove_trailing_zeroes(ref expected.digits)); -} - - -fn check_r_mod_n(n: u128, ref expected: MPNat) { - let mut x = MPNatTrait::from_big_endian(n.to_be_bytes_padded()); - let mut out: Felt252Vec = Felt252VecImpl::new(); - out.expand(x.digits.len()).unwrap(); - compute_r_mod_n(ref x, ref out); - let mut result = MPNat { digits: out }; - assert!(result.digits.equal_remove_trailing_zeroes(ref expected.digits)); -} - -fn check_in_place_shl(n: u128, shift: u32) { - let mut x = MPNatTrait::from_big_endian(n.to_be_bytes_padded()); - in_place_shl(ref x.digits, shift); - let mut result = mp_nat_to_u128(ref x); - - let mask = u128_wrapping_sub(BASE.wrapping_pow(x.digits.len().into()), 1); - assert_eq!(result, n.wrapping_shl(shift.into()) & mask); -} - -fn check_in_place_shr(n: u128, shift: u32) { - let mut x = MPNatTrait::from_big_endian(n.to_be_bytes_padded()); - in_place_shr(ref x.digits, shift); - let mut result = mp_nat_to_u128(ref x); - - assert_eq!(result, n.wrapping_shr(shift.into())); -} - -fn check_mod_inv(n: Word) { - let n_inv = mod_inv(n); - assert_eq!(n.wrapping_mul(n_inv), 1); -} - -fn check_big_wrapping_pow(a: u128, b: u32, expected_bytes: Span) { - let mut x = MPNatTrait::from_big_endian(a.to_be_bytes_padded()); - let mut y = b.to_be_bytes_padded(); - - let mut scratch = Felt252VecImpl::new(); - scratch.expand(1 + (expected_bytes.len() / WORD_BYTES)).unwrap(); - - let mut result = big_wrapping_pow(ref x, y, ref scratch); - - let mut expected = MPNatTrait::from_big_endian(expected_bytes); - assert!(result.digits.equal_remove_trailing_zeroes(ref expected.digits)); -} - -fn check_big_wrapping_mul(a: u128, b: u128, output_digits: usize, ref expected: MPNat) { - let mut x = MPNatTrait::from_big_endian(a.to_be_bytes_padded()); - let mut y = MPNatTrait::from_big_endian(b.to_be_bytes_padded()); - - let mut out = Felt252VecImpl::new(); - out.expand(output_digits).unwrap(); - - big_wrapping_mul(ref x, ref y, ref out); - let mut result = MPNat { digits: out }; - - assert!(result.digits.equal_remove_trailing_zeroes(ref expected.digits)); -} - -fn check_big_sq(a: u128, ref expected: MPNat) { - let mut x = MPNatTrait::from_big_endian(a.to_be_bytes_padded()); - let mut out = Felt252VecImpl::new(); - out.expand(2 * x.digits.len() + 1).unwrap(); - - big_sq(ref x, ref out); - - let mut result = MPNat { digits: out }; - assert!(result.digits.equal_remove_trailing_zeroes(ref expected.digits)); -} - -#[test] -fn test_monsq_alpha() { - let mut x = Felt252VecImpl::new(); - x.push(0xf72fc634c83435bc); - x.push(0xa6b0ce70ac511873); - let mut x = MPNat { digits: x }; - - let mut y = Felt252VecImpl::new(); - y.push(0xf3e77eceb2ecfce5); - y.push(0xc4550871a1cfc67a); - let mut y = MPNat { digits: y }; - - let n_prime = 0xa51080a4eb8b9f13; - let mut scratch = Felt252VecImpl::new(); - scratch.expand(5).unwrap(); - - monsq(ref x, ref y, n_prime, ref scratch); -} - - -#[test] -fn test_monsq_0() { - check_monsq(1, 31); -} - -#[test] -fn test_monsq_1() { - check_monsq(6, 31); -} - -#[test] -fn test_monsq_2() { - // This example is intentionally chosen because 5 * 5 = 25 = 0 mod 25, - // therefore it requires the final subtraction step in the algorithm. - check_monsq(5, 25); -} - -#[test] -fn test_monsq_3() { - check_monsq(0x1FFF_FFFF_FFFF_FFF0, 0x1FFF_FFFF_FFFF_FFF1); -} - -#[test] -fn test_monsq_4() { - check_monsq(0x16FF_221F_CB7D, 0x011E_842B_6BAA_5017_EBF2_8293); -} - -#[test] -fn test_monsq_5() { - check_monsq(0x0A2D_63F5_CFF9, 0x1F3B_3BD9_43EF); -} - -#[test] -fn test_monsq_6() { - check_monsq(0xa6b0ce71a380dea7c83435bc, 0xc4550871a1cfc67af3e77eceb2ecfce5,); -} - -#[test] -fn test_monpro_0() { - let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); - expected_digits.push(2); - let mut expected = MPNat { digits: expected_digits }; - - check_monpro(1, 1, 31, ref expected); -} - -#[test] -fn test_monpro_1() { - let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); - expected_digits.push(22); - let mut expected = MPNat { digits: expected_digits }; - - check_monpro(6, 7, 31, ref expected); -} - -#[test] -fn test_monpro_2() { - let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); - expected_digits.push(0); - let mut expected = MPNat { digits: expected_digits }; - - // This example is intentionally chosen because 5 * 7 = 35 = 0 mod 35, - // therefore it requires the final subtraction step in the algorithm. - check_monpro(5, 7, 35, ref expected); -} - -#[test] -fn test_monpro_3() { - let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); - expected_digits.push(384307168202282284); - - let mut expected = MPNat { digits: expected_digits }; - - // This example is intentionally chosen because 5 * 7 = 35 = 0 mod 35, - // therefore it requires the final subtraction step in the algorithm. - check_monpro(0x1FFF_FFFF_FFFF_FFF0, 0x1234, 0x1FFF_FFFF_FFFF_FFF1, ref expected); -} - -#[test] -fn test_monpro_4() { - let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); - expected_digits.push(0); - let mut expected = MPNat { digits: expected_digits }; - - // This example is intentionally chosen because 5 * 7 = 35 = 0 mod 35, - // therefore it requires the final subtraction step in the algorithm. - check_monpro(0x16FF_221F_CB7D, 0x0C75_8535_434F, 0x011E_842B_6BAA_5017_EBF2_8293, ref expected); -} - -#[test] -fn test_monpro_5() { - let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); - expected_digits.push(4425093052866); - let mut expected = MPNat { digits: expected_digits }; - - // This example is intentionally chosen because 5 * 7 = 35 = 0 mod 35, - // therefore it requires the final subtraction step in the algorithm. - check_monpro(0x0A2D_63F5_CFF9, 0x1B21_FF3C_FA8E, 0x1F3B_3BD9_43EF, ref expected); -} - -#[test] -fn test_r_mod_n_0() { - let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); - expected_digits.push(1); - let mut expected = MPNat { digits: expected_digits }; - - check_r_mod_n(0x01_00_00_00_01, ref expected); -} - -#[test] -fn test_r_mod_n_1() { - let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); - expected_digits.push(549722259457); - let mut expected = MPNat { digits: expected_digits }; - - check_r_mod_n(0x80_00_00_00_01, ref expected); -} - -#[test] -fn test_r_mod_n_2() { - let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); - expected_digits.push(1); - let mut expected = MPNat { digits: expected_digits }; - - check_r_mod_n(0xFFFF_FFFF_FFFF_FFFF, ref expected); -} - -#[test] -fn test_r_mod_n_3() { - let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); - expected_digits.push(1); - let mut expected = MPNat { digits: expected_digits }; - - check_r_mod_n(0x0001_0000_0000_0000_0001, ref expected); -} - -#[test] -fn test_r_mod_n_4() { - let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); - expected_digits.push(18446181123756130305); - expected_digits.push(32767); - - let mut expected = MPNat { digits: expected_digits }; - - check_r_mod_n(0x8000_0000_0000_0000_0001, ref expected); -} - -#[test] -fn test_r_mod_n_5() { - let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); - expected_digits.push(3491005389787767287); - expected_digits.push(2668502225); - - let mut expected = MPNat { digits: expected_digits }; - - check_r_mod_n(0xbf2d_c9a3_82c5_6e85_b033_7651, ref expected); -} - -#[test] -fn test_r_mod_n_6() { - let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); - expected_digits.push(4294967296); - - let mut expected = MPNat { digits: expected_digits }; - - check_r_mod_n(0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF, ref expected); -} - -#[test] -fn test_in_place_shl() { - check_in_place_shl(0, 0); - check_in_place_shl(1, 10); - check_in_place_shl(WORD_MAX.into(), 5); - check_in_place_shl(DOUBLE_WORD_MAX.into(), 16); -} - -#[test] -fn test_in_place_shr() { - check_in_place_shr(0, 0); - check_in_place_shr(1, 10); - check_in_place_shr(0x1234_5678, 10); - check_in_place_shr(WORD_MAX.into(), 5); - check_in_place_shr(DOUBLE_WORD_MAX, 16); -} - -#[test] -#[available_gas(10000000000000)] -fn test_mod_inv_0() { - let mut i = 1; - loop { - if i == 1025 { - break; - }; - - check_mod_inv(2 * i - 1); - i += 1; - } -} - -#[test] -#[available_gas(10000000000000)] -fn test_mod_inv_1() { - let mut i = 0; - loop { - if i == 1025 { - break; - }; - - check_mod_inv(0xFF_FF_FF_FF - 2 * i); - i += 1; - } -} - -#[test] -fn test_big_wrapping_pow_0() { - let expected_bytes: Span = array![1].span(); - check_big_wrapping_pow(1, 1, expected_bytes); -} - -#[test] -fn test_big_wrapping_pow_1() { - let expected_bytes: Span = array![100].span(); - - check_big_wrapping_pow(10, 2, expected_bytes); -} - -#[test] -fn test_big_wrapping_pow_2() { - let expected_bytes: Span = array![1, 0, 0, 0, 0].span(); - - check_big_wrapping_pow(2, 32, expected_bytes); -} - -#[test] -fn test_big_wrapping_pow_3() { - let expected_bytes: Span = array![1, 0, 0, 0, 0, 0, 0, 0, 0].span(); - check_big_wrapping_pow(2, 64, expected_bytes); -} - -#[test] -#[available_gas(10000000000000)] -fn test_big_wrapping_pow_4() { - let expected_bytes: Span = array![ - 3, - 218, - 116, - 252, - 230, - 21, - 167, - 46, - 59, - 185, - 199, - 194, - 149, - 140, - 133, - 157, - 60, - 102, - 160, - 27, - 104, - 79, - 16, - 104, - 20, - 104, - 116, - 207, - 214, - 100, - 237, - 159, - 0, - 245, - 249, - 156, - 52, - 33, - 217, - 113, - 130, - 6, - 65, - 78, - 49, - 141, - 141, - 160, - 29, - 125, - 168, - 236, - 88, - 174, - 146, - 81, - 137, - 165, - 242, - 90, - 251, - 115, - 144, - 169, - 141, - 66, - 207, - 230, - 56, - 199, - 140, - 109, - 7, - 99, - 35, - 155, - 88, - 29, - 90, - 192, - 55, - 127, - 112, - 26, - 176, - 181, - 13, - 72, - 107, - 209, - 1, - 210, - 88, - 233, - 185, - 87, - 108, - 122, - 168, - 137, - 255, - 36, - 201, - 185, - 31, - 36, - 51, - 208, - 64, - 154, - 113, - 233, - 71, - 95, - 35, - 253, - 0, - 3, - 159, - 183, - 10, - 83, - 233, - 88, - 96, - 19, - 104, - 229, - 132, - 73, - 219, - 152, - 126, - 215, - 249, - 46, - 110, - 157, - 234, - 2, - 100, - 178, - 150, - 110, - 217, - 246, - 128, - 219, - 121, - 21, - 234, - 55, - 101, - 81, - 207, - 191, - 200, - 201, - 2, - 40, - 13, - 80, - 107, - 226, - 143, - 164, - 254, - 91, - 54, - 46, - 254, - 7, - 14, - 136, - 149, - 194, - 6, - 191, - 14, - 49, - 140, - 193, - 40, - 1, - 138, - 165, - 82, - 34, - 33, - 169, - 41, - 136, - 130, - 47, - 84, - 173, - 58, - 121, - 192, - 247, - 98, - 237, - 165, - 215, - 161, - 198, - 87, - 228, - 76, - 160, - 66, - 78, - 169, - 139, - 234, - 169, - 83, - 15, - 16, - 192, - 170, - 71, - 227, - 232, - 116, - 189, - 81, - 64, - 104, - 182, - 129, - 203, - 191, - 210, - 151, - 132, - 254, - 239, - 19, - 138, - 49, - 113, - 140, - 77, - 38, - 49, - 117, - 127, - 203, - 123, - 127, - 49, - 32, - 61, - 108, - 120, - 133, - 119, - 8, - 232, - 84, - 57, - 103, - 197, - 160, - 65, - 191, - 82, - 253, - 60, - 191, - 209, - 63, - 176, - 43, - 33, - 54, - 75, - 17, - 73, - 222, - 198, - 80, - 5, - 14, - 50, - 117, - 156, - 77, - 147, - 190, - 230, - 143, - 47, - 149, - 180, - 203, - 144, - 202, - 102, - 231, - 2, - 91, - 22, - 101, - 178, - 211, - 233, - 109, - 156, - 72, - 151, - 199, - 189, - 90, - 76, - 21, - 112, - 21, - 2, - 44, - 96, - 42, - 141, - 217, - 142, - 23, - 75, - 248, - 209, - 26, - 3, - 198, - 103, - 227, - 103, - 140, - 99, - 75, - 211, - 152, - 109, - 19, - 72, - 6, - 116, - 67, - 70, - 32, - 45, - 5, - 113, - 179, - 252, - 2, - 202, - 115, - 244, - 68, - 128, - 156, - 233, - 227, - 211, - 5, - 146, - 147, - 186, - 34, - 3, - 105, - 147, - 64, - 79, - 172, - 141, - 14, - 60, - 69, - 249, - 169, - 76, - 252, - 84, - 151, - 49, - 81, - 246, - 185, - 181, - 181, - 226, - 28, - 152, - 30, - 47, - 248, - 103, - 21, - 184, - 140, - 193, - 112, - 139, - 250, - 206, - 35, - 180, - 122, - 32, - 151, - 105, - 30, - 193, - 68, - 232, - 170, - 174, - 254, - 143, - 29, - 165, - 194, - 14, - 164, - 35, - 25, - 250, - 86, - 76, - 213, - 159, - 21, - 0, - 212, - 146, - 21, - 8, - 180, - 73, - 250, - 116, - 137, - 221, - 20, - 22, - 146, - 169, - 120, - 166, - 229, - 226, - 136, - 201, - 177, - 49, - 21, - 228, - 191, - 246, - 26, - 36, - 183, - 175, - 137, - 71, - 4, - 46, - 235, - 197, - 99, - 0, - 142, - 97, - 184, - 34, - 84, - 254, - 41, - 95, - 198, - 178, - 48, - 105, - 215, - 72, - 155, - 238, - 51, - 164, - 52, - 179, - 126, - 254, - 100, - 35, - 236, - 63, - 215, - 238, - 217, - 239, - 229, - 160, - 192, - 33, - 82, - 165, - 81, - 149, - 186, - 53, - 109, - 184, - 187, - 186, - 8, - 43, - 249, - 20, - 37, - 255, - 241, - 18, - 61, - 97, - 229, - 29, - 201, - 144, - 92, - 202, - 215, - 161, - 165, - 133, - 89, - 180, - 246, - 37, - 16, - 133, - 226, - 209, - 23, - 61, - 241, - 25, - 9, - 150, - 154, - 150, - 133, - 210, - 62, - 115, - 34, - 201, - 187, - 217, - 3, - 82, - 102, - 174, - 233, - 33, - 31, - 7, - 4, - 88, - 70, - 173, - 157, - 111, - 96, - 102, - 223, - 157, - 224, - 158, - 235, - 191, - 55, - 219, - 218, - 146, - 233, - 242, - 250, - 170, - 100, - 68, - 37, - 56, - 251, - 109, - 112, - 217, - 209, - 46, - 229, - 198, - 198, - 156, - 198, - 70, - 76, - 131, - 79, - 40, - 25, - 176, - 21, - 43, - 31, - 121, - 204, - 225, - 128, - 182, - 191, - 148, - 72, - 22, - 112, - 63, - 223, - 182, - 155, - 177, - 183, - 72, - 111, - 6, - 196, - 250, - 189, - 45, - 97, - 182, - 14, - 219, - 189, - 50, - 226, - 91, - 1, - 86, - 95, - 131, - 120, - 224, - 0, - 71, - 28, - 151, - 69, - 24, - 93, - 82, - 237, - 136, - 103, - 90, - 247, - 173, - 204, - 121, - 199, - 17, - 164, - 80, - 49, - 183, - 10, - 200, - 235, - 56, - 72, - 72, - 147, - 150, - 223, - 110, - 165, - 60, - 13, - 251, - 42, - 193, - 78, - 212, - 166, - 178, - 103, - 19, - 35, - 69, - 10, - 137, - 62, - 13, - 90, - 203, - 126, - 203, - 207, - 190, - 184, - 89, - 118, - 186, - 203, - 6, - 115, - 158, - 168, - 35, - 206, - 227, - 48, - 221, - 252, - 190, - 166, - 249, - 96, - 92, - 244, - 77, - 213, - 119, - 44, - 207, - 17, - 16, - 118, - 104, - 106, - 188, - 205, - 5, - 240, - 14, - 181, - 227, - 4, - 11, - 32, - 91, - 224, - 78, - 175, - 49, - 19, - 12, - 233, - 131, - 141, - 47, - 32, - 14, - 195, - 214, - 77, - 158, - 39, - 114, - 167, - 37, - 16, - 249, - 73, - 167, - 230, - 165, - 19, - 4, - 199, - 227, - 251, - 184, - 131, - 137, - 74, - 176, - 116, - 35, - 182, - 121, - 62, - 114, - 64, - 163, - 84, - 208, - 111, - 56, - 191, - 88, - 130, - 64, - 64, - 181, - 162, - 53, - 34, - 16, - 179, - 155, - 137, - 138, - 101, - 121, - 73, - 234, - 189, - 100, - 141, - 122, - 123, - 79, - 200, - 90, - 208, - 83, - 253, - 124, - 125, - 116, - 72, - 138, - 63, - 42, - 144, - 200, - 73, - 233, - 113, - 143, - 85, - 140, - 16, - 240, - 230, - 42, - 114, - 137, - 193, - 10, - 129, - 124, - 193, - 104, - 177, - 55, - 156, - 173, - 135, - 168, - 217, - 1, - 46, - 41, - 132, - 17, - 222, - 178, - 226, - 24, - 108, - 117, - 199, - 171, - 232, - 129, - 82, - 225, - 214, - 105, - 94, - 188, - 72, - 62, - 91, - 193, - 188, - 18, - 33, - 131, - 18, - 194, - 70, - 151, - 187, - 42, - 5, - 62, - 85, - 38, - 134, - 252, - 183, - 227, - 120, - 19, - 152, - 243, - 235, - 114, - 208, - 78, - 57, - 113, - 217, - 182, - 125, - 195, - 64, - 229, - 232, - 54, - 118, - 11, - 119, - 163, - 235, - 12, - 67, - 90, - 246, - 76, - 219, - 200, - 124, - 234, - 41, - 172, - 31, - 167, - 213, - 127, - 100, - 163, - 72, - 44, - 107, - 171, - 229, - 189, - 68, - 201, - 244, - 154, - 27, - 172, - 228, - 234, - 192, - 156, - 127, - 170, - 9, - 78, - 166, - 249, - 154, - 178, - 179, - 172, - 220, - 205, - 220, - 60, - 86, - 98, - 134, - 60, - 134, - 89, - 244, - 187, - 231, - 128, - 6, - 109, - 152, - 251, - 44, - 208, - 238, - 169, - 71, - 51, - 192, - 242, - 57, - 8, - 62, - 206, - 94, - 94, - 25, - 220, - 160, - 175, - 35, - 113, - 66, - 42, - 134, - 241, - 57, - 253, - 44, - 244, - 163, - 158, - 152, - 147, - 79, - 142, - 190, - 139, - 222, - 202, - 216, - 220, - 47, - 179, - 207, - 199, - 104, - 1, - 21, - 106, - 142, - 188, - 105, - 247, - 111, - 202, - 78, - 145, - 66, - 216, - 222, - 96, - 138, - 133, - 28, - 235, - 204, - 100, - 183, - 232, - 65, - 138, - 196, - 133, - 23, - 154, - 0, - 187, - 252, - 32, - 106, - 76, - 94, - 129, - 173, - 13, - 79, - 167, - 103, - 54, - 51, - 102, - 224, - 231, - 159, - 127, - 54, - 131, - 122, - 65, - 83, - 195, - 9, - 175, - 45, - 179, - 32, - 118, - 230, - 101, - 85, - 13, - 85, - 234, - 26, - 16, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - ] - .span(); - check_big_wrapping_pow(2766, 844, expected_bytes); -} - -#[test] -fn test_big_wrapping_mul_0() { - let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); - expected_digits.push(0); - - let mut expected = MPNat { digits: expected_digits }; - - check_big_wrapping_mul(0, 0, 1, ref expected); -} - - -#[test] -fn test_big_wrapping_mul_1() { - let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); - expected_digits.push(1); - - let mut expected = MPNat { digits: expected_digits }; - - check_big_wrapping_mul(1, 1, 1, ref expected); -} - -#[test] -fn test_big_wrapping_mul_2() { - let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); - expected_digits.push(42); - - let mut expected = MPNat { digits: expected_digits }; - - check_big_wrapping_mul(7, 6, 1, ref expected); -} - -#[test] -fn test_big_wrapping_mul_3() { - let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); - expected_digits.push(1); - expected_digits.push(18446744073709551614); - - let mut expected = MPNat { digits: expected_digits }; - - check_big_wrapping_mul(WORD_MAX.into(), WORD_MAX.into(), 2, ref expected); -} - -#[test] -fn test_big_wrapping_mul_4() { - let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); - expected_digits.push(1); - - let mut expected = MPNat { digits: expected_digits }; - - check_big_wrapping_mul(WORD_MAX.into(), WORD_MAX.into(), 1, ref expected); -} - -#[test] -fn test_big_wrapping_mul_5() { - let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); - expected_digits.push(42); - - let mut expected = MPNat { digits: expected_digits }; - - check_big_wrapping_mul(DOUBLE_WORD_MAX - 5, DOUBLE_WORD_MAX - 6, 2, ref expected); -} - -#[test] -fn test_big_wrapping_mul_6() { - let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); - expected_digits.push(6727192404480162174); - expected_digits.push(3070707315540124665); - - let mut expected = MPNat { digits: expected_digits }; - - check_big_wrapping_mul(0xa945_aa5e_429a_6d1a, 0x4072_d45d_3355_237b, 3, ref expected); -} - -#[test] -fn test_big_wrapping_mul_7() { - let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); - expected_digits.push(2063196614268007784); - expected_digits.push(7048986299143829482); - expected_digits.push(14065833420641261004); - - let mut expected = MPNat { digits: expected_digits }; - - check_big_wrapping_mul( - 0x8ae1_5515_fc92_b1c0_b473_8ce8_6bbf_7218, - 0x43e9_8b77_1f7c_aa93_6c4c_85e9_7fd0_504f, - 3, - ref expected - ); -} - -#[test] -fn test_big_sq_0() { - let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); - expected_digits.push(0); - - let mut expected = MPNat { digits: expected_digits }; - - check_big_sq(0, ref expected); -} - -#[test] -fn test_big_sq_1() { - let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); - expected_digits.push(1); - - let mut expected = MPNat { digits: expected_digits }; - - check_big_sq(1, ref expected); -} - -#[test] -fn test_big_sq_2() { - let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); - expected_digits.push(1); - expected_digits.push(18446744073709551614); - - let mut expected = MPNat { digits: expected_digits }; - - check_big_sq(WORD_MAX.into(), ref expected); -} - -#[test] -fn test_big_sq_3() { - let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); - expected_digits.push(4); - expected_digits.push(18446744073709551608); - expected_digits.push(3); - - let mut expected = MPNat { digits: expected_digits }; - - check_big_sq(2 * WORD_MAX.into(), ref expected); -} - -#[test] -fn test_big_sq_4() { - let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); - expected_digits.push(0); - - let mut expected = MPNat { digits: expected_digits }; - - check_big_sq(0, ref expected); -} - -#[test] -fn test_big_sq_5() { - let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); - expected_digits.push(2532367871917050473); - expected_digits.push(16327525306720758713); - expected_digits.push(15087745550001425684); - expected_digits.push(5708046406239628566); - - let mut expected = MPNat { digits: expected_digits }; - - check_big_sq(0x8e67904953db9a2bf6da64bf8bda866d, ref expected); -} - - -#[test] -fn test_big_sq_6() { - let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); - expected_digits.push(15092604974397072849); - expected_digits.push(3791921091882282235); - expected_digits.push(12594445234582458012); - expected_digits.push(7165619740963215273); - - let mut expected = MPNat { digits: expected_digits }; - - check_big_sq(0x9f8dc1c3fc0bf50fe75ac3bbc03124c9, ref expected); -} - -#[test] -fn test_big_sq_7() { - let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); - expected_digits.push(5163998055150312593); - expected_digits.push(8460506958278925118); - expected_digits.push(17089393176389340230); - expected_digits.push(6902937458884066534); - - let mut expected = MPNat { digits: expected_digits }; - - check_big_sq(0x9c9a17378f3d064e5eaa80eeb3850cd7, ref expected); -} - - -#[test] -fn test_big_sq_8() { - let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); - expected_digits.push(2009857620356723108); - expected_digits.push(5657228334642978155); - expected_digits.push(88889113116670247); - expected_digits.push(12075559273075793199); - - let mut expected = MPNat { digits: expected_digits }; - - check_big_sq(0xcf2025cee03025d247ad190e9366d926, ref expected); -} - -#[test] -fn test_big_sq_9() { - let mut expected_digits: Felt252Vec = Felt252VecImpl::new(); - expected_digits.push(1); - expected_digits.push(0); - expected_digits.push(18446744073709551614); - expected_digits.push(18446744073709551615); - - let mut expected = MPNat { digits: expected_digits }; - - check_big_sq(DOUBLE_WORD_MAX, ref expected); -} - -// Test for addition overflows in the big_sq inner loop */ -#[test] -fn test_big_sq_10() { - let mut x = MPNatTrait::from_big_endian( - array![ - 0xff, - 0xff, - 0xff, - 0xff, - 0x80, - 0x00, - 0x00, - 0x00, - 0x80, - 0x00, - 0x00, - 0x00, - 0x40, - 0x00, - 0x00, - 0x00, - 0xff, - 0xff, - 0xff, - 0xff, - 0x80, - 0x00, - 0x00, - 0x00, - ] - .span() - ); - - let mut out = Felt252VecImpl::new(); - out.expand(2 * x.digits.len() + 1).unwrap(); - - big_sq(ref x, ref out); - let mut result = MPNat { digits: out }; - - let mut expected = MPNatTrait::from_big_endian( - array![ - 0xff, - 0xff, - 0xff, - 0xff, - 0x00, - 0x00, - 0x00, - 0x01, - 0x40, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x01, - 0xff, - 0xff, - 0xff, - 0xfe, - 0x40, - 0x00, - 0x00, - 0x01, - 0x90, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0xbf, - 0xff, - 0xff, - 0xff, - 0x00, - 0x00, - 0x00, - 0x00, - 0x40, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - ] - .span() - ); - - assert!(result.digits.equal_remove_trailing_zeroes(ref expected.digits)); -} - -#[test] -fn test_borrowing_sub() { - assert_eq!(borrowing_sub(0, 0, false), (0, false)); - assert_eq!(borrowing_sub(1, 0, false), (1, false)); - assert_eq!(borrowing_sub(47, 5, false), (42, false)); - assert_eq!(borrowing_sub(101, 7, true), (93, false)); - assert_eq!(borrowing_sub(0x00_00_01_00, 0x00_00_02_00, false), (WORD_MAX - 0xFF, true)); - assert_eq!(borrowing_sub(0x00_00_01_00, 0x00_00_10_00, true), (WORD_MAX - 0x0F_00, true)); -} - - -#[test] -fn test_shifted_carrying_mul() { - assert_eq!(shifted_carrying_mul(0, 0, 0, 0), (0, 0)); - assert_eq!(shifted_carrying_mul(0, 6, 7, 0), (42, 0)); - assert_eq!(shifted_carrying_mul(0, 6, 7, 8), (50, 0)); - assert_eq!(shifted_carrying_mul(5, 6, 7, 8), (55, 0)); - assert_eq!( - shifted_carrying_mul( - WORD_MAX - 0x11, WORD_MAX - 0x1234, WORD_MAX - 0xABCD, WORD_MAX - 0xFF - ), - (0x0C_38_0C_94, WORD_MAX - 0xBE00) - ); - assert_eq!(shifted_carrying_mul(WORD_MAX, WORD_MAX, WORD_MAX, WORD_MAX), (WORD_MAX, WORD_MAX)); -} diff --git a/crates/utils/tests/test_modexp/test_mpnat.cairo b/crates/utils/tests/test_modexp/test_mpnat.cairo deleted file mode 100644 index ff9d60420..000000000 --- a/crates/utils/tests/test_modexp/test_mpnat.cairo +++ /dev/null @@ -1,360 +0,0 @@ -use alexandria_data_structures::vec::VecTrait; -use alexandria_data_structures::vec::{Felt252Vec, Felt252VecImpl}; -use core::result::ResultTrait; -use core::traits::Into; - -use utils::crypto::modexp::arith::{ - mod_inv, monsq, monpro, compute_r_mod_n, in_place_shl, in_place_shr, big_wrapping_pow, - big_wrapping_mul, big_sq, borrowing_sub, shifted_carrying_mul -}; -use utils::crypto::modexp::mpnat::{ - MPNat, MPNatTrait, WORD_MAX, DOUBLE_WORD_MAX, Word, DoubleWord, WORD_BYTES -}; -use utils::helpers::{Felt252VecTrait, ToBytes, FromBytes}; -use utils::math::{Bitshift, WrappingBitshift}; - -// the tests are taken from -// [aurora-engine](https://github.com/aurora-is-near/aurora-engine/blob/1213f2c7c035aa523601fced8f75bef61b4728ab/engine-modexp/src/mpnat.rs#L825) - -pub fn mp_nat_to_u128(ref x: MPNat) -> u128 { - let result = x.digits.to_le_bytes(); - let mut i: usize = 0; - loop { - if i == result.len() { - break; - }; - - i += 1; - }; - result.from_le_bytes().unwrap() -} - -fn check_modpow_even(base: u128, exp: u128, modulus: u128, expected: u128) { - let mut x = MPNatTrait::from_big_endian(base.to_be_bytes()); - let mut m = MPNatTrait::from_big_endian(modulus.to_be_bytes()); - let mut result = x.modpow(exp.to_be_bytes_padded(), ref m); - let result = mp_nat_to_u128(ref result); - assert_eq!(result, expected); -} - -fn check_modpow_with_power_of_two(base: u128, exp: u128, modulus: u128, expected: u128) { - let mut x = MPNatTrait::from_big_endian(base.to_be_bytes()); - let mut m = MPNatTrait::from_big_endian(modulus.to_be_bytes()); - let mut result = x.modpow_with_power_of_two(exp.to_be_bytes(), ref m); - let result = mp_nat_to_u128(ref result); - assert_eq!(result, expected); -} - -fn check_modpow_montgomery(base: u128, exp: u128, modulus: u128, expected: u128) { - let mut x = MPNatTrait::from_big_endian(base.to_be_bytes()); - let mut m = MPNatTrait::from_big_endian(modulus.to_be_bytes()); - let mut result = x.modpow_montgomery(exp.to_be_bytes(), ref m); - let result = mp_nat_to_u128(ref result); - assert_eq!(result, expected, "({base} ^ {exp}) % {modulus} failed check_modpow_montgomery"); -} - -fn check_sub_to_same_size(a: u128, n: u128) { - let mut x = MPNatTrait::from_big_endian(a.to_be_bytes()); - let mut y = MPNatTrait::from_big_endian(n.to_be_bytes()); - x.sub_to_same_size(ref y); - - assert!(x.digits.len() <= y.digits.len()); - let result = mp_nat_to_u128(ref x); - assert_eq!(result % n, a % n, "{a} % {n} failed sub_to_same_size check"); -} - - -fn check_is_odd(n: u128) { - let mut mp = MPNatTrait::from_big_endian(n.to_be_bytes()); - assert_eq!(mp.is_odd(), n % 2 == 1, "{n} failed is_odd test"); -} - -fn check_is_p2(n: u128, expected_result: bool) { - let mut mp = MPNatTrait::from_big_endian(n.to_be_bytes()); - assert_eq!(mp.is_power_of_two(), expected_result, "{n} failed is_power_of_two test"); -} - -#[test] -#[available_gas(100000000000000)] -fn test_modpow_even() { - check_modpow_even(3, 5, 500, 243); - check_modpow_even(3, 5, 20, 3); - check_modpow_even( - 0x2ff4f4df4c518867207c84b57a77aa50, - 0xca83c2925d17c577c9a03598b6f360, - 0xf863d4f17a5405d84814f54c92f803c8, - 0x8d216c9a1fb275ed18eb340ed43cacc0, - ); - check_modpow_even( - 0x13881e1614244c56d15ac01096b070e7, - 0x336df5b4567cbe4c093271dc151e6c72, - 0x7540f399a0b6c220f1fc60d2451a1ff0, - 0x1251d64c552e8f831f5b841d2811f9c1, - ); - check_modpow_even( - 0x774d5b2494a449d8f22b22ea542d4ddf, - 0xd2f602e1688f271853e7794503c2837e, - 0xa80d20ebf75f92192159197b60f36e8e, - 0x3fbbba42489b27fc271fb39f54aae2e1, - ); - check_modpow_even( - 0x756e409cc3583a6b68ae27ccd9eb3d50, - 0x16dafb38a334288954d038bedbddc970, - 0x1f9b2237f09413d1fc44edf9bd02b8bc, - 0x9347445ac61536a402723cd07a3f5a4, - ); - check_modpow_even( - 0x6dcb8405e2cc4dcebee3e2b14861b47d, - 0xe6c1e5251d6d5deb8dddd0198481d671, - 0xe34a31d814536e8b9ff6cc5300000000, - 0xaa86af638386880334694967564d0c3d, - ); - check_modpow_even( - 0x9c12fe4a1a97d17c1e4573247a43b0e5, - 0x466f3e0a2e8846b8c48ecbf612b96412, - 0x710d7b9d5718acff0000000000000000, - 0x569bf65929e71cd10a553a8623bdfc99, - ); - check_modpow_even( - 0x6d018fdeaa408222cb10ff2c36124dcf, - 0x8e35fc05d490bb138f73c2bc284a67a7, - 0x6c237160750d78400000000000000000, - 0x3fe14e11392c6c6be8efe956c965d5af, - ); -} - -#[test] -fn test_modpow_with_power_of_two() { - check_modpow_with_power_of_two(3, 2, 1.wrapping_shl(30), 9); - check_modpow_with_power_of_two(3, 5, 1.wrapping_shl(30), 243); - check_modpow_with_power_of_two(3, 1_000_000, 1.wrapping_shl(30), 641836289); - check_modpow_with_power_of_two(3, 1_000_000, 1.wrapping_shl(31), 1715578113); - check_modpow_with_power_of_two(3, 1_000_000, 1.wrapping_shl(32), 3863061761); - check_modpow_with_power_of_two( - 0xabcd_ef01_2345_6789_1111, 0x1234_5678_90ab_cdef, 1.wrapping_shl(5), 17, - ); - check_modpow_with_power_of_two( - 0x3f47_9dc0_d5b9_6003, - 0xa180_e045_e314_8581, - 1.wrapping_shl(118), - 0x0028_3d19_e6cc_b8a0_e050_6abb_b9b1_1a03, - ); -} - -#[test] -#[available_gas(100000000000000)] -fn test_modpow_montgomery() { - check_modpow_montgomery(3, 5, 0x9346_9d50_1f74_d1c1, 243); - check_modpow_montgomery(3, 5, 19, 15); - check_modpow_montgomery( - 0x5c4b74ec760dfb021499f5c5e3c69222, - 0x62b2a34b21cf4cc036e880b3fb59fe09, - 0x7b799c4502cd69bde8bb12601ce3ff15, - 0x10c9d9071d0b86d6a59264d2f461200, - ); - check_modpow_montgomery( - 0xadb5ce8589030e3a9112123f4558f69c, - 0xb002827068f05b84a87431a70fb763ab, - 0xc4550871a1cfc67af3e77eceb2ecfce5, - 0x7cb78c0e1c1b43f6412e9d1155ea96d2, - ); - check_modpow_montgomery( - 0x26eb51a5d9bf15a536b6e3c67867b492, - 0xddf007944a79bf55806003220a58cc6, - 0xc96275a80c694a62330872b2690f8773, - 0x23b75090ead913def3a1e0bde863eda7, - ); - check_modpow_montgomery( - 0xb93fa81979e597f548c78f2ecb6800f3, - 0x5fad650044963a271898d644984cb9f0, - 0xbeb60d6bd0439ea39d447214a4f8d3ab, - 0x354e63e6a5e007014acd3e5ea88dc3ad, - ); - check_modpow_montgomery( - 0x1993163e4f578869d04949bc005c878f, - 0x8cb960f846475690259514af46868cf5, - 0x52e104dc72423b534d8e49d878f29e3b, - 0x2aa756846258d5cfa6a3f8b9b181a11c, - ); -} - -#[test] -fn test_sub_to_same_size() { - check_sub_to_same_size(0x10_00_00_00_00, 0xFF_00_00_00); - check_sub_to_same_size(0x10_00_00_00_00, 0x01_00_00_00); - check_sub_to_same_size(0x35_00_00_00_00, 0x01_00_00_00); - check_sub_to_same_size(0xEF_00_00_00_00_00_00, 0x02_FF_FF_FF); - - let n = 10; - let a = 57 + 2 * n + 0x1234_0000_0000 * n + 0x000b_0000_0000_0000_0000 * n; - check_sub_to_same_size(a, n); - - // Test that borrow equals self_most_sig at end of sub_to_same_size */ - { - let mut x = MPNatTrait::from_big_endian( - array![ - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0xae, - 0x5f, - 0xf0, - 0x8b, - 0xfc, - 0x02, - 0x71, - 0xa4, - 0xfe, - 0xe0, - 0x49, - 0x02, - 0xc9, - 0xd9, - 0x12, - 0x61, - 0x8e, - 0xf5, - 0x02, - 0x2c, - 0xa0, - 0x00, - 0x00, - 0x00, - ] - .span() - ); - let mut y = MPNatTrait::from_big_endian( - array![ - 0xae, - 0x5f, - 0xf0, - 0x8b, - 0xfc, - 0x02, - 0x71, - 0xa4, - 0xfe, - 0xe0, - 0x49, - 0x0f, - 0x70, - 0x00, - 0x00, - 0x00, - ] - .span() - ); - x.sub_to_same_size(ref y); - } - - // Additional test for sub_to_same_size q_hat/r_hat adjustment logic */ - { - let mut x = MPNatTrait::from_big_endian( - array![ - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0xff, - 0xff, - 0xff, - 0xff, - 0x00, - 0x00, - 0x00, - 0x00, - 0x01, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - ] - .span() - ); - let mut y = MPNatTrait::from_big_endian( - array![ - 0xff, - 0xff, - 0xff, - 0xff, - 0x00, - 0x00, - 0x00, - 0x00, - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, - 0x00, - 0x00, - 0x00, - ] - .span() - ); - x.sub_to_same_size(ref y); - } -} - -#[test] -#[available_gas(100000000000000)] -fn test_mp_nat_is_odd() { - let mut n = 0; - loop { - if n == 1025 { - break; - }; - check_is_odd(n); - - n += 1; - }; - - let mut n = 0xFF_FF_FF_FF_00_00_00_00; - - loop { - if n == 0xFF_FF_FF_FF_00_00_04_01 { - break; - } - - check_is_odd(n); - n += 1; - }; -} - -#[test] -fn test_mp_nat_is_power_of_two() { - check_is_p2(0, false); - check_is_p2(1, true); - check_is_p2(1327, false); - check_is_p2((1.shl(1)) + (1.shl(35)), false); - check_is_p2(1.shl(1), true); - check_is_p2(1.shl(2), true); - check_is_p2(1.shl(3), true); - check_is_p2(1.shl(4), true); - check_is_p2(1.shl(5), true); - check_is_p2(1.shl(31), true); - check_is_p2(1.shl(32), true); - check_is_p2(1.shl(64), true); - check_is_p2(1.shl(65), true); - check_is_p2(1.shl(127), true); -}