Skip to main content

iris_ztd/
hash.rs

1#[cfg(feature = "wasm")]
2use alloc::{boxed::Box, format, string::ToString};
3use core::fmt;
4use crypto_bigint::{nlimbs, NonZero, Uint};
5use either::Either;
6use serde::{Deserialize, Serialize};
7
8use crate::{
9    belt::{Belt, PRIME},
10    crypto::cheetah::CheetahPoint,
11    tip5::hash::{hash_fixed, hash_varlen},
12};
13
14#[cfg(feature = "alloc")]
15use crate::Noun;
16#[cfg(feature = "alloc")]
17use crate::Zeroable;
18#[cfg(feature = "alloc")]
19use alloc::{string::String, vec, vec::Vec};
20#[cfg(feature = "alloc")]
21use ibig::{ops::DivRem, UBig};
22
23#[cfg(feature = "alloc")]
24pub fn belts_from_bytes(bytes: &[u8]) -> Vec<Belt> {
25    belts_from_ubig(UBig::from_be_bytes(bytes))
26}
27
28#[cfg(feature = "alloc")]
29pub fn belts_from_ubig(num: UBig) -> Vec<Belt> {
30    let p = UBig::from(PRIME);
31    let mut belts = Vec::new();
32    let mut remainder = num;
33    let zero = UBig::from(0u64);
34
35    while remainder != zero {
36        let (quotient, rem) = remainder.div_rem(&p);
37        belts.push(Belt(rem.try_into().unwrap()));
38        remainder = quotient;
39    }
40
41    belts
42}
43
44#[cfg(feature = "alloc")]
45pub fn belts_to_bytes(belts: &[Belt]) -> Vec<u8> {
46    belts_to_ubig(belts).to_be_bytes()
47}
48
49#[cfg(feature = "alloc")]
50pub fn belts_to_ubig(belts: &[Belt]) -> UBig {
51    let p = UBig::from(PRIME);
52    let mut num = UBig::from(0u64);
53    for belt in belts {
54        num = num * &p + UBig::from(belt.0);
55    }
56    num
57}
58
59#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
60pub struct Base58Belts<const N: usize>(pub [Belt; N]);
61
62impl<const N: usize> Serialize for Base58Belts<N>
63where
64    Self: Limbable,
65{
66    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
67    where
68        S: serde::Serializer,
69    {
70        let bytes = self.to_bytes_arr();
71        let mut buf = <Self as Limbable>::bs58_buf();
72        let bytes = bytes.as_ref();
73        let start = bytes.iter().position(|&b| b != 0).unwrap_or(bytes.len());
74        let bytes = &bytes[start..];
75        let len = bs58::encode(bytes)
76            .onto(buf.as_mut())
77            .map_err(serde::ser::Error::custom)?;
78        let s = core::str::from_utf8(&buf.as_ref()[..len]).map_err(serde::ser::Error::custom)?;
79        serializer.serialize_str(s)
80    }
81}
82
83impl<'de, const N: usize> Deserialize<'de> for Base58Belts<N>
84where
85    Self: Limbable,
86{
87    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
88    where
89        D: serde::Deserializer<'de>,
90    {
91        struct Base58Visitor<const M: usize>;
92
93        impl<'de, const M: usize> serde::de::Visitor<'de> for Base58Visitor<M>
94        where
95            Base58Belts<M>: Limbable,
96        {
97            type Value = Base58Belts<M>;
98
99            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
100                formatter.write_str("a base58-encoded string")
101            }
102
103            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
104            where
105                E: serde::de::Error,
106            {
107                Base58Belts::<M>::try_from(v).map_err(E::custom)
108            }
109        }
110
111        deserializer.deserialize_str(Base58Visitor::<N>)
112    }
113}
114
115#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Hash)]
116#[iris_ztd_derive::wasm_noun_codec]
117#[cfg_attr(feature = "wasm", tsify(type = "string & { __tag_digest: undefined }"))]
118#[serde(from = "Base58Belts<5>")]
119#[serde(into = "Base58Belts<5>")]
120pub struct Digest(pub [Belt; 5]);
121
122#[cfg(feature = "alloc")]
123#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
124pub struct HashableList<T>(pub T);
125
126/// Convert big-endian bytes of any length to u64, asserting no overflow.
127fn be_bytes_to_u64(bytes: &[u8]) -> u64 {
128    if bytes.len() > 8 {
129        assert!(
130            bytes[..bytes.len() - 8].iter().all(|&x| x == 0),
131            "value overflows u64"
132        );
133    }
134    let mut buf = [0u8; 8];
135    let start = 8usize.saturating_sub(bytes.len());
136    buf[start..].copy_from_slice(&bytes[bytes.len().saturating_sub(8)..]);
137    u64::from_be_bytes(buf)
138}
139
140pub trait Limbable {
141    const LIMBS: usize;
142    const BYTES: usize;
143    /// Buffer size for base58 encode/decode. Must be >= ceil(BYTES * 1.366).
144    const BS58_BUF_SIZE: usize;
145    type UintType: From<u64>
146        + core::ops::MulAssign
147        + core::ops::Mul<Output = Self::UintType>
148        + core::ops::AddAssign
149        + Copy
150        + core::fmt::Debug;
151    type BytesArray: AsRef<[u8]>
152        + AsMut<[u8]>
153        + core::ops::Index<usize, Output = u8>
154        + core::ops::IndexMut<usize, Output = u8>;
155    type Bs58Buf: AsRef<[u8]> + AsMut<[u8]>;
156    fn bs58_buf() -> Self::Bs58Buf;
157    fn to_be_bytes(uint: Self::UintType) -> Self::BytesArray;
158    fn from_be_bytes(bytes: &[u8]) -> Self::UintType;
159    fn div_rem(a: Self::UintType, b: Self::UintType) -> (Self::UintType, Self::UintType);
160    fn is_zero(val: &Self::UintType) -> bool;
161}
162
163impl Limbable for Base58Belts<5> {
164    const LIMBS: usize = nlimbs!(64 * 5);
165    const BYTES: usize = 8 * 5;
166    const BS58_BUF_SIZE: usize = Self::BYTES * 2;
167    type UintType = Uint<{ Self::LIMBS }>;
168    type BytesArray = [u8; Self::BYTES];
169    type Bs58Buf = [u8; Self::BS58_BUF_SIZE];
170    fn bs58_buf() -> Self::Bs58Buf {
171        [0u8; Self::BS58_BUF_SIZE]
172    }
173    fn to_be_bytes(uint: Self::UintType) -> [u8; Self::BYTES] {
174        uint.to_be_bytes()
175    }
176    fn from_be_bytes(bytes: &[u8]) -> Self::UintType {
177        let mut buf = [0u8; Self::BYTES];
178        buf[Self::BYTES - bytes.len()..].copy_from_slice(bytes);
179        Self::UintType::from_be_slice(&buf)
180    }
181    fn div_rem(a: Self::UintType, b: Self::UintType) -> (Self::UintType, Self::UintType) {
182        let nz = NonZero::new(b).expect("division by zero");
183        a.div_rem(&nz)
184    }
185    fn is_zero(val: &Self::UintType) -> bool {
186        *val == Self::UintType::from(0u64)
187    }
188}
189
190impl Limbable for Base58Belts<6> {
191    const LIMBS: usize = nlimbs!(64 * 6);
192    const BYTES: usize = 8 * 6;
193    const BS58_BUF_SIZE: usize = Self::BYTES * 2;
194    type UintType = Uint<{ Self::LIMBS }>;
195    type BytesArray = [u8; Self::BYTES];
196    type Bs58Buf = [u8; Self::BS58_BUF_SIZE];
197    fn bs58_buf() -> Self::Bs58Buf {
198        [0u8; Self::BS58_BUF_SIZE]
199    }
200    fn to_be_bytes(uint: Self::UintType) -> [u8; Self::BYTES] {
201        uint.to_be_bytes()
202    }
203    fn from_be_bytes(bytes: &[u8]) -> Self::UintType {
204        let mut buf = [0u8; Self::BYTES];
205        buf[Self::BYTES - bytes.len()..].copy_from_slice(bytes);
206        Self::UintType::from_be_slice(&buf)
207    }
208    fn div_rem(a: Self::UintType, b: Self::UintType) -> (Self::UintType, Self::UintType) {
209        let nz = NonZero::new(b).expect("division by zero");
210        a.div_rem(&nz)
211    }
212    fn is_zero(val: &Self::UintType) -> bool {
213        *val == Self::UintType::from(0u64)
214    }
215}
216
217impl Limbable for Base58Belts<7> {
218    const LIMBS: usize = nlimbs!(64 * 7);
219    const BYTES: usize = 8 * 7;
220    const BS58_BUF_SIZE: usize = Self::BYTES * 2;
221    type UintType = Uint<{ Self::LIMBS }>;
222    type BytesArray = [u8; Self::BYTES];
223    type Bs58Buf = [u8; Self::BS58_BUF_SIZE];
224    fn bs58_buf() -> Self::Bs58Buf {
225        [0u8; Self::BS58_BUF_SIZE]
226    }
227    fn to_be_bytes(uint: Self::UintType) -> [u8; Self::BYTES] {
228        uint.to_be_bytes()
229    }
230    fn from_be_bytes(bytes: &[u8]) -> Self::UintType {
231        let mut buf = [0u8; Self::BYTES];
232        buf[Self::BYTES - bytes.len()..].copy_from_slice(bytes);
233        Self::UintType::from_be_slice(&buf)
234    }
235    fn div_rem(a: Self::UintType, b: Self::UintType) -> (Self::UintType, Self::UintType) {
236        let nz = NonZero::new(b).expect("division by zero");
237        a.div_rem(&nz)
238    }
239    fn is_zero(val: &Self::UintType) -> bool {
240        *val == Self::UintType::from(0u64)
241    }
242}
243
244impl From<[u64; 5]> for Digest {
245    fn from(belts: [u64; 5]) -> Self {
246        Digest(belts.map(Belt))
247    }
248}
249
250impl From<Digest> for Base58Belts<5> {
251    fn from(digest: Digest) -> Self {
252        Base58Belts(digest.0)
253    }
254}
255
256impl From<Base58Belts<5>> for Digest {
257    fn from(belts: Base58Belts<5>) -> Self {
258        Digest(belts.0)
259    }
260}
261
262impl<const N: usize> From<[u64; N]> for Base58Belts<N> {
263    fn from(belts: [u64; N]) -> Self {
264        Base58Belts(belts.map(Belt))
265    }
266}
267
268impl<const N: usize> Base58Belts<N>
269where
270    Self: Limbable,
271{
272    pub fn to_uint(&self) -> <Self as Limbable>::UintType {
273        let p = <Self as Limbable>::UintType::from(PRIME);
274        let mut result = <Self as Limbable>::UintType::from(0u64);
275        let mut power = <Self as Limbable>::UintType::from(1u64);
276
277        for belt in &self.0 {
278            result += <Self as Limbable>::UintType::from(belt.0) * power;
279            power *= p;
280        }
281
282        result
283    }
284
285    pub fn to_bytes_arr(&self) -> <Self as Limbable>::BytesArray {
286        Self::to_be_bytes(self.to_uint())
287    }
288
289    pub fn from_bytes(bytes: &[u8]) -> Self {
290        let p = <Self as Limbable>::UintType::from(PRIME);
291        let num = <Self as Limbable>::from_be_bytes(bytes);
292
293        let mut belts = [Belt(0); N];
294        let mut remainder = num;
295
296        for b in &mut belts[..] {
297            let (quotient, rem) = <Self as Limbable>::div_rem(remainder, p);
298            *b = Belt(be_bytes_to_u64(Self::to_be_bytes(rem).as_ref()));
299            remainder = quotient;
300        }
301
302        assert!(
303            <Self as Limbable>::is_zero(&remainder),
304            "Invalid belt count"
305        );
306
307        Base58Belts(belts)
308    }
309}
310
311#[cfg(feature = "alloc")]
312impl<const N: usize> Base58Belts<N> {
313    pub fn to_ubig(&self) -> UBig {
314        let p = UBig::from(PRIME);
315        let mut result = UBig::from(0u64);
316        let mut power = UBig::from(1u64);
317
318        for belt in &self.0 {
319            result += UBig::from(belt.0) * &power;
320            power *= &p;
321        }
322
323        result
324    }
325
326    pub fn to_bytes(&self) -> Vec<u8> {
327        let res = self.to_ubig();
328        let res_bytes = res.to_be_bytes();
329        let expected_len = N * 8; // Each belt is 8 bytes
330
331        let mut bytes = vec![0u8; expected_len];
332        let start_offset = expected_len.saturating_sub(res_bytes.len());
333        bytes[start_offset..].copy_from_slice(&res_bytes);
334        bytes
335    }
336}
337
338// Digest-specific implementations that delegate to Base58Belts<5>
339#[cfg(feature = "alloc")]
340impl Digest {
341    pub fn to_ubig(&self) -> UBig {
342        Base58Belts::<5>::from(*self).to_ubig()
343    }
344
345    pub fn to_bytes(&self) -> [u8; 40] {
346        let vec = Base58Belts::<5>::from(*self).to_bytes();
347        let mut arr = [0u8; 40];
348        arr.copy_from_slice(&vec);
349        arr
350    }
351
352    pub fn from_bytes(bytes: &[u8]) -> Self {
353        Base58Belts::<5>::from_bytes(bytes).into()
354    }
355}
356
357#[cfg(feature = "alloc")]
358#[iris_ztd_derive::wasm_member_methods]
359impl Digest {
360    pub fn to_atom(&self) -> Noun {
361        Noun::Atom(self.to_ubig())
362    }
363
364    pub fn from_atom(atom: Noun) -> Self {
365        let Noun::Atom(atom) = atom else {
366            panic!("not an atom");
367        };
368        Self::from_bytes(&atom.to_be_bytes())
369    }
370}
371
372// Display and TryFrom implementations for Base58Belts<N> (no-alloc)
373impl<const N: usize> fmt::Display for Base58Belts<N>
374where
375    Self: Limbable,
376{
377    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
378        let bytes = self.to_bytes_arr();
379        let bytes = bytes.as_ref();
380        let start = bytes.iter().position(|&b| b != 0).unwrap_or(bytes.len());
381        let bytes = &bytes[start..];
382        let mut buf = <Self as Limbable>::bs58_buf();
383        let len = bs58::encode(bytes)
384            .onto(buf.as_mut())
385            .map_err(|_| fmt::Error)?;
386        let s = core::str::from_utf8(&buf.as_ref()[..len]).map_err(|_| fmt::Error)?;
387        f.write_str(s)
388    }
389}
390
391impl<const N: usize> TryFrom<&str> for Base58Belts<N>
392where
393    Self: Limbable,
394{
395    type Error = &'static str;
396
397    fn try_from(s: &str) -> Result<Self, Self::Error> {
398        let mut buf = <Self as Limbable>::bs58_buf();
399        let len = bs58::decode(s)
400            .onto(buf.as_mut())
401            .map_err(|_| "unable to decode base58 belts")?;
402        Ok(Base58Belts::from_bytes(&buf.as_ref()[..len]))
403    }
404}
405
406// Digest implementations delegate to Base58Belts<5>
407impl fmt::Display for Digest {
408    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
409        Base58Belts::<5>::from(*self).fmt(f)
410    }
411}
412
413impl fmt::Debug for Digest {
414    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
415        write!(f, "Digest({})", self)
416    }
417}
418
419impl TryFrom<&str> for Digest {
420    type Error = &'static str;
421
422    fn try_from(s: &str) -> Result<Self, Self::Error> {
423        Ok(Base58Belts::<5>::try_from(s)?.into())
424    }
425}
426
427#[cfg(feature = "alloc")]
428pub fn hash_noun(leaves: &[Belt], dyck: &[Belt]) -> Digest {
429    let mut combined = Vec::with_capacity(1 + leaves.len() + dyck.len());
430    combined.push(Belt(leaves.len() as u64));
431    combined.extend_from_slice(leaves);
432    combined.extend_from_slice(dyck);
433    Digest(hash_varlen(&combined).map(Belt))
434}
435
436pub trait Hashable {
437    fn hash(&self) -> Digest;
438    fn leaf_count(&self) -> usize;
439    fn hashable_pair<'a>(&'a self) -> Option<(impl Hashable + 'a, impl Hashable + 'a)>;
440}
441
442impl Hashable for Belt {
443    fn hash(&self) -> Digest {
444        let v = [Belt(1), *self];
445        Digest(hash_varlen(&v).map(Belt))
446    }
447
448    fn leaf_count(&self) -> usize {
449        1
450    }
451
452    fn hashable_pair<'a>(&'a self) -> Option<(impl Hashable + 'a, impl Hashable + 'a)> {
453        Option::<((), ())>::None
454    }
455}
456
457impl Hashable for u64 {
458    fn hash(&self) -> Digest {
459        Belt(*self).hash()
460    }
461
462    fn leaf_count(&self) -> usize {
463        1
464    }
465
466    fn hashable_pair<'a>(&'a self) -> Option<(impl Hashable + 'a, impl Hashable + 'a)> {
467        Option::<((), ())>::None
468    }
469}
470
471impl Hashable for u32 {
472    fn hash(&self) -> Digest {
473        Belt(*self as u64).hash()
474    }
475
476    fn leaf_count(&self) -> usize {
477        1
478    }
479
480    fn hashable_pair<'a>(&'a self) -> Option<(impl Hashable + 'a, impl Hashable + 'a)> {
481        Option::<((), ())>::None
482    }
483}
484
485impl Hashable for usize {
486    fn hash(&self) -> Digest {
487        (*self as u64).hash()
488    }
489
490    fn leaf_count(&self) -> usize {
491        1
492    }
493
494    fn hashable_pair<'a>(&'a self) -> Option<(impl Hashable + 'a, impl Hashable + 'a)> {
495        Option::<((), ())>::None
496    }
497}
498
499impl Hashable for i32 {
500    fn hash(&self) -> Digest {
501        (*self as u64).hash()
502    }
503
504    fn leaf_count(&self) -> usize {
505        1
506    }
507
508    fn hashable_pair<'a>(&'a self) -> Option<(impl Hashable + 'a, impl Hashable + 'a)> {
509        Option::<((), ())>::None
510    }
511}
512
513impl Hashable for bool {
514    fn hash(&self) -> Digest {
515        (if *self { 0 } else { 1 }).hash()
516    }
517
518    fn leaf_count(&self) -> usize {
519        1
520    }
521
522    fn hashable_pair<'a>(&'a self) -> Option<(impl Hashable + 'a, impl Hashable + 'a)> {
523        Option::<((), ())>::None
524    }
525}
526
527impl Hashable for Digest {
528    fn hash(&self) -> Digest {
529        *self
530    }
531
532    fn leaf_count(&self) -> usize {
533        1
534    }
535
536    fn hashable_pair<'a>(&'a self) -> Option<(impl Hashable + 'a, impl Hashable + 'a)> {
537        Option::<((), ())>::None
538    }
539}
540
541impl<T: Hashable + ?Sized> Hashable for &T {
542    fn hash(&self) -> Digest {
543        (**self).hash()
544    }
545
546    fn leaf_count(&self) -> usize {
547        (**self).leaf_count()
548    }
549
550    fn hashable_pair<'a>(&'a self) -> Option<(impl Hashable + 'a, impl Hashable + 'a)> {
551        (**self).hashable_pair()
552    }
553}
554
555impl<T: Hashable, P: Hashable> Hashable for Either<T, P> {
556    fn hash(&self) -> Digest {
557        match self {
558            Either::Left(v) => v.hash(),
559            Either::Right(v) => v.hash(),
560        }
561    }
562
563    fn leaf_count(&self) -> usize {
564        match self {
565            Either::Left(v) => v.leaf_count(),
566            Either::Right(v) => v.leaf_count(),
567        }
568    }
569
570    fn hashable_pair<'a>(&'a self) -> Option<(impl Hashable + 'a, impl Hashable + 'a)> {
571        match self {
572            Either::Left(v) => v
573                .hashable_pair()
574                .map(|(a, b)| (Either::Left(a), Either::Left(b))),
575            Either::Right(v) => v
576                .hashable_pair()
577                .map(|(a, b)| (Either::Right(a), Either::Right(b))),
578        }
579    }
580}
581
582impl<T: Hashable> Hashable for Option<T> {
583    fn hash(&self) -> Digest {
584        match self {
585            None => 0.hash(),
586            Some(v) => (&0, v).hash(),
587        }
588    }
589
590    fn leaf_count(&self) -> usize {
591        match self {
592            None => 1,
593            Some(v) => (&0, v).leaf_count(),
594        }
595    }
596
597    fn hashable_pair<'a>(&'a self) -> Option<(impl Hashable + 'a, impl Hashable + 'a)> {
598        self.as_ref().map(|v| (0, v))
599    }
600}
601
602#[cfg(feature = "alloc")]
603impl<T: Hashable> Hashable for Zeroable<T> {
604    fn hash(&self) -> Digest {
605        match &self.0 {
606            None => 0.hash(),
607            Some(v) => v.hash(),
608        }
609    }
610
611    fn leaf_count(&self) -> usize {
612        match &self.0 {
613            None => 1,
614            Some(v) => v.leaf_count(),
615        }
616    }
617
618    fn hashable_pair<'a>(&'a self) -> Option<(impl Hashable + 'a, impl Hashable + 'a)> {
619        match &self.0 {
620            None => None,
621            Some(v) => v.hashable_pair(),
622        }
623    }
624}
625
626impl Hashable for () {
627    fn hash(&self) -> Digest {
628        0.hash()
629    }
630
631    fn leaf_count(&self) -> usize {
632        1
633    }
634
635    fn hashable_pair<'a>(&'a self) -> Option<(impl Hashable + 'a, impl Hashable + 'a)> {
636        Option::<((), ())>::None
637    }
638}
639
640macro_rules! impl_hashable_for_tuple {
641    ($T0:ident) => {};
642    ($T0:ident, $T1:ident) => {
643        impl<$T0: Hashable, $T1: Hashable> Hashable for ($T0, $T1) {
644            fn hash(&self) -> Digest {
645                let mut belts = [Belt(0); 10];
646                belts[..5].copy_from_slice(&self.0.hash().0);
647                belts[5..].copy_from_slice(&self.1.hash().0);
648                Digest(hash_fixed(&mut belts).map(|u| Belt(u)))
649            }
650
651            fn leaf_count(&self) -> usize {
652                self.0.leaf_count() + self.1.leaf_count()
653            }
654
655            fn hashable_pair<'a>(&'a self) -> Option<(impl Hashable + 'a, impl Hashable + 'a)> {
656                Some((&self.0, &self.1))
657            }
658        }
659    };
660    ($T:ident, $($U:ident),+) => {
661        impl<$T: Hashable, $($U: Hashable),*> Hashable for ($T, $($U),*) {
662            fn hash(&self) -> Digest {
663                #[allow(non_snake_case)]
664                let ($T, $($U),*) = self;
665                ($T, ($($U,)*)).hash()
666            }
667
668            fn leaf_count(&self) -> usize {
669                #[allow(non_snake_case)]
670                let ($T, $($U),*) = self;
671                $T.leaf_count() + ($($U.leaf_count()),*).leaf_count()
672            }
673
674            fn hashable_pair<'a>(&'a self) -> Option<(impl Hashable + 'a, impl Hashable + 'a)> {
675                #[allow(non_snake_case)]
676                let ($T, $($U),*) = self;
677                Some(($T, ($($U,)*)))
678            }
679        }
680
681        impl_hashable_for_tuple!($($U),*);
682    };
683}
684
685impl_hashable_for_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T);
686
687impl<T: Hashable> Hashable for &[T] {
688    fn hash(&self) -> Digest {
689        let (first, rest) = self.split_first().unwrap();
690        if rest.is_empty() {
691            first.hash()
692        } else {
693            (first.hash(), rest.hash()).hash()
694        }
695    }
696
697    fn leaf_count(&self) -> usize {
698        1
699    }
700
701    fn hashable_pair<'a>(&'a self) -> Option<(impl Hashable + 'a, impl Hashable + 'a)> {
702        Option::<((), ())>::None
703    }
704}
705
706#[cfg(feature = "alloc")]
707impl<T: Hashable> Hashable for Vec<T> {
708    fn hash(&self) -> Digest {
709        fn hash_slice<T: Hashable>(arr: &[T]) -> Digest {
710            match arr.split_first() {
711                None => 0.hash(),
712                Some((first, rest)) => (first.hash(), hash_slice(rest)).hash(),
713            }
714        }
715        hash_slice(self.as_slice())
716    }
717
718    fn leaf_count(&self) -> usize {
719        1
720    }
721
722    fn hashable_pair<'a>(&'a self) -> Option<(impl Hashable + 'a, impl Hashable + 'a)> {
723        Option::<((), ())>::None
724    }
725}
726
727#[cfg(feature = "alloc")]
728impl<T: core::ops::Deref<Target = [O]>, O: Hashable> Hashable for HashableList<T> {
729    fn hash(&self) -> Digest {
730        let hashes = &self.0.iter().map(|v| v.hash()).collect::<Vec<_>>();
731
732        let mut belts = vec![];
733        belts.push(Belt(hashes.len() as u64 * 5 + 1));
734        belts.extend(hashes.iter().flat_map(|b| b.0));
735        belts.push(Belt(0));
736
737        for _ in 0..hashes.len() {
738            belts.extend([0, 0, 1, 0, 1, 0, 1, 0, 1, 1].map(Belt));
739        }
740
741        Digest(hash_varlen(&belts).map(Belt))
742    }
743
744    fn leaf_count(&self) -> usize {
745        1
746    }
747
748    fn hashable_pair<'a>(&'a self) -> Option<(impl Hashable + 'a, impl Hashable + 'a)> {
749        Option::<((), ())>::None
750    }
751}
752
753impl Hashable for &str {
754    fn hash(&self) -> Digest {
755        self.bytes()
756            .enumerate()
757            .fold(0u64, |acc, (i, byte)| acc | ((byte as u64) << (i * 8)))
758            .hash()
759    }
760
761    fn leaf_count(&self) -> usize {
762        1
763    }
764
765    fn hashable_pair<'a>(&'a self) -> Option<(impl Hashable + 'a, impl Hashable + 'a)> {
766        Option::<((), ())>::None
767    }
768}
769
770#[cfg(feature = "alloc")]
771impl Hashable for String {
772    fn hash(&self) -> Digest {
773        self.bytes()
774            .enumerate()
775            .fold(0u64, |acc, (i, byte)| acc | ((byte as u64) << (i * 8)))
776            .hash()
777    }
778
779    fn leaf_count(&self) -> usize {
780        1
781    }
782
783    fn hashable_pair<'a>(&'a self) -> Option<(impl Hashable + 'a, impl Hashable + 'a)> {
784        Option::<((), ())>::None
785    }
786}
787
788#[cfg(feature = "alloc")]
789impl Hashable for Noun {
790    fn hash(&self) -> Digest {
791        fn visit(noun: &Noun, leaves: &mut Vec<Belt>, dyck: &mut Vec<Belt>) {
792            match noun {
793                Noun::Atom(b) => leaves.push(Belt(b.try_into().expect("atom too large"))),
794                Noun::Cell(left, right) => {
795                    dyck.push(Belt(0));
796                    visit(left, leaves, dyck);
797                    dyck.push(Belt(1));
798                    visit(right, leaves, dyck);
799                }
800            }
801        }
802
803        let mut leaves = Vec::new();
804        let mut dyck = Vec::new();
805        visit(self, &mut leaves, &mut dyck);
806        hash_noun(&leaves, &dyck)
807    }
808
809    fn leaf_count(&self) -> usize {
810        1
811    }
812
813    fn hashable_pair<'a>(&'a self) -> Option<(impl Hashable + 'a, impl Hashable + 'a)> {
814        Option::<((), ())>::None
815    }
816}
817
818impl Hashable for CheetahPoint {
819    fn hash(&self) -> Digest {
820        // This is equivalent to converting CheetahPoint to noun, and then hashing that.
821        let dyck = [
822            0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1,
823        ]
824        .map(Belt);
825        let mut leaves = [Belt(0); 6 + 6 + 1];
826        leaves[..6].copy_from_slice(&self.x.0);
827        leaves[6..12].copy_from_slice(&self.y.0);
828        leaves[12] = Belt(!self.inf as u64);
829        let mut hash = [Belt(0); 1 + 24 + 6 + 6 + 1];
830        hash[0] = Belt(leaves.len() as u64);
831        hash[1..14].copy_from_slice(&leaves);
832        hash[14..38].copy_from_slice(&dyck);
833        Digest(hash_varlen(&hash).map(Belt))
834    }
835
836    fn leaf_count(&self) -> usize {
837        1
838    }
839
840    fn hashable_pair<'a>(&'a self) -> Option<(impl Hashable + 'a, impl Hashable + 'a)> {
841        Option::<((), ())>::None
842    }
843}
844
845#[cfg(test)]
846mod tests {
847    use super::*;
848    use alloc::string::ToString;
849
850    #[test]
851    fn test_vec_hash() {
852        let vec = vec![0u64, 1u64];
853        let vec = HashableList(vec);
854        assert_eq!(
855            vec.hash().to_string(),
856            "5F6UZhcWYBDSJ3CvevfiABhdSjc9qNh29KcH5rs8FJB4NNPHRn3oqQJ"
857        );
858    }
859}