orchard/src/note.rs

120 lines
3.3 KiB
Rust
Raw Normal View History

2021-03-12 16:04:13 -08:00
use group::GroupEncoding;
use pasta_curves::pallas;
2021-04-14 21:14:34 -07:00
use rand::RngCore;
2021-03-12 16:04:13 -08:00
use crate::{
2021-04-14 21:14:34 -07:00
keys::{FullViewingKey, SpendingKey},
2021-03-12 16:04:13 -08:00
spec::{prf_expand, to_base, to_scalar},
value::NoteValue,
Address,
};
mod commitment;
pub use self::commitment::{ExtractedNoteCommitment, NoteCommitment};
2021-01-20 12:09:09 -08:00
2021-03-15 18:27:08 -07:00
mod nullifier;
pub use self::nullifier::Nullifier;
2021-02-08 07:21:04 -08:00
/// The ZIP 212 seed randomness for a note.
#[derive(Debug)]
struct RandomSeed([u8; 32]);
impl RandomSeed {
2021-04-14 21:14:34 -07:00
pub(crate) fn random(rng: &mut impl RngCore) -> Self {
let mut bytes = [0; 32];
rng.fill_bytes(&mut bytes);
RandomSeed(bytes)
}
2021-03-12 16:04:13 -08:00
/// Defined in [Zcash Protocol Spec § 4.7.3: Sending Notes (Orchard)][orchardsend].
///
/// [orchardsend]: https://zips.z.cash/protocol/nu5.pdf#orchardsend
fn psi(&self) -> pallas::Base {
to_base(prf_expand(&self.0, &[0x09]))
2021-02-08 07:21:04 -08:00
}
2021-03-12 16:04:13 -08:00
/// Defined in [Zcash Protocol Spec § 4.7.3: Sending Notes (Orchard)][orchardsend].
///
/// [orchardsend]: https://zips.z.cash/protocol/nu5.pdf#orchardsend
fn esk(&self) -> pallas::Scalar {
to_scalar(prf_expand(&self.0, &[0x04]))
2021-02-08 07:21:04 -08:00
}
}
2021-01-20 12:09:09 -08:00
/// A discrete amount of funds received by an address.
#[derive(Debug)]
pub struct Note {
2021-01-20 12:09:09 -08:00
/// The recipient of the funds.
recipient: Address,
2021-01-20 12:09:09 -08:00
/// The value of this note.
value: NoteValue,
2021-02-08 07:21:04 -08:00
/// A unique creation ID for this note.
///
/// This is set to the nullifier of the note that was spent in the [`Action`] that
/// created this note.
///
/// [`Action`]: crate::bundle::Action
rho: Nullifier,
/// The seed randomness for various note components.
rseed: RandomSeed,
2021-01-20 12:09:09 -08:00
}
impl Note {
2021-04-14 21:14:34 -07:00
/// Generates a dummy spent note.
///
/// Defined in [Zcash Protocol Spec § 4.8.3: Dummy Notes (Orchard)][orcharddummynotes].
///
/// [orcharddummynotes]: https://zips.z.cash/protocol/nu5.pdf#orcharddummynotes
pub(crate) fn dummy(
rng: &mut impl RngCore,
rho: Option<Nullifier>,
) -> (SpendingKey, FullViewingKey, Self) {
let sk = SpendingKey::random(rng);
let fvk: FullViewingKey = (&sk).into();
2021-04-14 21:14:34 -07:00
let recipient = fvk.default_address();
let note = Note {
recipient,
value: NoteValue::zero(),
2021-04-14 21:14:34 -07:00
rho: rho.unwrap_or_else(|| Nullifier::dummy(rng)),
rseed: RandomSeed::random(rng),
};
(sk, fvk, note)
2021-04-14 21:14:34 -07:00
}
2021-04-14 21:34:51 -07:00
/// Returns the value of this note.
pub fn value(&self) -> NoteValue {
self.value
}
2021-01-20 12:09:09 -08:00
/// Derives the commitment to this note.
2021-03-12 16:04:13 -08:00
///
/// Defined in [Zcash Protocol Spec § 3.2: Notes][notes].
///
/// [notes]: https://zips.z.cash/protocol/nu5.pdf#notes
2021-01-20 12:09:09 -08:00
pub fn commitment(&self) -> NoteCommitment {
2021-03-12 16:04:13 -08:00
let g_d = self.recipient.g_d();
// `Note` will always have a note commitment by construction.
2021-03-12 16:04:13 -08:00
NoteCommitment::derive(
g_d.to_bytes(),
self.recipient.pk_d().to_bytes(),
self.value,
self.rho.0,
self.rseed.psi(),
(&self.rseed).into(),
)
.unwrap()
2021-01-20 12:09:09 -08:00
}
/// Derives the nullifier for this note.
2021-03-15 18:27:08 -07:00
pub fn nullifier(&self, fvk: &FullViewingKey) -> Nullifier {
Nullifier::derive(fvk.nk(), self.rho.0, self.rseed.psi(), self.commitment())
2021-01-20 12:09:09 -08:00
}
}
/// An encrypted note.
#[derive(Debug)]
pub struct EncryptedNote;