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