Skip to content

Commit 895be71

Browse files
authored
Added hints felt unpacking for blake (#2032)
This PR is an as-is copy of AlonT's PR pushed to a fork repo.
1 parent 2b5ceaf commit 895be71

File tree

4 files changed

+199
-2
lines changed

4 files changed

+199
-2
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333

3434
* feat: Add `ProverInfo` and extract the relevant information for it from the runner [#2001](https://github.com/lambdaclass/cairo-vm/pull/2001)
3535

36+
* feat: Support hints for new blake felt serialization library code [#1994](https://github.com/lambdaclass/cairo-vm/pull/1994)
37+
3638
#### [2.0.1] - 2025-03-17
3739

3840
* feat: Limited padding of builtin segments to >=16 [#1981](https://github.com/lambdaclass/cairo-vm/pull/1981)

vm/src/hint_processor/builtin_hint_processor/blake2s_utils.rs

Lines changed: 179 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::hint_processor::hint_processor_utils::felt_to_usize;
12
use crate::stdlib::{borrow::Cow, collections::HashMap, prelude::*};
23

34
use crate::types::errors::math_errors::MathError;
@@ -17,9 +18,11 @@ use crate::{
1718
vm::{errors::hint_errors::HintError, vm_core::VirtualMachine},
1819
};
1920

21+
use num_bigint::BigUint;
22+
use num_integer::Integer;
2023
use num_traits::ToPrimitive;
2124

22-
use super::hint_utils::get_integer_from_var_name;
25+
use super::hint_utils::{get_integer_from_var_name, insert_value_into_ap};
2326

2427
fn get_fixed_size_u32_array<const T: usize>(
2528
h_range: &Vec<Cow<Felt252>>,
@@ -242,6 +245,84 @@ pub fn blake2s_add_uint256_bigend(
242245
Ok(())
243246
}
244247

248+
/* Implements Hint:
249+
memory[ap] = (ids.end != ids.packed_values) and (memory[ids.packed_values] < 2**63)
250+
*/
251+
pub fn is_less_than_63_bits_and_not_end(
252+
vm: &mut VirtualMachine,
253+
ids_data: &HashMap<String, HintReference>,
254+
ap_tracking: &ApTracking,
255+
) -> Result<(), HintError> {
256+
let end = get_ptr_from_var_name("end", vm, ids_data, ap_tracking)?;
257+
let packed_values = get_ptr_from_var_name("packed_values", vm, ids_data, ap_tracking)?;
258+
259+
if end == packed_values {
260+
insert_value_into_ap(vm, 0)?
261+
} else {
262+
let val = vm.get_integer(packed_values)?;
263+
insert_value_into_ap(
264+
vm,
265+
(val.to_biguint() < (BigUint::from(1_u32) << 63)) as usize,
266+
)?
267+
}
268+
Ok(())
269+
}
270+
271+
/* Implements Hint:
272+
offset = 0
273+
for i in range(ids.packed_values_len):
274+
val = (memory[ids.packed_values + i] % PRIME)
275+
val_len = 2 if val < 2**63 else 8
276+
if val_len == 8:
277+
val += 2**255
278+
for i in range(val_len - 1, -1, -1):
279+
val, memory[ids.unpacked_u32s + offset + i] = divmod(val, 2**32)
280+
assert val == 0
281+
offset += val_len
282+
*/
283+
pub fn blake2s_unpack_felts(
284+
vm: &mut VirtualMachine,
285+
ids_data: &HashMap<String, HintReference>,
286+
ap_tracking: &ApTracking,
287+
) -> Result<(), HintError> {
288+
let packed_values_len =
289+
get_integer_from_var_name("packed_values_len", vm, ids_data, ap_tracking)?;
290+
let packed_values = get_ptr_from_var_name("packed_values", vm, ids_data, ap_tracking)?;
291+
let unpacked_u32s = get_ptr_from_var_name("unpacked_u32s", vm, ids_data, ap_tracking)?;
292+
293+
let vals = vm.get_integer_range(packed_values, felt_to_usize(&packed_values_len)?)?;
294+
let pow2_32 = BigUint::from(1_u32) << 32;
295+
let pow2_63 = BigUint::from(1_u32) << 63;
296+
let pow2_255 = BigUint::from(1_u32) << 255;
297+
298+
// Split value into either 2 or 8 32-bit limbs.
299+
let out: Vec<MaybeRelocatable> = vals
300+
.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+
}
316+
})
317+
.map(Felt252::from)
318+
.map(MaybeRelocatable::from)
319+
.collect();
320+
321+
vm.load_data(unpacked_u32s, &out)
322+
.map_err(HintError::Memory)?;
323+
Ok(())
324+
}
325+
245326
/* Implements Hint:
246327
%{
247328
from starkware.cairo.common.cairo_blake2s.blake2s_utils import IV, blake2s_compress
@@ -604,6 +685,103 @@ mod tests {
604685
.is_none());
605686
}
606687

688+
#[test]
689+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
690+
fn is_less_than_63_bits_and_not_end_ends() {
691+
let hint_code = hint_code::IS_LESS_THAN_63_BITS_AND_NOT_END;
692+
//Create vm
693+
let mut vm = vm!();
694+
//Insert ids into memory
695+
vm.segments = segments![((1, 0), (1, 2)), ((1, 1), (1, 2)), ((1, 2), 123)];
696+
vm.set_fp(3);
697+
vm.set_ap(3);
698+
let ids_data = ids_data!["end", "packed_values", "value"];
699+
//Execute the hint
700+
assert_matches!(run_hint!(vm, ids_data, hint_code), Ok(()));
701+
//Check data ptr
702+
check_memory![vm.segments.memory, ((1, 3), 0)];
703+
}
704+
705+
#[test]
706+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
707+
fn is_less_than_63_bits_and_not_end_small() {
708+
let hint_code = hint_code::IS_LESS_THAN_63_BITS_AND_NOT_END;
709+
//Create vm
710+
let mut vm = vm!();
711+
//Insert ids into memory
712+
vm.segments = segments![((1, 0), (1, 3)), ((1, 1), (1, 2)), ((1, 2), 123)];
713+
vm.set_fp(3);
714+
vm.set_ap(3);
715+
let ids_data = ids_data!["end", "packed_values", "value"];
716+
//Execute the hint
717+
assert_matches!(run_hint!(vm, ids_data, hint_code), Ok(()));
718+
//Check data ptr
719+
check_memory![vm.segments.memory, ((1, 3), 1)];
720+
}
721+
722+
#[test]
723+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
724+
fn is_less_than_63_bits_and_not_end_big() {
725+
let hint_code = hint_code::IS_LESS_THAN_63_BITS_AND_NOT_END;
726+
//Create vm
727+
let mut vm = vm!();
728+
//Insert ids into memory
729+
vm.segments = segments![
730+
((1, 0), (1, 3)),
731+
((1, 1), (1, 2)),
732+
((1, 2), 0x10000000000000000)
733+
];
734+
vm.set_fp(3);
735+
vm.set_ap(3);
736+
let ids_data = ids_data!["end", "packed_values", "value"];
737+
//Execute the hint
738+
assert_matches!(run_hint!(vm, ids_data, hint_code), Ok(()));
739+
//Check data ptr
740+
check_memory![vm.segments.memory, ((1, 3), 0)];
741+
}
742+
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
748+
let mut vm = vm!();
749+
//Insert ids into memory
750+
vm.segments = segments![
751+
((1, 0), 2),
752+
((1, 1), (1, 3)),
753+
((1, 2), (2, 0)),
754+
((1, 3), 0x123456781234),
755+
((1, 4), 0x1234abcd5678efab1234abcd)
756+
];
757+
vm.set_fp(5);
758+
vm.set_ap(5);
759+
let ids_data = ids_data![
760+
"packed_values_len",
761+
"packed_values",
762+
"unpacked_u32s",
763+
"small_value",
764+
"big_value"
765+
];
766+
vm.segments.add();
767+
//Execute the hint
768+
assert_matches!(run_hint!(vm, ids_data, hint_code), Ok(()));
769+
//Check data ptr
770+
check_memory![
771+
vm.segments.memory,
772+
((2, 0), 0x1234),
773+
((2, 1), 0x56781234),
774+
((2, 2), 0x80000000),
775+
((2, 3), 0),
776+
((2, 4), 0),
777+
((2, 5), 0),
778+
((2, 6), 0),
779+
((2, 7), 0x1234abcd),
780+
((2, 8), 0x5678efab),
781+
((2, 9), 0x1234abcd)
782+
];
783+
}
784+
607785
#[test]
608786
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
609787
fn blake2s_add_uint256_bigend_valid_non_zero() {

vm/src/hint_processor/builtin_hint_processor/builtin_hint_processor_definition.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#[cfg(feature = "cairo-0-secp-hints")]
22
use super::secp::cairo0_hints;
33
use super::{
4-
blake2s_utils::finalize_blake2s_v3,
4+
blake2s_utils::{blake2s_unpack_felts, finalize_blake2s_v3, is_less_than_63_bits_and_not_end},
55
ec_recover::{
66
ec_recover_divmod_n_packed, ec_recover_product_div_m, ec_recover_product_mod,
77
ec_recover_sub_a_b,
@@ -360,6 +360,12 @@ impl HintProcessorLogic for BuiltinHintProcessor {
360360
hint_code::BLAKE2S_ADD_UINT256_BIGEND => {
361361
blake2s_add_uint256_bigend(vm, &hint_data.ids_data, &hint_data.ap_tracking)
362362
}
363+
hint_code::IS_LESS_THAN_63_BITS_AND_NOT_END => {
364+
is_less_than_63_bits_and_not_end(vm, &hint_data.ids_data, &hint_data.ap_tracking)
365+
}
366+
hint_code::BLAKE2S_UNPACK_FELTS => {
367+
blake2s_unpack_felts(vm, &hint_data.ids_data, &hint_data.ap_tracking)
368+
}
363369
hint_code::UNSAFE_KECCAK => {
364370
unsafe_keccak(vm, exec_scopes, &hint_data.ids_data, &hint_data.ap_tracking)
365371
}

vm/src/hint_processor/builtin_hint_processor/hint_code.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,17 @@ segments.write_arg(ids.data + 4, [(ids.high >> (B * i)) & MASK for i in range(4)
426426
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)])"#}),
429+
(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
431+
for i in range(ids.packed_values_len):
432+
val = (memory[ids.packed_values + i] % PRIME)
433+
val_len = 2 if val < 2**63 else 8
434+
if val_len == 8:
435+
val += 2**255
436+
for i in range(val_len - 1, -1, -1):
437+
val, memory[ids.unpacked_u32s + offset + i] = divmod(val, 2**32)
438+
assert val == 0
439+
offset += val_len"#}),
429440
(EXAMPLE_BLAKE2S_COMPRESS, indoc! {r#"from starkware.cairo.common.cairo_blake2s.blake2s_utils import IV, blake2s_compress
430441
431442
_blake2s_input_chunk_size_felts = int(ids.BLAKE2S_INPUT_CHUNK_SIZE_FELTS)

0 commit comments

Comments
 (0)