@@ -268,51 +268,88 @@ 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
289
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):
279
301
val, memory[ids.unpacked_u32s + offset + i] = divmod(val, 2**32)
280
302
assert val == 0
281
303
offset += val_len
282
304
*/
283
- pub fn blake2s_unpack_felts (
305
+ pub fn split_packed_felts (
284
306
vm : & mut VirtualMachine ,
285
307
ids_data : & HashMap < String , HintReference > ,
286
308
ap_tracking : & ApTracking ,
309
+ mode : BlakeEncodingMode ,
287
310
) -> Result < ( ) , HintError > {
288
311
let packed_values_len =
289
312
get_integer_from_var_name ( "packed_values_len" , vm, ids_data, ap_tracking) ?;
290
313
let packed_values = get_ptr_from_var_name ( "packed_values" , vm, ids_data, ap_tracking) ?;
291
314
let unpacked_u32s = get_ptr_from_var_name ( "unpacked_u32s" , vm, ids_data, ap_tracking) ?;
292
315
293
316
let vals = vm. get_integer_range ( packed_values, felt_to_usize ( & packed_values_len) ?) ?;
317
+
294
318
let pow2_32 = BigUint :: from ( 1_u32 ) << 32 ;
295
319
let pow2_63 = BigUint :: from ( 1_u32 ) << 63 ;
296
320
let pow2_255 = BigUint :: from ( 1_u32 ) << 255 ;
297
321
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.
299
347
let out: Vec < MaybeRelocatable > = vals
300
348
. 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) ,
316
353
} )
317
354
. map ( Felt252 :: from)
318
355
. map ( MaybeRelocatable :: from)
@@ -740,22 +777,28 @@ mod tests {
740
777
check_memory ! [ vm. segments. memory, ( ( 1 , 3 ) , 0 ) ] ;
741
778
}
742
779
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 > ) {
748
787
let mut vm = vm ! ( ) ;
749
- //Insert ids into memory
750
788
vm. segments = segments ! [
789
+ // ids.packed_values_len = 2
751
790
( ( 1 , 0 ) , 2 ) ,
791
+ // ids.packed_values = (1,3)
752
792
( ( 1 , 1 ) , ( 1 , 3 ) ) ,
793
+ // ids.unpacked_u32s = (2,0)
753
794
( ( 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)
756
798
] ;
757
799
vm. set_fp ( 5 ) ;
758
800
vm. set_ap ( 5 ) ;
801
+
759
802
let ids_data = ids_data ! [
760
803
"packed_values_len" ,
761
804
"packed_values" ,
@@ -764,21 +807,62 @@ mod tests {
764
807
"big_value"
765
808
] ;
766
809
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
+ ) ;
770
822
check_memory ! [
771
823
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 ) ,
775
853
( ( 2 , 3 ) , 0 ) ,
776
854
( ( 2 , 4 ) , 0 ) ,
777
855
( ( 2 , 5 ) , 0 ) ,
778
856
( ( 2 , 6 ) , 0 ) ,
779
- ( ( 2 , 7 ) , 0x1234abcd ) ,
857
+ ( ( 2 , 7 ) , 0 ) ,
780
858
( ( 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 ) ,
782
866
] ;
783
867
}
784
868
0 commit comments