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
126fn 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 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; 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#[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
372impl<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
406impl 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 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}