Skip to content

Commit f8aa071

Browse files
Add_hint_for_splitting_data_for_blake_with_no_encoding
1 parent 4226352 commit f8aa071

File tree

3 files changed

+145
-41
lines changed

3 files changed

+145
-41
lines changed

vm/src/hint_processor/builtin_hint_processor/blake2s_utils.rs

Lines changed: 119 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -268,51 +268,88 @@ pub fn is_less_than_63_bits_and_not_end(
268268
Ok(())
269269
}
270270

271-
/* Implements Hint:
271+
/// Represents the encoding mode for Blake2s packed felts splitting.
272+
///
273+
/// - `NoEncoding`: Always splits the value into 8 limbs (u32 words).
274+
/// - `UseEncoding`: Uses 2 limbs if the value is less than 2^63, otherwise splits
275+
/// into 8 limbs after adding 2^255.
276+
///
277+
/// This is used to control how packed felts are unpacked into u32 limbs for Blake2s hashing.
278+
pub enum BlakeEncodingMode {
279+
NoEncoding,
280+
UseEncoding,
281+
}
282+
283+
/* If mode is `BlakeEncodingMode::UseEncoding`, implements the following hint:
272284
offset = 0
273285
for i in range(ids.packed_values_len):
274286
val = (memory[ids.packed_values + i] % PRIME)
275287
val_len = 2 if val < 2**63 else 8
276288
if val_len == 8:
277289
val += 2**255
278-
for i in range(val_len - 1, -1, -1):
290+
for i in range(val_len):
291+
val, memory[ids.unpacked_u32s + offset + i] = divmod(val, 2**32)
292+
assert val == 0
293+
offset += val_len
294+
295+
If mode is `BlakeEncodingMode::NoEncoding`, implements the following hint:
296+
offset = 0
297+
for i in range(ids.packed_values_len):
298+
val = (memory[ids.packed_values + i] % PRIME)
299+
val_len = 8
300+
for i in range(val_len):
279301
val, memory[ids.unpacked_u32s + offset + i] = divmod(val, 2**32)
280302
assert val == 0
281303
offset += val_len
282304
*/
283-
pub fn blake2s_unpack_felts(
305+
pub fn split_packed_felts(
284306
vm: &mut VirtualMachine,
285307
ids_data: &HashMap<String, HintReference>,
286308
ap_tracking: &ApTracking,
309+
mode: BlakeEncodingMode,
287310
) -> Result<(), HintError> {
288311
let packed_values_len =
289312
get_integer_from_var_name("packed_values_len", vm, ids_data, ap_tracking)?;
290313
let packed_values = get_ptr_from_var_name("packed_values", vm, ids_data, ap_tracking)?;
291314
let unpacked_u32s = get_ptr_from_var_name("unpacked_u32s", vm, ids_data, ap_tracking)?;
292315

293316
let vals = vm.get_integer_range(packed_values, felt_to_usize(&packed_values_len)?)?;
317+
294318
let pow2_32 = BigUint::from(1_u32) << 32;
295319
let pow2_63 = BigUint::from(1_u32) << 63;
296320
let pow2_255 = BigUint::from(1_u32) << 255;
297321

298-
// Split value into either 2 or 8 32-bit limbs.
322+
// Split the value into 8 limbs, each of which is a u32.
323+
let split_fixed8 = |mut val: BigUint| -> Vec<BigUint> {
324+
let mut limbs = vec![BigUint::from(0_u32); 8];
325+
for limb in &mut limbs {
326+
let (q, r) = val.div_rem(&pow2_32);
327+
*limb = r;
328+
val = q;
329+
}
330+
limbs
331+
};
332+
333+
// Split the value into 2 limbs if it is less than 2^63, or 8 limbs after adding 2^255.
334+
let split_encoded = |mut val: BigUint| -> Vec<BigUint> {
335+
if val < pow2_63 {
336+
// Two‑limb representation.
337+
let (high, low) = val.div_rem(&pow2_32);
338+
vec![low, high]
339+
} else {
340+
// Eight limbs after adding 2^255.
341+
val += &pow2_255;
342+
split_fixed8(val)
343+
}
344+
};
345+
346+
// Unpack the values into u32 limbs in little-endian order according to the specified mode.
299347
let out: Vec<MaybeRelocatable> = vals
300348
.into_iter()
301-
.map(|val| val.to_biguint())
302-
.flat_map(|val| {
303-
if val < pow2_63 {
304-
let (high, low) = val.div_rem(&pow2_32);
305-
vec![high, low]
306-
} else {
307-
let mut limbs = vec![BigUint::from(0_u32); 8];
308-
let mut val: BigUint = val + &pow2_255;
309-
for limb in limbs.iter_mut().rev() {
310-
let (q, r) = val.div_rem(&pow2_32);
311-
*limb = r;
312-
val = q;
313-
}
314-
limbs
315-
}
349+
.map(|v| v.to_biguint())
350+
.flat_map(|val| match mode {
351+
BlakeEncodingMode::NoEncoding => split_fixed8(val),
352+
BlakeEncodingMode::UseEncoding => split_encoded(val),
316353
})
317354
.map(Felt252::from)
318355
.map(MaybeRelocatable::from)
@@ -740,22 +777,28 @@ mod tests {
740777
check_memory![vm.segments.memory, ((1, 3), 0)];
741778
}
742779

743-
#[test]
744-
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
745-
fn blake2s_unpack_felts() {
746-
let hint_code = hint_code::BLAKE2S_UNPACK_FELTS;
747-
//Create vm
780+
/// Builds a VM, writes the packed_values_len, packed_values, unpacked_u32s and the
781+
/// actual small and big felts to the memory.
782+
/// Returns the VM and the ids_data HashMap.
783+
fn prepare_vm_for_splitting_felts_for_blake(
784+
small_val: i128,
785+
big_val: i128,
786+
) -> (VirtualMachine, HashMap<String, HintReference>) {
748787
let mut vm = vm!();
749-
//Insert ids into memory
750788
vm.segments = segments![
789+
// ids.packed_values_len = 2
751790
((1, 0), 2),
791+
// ids.packed_values = (1,3)
752792
((1, 1), (1, 3)),
793+
// ids.unpacked_u32s = (2,0)
753794
((1, 2), (2, 0)),
754-
((1, 3), 0x123456781234),
755-
((1, 4), 0x1234abcd5678efab1234abcd)
795+
// packed small / big felts
796+
((1, 3), small_val),
797+
((1, 4), big_val)
756798
];
757799
vm.set_fp(5);
758800
vm.set_ap(5);
801+
759802
let ids_data = ids_data![
760803
"packed_values_len",
761804
"packed_values",
@@ -764,21 +807,62 @@ mod tests {
764807
"big_value"
765808
];
766809
vm.segments.add();
767-
//Execute the hint
768-
assert_matches!(run_hint!(vm, ids_data, hint_code), Ok(()));
769-
//Check data ptr
810+
(vm, ids_data)
811+
}
812+
813+
#[test]
814+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
815+
fn blake2s_encode_and_split_felts() {
816+
let (mut vm, ids_data) =
817+
prepare_vm_for_splitting_felts_for_blake(0x123456781234, 0x1234abcd5678efab1234abcd);
818+
assert_matches!(
819+
run_hint!(vm, ids_data, hint_code::BLAKE2S_ENCODE_AND_SPLIT_FELTS),
820+
Ok(())
821+
);
770822
check_memory![
771823
vm.segments.memory,
772-
((2, 0), 0x1234),
773-
((2, 1), 0x56781234),
774-
((2, 2), 0x80000000),
824+
((2, 0), 0x56781234),
825+
((2, 1), 0x1234),
826+
((2, 2), 0x1234abcd),
827+
((2, 3), 0x5678efab),
828+
((2, 4), 0x1234abcd),
829+
((2, 5), 0),
830+
((2, 6), 0),
831+
((2, 7), 0),
832+
((2, 8), 0),
833+
((2, 9), 0x80000000),
834+
];
835+
}
836+
837+
#[test]
838+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
839+
fn blake2s_split_felts_to_u32s() {
840+
let (mut vm, ids_data) = prepare_vm_for_splitting_felts_for_blake(
841+
0x123456781234,
842+
0x1234abcd5678efab1234abcd5678efab,
843+
);
844+
assert_matches!(
845+
run_hint!(vm, ids_data, hint_code::BLAKE2S_SPLIT_FELTS_TO_U32S),
846+
Ok(())
847+
);
848+
check_memory![
849+
vm.segments.memory,
850+
((2, 0), 0x56781234),
851+
((2, 1), 0x1234),
852+
((2, 2), 0),
775853
((2, 3), 0),
776854
((2, 4), 0),
777855
((2, 5), 0),
778856
((2, 6), 0),
779-
((2, 7), 0x1234abcd),
857+
((2, 7), 0),
780858
((2, 8), 0x5678efab),
781-
((2, 9), 0x1234abcd)
859+
((2, 9), 0x1234abcd),
860+
((2, 10), 0x5678efab),
861+
((2, 11), 0x1234abcd),
862+
((2, 12), 0),
863+
((2, 13), 0),
864+
((2, 14), 0),
865+
((2, 15), 0),
782866
];
783867
}
784868

vm/src/hint_processor/builtin_hint_processor/builtin_hint_processor_definition.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
use super::blake2s_utils::example_blake2s_compress;
22
use super::{
3-
blake2s_utils::{blake2s_unpack_felts, finalize_blake2s_v3, is_less_than_63_bits_and_not_end},
3+
blake2s_utils::{
4+
finalize_blake2s_v3, is_less_than_63_bits_and_not_end, split_packed_felts,
5+
BlakeEncodingMode,
6+
},
47
ec_recover::{
58
ec_recover_divmod_n_packed, ec_recover_product_div_m, ec_recover_product_mod,
69
ec_recover_sub_a_b,
@@ -363,9 +366,18 @@ impl HintProcessorLogic for BuiltinHintProcessor {
363366
hint_code::IS_LESS_THAN_63_BITS_AND_NOT_END => {
364367
is_less_than_63_bits_and_not_end(vm, &hint_data.ids_data, &hint_data.ap_tracking)
365368
}
366-
hint_code::BLAKE2S_UNPACK_FELTS => {
367-
blake2s_unpack_felts(vm, &hint_data.ids_data, &hint_data.ap_tracking)
368-
}
369+
hint_code::BLAKE2S_ENCODE_AND_SPLIT_FELTS => split_packed_felts(
370+
vm,
371+
&hint_data.ids_data,
372+
&hint_data.ap_tracking,
373+
BlakeEncodingMode::UseEncoding,
374+
),
375+
hint_code::BLAKE2S_SPLIT_FELTS_TO_U32S => split_packed_felts(
376+
vm,
377+
&hint_data.ids_data,
378+
&hint_data.ap_tracking,
379+
BlakeEncodingMode::NoEncoding,
380+
),
369381
hint_code::UNSAFE_KECCAK => {
370382
unsafe_keccak(vm, exec_scopes, &hint_data.ids_data, &hint_data.ap_tracking)
371383
}

vm/src/hint_processor/builtin_hint_processor/hint_code.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -427,13 +427,21 @@ MASK = 2 ** 32 - 1
427427
segments.write_arg(ids.data, [(ids.high >> (B * (3 - i))) & MASK for i in range(4)])
428428
segments.write_arg(ids.data + 4, [(ids.low >> (B * (3 - i))) & MASK for i in range(4)])"#}),
429429
(IS_LESS_THAN_63_BITS_AND_NOT_END, indoc! {r#"memory[ap] = to_felt_or_relocatable((ids.end != ids.packed_values) and (memory[ids.packed_values] < 2**63))"#}),
430-
(BLAKE2S_UNPACK_FELTS, indoc! {r#"offset = 0
430+
(BLAKE2S_ENCODE_AND_SPLIT_FELTS, indoc! {r#"offset = 0
431431
for i in range(ids.packed_values_len):
432432
val = (memory[ids.packed_values + i] % PRIME)
433433
val_len = 2 if val < 2**63 else 8
434434
if val_len == 8:
435435
val += 2**255
436-
for i in range(val_len - 1, -1, -1):
436+
for i in range(val_len):
437+
val, memory[ids.unpacked_u32s + offset + i] = divmod(val, 2**32)
438+
assert val == 0
439+
offset += val_len"#}),
440+
(BLAKE2S_SPLIT_FELTS_TO_U32S, indoc! {r#"offset = 0
441+
for i in range(ids.packed_values_len):
442+
val = (memory[ids.packed_values + i] % PRIME)
443+
val_len = 8
444+
for i in range(val_len):
437445
val, memory[ids.unpacked_u32s + offset + i] = divmod(val, 2**32)
438446
assert val == 0
439447
offset += val_len"#}),

0 commit comments

Comments
 (0)