Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 5 additions & 30 deletions crates/starknet-types-core/src/hash/blake2s.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
}
}
Expand All @@ -133,80 +131,60 @@ 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() {
let too_short = [0u8; 31];
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");
Expand All @@ -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");
Expand All @@ -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")]
Expand Down
Loading