@@ -268,51 +268,89 @@ pub fn is_less_than_63_bits_and_not_end(
268
268
Ok ( ( ) )
269
269
}
270
270
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:
272
284
offset = 0
273
285
for i in range(ids.packed_values_len):
274
286
val = (memory[ids.packed_values + i] % PRIME)
275
287
val_len = 2 if val < 2**63 else 8
276
288
if val_len == 8:
277
- val += 2**255
278
- for i in range(val_len - 1, -1, -1):
289
+ # Treat `val` as a u256 and set its most significant bit (bit 255).
290
+ val += 1 << 255
291
+ for i in range(val_len):
292
+ val, memory[ids.unpacked_u32s + offset + i] = divmod(val, 2**32)
293
+ assert val == 0
294
+ offset += val_len
295
+
296
+ If mode is `BlakeEncodingMode::NoEncoding`, implements the following hint:
297
+ offset = 0
298
+ for i in range(ids.packed_values_len):
299
+ val = (memory[ids.packed_values + i] % PRIME)
300
+ val_len = 8
301
+ for i in range(val_len):
279
302
val, memory[ids.unpacked_u32s + offset + i] = divmod(val, 2**32)
280
303
assert val == 0
281
304
offset += val_len
282
305
*/
283
- pub fn blake2s_unpack_felts (
306
+ pub fn split_packed_felts (
284
307
vm : & mut VirtualMachine ,
285
308
ids_data : & HashMap < String , HintReference > ,
286
309
ap_tracking : & ApTracking ,
310
+ mode : BlakeEncodingMode ,
287
311
) -> Result < ( ) , HintError > {
288
312
let packed_values_len =
289
313
get_integer_from_var_name ( "packed_values_len" , vm, ids_data, ap_tracking) ?;
290
314
let packed_values = get_ptr_from_var_name ( "packed_values" , vm, ids_data, ap_tracking) ?;
291
315
let unpacked_u32s = get_ptr_from_var_name ( "unpacked_u32s" , vm, ids_data, ap_tracking) ?;
292
316
293
317
let vals = vm. get_integer_range ( packed_values, felt_to_usize ( & packed_values_len) ?) ?;
318
+
294
319
let pow2_32 = BigUint :: from ( 1_u32 ) << 32 ;
295
320
let pow2_63 = BigUint :: from ( 1_u32 ) << 63 ;
296
321
let pow2_255 = BigUint :: from ( 1_u32 ) << 255 ;
297
322
298
- // Split value into either 2 or 8 32-bit limbs.
323
+ // Split the value into 8 limbs, each of which is a u32.
324
+ let split_fixed8 = |mut val : BigUint | -> Vec < BigUint > {
325
+ let mut limbs = vec ! [ BigUint :: from( 0_u32 ) ; 8 ] ;
326
+ for limb in & mut limbs {
327
+ let ( q, r) = val. div_rem ( & pow2_32) ;
328
+ * limb = r;
329
+ val = q;
330
+ }
331
+ limbs
332
+ } ;
333
+
334
+ // Split the value into 2 limbs if it is less than 2^63, or 8 limbs after adding 2^255.
335
+ let split_encoded = |mut val : BigUint | -> Vec < BigUint > {
336
+ if val < pow2_63 {
337
+ // Two‑limb representation.
338
+ let ( high, low) = val. div_rem ( & pow2_32) ;
339
+ vec ! [ low, high]
340
+ } else {
341
+ // Eight limbs after adding 2^255.
342
+ val += & pow2_255;
343
+ split_fixed8 ( val)
344
+ }
345
+ } ;
346
+
347
+ // Unpack the values into u32 limbs in little-endian order according to the specified mode.
299
348
let out: Vec < MaybeRelocatable > = vals
300
349
. 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
- }
350
+ . map ( |v| v. to_biguint ( ) )
351
+ . flat_map ( |val| match mode {
352
+ BlakeEncodingMode :: NoEncoding => split_fixed8 ( val) ,
353
+ BlakeEncodingMode :: UseEncoding => split_encoded ( val) ,
316
354
} )
317
355
. map ( Felt252 :: from)
318
356
. map ( MaybeRelocatable :: from)
@@ -740,22 +778,28 @@ mod tests {
740
778
check_memory ! [ vm. segments. memory, ( ( 1 , 3 ) , 0 ) ] ;
741
779
}
742
780
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
781
+ /// Builds a VM, writes the packed_values_len, packed_values, unpacked_u32s and the
782
+ /// actual small and big felts to the memory.
783
+ /// Returns the VM and the ids_data HashMap.
784
+ fn prepare_vm_for_splitting_felts_for_blake (
785
+ small_val : i128 ,
786
+ big_val : i128 ,
787
+ ) -> ( VirtualMachine , HashMap < String , HintReference > ) {
748
788
let mut vm = vm ! ( ) ;
749
- //Insert ids into memory
750
789
vm. segments = segments ! [
790
+ // ids.packed_values_len = 2
751
791
( ( 1 , 0 ) , 2 ) ,
792
+ // ids.packed_values = (1,3)
752
793
( ( 1 , 1 ) , ( 1 , 3 ) ) ,
794
+ // ids.unpacked_u32s = (2,0)
753
795
( ( 1 , 2 ) , ( 2 , 0 ) ) ,
754
- ( ( 1 , 3 ) , 0x123456781234 ) ,
755
- ( ( 1 , 4 ) , 0x1234abcd5678efab1234abcd )
796
+ // packed small / big felts
797
+ ( ( 1 , 3 ) , small_val) ,
798
+ ( ( 1 , 4 ) , big_val)
756
799
] ;
757
800
vm. set_fp ( 5 ) ;
758
801
vm. set_ap ( 5 ) ;
802
+
759
803
let ids_data = ids_data ! [
760
804
"packed_values_len" ,
761
805
"packed_values" ,
@@ -764,21 +808,62 @@ mod tests {
764
808
"big_value"
765
809
] ;
766
810
vm. segments . add ( ) ;
767
- //Execute the hint
768
- assert_matches ! ( run_hint!( vm, ids_data, hint_code) , Ok ( ( ) ) ) ;
769
- //Check data ptr
811
+ ( vm, ids_data)
812
+ }
813
+
814
+ #[ test]
815
+ #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
816
+ fn blake2s_encode_and_split_felts ( ) {
817
+ let ( mut vm, ids_data) =
818
+ prepare_vm_for_splitting_felts_for_blake ( 0x123456781234 , 0x1234abcd5678efab1234abcd ) ;
819
+ assert_matches ! (
820
+ run_hint!( vm, ids_data, hint_code:: BLAKE2S_ENCODE_AND_SPLIT_FELTS ) ,
821
+ Ok ( ( ) )
822
+ ) ;
770
823
check_memory ! [
771
824
vm. segments. memory,
772
- ( ( 2 , 0 ) , 0x1234 ) ,
773
- ( ( 2 , 1 ) , 0x56781234 ) ,
774
- ( ( 2 , 2 ) , 0x80000000 ) ,
825
+ ( ( 2 , 0 ) , 0x56781234 ) ,
826
+ ( ( 2 , 1 ) , 0x1234 ) ,
827
+ ( ( 2 , 2 ) , 0x1234abcd ) ,
828
+ ( ( 2 , 3 ) , 0x5678efab ) ,
829
+ ( ( 2 , 4 ) , 0x1234abcd ) ,
830
+ ( ( 2 , 5 ) , 0 ) ,
831
+ ( ( 2 , 6 ) , 0 ) ,
832
+ ( ( 2 , 7 ) , 0 ) ,
833
+ ( ( 2 , 8 ) , 0 ) ,
834
+ ( ( 2 , 9 ) , 0x80000000 ) ,
835
+ ] ;
836
+ }
837
+
838
+ #[ test]
839
+ #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
840
+ fn blake2s_split_felts_to_u32s ( ) {
841
+ let ( mut vm, ids_data) = prepare_vm_for_splitting_felts_for_blake (
842
+ 0x123456781234 ,
843
+ 0x1234abcd5678efab1234abcd5678efab ,
844
+ ) ;
845
+ assert_matches ! (
846
+ run_hint!( vm, ids_data, hint_code:: BLAKE2S_SPLIT_FELTS_TO_U32S ) ,
847
+ Ok ( ( ) )
848
+ ) ;
849
+ check_memory ! [
850
+ vm. segments. memory,
851
+ ( ( 2 , 0 ) , 0x56781234 ) ,
852
+ ( ( 2 , 1 ) , 0x1234 ) ,
853
+ ( ( 2 , 2 ) , 0 ) ,
775
854
( ( 2 , 3 ) , 0 ) ,
776
855
( ( 2 , 4 ) , 0 ) ,
777
856
( ( 2 , 5 ) , 0 ) ,
778
857
( ( 2 , 6 ) , 0 ) ,
779
- ( ( 2 , 7 ) , 0x1234abcd ) ,
858
+ ( ( 2 , 7 ) , 0 ) ,
780
859
( ( 2 , 8 ) , 0x5678efab ) ,
781
- ( ( 2 , 9 ) , 0x1234abcd )
860
+ ( ( 2 , 9 ) , 0x1234abcd ) ,
861
+ ( ( 2 , 10 ) , 0x5678efab ) ,
862
+ ( ( 2 , 11 ) , 0x1234abcd ) ,
863
+ ( ( 2 , 12 ) , 0 ) ,
864
+ ( ( 2 , 13 ) , 0 ) ,
865
+ ( ( 2 , 14 ) , 0 ) ,
866
+ ( ( 2 , 15 ) , 0 ) ,
782
867
] ;
783
868
}
784
869
0 commit comments