1
1
use crate :: common:: State ;
2
2
use itertools:: Itertools ;
3
3
use num_bigint:: BigUint ;
4
- use num_traits:: { One , Zero } ;
4
+ use num_traits:: Zero ;
5
5
use pairing:: arithmetic:: FieldExt ;
6
6
use pairing:: bn256:: Fr as Fp ;
7
7
use std:: ops:: { Index , IndexMut } ;
8
8
9
- pub const B2 : u64 = 2 ;
10
- pub const B13 : u64 = 13 ;
11
- pub const B9 : u64 = 9 ;
9
+ pub const B2 : u8 = 2 ;
10
+ pub const B13 : u8 = 13 ;
11
+ pub const B9 : u8 = 9 ;
12
12
13
13
/// Base 9 coef mapper scalers
14
14
/// f_logic(x1, x2, x3, x4) = x1 ^ (!x2 & x3) ^ x4
15
15
/// f_arith(x1, x2, x3, x4) = 2*x1 + x2 + 3*x3 + 2*x4
16
16
/// where x1, x2, x3, x4 are binary.
17
17
/// We have the property that `0 <= f_arith(...) < 9` and
18
18
/// the map from `f_arith(...)` to `f_logic(...)` is injective.
19
- pub const A1 : u64 = 2u64 ;
20
- pub const A2 : u64 = 1u64 ;
21
- pub const A3 : u64 = 3u64 ;
22
- pub const A4 : u64 = 2u64 ;
19
+ pub const A1 : u8 = 2 ;
20
+ pub const A2 : u8 = 1 ;
21
+ pub const A3 : u8 = 3 ;
22
+ pub const A4 : u8 = 2 ;
23
23
24
24
pub type Lane13 = BigUint ;
25
25
pub type Lane9 = BigUint ;
@@ -87,10 +87,6 @@ impl Clone for StateBigInt {
87
87
}
88
88
}
89
89
90
- pub fn mod_u64 ( a : & BigUint , b : u64 ) -> u64 {
91
- ( a % b) . iter_u64_digits ( ) . take ( 1 ) . next ( ) . unwrap_or ( 0 )
92
- }
93
-
94
90
pub fn convert_b2_to_b13 ( a : u64 ) -> Lane13 {
95
91
let mut lane13: BigUint = Zero :: zero ( ) ;
96
92
for i in 0 ..64 {
@@ -117,7 +113,7 @@ pub fn convert_b2_to_b9(a: u64) -> Lane9 {
117
113
///
118
114
/// For example, if we have 5 bits set and 7 bits unset, then we have `x` as 5
119
115
/// and the xor result to be 1.
120
- pub fn convert_b13_coef ( x : u64 ) -> u64 {
116
+ pub fn convert_b13_coef ( x : u8 ) -> u8 {
121
117
assert ! ( x < 13 ) ;
122
118
x & 1
123
119
}
@@ -127,55 +123,49 @@ pub fn convert_b13_coef(x: u64) -> u64 {
127
123
///
128
124
/// The input `x` is a chunk of a base 9 number and it represents the arithmatic
129
125
/// result of `2*a + b + 3*c + 2*d`, where `a`, `b`, `c`, and `d` each is a bit.
130
- pub fn convert_b9_coef ( x : u64 ) -> u64 {
126
+ pub fn convert_b9_coef ( x : u8 ) -> u8 {
131
127
assert ! ( x < 9 ) ;
132
- let bit_table: [ u64 ; 9 ] = [ 0 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 ] ;
128
+ let bit_table: [ u8 ; 9 ] = [ 0 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 ] ;
133
129
bit_table[ x as usize ]
134
130
}
135
131
132
+ // We assume the input comes from Theta step and has 65 chunks
136
133
pub fn convert_b13_lane_to_b9 ( x : Lane13 , rot : u32 ) -> Lane9 {
137
- let mut base = BigUint :: from ( B9 ) . pow ( rot) ;
138
- let mut special_chunk = Zero :: zero ( ) ;
139
- let mut raw = x;
140
- let mut acc: Lane9 = Zero :: zero ( ) ;
141
-
142
- for i in 0 ..65 {
143
- let remainder: u64 = mod_u64 ( & raw , B13 ) ;
144
- if i == 0 || i == 64 {
145
- special_chunk += remainder;
146
- } else {
147
- acc += convert_b13_coef ( remainder) * base. clone ( ) ;
148
- }
149
- raw /= B13 ;
150
- base *= B9 ;
151
- if i == 63 - rot {
152
- base = One :: one ( ) ;
153
- }
154
- }
155
- acc += convert_b13_coef ( special_chunk) * BigUint :: from ( B9 ) . pow ( rot) ;
156
- acc
134
+ // 65 chunks
135
+ let mut chunks = x. to_radix_le ( B13 . into ( ) ) ;
136
+ chunks. resize ( 65 , 0 ) ;
137
+ // 0 and 64 was separated in Theta, we now combined them together
138
+ let special = chunks. get ( 0 ) . unwrap ( ) + chunks. get ( 64 ) . unwrap ( ) ;
139
+ // middle 63 chunks
140
+ let middle = chunks. get ( 1 ..64 ) . unwrap ( ) ;
141
+ // split at offset
142
+ let ( left, right) = middle. split_at ( 63 - rot as usize ) ;
143
+ // rotated has 64 chunks
144
+ // left is rotated right, and the right is wrapped over to left
145
+ // with the special chunk in the middle
146
+ let rotated: Vec < u8 > = right
147
+ . iter ( )
148
+ . chain ( vec ! [ special] . iter ( ) )
149
+ . chain ( left. iter ( ) )
150
+ . map ( |& x| convert_b13_coef ( x) )
151
+ . collect_vec ( ) ;
152
+ BigUint :: from_radix_le ( & rotated, B9 . into ( ) ) . unwrap_or_default ( )
157
153
}
158
154
159
155
pub fn convert_lane < F > (
160
156
lane : BigUint ,
161
- from_base : u64 ,
162
- to_base : u64 ,
157
+ from_base : u8 ,
158
+ to_base : u8 ,
163
159
coef_transform : F ,
164
160
) -> BigUint
165
161
where
166
- F : Fn ( u64 ) -> u64 ,
162
+ F : Fn ( u8 ) -> u8 ,
167
163
{
168
- let mut base: BigUint = One :: one ( ) ;
169
- let mut raw = lane;
170
- let mut acc: BigUint = Zero :: zero ( ) ;
171
-
172
- for _ in 0 ..64 {
173
- let remainder: u64 = mod_u64 ( & raw , B9 ) ;
174
- acc += coef_transform ( remainder) * base. clone ( ) ;
175
- raw /= from_base;
176
- base *= to_base;
177
- }
178
- acc
164
+ let chunks = lane. to_radix_be ( from_base. into ( ) ) ;
165
+ let converted_chunks: Vec < u8 > =
166
+ chunks. iter ( ) . map ( |& x| coef_transform ( x) ) . collect ( ) ;
167
+ BigUint :: from_radix_be ( & converted_chunks, to_base. into ( ) )
168
+ . unwrap_or_default ( )
179
169
}
180
170
181
171
pub fn convert_b9_lane_to_b13 ( x : Lane9 ) -> Lane13 {
@@ -215,17 +205,11 @@ pub fn big_uint_to_field<F: FieldExt>(a: &BigUint) -> F {
215
205
216
206
/// This function allows us to inpect coefficients of big-numbers in different
217
207
/// bases.
218
- pub fn inspect ( x : BigUint , name : & str , base : u64 ) {
219
- let mut raw = x. clone ( ) ;
220
- let mut info: Vec < ( u32 , u64 ) > = vec ! [ ] ;
221
-
222
- for i in 0 ..65 {
223
- let remainder: u64 = mod_u64 ( & raw , base) ;
224
- raw /= base;
225
- if remainder != 0 {
226
- info. push ( ( i, remainder) ) ;
227
- }
228
- }
208
+ pub fn inspect ( x : BigUint , name : & str , base : u8 ) {
209
+ let mut chunks = x. to_radix_le ( base. into ( ) ) ;
210
+ chunks. resize ( 65 , 0 ) ;
211
+ let info: Vec < ( usize , u8 ) > =
212
+ ( 0 ..65 ) . zip ( chunks. iter ( ) . copied ( ) ) . collect_vec ( ) ;
229
213
println ! ( "inspect {} {} info {:?}" , name, x, info) ;
230
214
}
231
215
@@ -283,3 +267,34 @@ pub fn state_bigint_to_field<F: FieldExt, const N: usize>(
283
267
arr[ 0 ..N ] . copy_from_slice ( & vector[ 0 ..N ] ) ;
284
268
arr
285
269
}
270
+
271
+ pub fn f_from_radix_be < F : FieldExt > ( buf : & [ u8 ] , base : u8 ) -> F {
272
+ let base = F :: from ( base. into ( ) ) ;
273
+ buf. iter ( )
274
+ . fold ( F :: zero ( ) , |acc, & x| acc * base + F :: from ( x. into ( ) ) )
275
+ }
276
+
277
+ #[ cfg( test) ]
278
+ mod tests {
279
+ use super :: * ;
280
+ use num_bigint:: BigUint ;
281
+ #[ test]
282
+ fn test_convert_b13_lane_to_b9 ( ) {
283
+ // the number 1 is chosen that `convert_b13_coef` has no effect
284
+ let mut a = vec ! [ 0 , 1 , 1 , 1 ] ;
285
+ a. resize ( 65 , 0 ) ;
286
+ let lane = BigUint :: from_radix_le ( & a, B13 . into ( ) ) . unwrap_or_default ( ) ;
287
+ assert_eq ! (
288
+ convert_b13_lane_to_b9( lane. clone( ) , 0 ) ,
289
+ BigUint :: from_radix_le( & a, B9 . into( ) ) . unwrap_or_default( )
290
+ ) ;
291
+
292
+ // rotate by 4
293
+ let mut b = vec ! [ 0 , 0 , 0 , 0 , 0 , 1 , 1 , 1 ] ;
294
+ b. resize ( 65 , 0 ) ;
295
+ assert_eq ! (
296
+ convert_b13_lane_to_b9( lane, 4 ) ,
297
+ BigUint :: from_radix_le( & b, B9 . into( ) ) . unwrap_or_default( )
298
+ ) ;
299
+ }
300
+ }
0 commit comments