miden_protocol/note/
nullifier.rs1use alloc::string::String;
2use core::fmt::{Debug, Display, Formatter};
3
4use miden_core::WORD_SIZE;
5use miden_crypto::WordError;
6use miden_crypto_derive::WordWrapper;
7
8use super::{
9 ByteReader,
10 ByteWriter,
11 Deserializable,
12 DeserializationError,
13 Felt,
14 Hasher,
15 Serializable,
16 Word,
17 ZERO,
18};
19use crate::note::{NoteDetails, NoteMetadata, NoteScriptRoot};
20
21const NULLIFIER_PREFIX_SHIFT: u8 = 48;
25
26#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, WordWrapper)]
42pub struct Nullifier(Word);
43
44impl Nullifier {
45 pub fn new(
47 script_root: NoteScriptRoot,
48 storage_commitment: Word,
49 asset_commitment: Word,
50 serial_num: Word,
51 metadata_word: Word,
52 attachments_commitment: Word,
53 ) -> Self {
54 let mut elements = [ZERO; 6 * WORD_SIZE];
55 elements[..4].copy_from_slice(serial_num.as_elements());
56 elements[4..8].copy_from_slice(script_root.as_elements());
57 elements[8..12].copy_from_slice(storage_commitment.as_elements());
58 elements[12..16].copy_from_slice(asset_commitment.as_elements());
59 elements[16..20].copy_from_slice(metadata_word.as_elements());
60 elements[20..24].copy_from_slice(attachments_commitment.as_elements());
61 Self(Hasher::hash_elements(&elements))
62 }
63
64 pub fn from_details_and_metadata(details: &NoteDetails, metadata: &NoteMetadata) -> Self {
66 Self::new(
67 details.script().root(),
68 details.storage().commitment(),
69 details.assets().commitment(),
70 details.serial_num(),
71 metadata.to_metadata_word(),
72 metadata.attachments_commitment(),
73 )
74 }
75
76 pub fn most_significant_felt(&self) -> Felt {
78 self.as_elements()[3]
79 }
80
81 pub fn prefix(&self) -> u16 {
85 (self.as_word()[3].as_canonical_u64() >> NULLIFIER_PREFIX_SHIFT) as u16
86 }
87
88 pub fn from_hex(hex_value: &str) -> Result<Self, WordError> {
93 Word::try_from(hex_value).map(Self::from_raw)
94 }
95
96 #[cfg(any(feature = "testing", test))]
97 pub fn dummy(n: u64) -> Self {
98 Self(Word::new([Felt::ZERO, Felt::ZERO, Felt::ZERO, Felt::new_unchecked(n)]))
99 }
100}
101
102impl Display for Nullifier {
103 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
104 f.write_str(&self.to_hex())
105 }
106}
107
108impl Debug for Nullifier {
109 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
110 Display::fmt(self, f)
111 }
112}
113
114impl Serializable for Nullifier {
118 fn write_into<W: ByteWriter>(&self, target: &mut W) {
119 target.write_bytes(&self.0.to_bytes());
120 }
121
122 fn get_size_hint(&self) -> usize {
123 Word::SERIALIZED_SIZE
124 }
125}
126
127impl Deserializable for Nullifier {
128 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
129 let nullifier = Word::read_from(source)?;
130 Ok(Self(nullifier))
131 }
132}
133
134#[cfg(test)]
138mod tests {
139 use crate::note::Nullifier;
140
141 #[test]
142 fn test_from_hex_and_back() {
143 let nullifier_hex = "0x41e7dbbc8ce63ec25cf2d76d76162f16ef8fd1195288171f5e5a3e178222f6d2";
144 let nullifier = Nullifier::from_hex(nullifier_hex).unwrap();
145
146 assert_eq!(nullifier_hex, nullifier.to_hex());
147 }
148}