use alloc::string::String;
use core::fmt::{Debug, Display, Formatter};
use super::{
ByteReader, ByteWriter, Deserializable, DeserializationError, Digest, Felt, Hasher,
NoteDetails, Serializable, Word, WORD_SIZE, ZERO,
};
use crate::utils::{hex_to_bytes, HexParseError};
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct Nullifier(Digest);
impl Nullifier {
pub fn new(
script_hash: Digest,
inputs_hash: Digest,
asset_hash: Digest,
serial_num: Word,
) -> Self {
let mut elements = [ZERO; 4 * WORD_SIZE];
elements[..4].copy_from_slice(&serial_num);
elements[4..8].copy_from_slice(script_hash.as_elements());
elements[8..12].copy_from_slice(inputs_hash.as_elements());
elements[12..].copy_from_slice(asset_hash.as_elements());
Self(Hasher::hash_elements(&elements))
}
pub fn as_elements(&self) -> &[Felt] {
self.0.as_elements()
}
pub fn most_significant_felt(&self) -> Felt {
self.as_elements()[3]
}
pub fn inner(&self) -> Digest {
self.0
}
pub fn from_hex(hex_value: &str) -> Result<Self, HexParseError> {
hex_to_bytes(hex_value).and_then(|bytes: [u8; 32]| {
let digest = Digest::try_from(bytes)?;
Ok(digest.into())
})
}
pub fn to_hex(&self) -> String {
self.0.to_hex()
}
}
impl Display for Nullifier {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.write_str(&self.to_hex())
}
}
impl Debug for Nullifier {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
Display::fmt(self, f)
}
}
impl From<&NoteDetails> for Nullifier {
fn from(note: &NoteDetails) -> Self {
Self::new(
note.script().hash(),
note.inputs().commitment(),
note.assets().commitment(),
note.serial_num(),
)
}
}
impl From<Word> for Nullifier {
fn from(value: Word) -> Self {
Self(value.into())
}
}
impl From<Digest> for Nullifier {
fn from(value: Digest) -> Self {
Self(value)
}
}
impl From<Nullifier> for Word {
fn from(nullifier: Nullifier) -> Self {
nullifier.0.into()
}
}
impl From<Nullifier> for [u8; 32] {
fn from(nullifier: Nullifier) -> Self {
nullifier.0.into()
}
}
impl From<&Nullifier> for Word {
fn from(nullifier: &Nullifier) -> Self {
nullifier.0.into()
}
}
impl From<&Nullifier> for [u8; 32] {
fn from(nullifier: &Nullifier) -> Self {
nullifier.0.into()
}
}
impl Serializable for Nullifier {
fn write_into<W: ByteWriter>(&self, target: &mut W) {
target.write_bytes(&self.0.to_bytes());
}
}
impl Deserializable for Nullifier {
fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
let nullifier = Digest::read_from(source)?;
Ok(Self(nullifier))
}
}
#[cfg(test)]
mod tests {
use crate::notes::Nullifier;
#[test]
fn test_from_hex_and_back() {
let nullifier_hex = "0x41e7dbbc8ce63ec25cf2d76d76162f16ef8fd1195288171f5e5a3e178222f6d2";
let nullifier = Nullifier::from_hex(nullifier_hex).unwrap();
assert_eq!(nullifier_hex, nullifier.to_hex());
}
}