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;
|
2021-04-19 15:26:58 -07:00
|
|
|
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.
|
2021-04-14 21:14:34 -07:00
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub(crate) struct RandomSeed([u8; 32]);
|
2021-02-08 07:21:04 -08:00
|
|
|
|
|
|
|
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)]
|
2021-01-21 04:16:50 -08:00
|
|
|
pub struct Note {
|
2021-01-20 12:09:09 -08:00
|
|
|
/// The recipient of the funds.
|
2021-01-21 04:16:50 -08:00
|
|
|
recipient: Address,
|
2021-01-20 12:09:09 -08:00
|
|
|
/// The value of this note.
|
2021-01-21 04:16:50 -08:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2021-01-21 04:16:50 -08:00
|
|
|
impl Note {
|
2021-04-14 21:14:34 -07:00
|
|
|
/// Generates a new note.
|
|
|
|
///
|
|
|
|
/// Defined in [Zcash Protocol Spec § 4.7.3: Sending Notes (Orchard)][orchardsend].
|
|
|
|
///
|
|
|
|
/// [orchardsend]: https://zips.z.cash/protocol/nu5.pdf#orchardsend
|
|
|
|
pub(crate) fn new(
|
|
|
|
recipient: Address,
|
|
|
|
value: NoteValue,
|
|
|
|
rho: Nullifier,
|
|
|
|
mut rng: impl RngCore,
|
|
|
|
) -> Self {
|
|
|
|
Note {
|
|
|
|
recipient,
|
|
|
|
value,
|
|
|
|
rho,
|
|
|
|
rseed: RandomSeed::random(&mut rng),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
2021-04-26 17:25:03 -07:00
|
|
|
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,
|
2021-04-20 16:00:19 -07:00
|
|
|
value: NoteValue::zero(),
|
2021-04-14 21:14:34 -07:00
|
|
|
rho: rho.unwrap_or_else(|| Nullifier::dummy(rng)),
|
|
|
|
rseed: RandomSeed::random(rng),
|
|
|
|
};
|
|
|
|
|
2021-04-26 17:25:03 -07:00
|
|
|
(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();
|
|
|
|
|
2021-04-19 15:05:56 -07:00
|
|
|
// `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(),
|
|
|
|
)
|
2021-04-19 15:05:56 -07:00
|
|
|
.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 {
|
2021-03-29 17:52:20 -07:00
|
|
|
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)]
|
2021-04-21 08:57:48 -07:00
|
|
|
pub struct TransmittedNoteCiphertext {
|
|
|
|
/// The serialization of the ephemeral public key
|
|
|
|
pub epk_bytes: [u8; 32],
|
|
|
|
/// The encrypted note ciphertext
|
|
|
|
pub enc_ciphertext: [u8; 580],
|
|
|
|
/// An encrypted value that allows the holder of the outgoing cipher
|
|
|
|
/// key for the note to recover the note plaintext.
|
|
|
|
pub out_ciphertext: [u8; 80],
|
|
|
|
}
|