1919 from .tweak_hash import TweakHasher
2020
2121
22- def _get_padded_layer (rand : Rand , nodes : List [HashDigest ], start_index : int ) -> HashTreeLayer :
22+ def _get_padded_layer (rand : Rand , nodes : List [HashDigest ], start_index : Uint64 ) -> HashTreeLayer :
2323 """
2424 Pads a layer of nodes with random hashes to simplify tree construction.
2525
@@ -38,21 +38,21 @@ def _get_padded_layer(rand: Rand, nodes: List[HashDigest], start_index: int) ->
3838 A new `HashTreeLayer` with the necessary padding applied.
3939 """
4040 nodes_with_padding : List [HashDigest ] = []
41- end_index = start_index + len (nodes ) - 1
41+ end_index = start_index + Uint64 ( len (nodes )) - Uint64 ( 1 )
4242
4343 # Prepend random padding if the layer starts at an odd index.
44- if start_index % 2 == 1 :
44+ if start_index % Uint64 ( 2 ) == Uint64 ( 1 ) :
4545 nodes_with_padding .append (rand .domain ())
4646
4747 # The actual start index of the padded layer is always the even
4848 # number at or immediately before the original start_index.
49- actual_start_index = start_index - (start_index % 2 )
49+ actual_start_index = start_index - (start_index % Uint64 ( 2 ) )
5050
5151 # Add the actual node content.
5252 nodes_with_padding .extend (nodes )
5353
5454 # Append random padding if the layer ends at an even index.
55- if end_index % 2 == 0 :
55+ if end_index % Uint64 ( 2 ) == Uint64 ( 0 ) :
5656 nodes_with_padding .append (rand .domain ())
5757
5858 return HashTreeLayer (start_index = actual_start_index , nodes = nodes_with_padding )
@@ -84,15 +84,15 @@ class HashSubTree(StrictBaseModel):
8484 - Two consecutive bottom trees (sliding window)
8585 """
8686
87- depth : int
87+ depth : Uint64
8888 """
8989 The total depth of the full tree (e.g., 32 for a 2^32 leaf space).
9090
9191 This represents the depth of the complete Merkle tree, not just this subtree.
9292 A subtree starting from layer `k` will have `depth - k` layers stored.
9393 """
9494
95- lowest_layer : int
95+ lowest_layer : Uint64
9696 """
9797 The lowest layer included in this subtree.
9898
@@ -175,7 +175,7 @@ def new(
175175
176176 # Start with the lowest layer nodes and apply initial padding.
177177 layers : List [HashTreeLayer ] = []
178- current_layer = _get_padded_layer (rand , lowest_layer_nodes , start_index )
178+ current_layer = _get_padded_layer (rand , lowest_layer_nodes , Uint64 ( start_index ) )
179179 layers .append (current_layer )
180180
181181 # Build the tree layer by layer from lowest_layer up to the root.
@@ -192,20 +192,20 @@ def new(
192192 )
193193 ):
194194 # Calculate the position of the parent node in the next level up.
195- parent_index = (current_layer .start_index // 2 ) + i
195+ parent_index = (current_layer .start_index // Uint64 ( 2 )) + Uint64 ( i )
196196 # Create the tweak for hashing these two children.
197197 tweak = TreeTweak (level = level + 1 , index = parent_index )
198198 # Hash the left and right children to get their parent.
199199 parent_node = hasher .apply (parameter , tweak , list (children ))
200200 parents .append (parent_node )
201201
202202 # Pad the new list of parents to prepare for the next iteration.
203- new_start_index = current_layer .start_index // 2
203+ new_start_index = current_layer .start_index // Uint64 ( 2 )
204204 current_layer = _get_padded_layer (rand , parents , new_start_index )
205205 layers .append (current_layer )
206206
207207 # Return the completed subtree.
208- return cls (depth = depth , lowest_layer = lowest_layer , layers = layers )
208+ return cls (depth = Uint64 ( depth ) , lowest_layer = Uint64 ( lowest_layer ) , layers = layers )
209209
210210 @classmethod
211211 def new_top_tree (
@@ -353,16 +353,16 @@ def new_bottom_tree(
353353
354354 # The root is at position (start_index >> (depth // 2)) = bottom_tree_index
355355 # within the middle layer. We need to find it in the stored nodes.
356- root_position_in_layer = bottom_tree_index - middle_layer .start_index
357- root = middle_layer .nodes [root_position_in_layer ]
356+ root_position_in_layer = Uint64 ( bottom_tree_index ) - middle_layer .start_index
357+ root = middle_layer .nodes [int ( root_position_in_layer ) ]
358358
359359 # Truncate layers to keep only 0 through depth/2 - 1.
360360 truncated_layers = full_tree .layers [: (depth // 2 )]
361361
362362 # Add a final layer containing just the root.
363- truncated_layers .append (HashTreeLayer (start_index = bottom_tree_index , nodes = [root ]))
363+ truncated_layers .append (HashTreeLayer (start_index = Uint64 ( bottom_tree_index ) , nodes = [root ]))
364364
365- return cls (depth = depth , lowest_layer = 0 , layers = truncated_layers )
365+ return cls (depth = Uint64 ( depth ) , lowest_layer = Uint64 ( 0 ) , layers = truncated_layers )
366366
367367 def root (self ) -> HashDigest :
368368 """
@@ -412,35 +412,35 @@ def path(self, position: Uint64) -> HashTreeOpening:
412412 raise ValueError ("Cannot generate path for empty subtree." )
413413
414414 lowest_layer = self .layers [0 ]
415- if int ( position ) < lowest_layer .start_index :
415+ if position < lowest_layer .start_index :
416416 raise ValueError ("Position is before the subtree's start index." )
417417
418- if int ( position ) >= lowest_layer .start_index + len (lowest_layer .nodes ):
418+ if position >= lowest_layer .start_index + Uint64 ( len (lowest_layer .nodes ) ):
419419 raise ValueError ("Position is beyond the subtree's range." )
420420
421421 co_path : List [HashDigest ] = []
422- current_position = int ( position )
422+ current_position = position
423423
424424 # Iterate through layers from lowest to highest, EXCLUDING the final root layer.
425425 # The root layer doesn't contribute a sibling to the authentication path.
426426 # self.layers[:-1] gives all layers except the last (root) layer.
427427 for layer in self .layers [:- 1 ]:
428428 # Determine the sibling's position by flipping the last bit.
429- sibling_position = current_position ^ 1
429+ sibling_position = current_position ^ Uint64 ( 1 )
430430 sibling_index = sibling_position - layer .start_index
431431
432432 # Ensure the sibling exists in this layer
433- if sibling_index < 0 or sibling_index >= len (layer .nodes ):
433+ if sibling_index < Uint64 ( 0 ) or sibling_index >= Uint64 ( len (layer .nodes ) ):
434434 raise ValueError (
435435 f"Sibling index { sibling_index } out of bounds for layer "
436436 f"with { len (layer .nodes )} nodes"
437437 )
438438
439439 # Add the sibling's hash to the co-path.
440- co_path .append (layer .nodes [sibling_index ])
440+ co_path .append (layer .nodes [int ( sibling_index ) ])
441441
442442 # Move to the parent's position for the next iteration.
443- current_position //= 2
443+ current_position = current_position // Uint64 ( 2 )
444444
445445 return HashTreeOpening (siblings = co_path )
446446
@@ -496,23 +496,23 @@ def combined_path(
496496 depth = top_tree .depth
497497
498498 # Validate even depth (required for top-bottom split).
499- if depth % 2 != 0 :
499+ if depth % Uint64 ( 2 ) != Uint64 ( 0 ) :
500500 raise ValueError (
501501 f"Top-bottom tree traversal requires even depth, got { depth } . "
502502 f"Cannot split tree into equal top and bottom halves."
503503 )
504504
505505 # Calculate parameters for bottom trees.
506- leafs_per_bottom_tree = 1 << (depth // 2 )
506+ leafs_per_bottom_tree = 1 << int (depth // Uint64 ( 2 ) )
507507
508508 # Determine which bottom tree this position belongs to.
509509 #
510510 # Bottom tree index = floor(position / sqrt(LIFETIME))
511- bottom_tree_index = int ( position ) // leafs_per_bottom_tree
511+ bottom_tree_index = position // Uint64 ( leafs_per_bottom_tree )
512512
513513 # Verify that the provided bottom_tree actually corresponds to this position.
514514 # The bottom tree's lowest layer starts at bottom_tree_index * leafs_per_bottom_tree.
515- expected_start = bottom_tree_index * leafs_per_bottom_tree
515+ expected_start = bottom_tree_index * Uint64 ( leafs_per_bottom_tree )
516516 actual_start = bottom_tree .layers [0 ].start_index
517517
518518 if actual_start != expected_start :
0 commit comments