1
1
use alloc:: boxed:: Box ;
2
- use core:: { fmt, iter, mem} ;
2
+ use core:: { fmt, iter, mem, slice , usize } ;
3
3
4
4
use crate :: { hash:: PortableHasher , stored, KeyHash , NodeHash , PortableHash , PortableUpdate } ;
5
5
@@ -263,19 +263,68 @@ mod tests {
263
263
}
264
264
}
265
265
266
+ pub struct Prefix {
267
+ /// This value will be 0 if the branch occurs in the first word of the hash key.
268
+ /// The value is the prior word if the branches parent's word index no more than 1 less.
269
+ /// If the parent's word index is more than 1 word prior,
270
+ /// we must store the multiword prefix outside of the branch, so the value is the index of the prefix.
271
+ /// The length of the prefix is the difference between the parent's word index and the branch's word index.
272
+ prior_word_or_prefix_idx : u32 ,
273
+ }
274
+
275
+ impl Prefix {
276
+ pub fn get_prefix < ' s , ' txn : ' s > (
277
+ & ' s self ,
278
+ prefixies : & ' txn PrefixesBuffer ,
279
+ word_idx : usize ,
280
+ parent_word_idx : usize ,
281
+ ) -> Option < & ' s [ u32 ] > {
282
+ if word_idx - parent_word_idx <= 1 {
283
+ if cfg ! ( debug_assertions) && word_idx == 0 {
284
+ debug_assert_eq ! ( self . prior_word_or_prefix_idx, 0 ) ;
285
+ }
286
+
287
+ Some ( slice:: from_ref ( & self . prior_word_or_prefix_idx ) )
288
+ } else {
289
+ let prefix_len = word_idx - parent_word_idx;
290
+ debug_assert ! ( prefix_len > 1 ) ;
291
+ prefixies. get_prefix (
292
+ self . prior_word_or_prefix_idx as usize ,
293
+ word_idx - parent_word_idx,
294
+ )
295
+ }
296
+ }
297
+ }
298
+
299
+ #[ derive( Clone , PartialEq , Eq , PartialOrd , Ord ) ]
300
+ pub struct PrefixesBuffer {
301
+ buffer : Vec < u32 > ,
302
+ }
303
+
304
+ impl PrefixesBuffer {
305
+ pub fn new ( ) -> Self {
306
+ Self { buffer : Vec :: new ( ) }
307
+ }
308
+
309
+ pub fn push_prefix ( & mut self , prefix : & [ u32 ] ) -> u32 {
310
+ let idx = self . buffer . len ( ) as u32 ;
311
+ self . buffer . extend_from_slice ( prefix) ;
312
+ idx
313
+ }
314
+
315
+ pub fn get_prefix ( & self , idx : usize , len : usize ) -> Option < & [ u32 ] > {
316
+ let end = idx + len;
317
+ self . buffer . get ( idx..end)
318
+ }
319
+ }
320
+
266
321
#[ cfg_attr( feature = "serde" , derive( serde:: Serialize , serde:: Deserialize ) ) ]
267
322
#[ derive( Clone , PartialEq , Eq , PartialOrd , Ord ) ]
268
323
pub struct Branch < NR > {
269
324
pub left : NR ,
270
325
pub right : NR ,
271
326
pub mask : BranchMask ,
272
- /// The word at the `(bit_idx / 32) - 1`.
273
- /// Common to both children.
274
- /// Will be 0 if this node is the root.
275
- pub prior_word : u32 ,
276
- /// The the segment of the hash key from the parent branch to `prior_word`.
277
- /// Will be empty if the parent_branch.mask.bit_idx / 32 == self.mask.bit_idx / 32.
278
- pub prefix : Box < [ u32 ] > ,
327
+ pub prefix : Prefix ,
279
328
}
280
329
281
330
impl < NR > fmt:: Debug for Branch < NR > {
@@ -352,6 +401,7 @@ impl<NR> Branch<NR> {
352
401
/// Hash a branch node with known child hashes.
353
402
///
354
403
/// Caller must ensure that the hasher is reset before calling this function.
404
+ ///
355
405
#[ inline]
356
406
pub fn hash_branch < H : PortableHasher < 32 > > (
357
407
& self ,
@@ -361,6 +411,7 @@ impl<NR> Branch<NR> {
361
411
) -> NodeHash {
362
412
hasher. portable_update ( left) ;
363
413
hasher. portable_update ( right) ;
414
+ // Security: it's important to hash the metadata to avoid a potential trie corruption attack.
364
415
hasher. portable_update ( self . mask . bit_idx . to_le_bytes ( ) ) ;
365
416
hasher. portable_update ( self . mask . left_prefix . to_le_bytes ( ) ) ;
366
417
hasher. portable_update ( self . prior_word . to_le_bytes ( ) ) ;
0 commit comments