1
+ use crate::utils::cast_num_to_u32 ;
2
+
1
3
/**
2
4
* @file methods to extract data efficiently from Field elements that represent 31 bytes of packed data
3
5
**/
@@ -463,7 +465,7 @@ global PATH_LOOKUP: [[bool; 5]; 32] = [
463
465
* some of the chunks will describe the bytes [0, ..., num_bytes - 1]
464
466
* some of the chunks will describe the bytes [num_bytes, ..., 31]
465
467
**/
466
- unconstrained fn __slice_field (f : Field , num_bytes : Field ) -> [Field ; 5 ] {
468
+ unconstrained fn __slice_field (f : Field , num_bytes : u32 ) -> [Field ; 5 ] {
467
469
let head_path = PATH_LOOKUP [num_bytes ];
468
470
let bytes : [u8 ; 32 ] = f .to_be_bytes ();
469
471
let bytes = bytes .map (|b : u8 | b as Field );
@@ -558,17 +560,17 @@ unconstrained fn __slice_field(f: Field, num_bytes: Field) -> [Field; 5] {
558
560
chunks
559
561
}
560
562
561
- unconstrained fn __divmod (numerator : Field , denominator : Field ) -> (Field , Field ) {
562
- let quotient = numerator as u32 / denominator as u32 ;
563
- let remainder = numerator as u32 % denominator as u32 ;
564
- (quotient as Field , remainder as Field )
563
+ unconstrained fn __divmod (numerator : u16 , denominator : u16 ) -> (u16 , u16 ) {
564
+ let quotient = numerator / denominator ;
565
+ let remainder = numerator % denominator ;
566
+ (quotient , remainder )
565
567
}
566
568
567
569
/**
568
570
* @brief cheeky divmod method for dividing a u16 by 31
569
571
* we know the quotient will fit into a 14 bit range check which will save us some fractional gates
570
572
**/
571
- fn divmod_31 (numerator : Field ) -> (Field , Field ) {
573
+ fn divmod_31 (numerator : u16 ) -> (u16 , u16 ) {
572
574
// Safety: we check the bit lengths of qf and rf and their relation to the numerator with assertions later
573
575
let (quotient , remainder ) = unsafe { __divmod (numerator , 31 ) };
574
576
@@ -582,7 +584,7 @@ fn divmod_31(numerator: Field) -> (Field, Field) {
582
584
583
585
// n / d = q
584
586
// d * q + r = n
585
- assert (qf * 31 as Field + rf == numerator as Field );
587
+ assert (qf * 31 + rf == numerator as Field );
586
588
(quotient , remainder )
587
589
}
588
590
@@ -603,7 +605,7 @@ unconstrained fn decompose(val: Field) -> [Field; 16] {
603
605
// 5 gates?
604
606
pub fn get_last_limb_path <let OutputFields : u32 >(last_limb_index : Field ) -> [Field ; OutputFields ] {
605
607
// TODO we offset by 1 explain why (0 byte length produces 0 - 1 which = invalid array index. we just add 1 and increase array length by 1 to compensate)
606
- let path = LAST_LIMB_PATH [last_limb_index + 1 ]; // 2
608
+ let path = LAST_LIMB_PATH [cast_num_to_u32 ( last_limb_index + 1 ) ]; // 2
607
609
// Safety: check the comments below
608
610
let path_valid_bits = unsafe { decompose (path ) };
609
611
let mut path_valid_sum : Field = 0 ;
@@ -624,7 +626,7 @@ pub fn get_last_limb_path<let OutputFields: u32>(last_limb_index: Field) -> [Fie
624
626
* where `head = f.slice(0, num_bytes)`, `tail = f.slice(num_bytes, 31)`
625
627
* @details cost 46 gates
626
628
**/
627
- pub fn slice_field (f : Field , num_bytes : Field ) -> (Field , Field ) {
629
+ pub fn slice_field (f : Field , num_bytes : u32 ) -> (Field , Field ) {
628
630
// Safety: we check the bit lengths of the chunks with assertions later
629
631
let chunks = unsafe { __slice_field (f , num_bytes ) };
630
632
chunks [0 ].assert_max_bit_size ::<8 >(); // 1.25 gates
@@ -676,62 +678,68 @@ pub fn slice_fields<let InputFields: u32, let OutputFields: u32>(
676
678
start_byte : Field ,
677
679
num_bytes : Field ,
678
680
) -> [Field ; OutputFields ] {
681
+ start_byte .assert_max_bit_size ::<16 >();
682
+ num_bytes .assert_max_bit_size ::<16 >();
679
683
// 3.5
680
- let (start_index , start_mod_31 ) = divmod_31 (start_byte );
684
+ let (start_index , start_mod_31 ) = divmod_31 (start_byte as u16 );
681
685
let num_underflow_bytes = start_mod_31 ;
682
686
// 3.5, 7
683
- let (num_bytes_div_31 , num_bytes_mod_31 ) = divmod_31 (num_bytes );
687
+ let (num_bytes_div_31 , num_bytes_mod_31 ) = divmod_31 (num_bytes as u16 );
684
688
685
689
// 2, 9
686
- let num_bytes_mod_31_is_0 = NUM_BYTES_MOD_31_IS_ZERO [num_bytes_mod_31 ];
690
+ let num_bytes_mod_31_is_0 = NUM_BYTES_MOD_31_IS_ZERO [num_bytes_mod_31 as u32 ];
687
691
// 2, 11
688
- let num_bytes_div_31_is_0 = NUM_BYTES_MOD_31_IS_ZERO [num_bytes_div_31 ];
692
+ let num_bytes_div_31_is_0 = NUM_BYTES_MOD_31_IS_ZERO [num_bytes_div_31 as u32 ];
689
693
690
694
// 1, 12
691
- let lookup = (-num_bytes_div_31_is_0 * num_bytes ) - start_mod_31 + 62 ;
695
+ let lookup = (-num_bytes_div_31_is_0 * num_bytes ) - start_mod_31 as Field + 62 ;
692
696
std:: as_witness (lookup );
693
697
// 3, 15
694
- let bytes_fit_into_limb = INTEGER_UP_TO_62_IS_GREATER_THAN_31 [lookup ] * num_bytes_div_31_is_0 ;
698
+ let bytes_fit_into_limb =
699
+ INTEGER_UP_TO_62_IS_GREATER_THAN_31 [cast_num_to_u32 (lookup )] * num_bytes_div_31_is_0 ;
695
700
std:: as_witness (bytes_fit_into_limb );
696
701
697
702
// 2, 17
698
- let num_unused_bytes_in_start_limb =
699
- (num_bytes + start_mod_31 - 31 ) * bytes_fit_into_limb + (31 - start_mod_31 );
703
+ let num_unused_bytes_in_start_limb = (num_bytes + start_mod_31 as Field - 31 )
704
+ * bytes_fit_into_limb
705
+ + (31 - start_mod_31 as Field );
700
706
std:: as_witness (num_unused_bytes_in_start_limb );
701
707
let num_remaining_bytes = num_bytes - num_unused_bytes_in_start_limb ;
702
708
703
709
// 4.5, 21.5
704
- let mut (num_whole_limbs , num_overflow_bytes ) = divmod_31 (num_remaining_bytes );
710
+ num_remaining_bytes .assert_max_bit_size ::<16 >();
711
+ let mut (num_whole_limbs , num_overflow_bytes ) = divmod_31 (num_remaining_bytes as u16 );
705
712
// 44, 65.5
706
- let (_ , tail ) = slice_field (data [start_index ], num_underflow_bytes );
713
+ let (_ , tail ) = slice_field (data [start_index as u32 ], num_underflow_bytes as u32 );
707
714
708
715
let mut previous = tail ;
709
716
710
717
let mut result = [0 ; OutputFields ];
711
718
712
719
// 4, 69.5
713
- let extra_head_section = INTEGER_UP_TO_62_IS_GREATER_THAN_31 [num_overflow_bytes - start_mod_31
714
- + 31 ]
720
+ let extra_head_section = INTEGER_UP_TO_62_IS_GREATER_THAN_31 [(
721
+ 31 + num_overflow_bytes - start_mod_31
722
+ ) as u32 ]
715
723
* (1 - bytes_fit_into_limb );
716
724
717
725
// 1, 70.5
718
- let index_of_output_limb : Field = (num_bytes_div_31 - num_bytes_mod_31_is_0 );
726
+ let index_of_output_limb : Field = (num_bytes_div_31 as Field - num_bytes_mod_31_is_0 );
719
727
// 5, 75.5
720
728
let path_valid_output : [Field ; OutputFields ] = get_last_limb_path (index_of_output_limb );
721
729
722
730
// 2, 77.5
723
- let tail_shift = BYTE_SHIFT [num_unused_bytes_in_start_limb ];
731
+ let tail_shift = BYTE_SHIFT [cast_num_to_u32 ( num_unused_bytes_in_start_limb ) ];
724
732
725
733
// 51, 128.5
726
734
for i in 0 ..(OutputFields - 1 ) {
727
735
// 0
728
736
let slice_valid = path_valid_output [i ];
729
737
// 1
730
- let data_index = (start_index + 1 + i as Field );
738
+ let data_index = (start_index as u32 + 1 + i );
731
739
// 2, 3
732
740
let input_slice = data [data_index ];
733
741
// 44, 47
734
- let (head , tail ) = slice_field (input_slice , num_underflow_bytes );
742
+ let (head , tail ) = slice_field (input_slice , num_underflow_bytes as u32 );
735
743
// 1, 48
736
744
let combined = previous * tail_shift + head ;
737
745
// 1, 49
@@ -741,26 +749,27 @@ pub fn slice_fields<let InputFields: u32, let OutputFields: u32>(
741
749
}
742
750
743
751
// 2, 130.5
744
- let slice_size = (num_bytes + start_mod_31 ) * bytes_fit_into_limb + num_overflow_bytes ;
752
+ let slice_size =
753
+ (num_bytes + start_mod_31 as Field ) * bytes_fit_into_limb + num_overflow_bytes as Field ;
745
754
746
755
// 1, 131.5
747
756
let use_previous_for_last_limb : Field = extra_head_section + bytes_fit_into_limb ;
748
757
749
758
// 1, 132.5
750
759
let mut index_of_overflow_limb = start_index + num_whole_limbs + 1 ;
751
760
// 2, 134.5
752
- let last_limb_from_data = data [index_of_overflow_limb ];
761
+ let last_limb_from_data = data [index_of_overflow_limb as u32 ];
753
762
// 2, 136.5
754
763
let slice_source =
755
764
(previous - last_limb_from_data ) * use_previous_for_last_limb + last_limb_from_data ;
756
765
757
766
// 44, 180.5
758
- let (head , _ ) = slice_field (slice_source , slice_size );
767
+ let (head , _ ) = slice_field (slice_source , cast_num_to_u32 ( slice_size ) );
759
768
760
769
// 3, 183.5
761
- let previous_shift = BYTE_SHIFT [31 - num_overflow_bytes ]; // could save 1 gate by making different shift table
770
+ let previous_shift = BYTE_SHIFT [31 - num_overflow_bytes as u32 ]; // could save 1 gate by making different shift table
762
771
// 2, 185.5
763
- let last_limb_shift = BYTE_SHIFT [num_bytes_mod_31 ];
772
+ let last_limb_shift = BYTE_SHIFT [num_bytes_mod_31 as u32 ];
764
773
// 1, 186.5
765
774
let mut last_limb = (previous * previous_shift );
766
775
std:: as_witness (last_limb );
@@ -891,7 +900,7 @@ mod test {
891
900
892
901
for i in 0 ..32 {
893
902
println (f"i = { i} " );
894
- let num_bytes = i as Field ;
903
+ let num_bytes = i ;
895
904
let (head , tail ) = slice_field (input , num_bytes );
896
905
let mut expected_head : Field = 0 ;
897
906
let mut expected_tail : Field = 0 ;
@@ -901,7 +910,7 @@ mod test {
901
910
}
902
911
for j in 0 ..(31 - num_bytes as u32 ) {
903
912
expected_tail *= 0x100 ;
904
- expected_tail += input_bytes [j as Field + num_bytes + 1 ] as Field ;
913
+ expected_tail += input_bytes [j + num_bytes + 1 ] as Field ;
905
914
}
906
915
assert (expected_head == head );
907
916
assert (expected_tail == tail );
0 commit comments