sapling_crypto/note/
commitment.rs

1use core::iter;
2
3use bitvec::{array::BitArray, order::Lsb0};
4use group::ff::PrimeField;
5use subtle::{ConstantTimeEq, CtOption};
6
7use crate::{
8    pedersen_hash::Personalization,
9    spec::{extract_p, windowed_pedersen_commit},
10    value::NoteValue,
11};
12
13/// The trapdoor for a Sapling note commitment.
14#[derive(Clone, Debug)]
15pub(crate) struct NoteCommitTrapdoor(pub(super) jubjub::Fr);
16
17/// A commitment to a note.
18#[derive(Clone, Debug)]
19pub struct NoteCommitment(jubjub::SubgroupPoint);
20
21impl NoteCommitment {
22    pub(crate) fn inner(&self) -> jubjub::SubgroupPoint {
23        self.0
24    }
25}
26
27impl NoteCommitment {
28    /// Derives a Sapling note commitment.
29    #[cfg(feature = "temporary-zcashd")]
30    pub fn temporary_zcashd_derive(
31        g_d: [u8; 32],
32        pk_d: [u8; 32],
33        v: NoteValue,
34        rcm: jubjub::Fr,
35    ) -> Self {
36        Self::derive(g_d, pk_d, v, NoteCommitTrapdoor(rcm))
37    }
38
39    /// $NoteCommit^Sapling$.
40    ///
41    /// Defined in [Zcash Protocol Spec ยง 5.4.8.2: Windowed Pedersen commitments][concretewindowedcommit].
42    ///
43    /// [concretewindowedcommit]: https://zips.z.cash/protocol/protocol.pdf#concretewindowedcommit
44    pub(super) fn derive(
45        g_d: [u8; 32],
46        pk_d: [u8; 32],
47        v: NoteValue,
48        rcm: NoteCommitTrapdoor,
49    ) -> Self {
50        NoteCommitment(windowed_pedersen_commit(
51            Personalization::NoteCommitment,
52            iter::empty()
53                .chain(v.to_le_bits().iter().by_vals())
54                .chain(BitArray::<_, Lsb0>::new(g_d).iter().by_vals())
55                .chain(BitArray::<_, Lsb0>::new(pk_d).iter().by_vals()),
56            rcm.0,
57        ))
58    }
59}
60
61/// The u-coordinate of the commitment to a note.
62#[derive(Copy, Clone, Debug)]
63pub struct ExtractedNoteCommitment(pub(super) bls12_381::Scalar);
64
65impl ExtractedNoteCommitment {
66    /// Deserialize the extracted note commitment from a byte array.
67    ///
68    /// This method enforces the [consensus rule][cmucanon] that the byte representation
69    /// of cmu MUST be canonical.
70    ///
71    /// [cmucanon]: https://zips.z.cash/protocol/protocol.pdf#outputencodingandconsensus
72    pub fn from_bytes(bytes: &[u8; 32]) -> CtOption<Self> {
73        bls12_381::Scalar::from_repr(*bytes).map(ExtractedNoteCommitment)
74    }
75
76    /// Serialize the value commitment to its canonical byte representation.
77    pub fn to_bytes(self) -> [u8; 32] {
78        self.0.to_repr()
79    }
80
81    pub(crate) fn inner(&self) -> jubjub::Base {
82        self.0
83    }
84}
85
86impl From<NoteCommitment> for ExtractedNoteCommitment {
87    fn from(cm: NoteCommitment) -> Self {
88        ExtractedNoteCommitment(extract_p(&cm.0))
89    }
90}
91
92impl From<&ExtractedNoteCommitment> for [u8; 32] {
93    fn from(cmu: &ExtractedNoteCommitment) -> Self {
94        cmu.to_bytes()
95    }
96}
97
98impl ConstantTimeEq for ExtractedNoteCommitment {
99    fn ct_eq(&self, other: &Self) -> subtle::Choice {
100        self.0.ct_eq(&other.0)
101    }
102}
103
104impl PartialEq for ExtractedNoteCommitment {
105    fn eq(&self, other: &Self) -> bool {
106        self.ct_eq(other).into()
107    }
108}
109
110impl Eq for ExtractedNoteCommitment {}