use std::iter; use bitvec::{array::BitArray, order::Lsb0}; use ff::PrimeFieldBits; use pasta_curves::{arithmetic::FieldExt, pallas}; use subtle::CtOption; use crate::{constants::L_ORCHARD_BASE, primitives::sinsemilla, spec::extract_p, value::NoteValue}; pub(super) struct NoteCommitTrapdoor(pub(super) pallas::Scalar); /// A commitment to a note. #[derive(Debug)] pub struct NoteCommitment(pub(super) pallas::Point); impl NoteCommitment { /// $NoteCommit^Orchard$. /// /// Defined in [Zcash Protocol Spec ยง 5.4.8.4: Sinsemilla commitments][concretesinsemillacommit]. /// /// [concretesinsemillacommit]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit pub(super) fn derive( g_d: [u8; 32], pk_d: [u8; 32], v: NoteValue, rho: pallas::Base, psi: pallas::Base, rcm: NoteCommitTrapdoor, ) -> CtOption { let domain = sinsemilla::CommitDomain::new("z.cash:Orchard-NoteCommit"); domain .commit( iter::empty() .chain(BitArray::::new(g_d).iter().by_val()) .chain(BitArray::::new(pk_d).iter().by_val()) .chain(v.to_le_bits().iter().by_val()) .chain(rho.to_le_bits().iter().by_val().take(L_ORCHARD_BASE)) .chain(psi.to_le_bits().iter().by_val().take(L_ORCHARD_BASE)), &rcm.0, ) .map(NoteCommitment) } } /// The x-coordinate of the commitment to a note. #[derive(Clone, Debug)] pub struct ExtractedNoteCommitment(pub(super) pallas::Base); impl ExtractedNoteCommitment { /// Deserialize the extracted note commitment from a byte array. pub fn from_bytes(bytes: &[u8; 32]) -> CtOption { pallas::Base::from_bytes(bytes).map(ExtractedNoteCommitment) } /// Serialize the value commitment to its canonical byte representation. pub fn to_bytes(&self) -> [u8; 32] { self.0.to_bytes() } } impl From for ExtractedNoteCommitment { fn from(cm: NoteCommitment) -> Self { ExtractedNoteCommitment(extract_p(&cm.0)) } } impl std::ops::Deref for ExtractedNoteCommitment { type Target = pallas::Base; fn deref(&self) -> &pallas::Base { &self.0 } }