sapling_crypto/note/
nullifier.rs

1use alloc::fmt;
2use alloc::vec::Vec;
3use core::array::TryFromSliceError;
4
5use subtle::{Choice, ConstantTimeEq};
6
7use super::NoteCommitment;
8use crate::{
9    keys::NullifierDerivingKey,
10    spec::{mixing_pedersen_hash, prf_nf},
11};
12
13/// Typesafe wrapper for nullifier values.
14#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
15pub struct Nullifier(pub [u8; 32]);
16
17impl fmt::Debug for Nullifier {
18    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19        f.debug_tuple("Nullifier")
20            .field(&hex::encode(self.0))
21            .finish()
22    }
23}
24
25impl Nullifier {
26    pub fn from_slice(bytes: &[u8]) -> Result<Nullifier, TryFromSliceError> {
27        bytes.try_into().map(Nullifier)
28    }
29
30    pub fn to_vec(&self) -> Vec<u8> {
31        self.0.to_vec()
32    }
33
34    /// $DeriveNullifier$.
35    ///
36    /// Defined in [Zcash Protocol Spec ยง 4.16: Note Commitments and Nullifiers][commitmentsandnullifiers].
37    ///
38    /// [commitmentsandnullifiers]: https://zips.z.cash/protocol/protocol.pdf#commitmentsandnullifiers
39    pub(super) fn derive(nk: &NullifierDerivingKey, cm: NoteCommitment, position: u64) -> Self {
40        let rho = mixing_pedersen_hash(cm.inner(), position);
41        Nullifier(prf_nf(&nk.0, &rho))
42    }
43}
44
45impl AsRef<[u8]> for Nullifier {
46    fn as_ref(&self) -> &[u8] {
47        &self.0
48    }
49}
50
51impl ConstantTimeEq for Nullifier {
52    fn ct_eq(&self, other: &Self) -> Choice {
53        self.0.ct_eq(&other.0)
54    }
55}