diff --git a/Cargo.lock b/Cargo.lock index 4d734f7769..b28d59d134 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -179,7 +179,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" dependencies = [ "num-traits", - "rand", + "rand 0.8.5", ] [[package]] @@ -917,7 +917,7 @@ dependencies = [ "num-prime", "num-traits", "proptest", - "rand", + "rand 0.8.5", "rstest", "rust_decimal", "serde", @@ -925,7 +925,7 @@ dependencies = [ "sha2", "sha3", "starknet-crypto", - "starknet-types-core 0.2.0", + "starknet-types-core 0.2.1", "thiserror", "wasm-bindgen-test", "zip", @@ -1932,7 +1932,21 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbc2a4da0d9e52ccfe6306801a112e81a8fc0c76aa3e4449fefeda7fef72bb34" dependencies = [ - "lambdaworks-math", + "lambdaworks-math 0.10.0", + "serde", + "sha2", + "sha3", +] + +[[package]] +name = "lambdaworks-crypto" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fce8f59622ed408c318c9b5eca17f1a1154159e3738b5c4d5a22a0dd3700c906" +dependencies = [ + "lambdaworks-math 0.12.0", + "rand 0.8.5", + "rand_chacha 0.3.1", "serde", "sha2", "sha3", @@ -1948,6 +1962,18 @@ dependencies = [ "serde_json", ] +[[package]] +name = "lambdaworks-math" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "405d65a26831650ba348a503a2881ed7a0483ef3ec17f66e0fc8e2f9c97fc7ca" +dependencies = [ + "getrandom 0.2.16", + "rand 0.8.5", + "serde", + "serde_json", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -2155,7 +2181,7 @@ checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", - "rand", + "rand 0.8.5", "serde", ] @@ -2201,7 +2227,7 @@ dependencies = [ "num-integer", "num-modular", "num-traits", - "rand", + "rand 0.8.5", ] [[package]] @@ -2469,8 +2495,8 @@ dependencies = [ "bitflags 2.9.0", "lazy_static", "num-traits", - "rand", - "rand_chacha", + "rand 0.8.5", + "rand_chacha 0.3.1", "rand_xorshift", "regex-syntax", "rusty-fork", @@ -2512,8 +2538,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", ] [[package]] @@ -2523,7 +2559,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.3", ] [[package]] @@ -2535,13 +2581,22 @@ dependencies = [ "getrandom 0.2.16", ] +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.2", +] + [[package]] name = "rand_xorshift" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" dependencies = [ - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -2992,7 +3047,7 @@ dependencies = [ "rfc6979", "sha2", "starknet-curve", - "starknet-types-core 0.2.0", + "starknet-types-core 0.2.1", "zeroize", ] @@ -3002,7 +3057,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22c898ae81b6409532374cf237f1bd752d068b96c6ad500af9ebbd0d9bb712f6" dependencies = [ - "starknet-types-core 0.2.0", + "starknet-types-core 0.2.1", ] [[package]] @@ -3011,8 +3066,8 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4037bcb26ce7c508448d221e570d075196fd4f6912ae6380981098937af9522a" dependencies = [ - "lambdaworks-crypto", - "lambdaworks-math", + "lambdaworks-crypto 0.10.0", + "lambdaworks-math 0.10.0", "lazy_static", "num-bigint", "num-integer", @@ -3024,19 +3079,21 @@ dependencies = [ [[package]] name = "starknet-types-core" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fa3d91e38f091dbc543d33589eb7716bed2a8eb1c20879e484561977832b60a" +checksum = "c043ab183b1cb1daab10d592719d27f283e7ef7e7ac8accd243b4e70b4e1c0d8" dependencies = [ "arbitrary", "blake2", "digest", - "lambdaworks-crypto", - "lambdaworks-math", + "lambdaworks-crypto 0.12.0", + "lambdaworks-math 0.12.0", "num-bigint", "num-integer", "num-traits", + "rand 0.9.2", "serde", + "size-of", "zeroize", ] diff --git a/vm/Cargo.toml b/vm/Cargo.toml index 84cda21268..9775afdbab 100644 --- a/vm/Cargo.toml +++ b/vm/Cargo.toml @@ -57,7 +57,7 @@ keccak = { workspace = true } hashbrown = { workspace = true } anyhow = { workspace = true } thiserror = { workspace = true } -starknet-types-core = { version = "0.2.0", default-features = false, features = ["serde", "curve", "num-traits", "hash"] } +starknet-types-core = { version = "0.2.1", default-features = false, features = ["serde", "curve", "num-traits", "hash"] } rust_decimal = { version = "1.35.0", default-features = false } # only for std diff --git a/vm/src/math_utils/mod.rs b/vm/src/math_utils/mod.rs index 03a467069d..959126a39f 100644 --- a/vm/src/math_utils/mod.rs +++ b/vm/src/math_utils/mod.rs @@ -24,10 +24,7 @@ lazy_static! { .collect::>(); } -pub const STWO_PRIME: u64 = (1 << 31) - 1; -const STWO_PRIME_U128: u128 = STWO_PRIME as u128; -const MASK_36: u64 = (1 << 36) - 1; -const MASK_8: u64 = (1 << 8) - 1; +pub const STWO_PRIME: u32 = (1 << 31) - 1; /// Returns the `n`th (up to the `251`th power) power of 2 as a [`Felt252`] /// in constant time. @@ -80,225 +77,6 @@ pub fn signed_felt_for_prime(value: Felt252, prime: &BigUint) -> BigInt { } } -/// QM31 utility function, used specifically for Stwo. -/// QM31 operations are to be relocated into https://github.com/lambdaclass/lambdaworks. -/// Reads four u64 coordinates from a single Felt252. -/// STWO_PRIME fits in 36 bits, hence each coordinate can be represented by 36 bits and a QM31 -/// element can be stored in the first 144 bits of a Felt252. -/// Returns an error if the input has over 144 bits or any coordinate is unreduced. -fn qm31_packed_reduced_read_coordinates(felt: Felt252) -> Result<[u64; 4], MathError> { - let limbs = felt.to_le_digits(); - if limbs[3] != 0 || limbs[2] >= 1 << 16 { - return Err(MathError::QM31UnreducedError(Box::new(felt))); - } - let coordinates = [ - (limbs[0] & MASK_36), - ((limbs[0] >> 36) + ((limbs[1] & MASK_8) << 28)), - ((limbs[1] >> 8) & MASK_36), - ((limbs[1] >> 44) + (limbs[2] << 20)), - ]; - for x in coordinates.iter() { - if *x >= STWO_PRIME { - return Err(MathError::QM31UnreducedError(Box::new(felt))); - } - } - Ok(coordinates) -} - -/// QM31 utility function, used specifically for Stwo. -/// QM31 operations are to be relocated into https://github.com/lambdaclass/lambdaworks. -/// Reduces four u64 coordinates and packs them into a single Felt252. -/// STWO_PRIME fits in 36 bits, hence each coordinate can be represented by 36 bits and a QM31 -/// element can be stored in the first 144 bits of a Felt252. -pub(crate) fn qm31_coordinates_to_packed_reduced(coordinates: [u64; 4]) -> Felt252 { - let bytes_part1 = ((coordinates[0] % STWO_PRIME) as u128 - + (((coordinates[1] % STWO_PRIME) as u128) << 36)) - .to_le_bytes(); - let bytes_part2 = ((coordinates[2] % STWO_PRIME) as u128 - + (((coordinates[3] % STWO_PRIME) as u128) << 36)) - .to_le_bytes(); - let mut result_bytes = [0u8; 32]; - result_bytes[0..9].copy_from_slice(&bytes_part1[0..9]); - result_bytes[9..18].copy_from_slice(&bytes_part2[0..9]); - Felt252::from_bytes_le(&result_bytes) -} - -/// QM31 utility function, used specifically for Stwo. -/// QM31 operations are to be relocated into https://github.com/lambdaclass/lambdaworks. -/// Computes the addition of two QM31 elements in reduced form. -/// Returns an error if either operand is not reduced. -pub(crate) fn qm31_packed_reduced_add( - felt1: Felt252, - felt2: Felt252, -) -> Result { - let coordinates1 = qm31_packed_reduced_read_coordinates(felt1)?; - let coordinates2 = qm31_packed_reduced_read_coordinates(felt2)?; - let result_unreduced_coordinates = [ - coordinates1[0] + coordinates2[0], - coordinates1[1] + coordinates2[1], - coordinates1[2] + coordinates2[2], - coordinates1[3] + coordinates2[3], - ]; - Ok(qm31_coordinates_to_packed_reduced( - result_unreduced_coordinates, - )) -} - -/// QM31 utility function, used specifically for Stwo. -/// QM31 operations are to be relocated into https://github.com/lambdaclass/lambdaworks. -/// Computes the negative of a QM31 element in reduced form. -/// Returns an error if the input is not reduced. -#[allow(dead_code)] -pub(crate) fn qm31_packed_reduced_neg(felt: Felt252) -> Result { - let coordinates = qm31_packed_reduced_read_coordinates(felt)?; - Ok(qm31_coordinates_to_packed_reduced([ - STWO_PRIME - coordinates[0], - STWO_PRIME - coordinates[1], - STWO_PRIME - coordinates[2], - STWO_PRIME - coordinates[3], - ])) -} - -/// QM31 utility function, used specifically for Stwo. -/// QM31 operations are to be relocated into https://github.com/lambdaclass/lambdaworks. -/// Computes the subtraction of two QM31 elements in reduced form. -/// Returns an error if either operand is not reduced. -pub(crate) fn qm31_packed_reduced_sub( - felt1: Felt252, - felt2: Felt252, -) -> Result { - let coordinates1 = qm31_packed_reduced_read_coordinates(felt1)?; - let coordinates2 = qm31_packed_reduced_read_coordinates(felt2)?; - let result_unreduced_coordinates = [ - STWO_PRIME + coordinates1[0] - coordinates2[0], - STWO_PRIME + coordinates1[1] - coordinates2[1], - STWO_PRIME + coordinates1[2] - coordinates2[2], - STWO_PRIME + coordinates1[3] - coordinates2[3], - ]; - Ok(qm31_coordinates_to_packed_reduced( - result_unreduced_coordinates, - )) -} - -/// QM31 utility function, used specifically for Stwo. -/// QM31 operations are to be relocated into https://github.com/lambdaclass/lambdaworks. -/// Computes the multiplication of two QM31 elements in reduced form. -/// Returns an error if either operand is not reduced. -pub(crate) fn qm31_packed_reduced_mul( - felt1: Felt252, - felt2: Felt252, -) -> Result { - let coordinates1_u64 = qm31_packed_reduced_read_coordinates(felt1)?; - let coordinates2_u64 = qm31_packed_reduced_read_coordinates(felt2)?; - let coordinates1 = coordinates1_u64.map(u128::from); - let coordinates2 = coordinates2_u64.map(u128::from); - - let result_coordinates = [ - ((5 * STWO_PRIME_U128 * STWO_PRIME_U128 + coordinates1[0] * coordinates2[0] - - coordinates1[1] * coordinates2[1] - + 2 * coordinates1[2] * coordinates2[2] - - 2 * coordinates1[3] * coordinates2[3] - - coordinates1[2] * coordinates2[3] - - coordinates1[3] * coordinates2[2]) - % STWO_PRIME_U128) as u64, - ((STWO_PRIME_U128 * STWO_PRIME_U128 - + coordinates1[0] * coordinates2[1] - + coordinates1[1] * coordinates2[0] - + 2 * (coordinates1[2] * coordinates2[3] + coordinates1[3] * coordinates2[2]) - + coordinates1[2] * coordinates2[2] - - coordinates1[3] * coordinates2[3]) - % STWO_PRIME_U128) as u64, - 2 * STWO_PRIME * STWO_PRIME + coordinates1_u64[0] * coordinates2_u64[2] - - coordinates1_u64[1] * coordinates2_u64[3] - + coordinates1_u64[2] * coordinates2_u64[0] - - coordinates1_u64[3] * coordinates2_u64[1], - coordinates1_u64[0] * coordinates2_u64[3] - + coordinates1_u64[1] * coordinates2_u64[2] - + coordinates1_u64[2] * coordinates2_u64[1] - + coordinates1_u64[3] * coordinates2_u64[0], - ]; - Ok(qm31_coordinates_to_packed_reduced(result_coordinates)) -} - -/// M31 utility function, used specifically for Stwo. -/// M31 operations are to be relocated into https://github.com/lambdaclass/lambdaworks. -/// Computes the inverse in the M31 field using Fermat's little theorem, i.e., returns -/// `v^(STWO_PRIME-2) modulo STWO_PRIME`, which is the inverse of v unless v % STWO_PRIME == 0. -pub(crate) fn pow2147483645(v: u64) -> u64 { - let t0 = (sqn(v, 2) * v) % STWO_PRIME; - let t1 = (sqn(t0, 1) * t0) % STWO_PRIME; - let t2 = (sqn(t1, 3) * t0) % STWO_PRIME; - let t3 = (sqn(t2, 1) * t0) % STWO_PRIME; - let t4 = (sqn(t3, 8) * t3) % STWO_PRIME; - let t5 = (sqn(t4, 8) * t3) % STWO_PRIME; - (sqn(t5, 7) * t2) % STWO_PRIME -} - -/// M31 utility function, used specifically for Stwo. -/// M31 operations are to be relocated into https://github.com/lambdaclass/lambdaworks. -/// Computes `v^(2^n) modulo STWO_PRIME`. -fn sqn(v: u64, n: usize) -> u64 { - let mut u = v; - for _ in 0..n { - u = (u * u) % STWO_PRIME; - } - u -} - -/// QM31 utility function, used specifically for Stwo. -/// QM31 operations are to be relocated into https://github.com/lambdaclass/lambdaworks. -/// Computes the inverse of a QM31 element in reduced form. -/// Returns an error if the denominator is zero or either operand is not reduced. -pub(crate) fn qm31_packed_reduced_inv(felt: Felt252) -> Result { - if felt.is_zero() { - return Err(MathError::DividedByZero); - } - let coordinates = qm31_packed_reduced_read_coordinates(felt)?; - - let b2_r = (coordinates[2] * coordinates[2] + STWO_PRIME * STWO_PRIME - - coordinates[3] * coordinates[3]) - % STWO_PRIME; - let b2_i = (2 * coordinates[2] * coordinates[3]) % STWO_PRIME; - - let denom_r = (coordinates[0] * coordinates[0] + STWO_PRIME * STWO_PRIME - - coordinates[1] * coordinates[1] - + 2 * STWO_PRIME - - 2 * b2_r - + b2_i) - % STWO_PRIME; - let denom_i = - (2 * coordinates[0] * coordinates[1] + 3 * STWO_PRIME - 2 * b2_i - b2_r) % STWO_PRIME; - - let denom_norm_squared = (denom_r * denom_r + denom_i * denom_i) % STWO_PRIME; - let denom_norm_inverse_squared = pow2147483645(denom_norm_squared); - - let denom_inverse_r = (denom_r * denom_norm_inverse_squared) % STWO_PRIME; - let denom_inverse_i = ((STWO_PRIME - denom_i) * denom_norm_inverse_squared) % STWO_PRIME; - - Ok(qm31_coordinates_to_packed_reduced([ - coordinates[0] * denom_inverse_r + STWO_PRIME * STWO_PRIME - - coordinates[1] * denom_inverse_i, - coordinates[0] * denom_inverse_i + coordinates[1] * denom_inverse_r, - coordinates[3] * denom_inverse_i + STWO_PRIME * STWO_PRIME - - coordinates[2] * denom_inverse_r, - 2 * STWO_PRIME * STWO_PRIME - - coordinates[2] * denom_inverse_i - - coordinates[3] * denom_inverse_r, - ])) -} - -/// QM31 utility function, used specifically for Stwo. -/// QM31 operations are to be relocated into https://github.com/lambdaclass/lambdaworks. -/// Computes the division of two QM31 elements in reduced form. -/// Returns an error if the input is zero. -pub(crate) fn qm31_packed_reduced_div( - felt1: Felt252, - felt2: Felt252, -) -> Result { - let felt2_inv = qm31_packed_reduced_inv(felt2)?; - qm31_packed_reduced_mul(felt1, felt2_inv) -} - ///Returns the integer square root of the nonnegative integer n. ///This is the floor of the exact square root of n. ///Unlike math.sqrt(), this function doesn't have rounding error issues. @@ -631,7 +409,7 @@ mod tests { use num_prime::RandPrime; #[cfg(feature = "std")] - use proptest::{array::uniform4, prelude::*}; + use proptest::prelude::*; // Only used in proptest for now #[cfg(feature = "std")] @@ -1179,174 +957,9 @@ mod tests { ) } - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn qm31_packed_reduced_read_coordinates_over_144_bits() { - let mut felt_bytes = [0u8; 32]; - felt_bytes[18] = 1; - let felt = Felt252::from_bytes_le(&felt_bytes); - assert_matches!( - qm31_packed_reduced_read_coordinates(felt), - Err(MathError::QM31UnreducedError(bx)) if *bx == felt - ); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn qm31_packed_reduced_read_coordinates_unreduced() { - let mut felt_bytes = [0u8; 32]; - felt_bytes[0] = 0xff; - felt_bytes[1] = 0xff; - felt_bytes[2] = 0xff; - felt_bytes[3] = (1 << 7) - 1; - let felt = Felt252::from_bytes_le(&felt_bytes); - assert_matches!( - qm31_packed_reduced_read_coordinates(felt), - Err(MathError::QM31UnreducedError(bx)) if *bx == felt - ); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn test_qm31_packed_reduced_add() { - let x_coordinates = [1414213562, 1732050807, 1618033988, 1234567890]; - let y_coordinates = [1234567890, 1414213562, 1732050807, 1618033988]; - let x = qm31_coordinates_to_packed_reduced(x_coordinates); - let y = qm31_coordinates_to_packed_reduced(y_coordinates); - let res = qm31_packed_reduced_add(x, y).unwrap(); - let res_coordinates = qm31_packed_reduced_read_coordinates(res); - assert_eq!( - res_coordinates, - Ok([ - (1414213562 + 1234567890) % STWO_PRIME, - (1732050807 + 1414213562) % STWO_PRIME, - (1618033988 + 1732050807) % STWO_PRIME, - (1234567890 + 1618033988) % STWO_PRIME, - ]) - ); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn test_qm31_packed_reduced_neg() { - let x_coordinates = [1749652895, 834624081, 1930174752, 2063872165]; - let x = qm31_coordinates_to_packed_reduced(x_coordinates); - let res = qm31_packed_reduced_neg(x).unwrap(); - let res_coordinates = qm31_packed_reduced_read_coordinates(res); - assert_eq!( - res_coordinates, - Ok([ - STWO_PRIME - x_coordinates[0], - STWO_PRIME - x_coordinates[1], - STWO_PRIME - x_coordinates[2], - STWO_PRIME - x_coordinates[3] - ]) - ); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn test_qm31_packed_reduced_sub() { - let x_coordinates = [ - (1414213562 + 1234567890) % STWO_PRIME, - (1732050807 + 1414213562) % STWO_PRIME, - (1618033988 + 1732050807) % STWO_PRIME, - (1234567890 + 1618033988) % STWO_PRIME, - ]; - let y_coordinates = [1414213562, 1732050807, 1618033988, 1234567890]; - let x = qm31_coordinates_to_packed_reduced(x_coordinates); - let y = qm31_coordinates_to_packed_reduced(y_coordinates); - let res = qm31_packed_reduced_sub(x, y).unwrap(); - let res_coordinates = qm31_packed_reduced_read_coordinates(res); - assert_eq!( - res_coordinates, - Ok([1234567890, 1414213562, 1732050807, 1618033988]) - ); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn test_qm31_packed_reduced_mul() { - let x_coordinates = [1414213562, 1732050807, 1618033988, 1234567890]; - let y_coordinates = [1259921049, 1442249570, 1847759065, 2094551481]; - let x = qm31_coordinates_to_packed_reduced(x_coordinates); - let y = qm31_coordinates_to_packed_reduced(y_coordinates); - let res = qm31_packed_reduced_mul(x, y).unwrap(); - let res_coordinates = qm31_packed_reduced_read_coordinates(res); - assert_eq!( - res_coordinates, - Ok([947980980, 1510986506, 623360030, 1260310989]) - ); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn test_qm31_packed_reduced_inv() { - let x_coordinates = [1259921049, 1442249570, 1847759065, 2094551481]; - let x = qm31_coordinates_to_packed_reduced(x_coordinates); - let res = qm31_packed_reduced_inv(x).unwrap(); - assert_eq!(qm31_packed_reduced_mul(x, res), Ok(Felt252::from(1))); - - let x_coordinates = [1, 2, 3, 4]; - let x = qm31_coordinates_to_packed_reduced(x_coordinates); - let res = qm31_packed_reduced_inv(x).unwrap(); - assert_eq!(qm31_packed_reduced_mul(x, res), Ok(Felt252::from(1))); - - let x_coordinates = [1749652895, 834624081, 1930174752, 2063872165]; - let x = qm31_coordinates_to_packed_reduced(x_coordinates); - let res = qm31_packed_reduced_inv(x).unwrap(); - assert_eq!(qm31_packed_reduced_mul(x, res), Ok(Felt252::from(1))); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn test_qm31_packed_reduced_div() { - let x_coordinates = [1259921049, 1442249570, 1847759065, 2094551481]; - let y_coordinates = [1414213562, 1732050807, 1618033988, 1234567890]; - let xy_coordinates = [947980980, 1510986506, 623360030, 1260310989]; - let x = qm31_coordinates_to_packed_reduced(x_coordinates); - let y = qm31_coordinates_to_packed_reduced(y_coordinates); - let xy = qm31_coordinates_to_packed_reduced(xy_coordinates); - - let res = qm31_packed_reduced_div(xy, y).unwrap(); - assert_eq!(res, x); - - let res = qm31_packed_reduced_div(xy, x).unwrap(); - assert_eq!(res, y); - } - - /// Necessary strat to use proptest on the QM31 test - #[cfg(feature = "std")] - fn configuration_strat() -> BoxedStrategy { - prop_oneof![Just(0), Just(1), Just(STWO_PRIME - 1), 0..STWO_PRIME].boxed() - } - #[cfg(feature = "std")] proptest! { - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn qm31_packed_reduced_inv_random(x_coordinates in uniform4(0u64..STWO_PRIME) - .prop_filter("All configs cant be 0", - |arr| !arr.iter().all(|x| *x == 0)) - ) { - let x = qm31_coordinates_to_packed_reduced(x_coordinates); - let res = qm31_packed_reduced_inv(x).unwrap(); - assert_eq!(qm31_packed_reduced_mul(x, res), Ok(Felt252::from(1))); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn qm31_packed_reduced_inv_extensive(x_coordinates in uniform4(configuration_strat()) - .prop_filter("All configs cant be 0", - |arr| !arr.iter().all(|x| *x == 0)) - .no_shrink() - ) { - let x = qm31_coordinates_to_packed_reduced(x_coordinates); - let res = qm31_packed_reduced_inv(x).unwrap(); - assert_eq!(qm31_packed_reduced_mul(x, res), Ok(Felt252::from(1))); - } - #[test] fn pow2_const_in_range_returns_power_of_2(x in 0..=251u32) { prop_assert_eq!(pow2_const(x), Felt252::TWO.pow(x)); diff --git a/vm/src/typed_operations.rs b/vm/src/typed_operations.rs index 4802160824..dcf95550ee 100644 --- a/vm/src/typed_operations.rs +++ b/vm/src/typed_operations.rs @@ -1,7 +1,5 @@ -use crate::math_utils::{ - qm31_packed_reduced_add, qm31_packed_reduced_div, qm31_packed_reduced_mul, - qm31_packed_reduced_sub, -}; +use starknet_types_core::qm31::QM31; + use crate::stdlib::prelude::*; use crate::types::relocatable::MaybeRelocatable; use crate::types::{errors::math_errors::MathError, instruction::OpcodeExtension}; @@ -22,9 +20,12 @@ pub fn typed_add( OpcodeExtension::Stone => Ok(x.add(y)?), OpcodeExtension::QM31Operation => { if let (MaybeRelocatable::Int(num_x), MaybeRelocatable::Int(num_y)) = (x, y) { - Ok(MaybeRelocatable::Int(qm31_packed_reduced_add( - *num_x, *num_y, - )?)) + let x_qm31 = QM31::unpack_from_felt(num_x) + .map_err(|e| MathError::QM31UnreducedError(Box::new(e.0)))?; + let y_qm31 = QM31::unpack_from_felt(num_y) + .map_err(|e| MathError::QM31UnreducedError(Box::new(e.0)))?; + let res = x_qm31 + y_qm31; + Ok(MaybeRelocatable::Int(res.pack_into_felt())) } else { Err(VirtualMachineError::Math(MathError::RelocatableQM31Add( Box::new((x.clone(), y.clone())), @@ -51,9 +52,12 @@ pub fn typed_sub( OpcodeExtension::Stone => Ok(x.sub(y)?), OpcodeExtension::QM31Operation => { if let (MaybeRelocatable::Int(num_x), MaybeRelocatable::Int(num_y)) = (x, y) { - Ok(MaybeRelocatable::Int(qm31_packed_reduced_sub( - *num_x, *num_y, - )?)) + let x_qm31 = QM31::unpack_from_felt(num_x) + .map_err(|e| MathError::QM31UnreducedError(Box::new(e.0)))?; + let y_qm31 = QM31::unpack_from_felt(num_y) + .map_err(|e| MathError::QM31UnreducedError(Box::new(e.0)))?; + let res = x_qm31 - y_qm31; + Ok(MaybeRelocatable::Int(res.pack_into_felt())) } else { Err(VirtualMachineError::Math(MathError::RelocatableQM31Sub( Box::new((x.clone(), y.clone())), @@ -79,9 +83,15 @@ pub fn typed_mul( if let (MaybeRelocatable::Int(num_x), MaybeRelocatable::Int(num_y)) = (x, y) { match opcode_extension { OpcodeExtension::Stone => Ok(MaybeRelocatable::Int(num_x * num_y)), - OpcodeExtension::QM31Operation => Ok(MaybeRelocatable::Int(qm31_packed_reduced_mul( - *num_x, *num_y, - )?)), + OpcodeExtension::QM31Operation => { + let x_qm31 = QM31::unpack_from_felt(num_x) + .map_err(|e| MathError::QM31UnreducedError(Box::new(e.0)))?; + let y_qm31 = QM31::unpack_from_felt(num_y) + .map_err(|e| MathError::QM31UnreducedError(Box::new(e.0)))?; + let res = x_qm31 * y_qm31; + + Ok(MaybeRelocatable::Int(res.pack_into_felt())) + } _ => Err(VirtualMachineError::InvalidTypedOperationOpcodeExtension( "typed_mul".to_owned().into_boxed_str(), )), @@ -107,7 +117,21 @@ pub fn typed_div( OpcodeExtension::Stone => { Ok(x.field_div(&y.try_into().map_err(|_| MathError::DividedByZero)?)) } - OpcodeExtension::QM31Operation => Ok(qm31_packed_reduced_div(*x, *y)?), + OpcodeExtension::QM31Operation => { + let x_qm31 = QM31::unpack_from_felt(x) + .map_err(|e| MathError::QM31UnreducedError(Box::new(e.0)))?; + let y_qm31 = QM31::unpack_from_felt(y) + .map_err(|e| MathError::QM31UnreducedError(Box::new(e.0)))?; + let res = (x_qm31 / y_qm31).map_err(|_| MathError::DividedByZero)?; + // let res = res.to_coefficients(); + // let res = QM31::from_coefficients( + // res.0 % STWO_PRIME, + // res.1 % STWO_PRIME, + // res.2 % STWO_PRIME, + // res.3 % STWO_PRIME, + // ); + Ok(res.pack_into_felt()) + } _ => Err(VirtualMachineError::InvalidTypedOperationOpcodeExtension( "typed_div".to_owned().into_boxed_str(), )), diff --git a/vm/src/vm/vm_core.rs b/vm/src/vm/vm_core.rs index 8afc9628be..711d79dcc9 100644 --- a/vm/src/vm/vm_core.rs +++ b/vm/src/vm/vm_core.rs @@ -1429,7 +1429,7 @@ impl VirtualMachineBuilder { mod tests { use super::*; use crate::felt_hex; - use crate::math_utils::{qm31_coordinates_to_packed_reduced, STWO_PRIME}; + use crate::math_utils::STWO_PRIME; use crate::stdlib::collections::HashMap; use crate::types::instruction::OpcodeExtension; use crate::types::layout_name::LayoutName; @@ -1452,6 +1452,7 @@ mod tests { }; use assert_matches::assert_matches; + use starknet_types_core::qm31::QM31; #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; @@ -2406,19 +2407,18 @@ mod tests { let vm = vm!(); - let op1_coordinates = [STWO_PRIME - 10, 5, STWO_PRIME - 5, 1]; - let dst_coordinates = [STWO_PRIME - 4, 2, 12, 3]; - let op1_packed = qm31_coordinates_to_packed_reduced(op1_coordinates); - let dst_packed = qm31_coordinates_to_packed_reduced(dst_coordinates); - let op1 = MaybeRelocatable::Int(op1_packed); - let dst = MaybeRelocatable::Int(dst_packed); + let op1_qm31 = QM31::from_coefficients(STWO_PRIME - 10, 5, STWO_PRIME - 5, 1); + let dst_qm31 = QM31::from_coefficients(STWO_PRIME - 4, 2, 12, 3); + + let op1 = MaybeRelocatable::Int(op1_qm31.pack_into_felt()); + let dst = MaybeRelocatable::Int(dst_qm31.pack_into_felt()); assert_matches!( vm.deduce_op0(&instruction, Some(&dst), Some(&op1)), Ok::<(Option, Option), VirtualMachineError>(( x, y - )) if x == Some(MaybeRelocatable::Int(qm31_coordinates_to_packed_reduced([6, STWO_PRIME-3, 17, 2]))) && - y == Some(MaybeRelocatable::Int(dst_packed)) + )) if QM31::unpack_from_felt(x.clone().unwrap().get_int_ref().unwrap()).unwrap() == QM31::from_coefficients(6, STWO_PRIME - 3, 17, 2) && + QM31::unpack_from_felt(y.clone().unwrap().get_int_ref().unwrap()).unwrap() == dst_qm31 ); } @@ -2442,19 +2442,17 @@ mod tests { let vm = vm!(); - let op1_coordinates = [0, 0, 1, 0]; - let dst_coordinates = [0, 0, 0, 1]; - let op1_packed = qm31_coordinates_to_packed_reduced(op1_coordinates); - let dst_packed = qm31_coordinates_to_packed_reduced(dst_coordinates); - let op1 = MaybeRelocatable::Int(op1_packed); - let dst = MaybeRelocatable::Int(dst_packed); + let op1_qm31 = QM31::from_coefficients(0, 0, 1, 0); + let dst_qm31 = QM31::from_coefficients(0, 0, 0, 1); + let op1 = MaybeRelocatable::Int(op1_qm31.pack_into_felt()); + let dst = MaybeRelocatable::Int(dst_qm31.pack_into_felt()); assert_matches!( vm.deduce_op0(&instruction, Some(&dst), Some(&op1)), Ok::<(Option, Option), VirtualMachineError>(( x, y - )) if x == Some(MaybeRelocatable::Int(qm31_coordinates_to_packed_reduced([0, 1, 0, 0]))) && - y == Some(MaybeRelocatable::Int(dst_packed)) + )) if QM31::unpack_from_felt(x.clone().unwrap().get_int_ref().unwrap()).unwrap() == QM31::from_coefficients(0, 1, 0, 0) && + QM31::unpack_from_felt(y.clone().unwrap().get_int_ref().unwrap()).unwrap() == dst_qm31 ); } @@ -2715,19 +2713,17 @@ mod tests { let vm = vm!(); - let op0_coordinates = [4, STWO_PRIME - 13, 3, 7]; - let dst_coordinates = [8, 7, 6, 5]; - let op0_packed = qm31_coordinates_to_packed_reduced(op0_coordinates); - let dst_packed = qm31_coordinates_to_packed_reduced(dst_coordinates); - let op0 = MaybeRelocatable::Int(op0_packed); - let dst = MaybeRelocatable::Int(dst_packed); + let op0_qm31 = QM31::from_coefficients(4, STWO_PRIME - 13, 3, 7); + let dst_qm31 = QM31::from_coefficients(8, 7, 6, 5); + let op0 = MaybeRelocatable::Int(op0_qm31.pack_into_felt()); + let dst = MaybeRelocatable::Int(dst_qm31.pack_into_felt()); assert_matches!( vm.deduce_op1(&instruction, Some(&dst), Some(op0)), Ok::<(Option, Option), VirtualMachineError>(( x, y - )) if x == Some(MaybeRelocatable::Int(qm31_coordinates_to_packed_reduced([4, 20, 3, STWO_PRIME - 2]))) && - y == Some(MaybeRelocatable::Int(dst_packed)) + )) if QM31::unpack_from_felt(x.clone().unwrap().get_int_ref().unwrap()).unwrap() == QM31::from_coefficients(4, 20, 3, STWO_PRIME - 2) && + QM31::unpack_from_felt(y.clone().unwrap().get_int_ref().unwrap()).unwrap() == dst_qm31 ); } @@ -2751,19 +2747,17 @@ mod tests { let vm = vm!(); - let op0_coordinates = [0, 1, 0, 0]; - let dst_coordinates = [STWO_PRIME - 1, 0, 0, 0]; - let op0_packed = qm31_coordinates_to_packed_reduced(op0_coordinates); - let dst_packed = qm31_coordinates_to_packed_reduced(dst_coordinates); - let op0 = MaybeRelocatable::Int(op0_packed); - let dst = MaybeRelocatable::Int(dst_packed); + let op0_qm31 = QM31::from_coefficients(0, 1, 0, 0); + let dst_qm31 = QM31::from_coefficients(STWO_PRIME - 1, 0, 0, 0); + let op0 = MaybeRelocatable::Int(op0_qm31.pack_into_felt()); + let dst = MaybeRelocatable::Int(dst_qm31.pack_into_felt()); assert_matches!( vm.deduce_op1(&instruction, Some(&dst), Some(op0)), Ok::<(Option, Option), VirtualMachineError>(( x, y - )) if x == Some(MaybeRelocatable::Int(qm31_coordinates_to_packed_reduced([0, 1, 0, 0]))) && - y == Some(MaybeRelocatable::Int(dst_packed)) + )) if QM31::unpack_from_felt(x.clone().unwrap().get_int_ref().unwrap()).unwrap() == QM31::from_coefficients(0, 1, 0, 0) && + QM31::unpack_from_felt(y.clone().unwrap().get_int_ref().unwrap()).unwrap() == dst_qm31 ); } @@ -2961,17 +2955,15 @@ mod tests { let vm = vm!(); - let op1_coordinates = [1, 2, 3, 4]; - let op0_coordinates = [10, 11, STWO_PRIME - 1, 13]; - let op1_packed = qm31_coordinates_to_packed_reduced(op1_coordinates); - let op0_packed = qm31_coordinates_to_packed_reduced(op0_coordinates); - let op1 = MaybeRelocatable::Int(op1_packed); - let op0 = MaybeRelocatable::Int(op0_packed); + let op1_qm31 = QM31::from_coefficients(1, 2, 3, 4); + let op0_qm31 = QM31::from_coefficients(10, 11, STWO_PRIME - 1, 13); + let op1 = MaybeRelocatable::Int(op1_qm31.pack_into_felt()); + let op0 = MaybeRelocatable::Int(op0_qm31.pack_into_felt()); assert_matches!( vm.compute_res(&instruction, &op0, &op1), Ok::, VirtualMachineError>(Some(MaybeRelocatable::Int( x - ))) if x == qm31_coordinates_to_packed_reduced([11, 13, 2, 17]) + ))) if QM31::unpack_from_felt(&x).unwrap() == QM31::from_coefficients(11, 13, 2, 17) ); } @@ -2995,17 +2987,15 @@ mod tests { let vm = vm!(); - let op1_coordinates = [0, 0, 1, 0]; - let op0_coordinates = [0, 0, 1, 0]; - let op1_packed = qm31_coordinates_to_packed_reduced(op1_coordinates); - let op0_packed = qm31_coordinates_to_packed_reduced(op0_coordinates); - let op1 = MaybeRelocatable::Int(op1_packed); - let op0 = MaybeRelocatable::Int(op0_packed); + let op1_qm31 = QM31::from_coefficients(0, 0, 1, 0); + let op0_qm31 = QM31::from_coefficients(0, 0, 1, 0); + let op1 = MaybeRelocatable::Int(op1_qm31.pack_into_felt()); + let op0 = MaybeRelocatable::Int(op0_qm31.pack_into_felt()); assert_matches!( vm.compute_res(&instruction, &op0, &op1), Ok::, VirtualMachineError>(Some(MaybeRelocatable::Int( x - ))) if x == qm31_coordinates_to_packed_reduced([2, 1, 0, 0]) + ))) if QM31::unpack_from_felt(&x).unwrap() == QM31::from_coefficients(2, 1, 0, 0) ); }