1use crate::protocol::serialization::{deserialize_fr, serialize_fr};
2
3use ark_bn254::Fr;
4use ark_ff::{BigInteger, PrimeField};
5use serde::{Deserialize, Serialize};
6
7#[derive(Clone, Serialize, Deserialize, PartialEq)]
8pub struct Note {
9 #[serde(serialize_with = "serialize_fr", deserialize_with = "deserialize_fr")]
10 pub asset_id: Fr,
11 #[serde(serialize_with = "serialize_fr", deserialize_with = "deserialize_fr")]
12 pub value: Fr,
13 #[serde(serialize_with = "serialize_fr", deserialize_with = "deserialize_fr")]
14 pub secret: Fr,
15 #[serde(serialize_with = "serialize_fr", deserialize_with = "deserialize_fr")]
16 pub nullifier: Fr,
17 #[serde(serialize_with = "serialize_fr", deserialize_with = "deserialize_fr")]
18 pub timelock: Fr,
19 #[serde(serialize_with = "serialize_fr", deserialize_with = "deserialize_fr")]
20 pub hashlock: Fr,
21}
22
23impl std::fmt::Debug for Note {
24 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25 f.debug_struct("Note")
26 .field("asset_id", &self.asset_id)
27 .field("value", &self.value)
28 .field("secret", &"[REDACTED]")
29 .field("nullifier", &"[REDACTED]")
30 .field("timelock", &self.timelock)
31 .field("hashlock", &self.hashlock)
32 .finish()
33 }
34}
35
36impl Note {
37 #[must_use]
38 pub fn serialize_to_bytes(&self) -> Vec<u8> {
39 let mut bytes = Vec::with_capacity(192);
40 bytes.extend_from_slice(&self.asset_id.into_bigint().to_bytes_be());
41 bytes.extend_from_slice(&self.value.into_bigint().to_bytes_be());
42 bytes.extend_from_slice(&self.secret.into_bigint().to_bytes_be());
43 bytes.extend_from_slice(&self.nullifier.into_bigint().to_bytes_be());
44 bytes.extend_from_slice(&self.timelock.into_bigint().to_bytes_be());
45 bytes.extend_from_slice(&self.hashlock.into_bigint().to_bytes_be());
46 bytes
47 }
48
49 #[must_use]
51 pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
52 if bytes.len() != 192 {
53 return None;
54 }
55 Some(Self {
56 asset_id: Fr::from_be_bytes_mod_order(&bytes[0..32]),
57 value: Fr::from_be_bytes_mod_order(&bytes[32..64]),
58 secret: Fr::from_be_bytes_mod_order(&bytes[64..96]),
59 nullifier: Fr::from_be_bytes_mod_order(&bytes[96..128]),
60 timelock: Fr::from_be_bytes_mod_order(&bytes[128..160]),
61 hashlock: Fr::from_be_bytes_mod_order(&bytes[160..192]),
62 })
63 }
64}
65
66#[cfg(test)]
67mod tests {
68 use super::*;
69 use ark_ff::One;
70 use ark_std::Zero;
71
72 fn sample_note() -> Note {
73 Note {
74 asset_id: Fr::from(42u64),
75 value: Fr::from(1000u64),
76 secret: Fr::from(999u64),
77 nullifier: Fr::from(777u64),
78 timelock: Fr::zero(),
79 hashlock: Fr::zero(),
80 }
81 }
82
83 #[test]
84 fn roundtrip_serialize_deserialize() {
85 let note = sample_note();
86 let bytes = note.serialize_to_bytes();
87 assert_eq!(bytes.len(), 192);
88 let decoded = Note::from_bytes(&bytes).expect("should decode");
89 assert_eq!(note, decoded);
90 }
91
92 #[test]
93 fn from_bytes_wrong_length() {
94 assert!(Note::from_bytes(&[0u8; 191]).is_none());
95 assert!(Note::from_bytes(&[0u8; 193]).is_none());
96 assert!(Note::from_bytes(&[]).is_none());
97 }
98
99 #[test]
100 fn roundtrip_with_one_values() {
101 let note = Note {
102 asset_id: Fr::one(),
103 value: Fr::one(),
104 secret: Fr::one(),
105 nullifier: Fr::one(),
106 timelock: Fr::one(),
107 hashlock: Fr::one(),
108 };
109 let bytes = note.serialize_to_bytes();
110 let decoded = Note::from_bytes(&bytes).expect("should decode");
111 assert_eq!(note, decoded);
112 }
113
114 #[test]
115 fn roundtrip_with_zero_values() {
116 let note = Note {
117 asset_id: Fr::zero(),
118 value: Fr::zero(),
119 secret: Fr::zero(),
120 nullifier: Fr::zero(),
121 timelock: Fr::zero(),
122 hashlock: Fr::zero(),
123 };
124 let bytes = note.serialize_to_bytes();
125 let decoded = Note::from_bytes(&bytes).expect("should decode");
126 assert_eq!(note, decoded);
127 }
128}