@@ -36,28 +36,76 @@ pub fn generate_blinders<T: RngCore>(rng: &mut T, n: usize) -> Vec<Fr> {
3636/// Get a bitstring to derive the verification scalars using binary decomposition. Used to [optimize the
3737/// verifier](crate::notes::optimizations#ipa-verification-scalars).
3838///
39- /// TODO: This can be done more elegantly
39+ /// TODO: This can be done more efficiently
4040pub fn get_verification_scalars_bitstring ( n : usize , logn : usize ) -> Vec < Vec < usize > > {
41- let mut bitstring: Vec < Vec < usize > > = Vec :: new ( ) ;
42- for _i in 0 ..n {
43- let vec_i: Vec < usize > = Vec :: new ( ) ;
44- bitstring. push ( vec_i) ;
45- }
41+ // Initialize gamma tracker: gamma_tracker[i] stores the list of gamma rounds applied to original index i.
42+ let mut bitstring: Vec < Vec < usize > > = vec ! [ Vec :: new( ) ; n] ;
43+
44+ // Initialize map: current_map[k] holds the list of *original indices* contributing to position k
45+ // in the vector of the current iteration.
46+ let mut current_map: Vec < Vec < usize > > = ( 0 ..n) . map ( |i| vec ! [ i] ) . collect ( ) ;
47+ let mut current_n = n; // Size of the vector in the current iteration.
48+
49+ for j in 0 ..logn { // Iterate through gamma rounds (j=0 -> gamma0, j=1 -> gamma1, ...)
50+ // --- Calculate folding parameters for the current vector size `current_n` ---
51+ let n_power_of_2 = current_n. next_power_of_two ( ) ;
52+ let n_first = n_power_of_2 >> 1 ;
53+ let n_fold = current_n - n_first;
54+ let ih = ( n_first - n_fold) / 2 ;
55+ let it = ih + n_fold;
56+
57+ // --- Identify T and S ranges based on *current* indices (k = 0 to current_n - 1) ---
58+ // --- Apply gamma j ---
59+ for k_source in n_first..current_n {
60+ // k_source is the position index in the *current* vector (current_map)
61+ if k_source < current_map. len ( ) { // Safety bounds check
62+ // Iterate through all original indices currently mapped to this position
63+ for & original_index in & current_map[ k_source] {
64+ // Record that gamma j was applied to this original index
65+ if original_index < bitstring. len ( ) { // Safety bounds check
66+ bitstring[ original_index] . push ( j) ;
67+ }
68+ }
69+ }
70+ }
4671
47- for j in 0 ..logn {
48- # [ allow ( clippy :: needless_range_loop ) ]
49- for i in 0 ..n {
50- let current_bitstring = format ! ( "{:b}" , i ) ;
51- let mut bit_vec : Vec < char > = current_bitstring . chars ( ) . collect ( ) ;
52- bit_vec . reverse ( ) ;
53- while bit_vec . len ( ) < logn {
54- bit_vec . push ( '0' ) ;
72+ // --- Prepare the map for the next iteration ---
73+ // Simulate the concatenation: I_next = S_left + T_folded + S_right
74+ let mut next_map : Vec < Vec < usize > > = Vec :: with_capacity ( n_first ) ; // Max possible size after folding
75+
76+ // 1. Concatenate S_left part (original indices from positions 0 to i_start_fold_target - 1)
77+ for k in 0 ..ih {
78+ if k < current_map . len ( ) { // Safety bounds check
79+ next_map . push ( current_map [ k ] . clone ( ) ) ; // Clone the list of original indices
5580 }
81+ }
5682
57- if bit_vec[ logn - j - 1 ] == '1' {
58- bitstring[ i] . push ( j) ;
83+ // 2. Concatenate Folded T part
84+ // Iterate through the target positions (left side of T)
85+ for k_target in ih..it {
86+ // Find the corresponding source position on the right side of T
87+ let k_source = k_target - ih + n_first;
88+
89+ if k_target < current_map. len ( ) && k_source < current_map. len ( ) { // Safety bounds check
90+ // Create the new combined list of original indices for the folded position.
91+ // The new position (index in next_map corresponding to k_target)
92+ // inherits the history (original indices) from both k_target and k_source.
93+ let mut combined_history = current_map[ k_target] . clone ( ) ;
94+ combined_history. extend ( current_map[ k_source] . iter ( ) . cloned ( ) ) ;
95+ next_map. push ( combined_history) ;
5996 }
6097 }
98+
99+ // 3. Concatenate S_right part (original indices from positions i_end_fold_target to n_first - 1)
100+ for k in it..n_first {
101+ if k < current_map. len ( ) { // Safety bounds check
102+ next_map. push ( current_map[ k] . clone ( ) ) ; // Clone the list of original indices
103+ }
104+ }
105+
106+ // --- Update state for the next iteration ---
107+ current_map = next_map;
108+ current_n = current_map. len ( ) ; // Update the size for the next round's calculations
61109 }
62110
63111 bitstring
0 commit comments