diff --git a/crates/starknet-types-core/src/hash/blake2s.rs b/crates/starknet-types-core/src/hash/blake2s.rs index 618c861b..2846cba1 100644 --- a/crates/starknet-types-core/src/hash/blake2s.rs +++ b/crates/starknet-types-core/src/hash/blake2s.rs @@ -76,13 +76,11 @@ impl Blake2Felt252 { unpacked_u32s.push(low); } else { // big: 8 limbs, big‐endian order. - let start = unpacked_u32s.len(); - for chunk in felt_as_be_bytes.chunks_exact(BYTES_PER_U32) { unpacked_u32s.push(u32::from_be_bytes(chunk.try_into().unwrap())); } - // set the MSB of the very first limb as the Cairo hint does with "+ 2**255". - unpacked_u32s[start] |= BIG_MARKER; + // set the MSB of the **entire 256-bit number** + unpacked_u32s[0] |= BIG_MARKER; } } unpacked_u32s @@ -122,7 +120,7 @@ impl Blake2Felt252 { byte_stream.extend_from_slice(&word.to_le_bytes()); } - // 3) Compute Blake2s-256 over the bytes and pack the first 224 bits into a Felt. + // 3) Compute Blake2s-256 over the bytes and pack the first 256 bits into a Felt. Self::blake2s_to_felt(&byte_stream) } } @@ -133,72 +131,53 @@ mod tests { use crate::felt::Felt; use rstest::rstest; - /// Test two-limb encoding for a small Felt (< 2^63) into high and low 32-bit words. #[test] fn test_encode_felts_to_u32s_small() { - // Last 8 bytes of 0x1122334455667788 in big-endian are [0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88]. - // High word = 0x11223344, low word = 0x55667788. let val = Felt::from_hex_unchecked("1122334455667788"); let words = Blake2Felt252::encode_felts_to_u32s(&[val]); assert_eq!(words, vec![0x11223344, 0x55667788]); } - /// Test eight-limb encoding and MSB marker for a big Felt (>= 2^63). #[test] fn test_encode_felts_to_u32s_big() { - // The value 2^63 (0x8000000000000000) triggers the "big" path. let val = Felt::from_hex_unchecked("8000000000000000"); let words = Blake2Felt252::encode_felts_to_u32s(&[val]); - // Expected limbs: split full 32-byte BE into eight 32-bit words. - // The seventh BE chunk [0x80,0x00,0x00,0x00] becomes 0x80000000 at index 6. - // Additionally, set the MSB marker (bit 31) on the first word. let mut expected = vec![0u32; 8]; - expected[6] = 0x8000_0000; - expected[0] |= 1 << 31; + expected[0] |= 0x8000_0000; + expected[7] = 0x8000_0000; assert_eq!(words, expected); } - /// Test packing of a 32-byte little-endian buffer into a 256-bit Felt. #[test] fn test_pack_256_le_to_felt_basic() { - // Test with small values that won't trigger modular reduction. let mut buf = [0u8; 32]; buf[0] = 0x01; buf[1] = 0x02; buf[2] = 0x03; buf[3] = 0x04; - // Leave the rest as zeros. let f = Blake2Felt252::pack_256_le_to_felt(&buf); let out = f.to_bytes_le(); - // For small values, the first few bytes should match exactly. assert_eq!(out[0], 0x01); assert_eq!(out[1], 0x02); assert_eq!(out[2], 0x03); assert_eq!(out[3], 0x04); - // Test that the packing formula works correctly for a simple case. let expected = Felt::from(0x01) + Felt::from(0x02) * Felt::from(1u64 << 8) + Felt::from(0x03) * Felt::from(1u64 << 16) + Felt::from(0x04) * Felt::from(1u64 << 24); assert_eq!(f, expected); - // Test with a value that exceeds the field prime P to verify modular reduction. - // Create a 32-byte buffer with all 0xFF bytes, representing 2^256 - 1. let max_buf = [0xFF_u8; 32]; let f_max = Blake2Felt252::pack_256_le_to_felt(&max_buf); - // The result should be (2^256 - 1) mod P. - // Since 2^256 = Felt::TWO.pow(256), we can compute this value directly. - // This tests that modular reduction works correctly when exceeding the field prime. let two_pow_256_minus_one = Felt::TWO.pow(256u32) - Felt::ONE; assert_eq!(f_max, two_pow_256_minus_one); } - /// Test that pack_256_le_to_felt panics when input is shorter than 32 bytes. #[test] #[should_panic(expected = "need at least 32 bytes to pack 8 words")] fn test_pack_256_le_to_felt_too_short() { @@ -206,7 +185,6 @@ mod tests { Blake2Felt252::pack_256_le_to_felt(&too_short); } - /// Test that hashing a single zero Felt produces the expected 256-bit Blake2s digest. #[test] fn test_hash_single_zero() { let zero = Felt::from_hex_unchecked("0"); @@ -217,7 +195,6 @@ mod tests { assert_eq!(hash, expected); } - /// Test that hashing an array of Felts [1, 2] produces the expected 256-bit Blake2s digest. #[test] fn test_hash_array_one_two() { let one = Felt::from_hex_unchecked("1"); @@ -229,8 +206,6 @@ mod tests { assert_eq!(hash, expected); } - /// Test the encode_felt252_data_and_calc_blake_hash function - /// with the same result as the Cairo v0.14 version. #[rstest] #[case::empty(vec![], "874258848688468311465623299960361657518391155660316941922502367727700287818")] #[case::boundary_under_2_63(vec![Felt::from((1u64 << 63) - 1)], "94160078030592802631039216199460125121854007413180444742120780261703604445")]