1use crate::belt::based_check;
2use crate::crypto::cheetah::F6lt;
3use alloc::{boxed::Box, collections::btree_map::BTreeMap, format, string::String, vec, vec::Vec};
4use bitvec::prelude::{BitSlice, BitVec, Lsb0};
5use core::fmt;
6use core::mem::MaybeUninit;
7use ibig::UBig;
8use num_traits::Zero;
9use serde::de::{Error as DeError, SeqAccess, Visitor};
10use serde::{ser::SerializeTuple, Serialize, Serializer};
11use serde::{Deserialize, Deserializer};
12
13use crate::{belt::Belt, crypto::cheetah::CheetahPoint, Digest};
14
15pub fn noun_serialize<T: NounEncode, S>(v: &T, serializer: S) -> Result<S::Ok, S::Error>
16where
17 S: Serializer,
18{
19 v.to_noun().serialize(serializer)
20}
21
22pub fn noun_deserialize<'de, T: NounDecode, D>(deserializer: D) -> Result<T, D::Error>
23where
24 D: Deserializer<'de>,
25{
26 let r = Noun::deserialize(deserializer)?;
27 T::from_noun(&r).ok_or_else(|| DeError::custom("unable to parse noun"))
28}
29
30#[derive(Clone, Debug, PartialEq, Eq)]
31pub enum Noun {
32 Atom(UBig),
33 Cell(Box<Noun>, Box<Noun>),
34}
35
36impl Noun {
37 #[allow(clippy::inherent_to_string_shadow_display)]
38 pub fn to_string(&self) -> String {
39 fn autocons(cell: &Noun) -> String {
40 match cell {
41 Noun::Atom(a) => format!("{}", a),
42 Noun::Cell(head, tail) => match &**tail {
43 Noun::Cell(_, _) => format!("{} {}", autocons(head), autocons(tail)),
44 Noun::Atom(a) if a.is_zero() => autocons(head),
45 Noun::Atom(_) => format!("{} . {}", autocons(head), autocons(tail)),
46 },
47 }
48 }
49
50 match self {
51 Noun::Atom(a) => format!("{}", a),
52 Noun::Cell(head, tail) => {
53 format!("[{}]", autocons(&Noun::Cell(head.clone(), tail.clone())))
54 }
55 }
56 }
57}
58
59impl Serialize for Noun {
60 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
61 where
62 S: Serializer,
63 {
64 match self {
65 Self::Atom(v) => serializer.serialize_str(&alloc::format!("{v:x}")),
66 Self::Cell(a, b) => {
67 let mut tup = serializer.serialize_tuple(2)?;
68 tup.serialize_element(a)?;
69 tup.serialize_element(b)?;
70 tup.end()
71 }
72 }
73 }
74}
75
76impl<'de> Deserialize<'de> for Noun {
77 fn deserialize<D>(de: D) -> Result<Self, D::Error>
78 where
79 D: Deserializer<'de>,
80 {
81 struct V;
82
83 impl<'de> Visitor<'de> for V {
84 type Value = Noun;
85
86 fn expecting(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
87 f.write_str("atom or cell")
88 }
89
90 fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
91 where
92 E: DeError,
93 {
94 let n = UBig::from_str_radix(s, 16).map_err(E::custom)?;
95 Ok(Noun::Atom(n))
96 }
97
98 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
99 where
100 A: SeqAccess<'de>,
101 {
102 let a = seq
103 .next_element::<Noun>()?
104 .ok_or_else(|| DeError::custom("cell missing car"))?;
105 let b = seq
106 .next_element::<Noun>()?
107 .ok_or_else(|| DeError::custom("cell missing cdr"))?;
108 Ok(Noun::Cell(Box::new(a), Box::new(b)))
109 }
110 }
111
112 de.deserialize_any(V)
113 }
114}
115
116impl fmt::Display for Noun {
117 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118 write!(f, "{}", self.to_string())
119 }
120}
121
122pub trait NounCode: NounEncode + NounDecode {}
123impl<T: NounEncode + NounDecode> NounCode for T {}
124
125pub trait NounEncode {
126 fn to_noun(&self) -> Noun;
127}
128
129pub trait NounDecode: Sized {
130 fn from_noun(noun: &Noun) -> Option<Self>;
131}
132
133fn atom(value: u64) -> Noun {
134 Noun::Atom(UBig::from(value))
135}
136
137fn cons(left: Noun, right: Noun) -> Noun {
138 Noun::Cell(Box::new(left), Box::new(right))
139}
140
141impl<T: NounEncode + ?Sized> NounEncode for &T {
142 fn to_noun(&self) -> Noun {
143 (**self).to_noun()
144 }
145}
146
147impl<T: NounEncode + ?Sized> NounEncode for Box<T> {
148 fn to_noun(&self) -> Noun {
149 (**self).to_noun()
150 }
151}
152
153impl<T: NounDecode> NounDecode for Box<T> {
154 fn from_noun(noun: &Noun) -> Option<Self> {
155 Some(Box::new(T::from_noun(noun)?))
156 }
157}
158
159impl NounEncode for Noun {
160 fn to_noun(&self) -> Noun {
161 self.clone()
162 }
163}
164
165impl NounDecode for Noun {
166 fn from_noun(noun: &Noun) -> Option<Self> {
167 Some(noun.clone())
168 }
169}
170
171impl NounEncode for () {
172 fn to_noun(&self) -> Noun {
173 atom(0)
174 }
175}
176
177impl NounDecode for () {
178 fn from_noun(noun: &Noun) -> Option<Self> {
179 if *noun == atom(0) {
180 Some(())
181 } else {
182 None
183 }
184 }
185}
186
187impl NounEncode for Belt {
188 fn to_noun(&self) -> Noun {
189 atom(self.0)
190 }
191}
192
193impl NounDecode for Belt {
194 fn from_noun(noun: &Noun) -> Option<Self> {
195 let Noun::Atom(a) = noun else {
196 return None;
197 };
198 let v = u64::try_from(a).ok()?;
199 if based_check(v) {
200 Some(Belt(v))
201 } else {
202 None
203 }
204 }
205}
206
207impl NounEncode for Digest {
208 fn to_noun(&self) -> Noun {
209 self.0.to_noun()
210 }
211}
212
213impl NounDecode for Digest {
214 fn from_noun(noun: &Noun) -> Option<Self> {
215 Some(Digest(<[Belt; 5]>::from_noun(noun)?))
216 }
217}
218
219impl NounEncode for CheetahPoint {
220 fn to_noun(&self) -> Noun {
221 (self.x.0, self.y.0, self.inf).to_noun()
222 }
223}
224
225impl NounDecode for CheetahPoint {
226 fn from_noun(noun: &Noun) -> Option<Self> {
227 let (x, y, inf) = NounDecode::from_noun(noun)?;
228 Some(Self {
229 x: F6lt(x),
230 y: F6lt(y),
231 inf,
232 })
233 }
234}
235
236macro_rules! impl_nounable_for_int {
237 ($($ty:ty),* $(,)?) => {
238 $(
239 impl NounEncode for $ty {
240 fn to_noun(&self) -> Noun {
241 atom(*self as u64)
242 }
243 }
244
245 impl NounDecode for $ty {
246 fn from_noun(noun: &Noun) -> Option<$ty> {
247 let Noun::Atom(a) = noun else {
248 return None;
249 };
250 <$ty>::try_from(a).ok()
251 }
252 }
253 )*
254 };
255}
256
257impl_nounable_for_int!(i32, i64, isize, u32, u64, usize);
258
259impl NounEncode for bool {
260 fn to_noun(&self) -> Noun {
261 atom(if *self { 0 } else { 1 })
262 }
263}
264
265impl NounDecode for bool {
266 fn from_noun(noun: &Noun) -> Option<Self> {
267 let Noun::Atom(a) = noun else {
268 return None;
269 };
270 if a == &UBig::from(0u64) {
271 Some(true)
272 } else if a == &UBig::from(1u64) {
273 Some(false)
274 } else {
275 None
276 }
277 }
278}
279
280impl<T: NounEncode> NounEncode for Option<T> {
281 fn to_noun(&self) -> Noun {
282 match self {
283 None => atom(0),
284 Some(value) => (0, value.to_noun()).to_noun(),
285 }
286 }
287}
288
289impl<T: NounDecode> NounDecode for Option<T> {
290 fn from_noun(noun: &Noun) -> Option<Self> {
291 match noun {
292 Noun::Cell(x, v) if **x == atom(0) => Some(Some(T::from_noun(v)?)),
293 Noun::Atom(x) if x.is_zero() => Some(None),
294 _ => None,
295 }
296 }
297}
298
299macro_rules! impl_nounable_for_tuple {
300 ($T0:ident => $i0:ident) => {};
301 ($T:ident => $t:ident $( $U:ident => $u:ident )+) => {
302 impl<$T: NounEncode, $($U: NounEncode),*> NounEncode for ($T, $($U),*) {
303 fn to_noun(&self) -> Noun {
304 let ($t, $($u),*) = self;
305 cons($t.to_noun(), ($($u),*).to_noun())
306 }
307 }
308
309 impl<$T: NounDecode, $($U: NounDecode),*> NounDecode for ($T, $($U),*) {
310 fn from_noun(noun: &Noun) -> Option<($T, $($U),*)> {
311 let Noun::Cell(a, b) = noun else {
312 return None;
313 };
314 let a = <$T>::from_noun(a)?;
315 #[allow(unused_parens)]
316 let ($($u),*) = <($($U),*)>::from_noun(b)?;
317 Some((a, $($u),*))
318 }
319 }
320
321 impl_nounable_for_tuple!($($U => $u)*);
322 };
323}
324
325impl_nounable_for_tuple!(
326 A => a
327 B => b
328 C => c
329 D => d
330 E => e
331 F => f
332 G => g
333 H => h
334 I => i
335 J => j
336 K => k
337);
338
339impl<T: NounEncode, const N: usize> NounEncode for [T; N] {
340 fn to_noun(&self) -> Noun {
341 match self.split_last() {
342 None => unreachable!(),
343 Some((last, rest)) => {
344 let mut acc = last.to_noun();
345 for item in rest.iter().rev() {
346 acc = cons(item.to_noun(), acc);
347 }
348 acc
349 }
350 }
351 }
352}
353
354impl<T: NounDecode, const N: usize> NounDecode for [T; N] {
355 fn from_noun(mut noun: &Noun) -> Option<Self> {
356 let mut ret = [(); N].map(|_| MaybeUninit::<T>::uninit());
357 for item in ret.iter_mut().take(N) {
358 let Noun::Cell(a, b) = noun else {
359 return None;
360 };
361 *item = MaybeUninit::<T>::new(T::from_noun(a)?);
362 noun = b;
363 }
364
365 Some(unsafe { ret.map(|v| v.assume_init()) })
367 }
368}
369
370impl<T: NounEncode> NounEncode for &[T] {
372 fn to_noun(&self) -> Noun {
373 match self.split_last() {
374 None => atom(0),
375 Some((last, rest)) => {
376 let mut acc = last.to_noun();
377 for item in rest.iter().rev() {
378 acc = cons(item.to_noun(), acc);
379 }
380 acc
381 }
382 }
383 }
384}
385
386impl<T: NounEncode> NounEncode for Vec<T> {
387 fn to_noun(&self) -> Noun {
388 let mut acc = atom(0);
389 for item in self.iter().rev() {
390 acc = cons(item.to_noun(), acc);
391 }
392 acc
393 }
394}
395
396impl<T: NounDecode> NounDecode for Vec<T> {
397 fn from_noun(mut noun: &Noun) -> Option<Self> {
398 let mut ret = vec![];
399 loop {
400 match noun {
401 Noun::Cell(a, b) => {
402 ret.push(T::from_noun(a)?);
403 noun = b;
404 }
405 Noun::Atom(v) => {
406 if v.is_zero() {
407 return Some(ret);
408 } else {
409 return None;
410 }
411 }
412 }
413 }
414 }
415}
416
417impl NounEncode for &str {
418 fn to_noun(&self) -> Noun {
419 Noun::Atom(UBig::from_le_bytes(self.as_bytes()))
420 }
421}
422
423impl NounEncode for String {
424 fn to_noun(&self) -> Noun {
425 self.as_str().to_noun()
426 }
427}
428
429impl NounDecode for String {
430 fn from_noun(noun: &Noun) -> Option<Self> {
431 let Noun::Atom(a) = noun else {
432 return None;
433 };
434 String::from_utf8(a.to_le_bytes()).ok()
435 }
436}
437
438pub fn jam(noun: Noun) -> Vec<u8> {
439 fn met0_u64_to_usize(value: u64) -> usize {
440 (u64::BITS - value.leading_zeros()) as usize
441 }
442
443 fn met0_atom(atom: &UBig) -> usize {
444 atom.bit_len()
445 }
446
447 fn mat_backref(buffer: &mut BitVec<u8, Lsb0>, backref: usize) {
448 if backref == 0 {
449 buffer.push(true);
450 buffer.push(true);
451 buffer.push(true);
452 return;
453 }
454 let backref_sz = met0_u64_to_usize(backref as u64);
455 let backref_sz_sz = met0_u64_to_usize(backref_sz as u64);
456 buffer.push(true);
457 buffer.push(true);
458 let buffer_len = buffer.len();
459 buffer.resize(buffer_len + backref_sz_sz, false);
460 buffer.push(true);
461 let size_bits = BitSlice::<usize, Lsb0>::from_element(&backref_sz);
462 buffer.extend_from_bitslice(&size_bits[..backref_sz_sz - 1]);
463 let backref_bits = BitSlice::<usize, Lsb0>::from_element(&backref);
464 buffer.extend_from_bitslice(&backref_bits[..backref_sz]);
465 }
466
467 fn mat_atom(buffer: &mut BitVec<u8, Lsb0>, atom: &UBig) {
468 if atom.is_zero() {
469 buffer.push(false);
470 buffer.push(true);
471 return;
472 }
473 let atom_sz = met0_atom(atom);
474 let atom_sz_sz = met0_u64_to_usize(atom_sz as u64);
475 buffer.push(false);
476 let buffer_len = buffer.len();
477 buffer.resize(buffer_len + atom_sz_sz, false);
478 buffer.push(true);
479 let size_bits = BitSlice::<usize, Lsb0>::from_element(&atom_sz);
480 buffer.extend_from_bitslice(&size_bits[..atom_sz_sz - 1]);
481 let atom_bytes = atom.to_le_bytes();
482 let atom_bits = BitSlice::<u8, Lsb0>::from_slice(&atom_bytes);
483 buffer.extend_from_bitslice(&atom_bits[..atom_sz]);
484 }
485
486 fn find_backref(backrefs: &[(Noun, usize)], target: &Noun) -> Option<usize> {
487 backrefs
488 .iter()
489 .find(|(noun, _)| noun == target)
490 .map(|(_, offset)| *offset)
491 }
492
493 let mut backrefs: Vec<(Noun, usize)> = Vec::new();
494 let mut stack = Vec::new();
495 stack.push(noun);
496 let mut buffer = BitVec::<u8, Lsb0>::new();
497
498 while let Some(current) = stack.pop() {
499 if let Some(backref) = find_backref(&backrefs, ¤t) {
500 match ¤t {
501 Noun::Atom(atom) => {
502 if met0_u64_to_usize(backref as u64) < met0_atom(atom) {
503 mat_backref(&mut buffer, backref);
504 } else {
505 mat_atom(&mut buffer, atom);
506 }
507 }
508 Noun::Cell(_, _) => {
509 mat_backref(&mut buffer, backref);
510 }
511 }
512 } else {
513 let offset = buffer.len();
514 backrefs.push((current.clone(), offset));
515 match current {
516 Noun::Atom(atom) => {
517 mat_atom(&mut buffer, &atom);
518 }
519 Noun::Cell(left, right) => {
520 buffer.push(true);
521 buffer.push(false);
522 stack.push(*right);
523 stack.push(*left);
524 }
525 }
526 }
527 }
528
529 buffer.into_vec()
530}
531
532pub fn cue(bytes: &[u8]) -> Option<Noun> {
533 cue_bitslice(BitSlice::from_slice(bytes))
534}
535
536pub fn cue_bitslice(buffer: &BitSlice<u8, Lsb0>) -> Option<Noun> {
537 #[derive(Copy, Clone)]
538 enum CueStackEntry {
539 DestinationPointer(*mut Noun),
540 BackRef(u64, *mut Noun),
541 }
542
543 pub fn next_up_to_n_bits<'a>(
544 cursor: &mut usize,
545 slice: &'a BitSlice<u8, Lsb0>,
546 n: usize,
547 ) -> &'a BitSlice<u8, Lsb0> {
548 let res = if (slice).len() >= *cursor + n {
549 &slice[*cursor..*cursor + n]
550 } else if slice.len() > *cursor {
551 &slice[*cursor..]
552 } else {
553 BitSlice::<u8, Lsb0>::empty()
554 };
555 *cursor += n;
556 res
557 }
558
559 pub fn rest_bits(cursor: usize, slice: &BitSlice<u8, Lsb0>) -> &BitSlice<u8, Lsb0> {
560 if slice.len() > cursor {
561 &slice[cursor..]
562 } else {
563 BitSlice::<u8, Lsb0>::empty()
564 }
565 }
566
567 fn get_size(cursor: &mut usize, buffer: &BitSlice<u8, Lsb0>) -> Option<usize> {
568 let buff_at_cursor = rest_bits(*cursor, buffer);
569 let bitsize = buff_at_cursor.first_one()?;
570 if bitsize == 0 {
571 *cursor += 1;
572 Some(0)
573 } else {
574 let mut size = [0u8; 8];
575 *cursor += bitsize + 1;
576 let size_bits = next_up_to_n_bits(cursor, buffer, bitsize - 1);
577 BitSlice::from_slice_mut(&mut size)[0..bitsize - 1].copy_from_bitslice(size_bits);
578 Some((u64::from_le_bytes(size) as usize) + (1 << (bitsize - 1)))
579 }
580 }
581
582 fn rub_backref(cursor: &mut usize, buffer: &BitSlice<u8, Lsb0>) -> Option<u64> {
583 let size = get_size(cursor, buffer)?;
585 if size == 0 {
586 Some(0)
587 } else if size <= 64 {
588 let mut backref = [0u8; 8];
590 BitSlice::from_slice_mut(&mut backref)[0..size]
591 .copy_from_bitslice(&buffer[*cursor..*cursor + size]);
592 *cursor += size;
593 Some(u64::from_le_bytes(backref))
594 } else {
595 None
596 }
597 }
598
599 fn rub_atom(cursor: &mut usize, buffer: &BitSlice<u8, Lsb0>) -> Option<UBig> {
600 let size = get_size(cursor, buffer)?;
601 let bits = next_up_to_n_bits(cursor, buffer, size);
602 if size == 0 {
603 Some(UBig::from(0u64))
604 } else if size < 64 {
605 let mut direct_raw = [0u8; 8];
607 BitSlice::from_slice_mut(&mut direct_raw)[0..bits.len()].copy_from_bitslice(bits);
608 Some(UBig::from(u64::from_le_bytes(direct_raw)))
609 } else {
610 let wordsize = (size + 63) >> 6;
612 let mut bytes = vec![0u8; wordsize * 8];
613 BitSlice::from_slice_mut(&mut bytes).copy_from_bitslice(bits);
614 Some(UBig::from_le_bytes(&bytes))
615 }
616 }
617
618 pub fn next_bit(cursor: &mut usize, slice: &BitSlice<u8, Lsb0>) -> bool {
619 if (*slice).len() > *cursor {
620 let res = slice[*cursor];
621 *cursor += 1;
622 res
623 } else {
624 false
625 }
626 }
627
628 let mut backref_map = BTreeMap::<u64, *mut Noun>::new();
629 let mut result = atom(0);
630 let mut cursor = 0;
631
632 let mut cue_stack = vec![];
633
634 cue_stack.push(CueStackEntry::DestinationPointer(&mut result as *mut Noun));
635
636 while let Some(stack_entry) = cue_stack.pop() {
637 unsafe {
638 match stack_entry {
640 CueStackEntry::DestinationPointer(dest_ptr) => {
641 if next_bit(&mut cursor, buffer) {
643 if next_bit(&mut cursor, buffer) {
645 let backref = rub_backref(&mut cursor, buffer)?;
646 *dest_ptr = (**backref_map.get(&backref)?).clone();
647 } else {
648 let mut head = Box::new(atom(0));
650 let head_ptr = (&mut *head) as *mut _;
651 let mut tail = Box::new(atom(0));
652 let tail_ptr = (&mut *tail) as *mut _;
653 *dest_ptr = Noun::Cell(head, tail);
654 let backref = (cursor - 2) as u64;
655 backref_map.insert(backref, dest_ptr);
656 cue_stack.push(CueStackEntry::BackRef(cursor as u64 - 2, dest_ptr));
657 cue_stack.push(CueStackEntry::DestinationPointer(tail_ptr));
658 cue_stack.push(CueStackEntry::DestinationPointer(head_ptr));
659 }
660 } else {
661 let backref: u64 = (cursor - 1) as u64;
663 *dest_ptr = Noun::Atom(rub_atom(&mut cursor, buffer)?);
664 backref_map.insert(backref, dest_ptr);
665 }
666 }
667 CueStackEntry::BackRef(backref, noun_ptr) => {
668 backref_map.insert(backref, noun_ptr);
669 }
670 }
671 }
672 }
673
674 Some(result)
675}