@@ -473,41 +473,116 @@ def checked_decompose_bits(a):
473473
474474
475475@inline
476- def checked_decompose_bits_and_compute_root_pow_const (a , domain_size ):
477- # Hint 6 nibbles (4 bits each) + 1 top-7-bit value = 7 hints
476+ def whir_4_merkle_step_and_pow (v , state_in , path_chunk , state_out , power_shift ):
477+ whir_do_4_merkle_levels (v , state_in , path_chunk , state_out )
478+ return ROOT ** (power_shift * v )
479+
480+
481+ @inline
482+ def whir_3_merkle_step_and_pow (v , state_in , path_chunk , state_out , power_shift ):
483+ whir_do_3_merkle_levels (v , state_in , path_chunk , state_out )
484+ return ROOT ** (power_shift * (v % 8 ))
485+
486+
487+ @inline
488+ def whir_2_merkle_step_and_pow (v , state_in , path_chunk , state_out , power_shift ):
489+ whir_do_2_merkle_levels (v , state_in , path_chunk , state_out )
490+ return ROOT ** (power_shift * (v % 4 ))
491+
492+
493+ @inline
494+ def whir_1_merkle_step_and_pow (v , state_in , path_chunk , state_out , power_shift ):
495+ whir_do_1_merkle_level (v , state_in , path_chunk , state_out )
496+ return ROOT ** (power_shift * (v % 2 ))
497+
498+
499+ @inline
500+ def decompose_and_verify_merkle_query (a , domain_size , prev_root , num_chunks ):
478501 nibbles = Array (6 )
479502 top7 : Imu
480503 hint_decompose_bits_merkle_whir (nibbles , top7 , a , 4 )
481504
482505 for i in unroll (0 , 6 ):
483506 assert nibbles [i ] < 16
484-
485507 assert top7 < 2 ** 7
486508
487509 partial_sum : Mut = nibbles [0 ]
488510 for i in unroll (1 , 6 ):
489511 partial_sum += nibbles [i ] * 16 ** i
490-
491512 if top7 == 2 ** 7 - 1 :
492513 assert partial_sum == 0
493-
494514 assert partial_sum + top7 * 2 ** 24 == a
495515
496- # Compute domain_generator^index
516+ leaf_data = Array (num_chunks * DIGEST_LEN )
517+ hint_witness ("merkle_leaf" , leaf_data )
518+ leaf_hash = slice_hash_rtl (leaf_data , num_chunks )
519+
520+ merkle_path = Array (domain_size * DIGEST_LEN )
521+ hint_witness ("merkle_path" , merkle_path )
522+
523+ n_nibbles = div_ceil (domain_size , 4 )
524+ states = Array ((n_nibbles - 1 ) * DIGEST_LEN )
525+
497526 prod : Mut = 1
498- for k in unroll (0 , (domain_size - domain_size % 4 ) / 4 ):
499- nib_pow = match_range (nibbles [k ], range (0 , 16 ), lambda v : ROOT ** (2 ** (TWO_ADICITY - domain_size + 4 * k ) * v ))
527+
528+ # First nibble: leaf_hash -> states[0]
529+ nib_pow = match_range (
530+ nibbles [0 ],
531+ range (0 , 16 ),
532+ lambda v : whir_4_merkle_step_and_pow (v , leaf_hash , merkle_path , states , 2 ** (TWO_ADICITY - domain_size )),
533+ )
534+ prod *= nib_pow
535+
536+ # Middle nibbles: states[k-1] -> states[k]
537+ for k in unroll (1 , n_nibbles - 1 ):
538+ nib_pow = match_range (
539+ nibbles [k ],
540+ range (0 , 16 ),
541+ lambda v : whir_4_merkle_step_and_pow (
542+ v ,
543+ states + (k - 1 ) * DIGEST_LEN ,
544+ merkle_path + 4 * k * DIGEST_LEN ,
545+ states + k * DIGEST_LEN ,
546+ 2 ** (TWO_ADICITY - domain_size + 4 * k ),
547+ ),
548+ )
500549 prod *= nib_pow
501550
502- if domain_size % 4 != 0 :
503- edge_pow = match_range (
504- nibbles [(domain_size - domain_size % 4 ) / 4 ],
551+ # Last nibble: states[-1] -> prev_root
552+ last_k = n_nibbles - 1
553+ last_state_in = states + (last_k - 1 ) * DIGEST_LEN
554+ last_path = merkle_path + 4 * last_k * DIGEST_LEN
555+ last_power_shift = 2 ** (TWO_ADICITY - domain_size + 4 * last_k )
556+ if domain_size % 4 == 0 :
557+ nib_pow = match_range (
558+ nibbles [last_k ],
559+ range (0 , 16 ),
560+ lambda v : whir_4_merkle_step_and_pow (v , last_state_in , last_path , prev_root , last_power_shift ),
561+ )
562+ prod *= nib_pow
563+ elif domain_size % 4 == 1 :
564+ nib_pow = match_range (
565+ nibbles [last_k ],
566+ range (0 , 16 ),
567+ lambda v : whir_1_merkle_step_and_pow (v , last_state_in , last_path , prev_root , last_power_shift ),
568+ )
569+ prod *= nib_pow
570+ elif domain_size % 4 == 2 :
571+ nib_pow = match_range (
572+ nibbles [last_k ],
505573 range (0 , 16 ),
506- lambda v : ROOT ** ( 2 ** ( TWO_ADICITY - domain_size + 4 * (( domain_size - domain_size % 4 ) / 4 )) * ( v % 2 ** ( domain_size % 4 )) ),
574+ lambda v : whir_2_merkle_step_and_pow ( v , last_state_in , last_path , prev_root , last_power_shift ),
507575 )
508- prod *= edge_pow
576+ prod *= nib_pow
577+ elif domain_size % 4 == 3 :
578+ nib_pow = match_range (
579+ nibbles [last_k ],
580+ range (0 , 16 ),
581+ lambda v : whir_3_merkle_step_and_pow (v , last_state_in , last_path , prev_root , last_power_shift ),
582+ )
583+ prod *= nib_pow
509584
510- return nibbles , prod
585+ return leaf_data , prod
511586
512587
513588def checked_decompose_bits_small_value_const (to_decompose , n_bits : Const ):
0 commit comments