miden_objects/note/
nullifier.rs1use alloc::string::String;
2use core::fmt::{Debug, Display, Formatter};
3
4use miden_crypto::WordError;
5
6use super::{
7 ByteReader,
8 ByteWriter,
9 Deserializable,
10 DeserializationError,
11 Felt,
12 Hasher,
13 NoteDetails,
14 Serializable,
15 WORD_SIZE,
16 Word,
17 ZERO,
18};
19
20const NULLIFIER_PREFIX_SHIFT: u8 = 48;
24
25#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
40pub struct Nullifier(Word);
41
42impl Nullifier {
43 pub fn new(
45 script_root: Word,
46 inputs_commitment: Word,
47 asset_commitment: Word,
48 serial_num: Word,
49 ) -> Self {
50 let mut elements = [ZERO; 4 * WORD_SIZE];
51 elements[..4].copy_from_slice(serial_num.as_elements());
52 elements[4..8].copy_from_slice(script_root.as_elements());
53 elements[8..12].copy_from_slice(inputs_commitment.as_elements());
54 elements[12..].copy_from_slice(asset_commitment.as_elements());
55 Self(Hasher::hash_elements(&elements))
56 }
57
58 pub fn as_elements(&self) -> &[Felt] {
60 self.0.as_elements()
61 }
62
63 pub fn most_significant_felt(&self) -> Felt {
65 self.as_elements()[3]
66 }
67
68 pub fn as_word(&self) -> Word {
70 self.0
71 }
72
73 pub fn prefix(&self) -> u16 {
77 (self.as_word()[3].as_int() >> NULLIFIER_PREFIX_SHIFT) as u16
78 }
79
80 pub fn from_hex(hex_value: &str) -> Result<Self, WordError> {
83 Word::try_from(hex_value).map(Self::from)
84 }
85
86 pub fn to_hex(&self) -> String {
88 self.0.to_hex()
89 }
90
91 #[cfg(any(feature = "testing", test))]
92 pub fn dummy(n: u64) -> Self {
93 use miden_core::FieldElement;
94
95 Self(Word::new([Felt::ZERO, Felt::ZERO, Felt::ZERO, Felt::new(n)]))
96 }
97}
98
99impl Display for Nullifier {
100 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
101 f.write_str(&self.to_hex())
102 }
103}
104
105impl Debug for Nullifier {
106 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
107 Display::fmt(self, f)
108 }
109}
110
111impl From<&NoteDetails> for Nullifier {
115 fn from(note: &NoteDetails) -> Self {
116 Self::new(
117 note.script().root(),
118 note.inputs().commitment(),
119 note.assets().commitment(),
120 note.serial_num(),
121 )
122 }
123}
124
125impl From<Word> for Nullifier {
126 fn from(digest: Word) -> Self {
127 Self(digest)
128 }
129}
130
131impl From<Nullifier> for Word {
135 fn from(nullifier: Nullifier) -> Self {
136 nullifier.0
137 }
138}
139
140impl From<Nullifier> for [u8; 32] {
141 fn from(nullifier: Nullifier) -> Self {
142 nullifier.0.into()
143 }
144}
145
146impl From<&Nullifier> for Word {
147 fn from(nullifier: &Nullifier) -> Self {
148 nullifier.0
149 }
150}
151
152impl From<&Nullifier> for [u8; 32] {
153 fn from(nullifier: &Nullifier) -> Self {
154 nullifier.0.into()
155 }
156}
157
158impl Serializable for Nullifier {
162 fn write_into<W: ByteWriter>(&self, target: &mut W) {
163 target.write_bytes(&self.0.to_bytes());
164 }
165}
166
167impl Deserializable for Nullifier {
168 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
169 let nullifier = Word::read_from(source)?;
170 Ok(Self(nullifier))
171 }
172}
173
174#[cfg(test)]
178mod tests {
179 use crate::note::Nullifier;
180
181 #[test]
182 fn test_from_hex_and_back() {
183 let nullifier_hex = "0x41e7dbbc8ce63ec25cf2d76d76162f16ef8fd1195288171f5e5a3e178222f6d2";
184 let nullifier = Nullifier::from_hex(nullifier_hex).unwrap();
185
186 assert_eq!(nullifier_hex, nullifier.to_hex());
187 }
188}