1#[cfg(not(feature = "std"))]
2use alloc::vec::Vec;
3use core::{cmp, mem};
4
5use ethrex_rlp::{
6 decode::RLPDecode,
7 encode::RLPEncode,
8 error::RLPDecodeError,
9 structs::{Decoder, Encoder},
10};
11
12#[inline]
24#[allow(unsafe_code)]
25unsafe fn expand_bytes_to_nibbles(bytes: &[u8], output: *mut u8) {
26 #[cfg(target_arch = "x86_64")]
27 {
28 unsafe { expand_bytes_to_nibbles_x86_64(bytes, output) };
30 return;
31 }
32 #[cfg(target_arch = "aarch64")]
33 {
34 unsafe { expand_bytes_to_nibbles_aarch64(bytes, output) };
36 return;
37 }
38 #[allow(unreachable_code)]
40 unsafe {
42 expand_bytes_to_nibbles_scalar(bytes, output)
43 };
44}
45
46#[cfg(target_arch = "x86_64")]
47#[allow(unsafe_code)]
48#[inline]
49unsafe fn expand_bytes_to_nibbles_x86_64(bytes: &[u8], output: *mut u8) {
50 use core::arch::x86_64::*;
51
52 let n = bytes.len();
53 let mut i = 0usize;
54
55 #[cfg(target_feature = "avx2")]
59 unsafe {
61 let mask256 = _mm256_set1_epi8(0x0F_u8 as i8);
62 while i + 32 <= n {
63 let v = _mm256_loadu_si256(bytes.as_ptr().add(i).cast::<__m256i>());
65 let hi = _mm256_and_si256(_mm256_srli_epi16(v, 4), mask256);
67 let lo = _mm256_and_si256(v, mask256);
69 let unpack_lo = _mm256_unpacklo_epi8(hi, lo);
73 let unpack_hi = _mm256_unpackhi_epi8(hi, lo);
74 let out_lo = _mm256_permute2x128_si256::<0x20>(unpack_lo, unpack_hi);
78 let out_hi = _mm256_permute2x128_si256::<0x31>(unpack_lo, unpack_hi);
79 _mm256_storeu_si256(output.add(i * 2).cast::<__m256i>(), out_lo);
80 _mm256_storeu_si256(output.add(i * 2 + 32).cast::<__m256i>(), out_hi);
81 i += 32;
82 }
83 }
84
85 unsafe {
89 let mask128 = _mm_set1_epi8(0x0F_u8 as i8);
90 while i + 16 <= n {
91 let v = _mm_loadu_si128(bytes.as_ptr().add(i).cast::<__m128i>());
92 let hi = _mm_and_si128(_mm_srli_epi16(v, 4), mask128);
93 let lo = _mm_and_si128(v, mask128);
94 let lo16 = _mm_unpacklo_epi8(hi, lo);
95 let hi16 = _mm_unpackhi_epi8(hi, lo);
96 _mm_storeu_si128(output.add(i * 2).cast::<__m128i>(), lo16);
97 _mm_storeu_si128(output.add(i * 2 + 16).cast::<__m128i>(), hi16);
98 i += 16;
99 }
100
101 while i < n {
103 let b = *bytes.get_unchecked(i);
104 *output.add(i * 2) = b >> 4;
105 *output.add(i * 2 + 1) = b & 0x0F;
106 i += 1;
107 }
108 }
109}
110
111#[cfg(target_arch = "aarch64")]
112#[target_feature(enable = "neon")]
113#[allow(unsafe_code)]
114#[inline]
115unsafe fn expand_bytes_to_nibbles_aarch64(bytes: &[u8], output: *mut u8) {
116 use core::arch::aarch64::*;
117
118 let n = bytes.len();
119 let mut i = 0usize;
120
121 unsafe {
124 let mask_0f = vdupq_n_u8(0x0F);
125 while i + 16 <= n {
126 let v = vld1q_u8(bytes.as_ptr().add(i));
127 let hi = vshrq_n_u8(v, 4);
129 let lo = vandq_u8(v, mask_0f);
130 let lo16 = vzip1q_u8(hi, lo); let hi16 = vzip2q_u8(hi, lo); vst1q_u8(output.add(i * 2), lo16);
134 vst1q_u8(output.add(i * 2 + 16), hi16);
135 i += 16;
136 }
137
138 while i < n {
140 let b = *bytes.get_unchecked(i);
141 *output.add(i * 2) = b >> 4;
142 *output.add(i * 2 + 1) = b & 0x0F;
143 i += 1;
144 }
145 }
146}
147
148#[allow(unsafe_code)]
149#[inline]
150unsafe fn expand_bytes_to_nibbles_scalar(bytes: &[u8], output: *mut u8) {
151 unsafe {
153 for (i, &b) in bytes.iter().enumerate() {
154 *output.add(i * 2) = b >> 4;
155 *output.add(i * 2 + 1) = b & 0x0F;
156 }
157 }
158}
159
160#[inline]
177#[allow(unsafe_code)]
178unsafe fn pack_nibble_pairs(nibbles: &[u8], output: *mut u8) {
179 debug_assert!(nibbles.len().is_multiple_of(2));
180 #[cfg(target_arch = "x86_64")]
181 {
182 unsafe { pack_nibble_pairs_x86_64(nibbles, output) };
183 return;
184 }
185 #[cfg(target_arch = "aarch64")]
186 {
187 unsafe { pack_nibble_pairs_aarch64(nibbles, output) };
188 return;
189 }
190 #[allow(unreachable_code)]
191 unsafe {
192 pack_nibble_pairs_scalar(nibbles, output)
193 };
194}
195
196#[cfg(target_arch = "x86_64")]
197#[allow(unsafe_code)]
198#[inline]
199unsafe fn pack_nibble_pairs_x86_64(nibbles: &[u8], output: *mut u8) {
200 let n = nibbles.len(); let mut i = 0usize; let mut o = 0usize; #[cfg(target_feature = "ssse3")]
208 unsafe {
210 use core::arch::x86_64::*;
211 let weights = _mm_set1_epi16(0x0110_u16 as i16); while i + 32 <= n {
214 let lo_chunk = _mm_loadu_si128(nibbles.as_ptr().add(i).cast::<__m128i>());
216 let hi_chunk = _mm_loadu_si128(nibbles.as_ptr().add(i + 16).cast::<__m128i>());
217 let lo_packed = _mm_maddubs_epi16(lo_chunk, weights);
219 let hi_packed = _mm_maddubs_epi16(hi_chunk, weights);
220 let result = _mm_packus_epi16(lo_packed, hi_packed);
222 _mm_storeu_si128(output.add(o).cast::<__m128i>(), result);
223 i += 32;
224 o += 16;
225 }
226 }
227
228 unsafe {
231 while i + 2 <= n {
232 *output.add(o) = (*nibbles.get_unchecked(i) << 4) | *nibbles.get_unchecked(i + 1);
233 i += 2;
234 o += 1;
235 }
236 }
237}
238
239#[cfg(target_arch = "aarch64")]
240#[target_feature(enable = "neon")]
241#[allow(unsafe_code)]
242#[inline]
243unsafe fn pack_nibble_pairs_aarch64(nibbles: &[u8], output: *mut u8) {
244 use core::arch::aarch64::*;
245
246 let n = nibbles.len();
247 let mut i = 0usize;
248 let mut o = 0usize;
249
250 unsafe {
252 while i + 32 <= n {
253 let v = vld2q_u8(nibbles.as_ptr().add(i));
255 let packed = vorrq_u8(vshlq_n_u8(v.0, 4), v.1);
258 vst1q_u8(output.add(o), packed);
259 i += 32;
260 o += 16;
261 }
262 while i + 2 <= n {
263 *output.add(o) = (*nibbles.get_unchecked(i) << 4) | *nibbles.get_unchecked(i + 1);
264 i += 2;
265 o += 1;
266 }
267 }
268}
269
270#[allow(unsafe_code)]
271#[inline]
272unsafe fn pack_nibble_pairs_scalar(nibbles: &[u8], output: *mut u8) {
273 unsafe {
275 let mut o = 0usize;
276 let mut i = 0usize;
277 let n = nibbles.len();
278 while i + 2 <= n {
279 *output.add(o) = (*nibbles.get_unchecked(i) << 4) | *nibbles.get_unchecked(i + 1);
280 i += 2;
281 o += 1;
282 }
283 }
284}
285#[allow(unsafe_code)]
294#[inline]
295fn count_common_prefix(a: &[u8], b: &[u8]) -> usize {
296 #[cfg(target_arch = "x86_64")]
297 {
298 return unsafe { count_common_prefix_x86_64(a, b) };
300 }
301 #[cfg(target_arch = "aarch64")]
302 {
303 return unsafe { count_common_prefix_aarch64(a, b) };
305 }
306 #[allow(unreachable_code)]
307 count_common_prefix_scalar(a, b)
308}
309
310#[cfg(target_arch = "x86_64")]
311#[allow(unsafe_code)]
312#[inline]
313unsafe fn count_common_prefix_x86_64(a: &[u8], b: &[u8]) -> usize {
314 use core::arch::x86_64::*;
315
316 let n = a.len().min(b.len());
317 let mut i = 0usize;
318
319 #[cfg(target_feature = "avx2")]
320 unsafe {
322 while i + 32 <= n {
323 let va = _mm256_loadu_si256(a.as_ptr().add(i).cast::<__m256i>());
324 let vb = _mm256_loadu_si256(b.as_ptr().add(i).cast::<__m256i>());
325 let eq = _mm256_cmpeq_epi8(va, vb);
327 let mask = _mm256_movemask_epi8(eq) as u32;
329 if mask != 0xFFFF_FFFF {
330 return i + mask.trailing_ones() as usize;
332 }
333 i += 32;
334 }
335 }
336
337 unsafe {
340 while i + 16 <= n {
341 let va = _mm_loadu_si128(a.as_ptr().add(i).cast::<__m128i>());
342 let vb = _mm_loadu_si128(b.as_ptr().add(i).cast::<__m128i>());
343 let eq = _mm_cmpeq_epi8(va, vb);
344 let mask = _mm_movemask_epi8(eq) as u16;
345 if mask != 0xFFFF {
346 return i + mask.trailing_ones() as usize;
347 }
348 i += 16;
349 }
350 }
351
352 i + count_common_prefix_scalar(&a[i..n], &b[i..n])
354}
355
356#[cfg(target_arch = "aarch64")]
357#[target_feature(enable = "neon")]
358#[allow(unsafe_code)]
359#[inline]
360unsafe fn count_common_prefix_aarch64(a: &[u8], b: &[u8]) -> usize {
361 use core::arch::aarch64::*;
362
363 let n = a.len().min(b.len());
364 let mut i = 0usize;
365
366 unsafe {
368 while i + 16 <= n {
369 let va = vld1q_u8(a.as_ptr().add(i));
370 let vb = vld1q_u8(b.as_ptr().add(i));
371 let eq = vceqq_u8(va, vb);
373 if vminvq_u8(eq) == 0xFF {
375 i += 16;
376 continue;
377 }
378 let mut eq_arr = [0u8; 16];
380 vst1q_u8(eq_arr.as_mut_ptr(), eq);
381 for (j, &byte) in eq_arr.iter().enumerate() {
382 if byte == 0 {
383 return i + j;
384 }
385 }
386 unreachable!()
387 }
388 }
389
390 i + count_common_prefix_scalar(&a[i..n], &b[i..n])
391}
392
393#[inline]
394fn count_common_prefix_scalar(a: &[u8], b: &[u8]) -> usize {
395 a.iter().zip(b.iter()).take_while(|(x, y)| x == y).count()
396}
397#[derive(
403 Debug,
404 Clone,
405 Default,
406 serde::Serialize,
407 serde::Deserialize,
408 rkyv::Deserialize,
409 rkyv::Serialize,
410 rkyv::Archive,
411)]
412pub struct Nibbles {
413 data: Vec<u8>,
414 already_consumed: Vec<u8>,
417}
418
419impl PartialEq for Nibbles {
422 fn eq(&self, other: &Nibbles) -> bool {
423 self.data == other.data
424 }
425}
426
427impl Eq for Nibbles {}
428
429impl PartialOrd for Nibbles {
430 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
431 Some(self.cmp(other))
432 }
433}
434
435impl Ord for Nibbles {
436 fn cmp(&self, other: &Self) -> cmp::Ordering {
437 self.data.cmp(&other.data)
438 }
439}
440
441impl core::hash::Hash for Nibbles {
442 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
443 self.data.hash(state);
444 }
445}
446
447impl Nibbles {
448 pub const fn from_hex(hex: Vec<u8>) -> Self {
450 Self {
451 data: hex,
452 already_consumed: vec![],
453 }
454 }
455
456 pub fn from_bytes(bytes: &[u8]) -> Self {
458 Self::from_raw(bytes, true)
459 }
460
461 pub fn from_raw(bytes: &[u8], is_leaf: bool) -> Self {
463 let extra = usize::from(is_leaf);
464 let mut data = Vec::with_capacity(bytes.len() * 2 + extra);
465
466 #[allow(unsafe_code)]
469 unsafe {
470 expand_bytes_to_nibbles(bytes, data.as_mut_ptr());
471 data.set_len(bytes.len() * 2);
472 }
473
474 if is_leaf {
475 data.push(16);
476 }
477
478 Self {
479 data,
480 already_consumed: vec![],
481 }
482 }
483
484 pub fn into_vec(self) -> Vec<u8> {
485 self.data
486 }
487
488 pub fn len(&self) -> usize {
490 self.data.len()
491 }
492
493 pub fn is_empty(&self) -> bool {
495 self.data.is_empty()
496 }
497
498 pub fn skip_prefix(&mut self, prefix: &Nibbles) -> bool {
501 if self.len() >= prefix.len() && &self.data[..prefix.len()] == prefix.as_ref() {
502 self.already_consumed.extend_from_slice(&prefix.data);
503 self.data.drain(..prefix.len());
504 true
505 } else {
506 false
507 }
508 }
509
510 pub fn compare_prefix(&self, prefix: &Nibbles) -> cmp::Ordering {
512 if self.len() > prefix.len() {
513 self.data[..prefix.len()].cmp(&prefix.data)
514 } else {
515 self.data[..].cmp(&prefix.data[..self.len()])
516 }
517 }
518
519 pub fn count_prefix(&self, other: &Nibbles) -> usize {
521 count_common_prefix(self.as_ref(), other.as_ref())
522 }
523
524 #[allow(clippy::should_implement_trait)]
526 pub fn next(&mut self) -> Option<u8> {
527 (!self.is_empty()).then(|| {
528 self.already_consumed.push(self.data[0]);
529 self.data.remove(0)
530 })
531 }
532
533 pub fn next_choice(&mut self) -> Option<usize> {
535 self.next().filter(|choice| *choice < 16).map(usize::from)
536 }
537
538 pub fn offset(&self, offset: usize) -> Nibbles {
540 let mut already_consumed = Vec::with_capacity(self.already_consumed.len() + offset);
541 already_consumed.extend_from_slice(&self.already_consumed);
542 already_consumed.extend_from_slice(&self.data[..offset]);
543 Nibbles {
544 data: self.data[offset..].to_vec(),
545 already_consumed,
546 }
547 }
548
549 pub fn slice(&self, start: usize, end: usize) -> Nibbles {
551 Nibbles::from_hex(self.data[start..end].to_vec())
552 }
553
554 pub fn extend(&mut self, other: &Nibbles) {
556 self.data.extend_from_slice(other.as_ref());
557 }
558
559 pub fn at(&self, i: usize) -> usize {
561 self.data[i] as usize
562 }
563
564 pub fn prepend(&mut self, nibble: u8) {
566 self.data.insert(0, nibble);
567 }
568
569 pub fn append(&mut self, nibble: u8) {
571 self.data.push(nibble);
572 }
573
574 #[allow(unsafe_code)]
577 pub fn encode_compact(&self) -> Vec<u8> {
578 let is_leaf = self.is_leaf();
579 let mut hex = if is_leaf {
580 &self.data[0..self.data.len() - 1]
581 } else {
582 &self.data[0..]
583 };
584 let prefix_nibble = if hex.len() % 2 == 1 {
591 let v = 0x10 + hex[0];
592 hex = &hex[1..];
593 v
594 } else {
595 0x00
596 };
597
598 let pair_count = hex.len() / 2;
599 let mut compact = Vec::with_capacity(1 + pair_count);
600 compact.push(prefix_nibble + if is_leaf { 0x20 } else { 0x00 });
601
602 unsafe {
607 let out_ptr = compact.as_mut_ptr().add(1);
608 pack_nibble_pairs(hex, out_ptr);
609 compact.set_len(1 + pair_count);
610 }
611
612 compact
613 }
614
615 pub fn decode_compact(compact: &[u8]) -> Self {
617 Self::from_hex(compact_to_hex(compact))
618 }
619
620 pub fn is_leaf(&self) -> bool {
622 if self.is_empty() {
623 false
624 } else {
625 self.data[self.data.len() - 1] == 16
626 }
627 }
628
629 pub fn to_bytes(&self) -> Vec<u8> {
631 let data = if !self.is_empty() && self.is_leaf() {
633 &self.data[..self.len() - 1]
634 } else {
635 &self.data[..]
636 };
637 data.chunks(2)
639 .map(|chunk| match chunk.len() {
640 1 => chunk[0] << 4,
641 _ => chunk[0] << 4 | chunk[1],
642 })
643 .collect::<Vec<_>>()
644 }
645
646 pub fn concat(&self, other: &Nibbles) -> Nibbles {
648 let mut data = Vec::with_capacity(self.data.len() + other.data.len());
649 data.extend_from_slice(&self.data);
650 data.extend_from_slice(&other.data);
651 Nibbles {
652 data,
653 already_consumed: self.already_consumed.clone(),
654 }
655 }
656
657 pub fn append_new(&self, nibble: u8) -> Nibbles {
659 let mut data = Vec::with_capacity(self.data.len() + 1);
660 data.extend_from_slice(&self.data);
661 data.push(nibble);
662 Nibbles {
663 data,
664 already_consumed: self.already_consumed.clone(),
665 }
666 }
667
668 pub fn current(&self) -> Nibbles {
670 Nibbles {
671 data: self.already_consumed.clone(),
672 already_consumed: vec![],
673 }
674 }
675
676 pub fn take(&mut self) -> Self {
678 Nibbles {
679 data: mem::take(&mut self.data),
680 already_consumed: mem::take(&mut self.already_consumed),
681 }
682 }
683}
684
685impl AsRef<[u8]> for Nibbles {
686 fn as_ref(&self) -> &[u8] {
687 &self.data
688 }
689}
690
691impl RLPEncode for Nibbles {
692 fn encode(&self, buf: &mut dyn bytes::BufMut) {
693 Encoder::new(buf).encode_field(&self.data).finish();
694 }
695}
696
697impl RLPDecode for Nibbles {
698 fn decode_unfinished(rlp: &[u8]) -> Result<(Self, &[u8]), RLPDecodeError> {
699 let decoder = Decoder::new(rlp)?;
700 let (data, decoder) = decoder.decode_field("data")?;
701 Ok((
702 Self {
703 data,
704 already_consumed: vec![],
705 },
706 decoder.finish()?,
707 ))
708 }
709}
710
711fn compact_to_hex(compact: &[u8]) -> Vec<u8> {
713 if compact.is_empty() {
714 return vec![];
715 }
716 let mut base = keybytes_to_hex(compact);
717 let end = if base[0] < 2 {
719 base.len() - 1
720 } else {
721 base.len()
722 };
723 let chop = 2 - (base[0] & 1) as usize;
725 base.drain(..chop);
726 base.truncate(end - chop);
727 base
728}
729
730fn keybytes_to_hex(keybytes: &[u8]) -> Vec<u8> {
732 let nibble_count = keybytes.len() * 2;
733 let mut nibbles = Vec::with_capacity(nibble_count + 1);
734
735 #[allow(unsafe_code)]
737 unsafe {
738 expand_bytes_to_nibbles(keybytes, nibbles.as_mut_ptr());
739 nibbles.set_len(nibble_count);
740 }
741 nibbles.push(16); nibbles
743}
744
745#[cfg(test)]
746mod tests {
747 use super::*;
748
749 fn expand_bytes_scalar_ref(bytes: &[u8]) -> Vec<u8> {
751 bytes.iter().flat_map(|&b| [b >> 4, b & 0x0F]).collect()
752 }
753
754 fn pack_nibble_pairs_scalar_ref(nibbles: &[u8]) -> Vec<u8> {
756 nibbles
757 .chunks_exact(2)
758 .map(|pair| (pair[0] << 4) | pair[1])
759 .collect()
760 }
761
762 #[test]
763 fn expand_bytes_to_nibbles_matches_scalar() {
764 for &len in &[0, 1, 2, 15, 16, 17, 31, 32, 33, 48, 64] {
766 let input: Vec<u8> = (0..len).map(|i| (i * 37 + 13) as u8).collect();
767 let expected = expand_bytes_scalar_ref(&input);
768
769 let mut actual = vec![0u8; input.len() * 2];
770 #[allow(unsafe_code)]
771 unsafe {
772 expand_bytes_to_nibbles(&input, actual.as_mut_ptr());
773 }
774 assert_eq!(actual, expected, "mismatch at input length {len}");
775 }
776 }
777
778 #[test]
779 fn pack_nibble_pairs_matches_scalar() {
780 for &nibble_count in &[0, 2, 4, 14, 16, 30, 32, 34, 48, 64] {
782 let input: Vec<u8> = (0..nibble_count).map(|i| (i % 16) as u8).collect();
783 let expected = pack_nibble_pairs_scalar_ref(&input);
784
785 let mut actual = vec![0u8; nibble_count / 2];
786 #[allow(unsafe_code)]
787 unsafe {
788 pack_nibble_pairs(&input, actual.as_mut_ptr());
789 }
790 assert_eq!(actual, expected, "mismatch at nibble count {nibble_count}");
791 }
792 }
793
794 #[test]
795 fn expand_then_pack_roundtrip() {
796 for &len in &[0, 1, 16, 32, 33] {
797 let input: Vec<u8> = (0..len).map(|i| (i * 53 + 7) as u8).collect();
798 let mut nibbles = vec![0u8; input.len() * 2];
799 #[allow(unsafe_code)]
800 unsafe {
801 expand_bytes_to_nibbles(&input, nibbles.as_mut_ptr());
802 }
803
804 let mut packed = vec![0u8; input.len()];
805 #[allow(unsafe_code)]
806 unsafe {
807 pack_nibble_pairs(&nibbles, packed.as_mut_ptr());
808 }
809 assert_eq!(packed, input, "roundtrip failed at length {len}");
810 }
811 }
812
813 #[test]
814 fn count_common_prefix_correctness() {
815 let a = vec![1u8, 2, 3, 4, 5];
817 assert_eq!(count_common_prefix(&a, &a), 5);
818
819 assert_eq!(count_common_prefix(&[1, 2, 3], &[4, 5, 6]), 0);
821
822 assert_eq!(count_common_prefix(&[1, 2, 3, 4], &[1, 2, 5, 6]), 2);
824
825 assert_eq!(count_common_prefix(&[], &[1, 2]), 0);
827 assert_eq!(count_common_prefix(&[1, 2], &[]), 0);
828 assert_eq!(count_common_prefix(&[], &[]), 0);
829
830 let long_a: Vec<u8> = (0..33).collect();
832 let mut long_b = long_a.clone();
833 long_b[32] = 255;
834 assert_eq!(count_common_prefix(&long_a, &long_b), 32);
835 }
836
837 #[test]
838 fn from_raw_leaf_flag() {
839 let bytes = &[0xAB, 0xCD];
840 let with_leaf = Nibbles::from_raw(bytes, true);
841 let without_leaf = Nibbles::from_raw(bytes, false);
842
843 assert_eq!(with_leaf.data, vec![0x0A, 0x0B, 0x0C, 0x0D, 16]);
844 assert_eq!(without_leaf.data, vec![0x0A, 0x0B, 0x0C, 0x0D]);
845 }
846}