orchard/src/note/commitment.rs

79 lines
2.4 KiB
Rust

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<Self> {
let domain = sinsemilla::CommitDomain::new("z.cash:Orchard-NoteCommit");
domain
.commit(
iter::empty()
.chain(BitArray::<Lsb0, _>::new(g_d).iter().by_val())
.chain(BitArray::<Lsb0, _>::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(Copy, Clone, Debug)]
pub struct ExtractedNoteCommitment(pub(super) pallas::Base);
impl ExtractedNoteCommitment {
/// ExtractedNoteCommitment for an uncommitted note.
pub fn uncommitted() -> Self {
Self(pallas::Base::zero())
}
/// Deserialize the extracted note commitment from a byte array.
pub fn from_bytes(bytes: &[u8; 32]) -> CtOption<Self> {
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<NoteCommitment> 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
}
}