Ensure that Notes always have valid commitments

Implements the change from spec version 2021.1.23 to sample a new rseed
if a note is generated without a valid commitment.
This commit is contained in:
Jack Grigg 2021-05-11 18:39:24 +08:00
parent d8cc596bbe
commit 736de1156b
5 changed files with 35 additions and 17 deletions

View File

@ -13,7 +13,7 @@ use crate::{
/// let sk = SpendingKey::from_bytes([7; 32]).unwrap(); /// let sk = SpendingKey::from_bytes([7; 32]).unwrap();
/// let address = FullViewingKey::from(&sk).default_address(); /// let address = FullViewingKey::from(&sk).default_address();
/// ``` /// ```
#[derive(Debug, Clone)] #[derive(Clone, Copy, Debug)]
pub struct Address { pub struct Address {
d: Diversifier, d: Diversifier,
pk_d: DiversifiedTransmissionKey, pk_d: DiversifiedTransmissionKey,

View File

@ -288,7 +288,7 @@ impl DiversifierKey {
/// Defined in [Zcash Protocol Spec § 4.2.3: Orchard Key Components][orchardkeycomponents]. /// Defined in [Zcash Protocol Spec § 4.2.3: Orchard Key Components][orchardkeycomponents].
/// ///
/// [orchardkeycomponents]: https://zips.z.cash/protocol/nu5.pdf#orchardkeycomponents /// [orchardkeycomponents]: https://zips.z.cash/protocol/nu5.pdf#orchardkeycomponents
#[derive(Debug, Clone)] #[derive(Clone, Copy, Debug)]
pub struct Diversifier([u8; 11]); pub struct Diversifier([u8; 11]);
impl Diversifier { impl Diversifier {
@ -408,7 +408,7 @@ impl From<&FullViewingKey> for OutgoingViewingKey {
/// Defined in [Zcash Protocol Spec § 4.2.3: Orchard Key Components][orchardkeycomponents]. /// Defined in [Zcash Protocol Spec § 4.2.3: Orchard Key Components][orchardkeycomponents].
/// ///
/// [orchardkeycomponents]: https://zips.z.cash/protocol/nu5.pdf#orchardkeycomponents /// [orchardkeycomponents]: https://zips.z.cash/protocol/nu5.pdf#orchardkeycomponents
#[derive(Debug, Clone)] #[derive(Clone, Copy, Debug)]
pub(crate) struct DiversifiedTransmissionKey(NonIdentityPallasPoint); pub(crate) struct DiversifiedTransmissionKey(NonIdentityPallasPoint);
impl DiversifiedTransmissionKey { impl DiversifiedTransmissionKey {

View File

@ -2,6 +2,7 @@
use group::GroupEncoding; use group::GroupEncoding;
use pasta_curves::pallas; use pasta_curves::pallas;
use rand::RngCore; use rand::RngCore;
use subtle::CtOption;
use crate::{ use crate::{
keys::{FullViewingKey, SpendingKey}, keys::{FullViewingKey, SpendingKey},
@ -72,11 +73,16 @@ impl Note {
rho: Nullifier, rho: Nullifier,
mut rng: impl RngCore, mut rng: impl RngCore,
) -> Self { ) -> Self {
Note { loop {
recipient, let note = Note {
value, recipient,
rho, value,
rseed: RandomSeed::random(&mut rng), rho,
rseed: RandomSeed::random(&mut rng),
};
if note.commitment_inner().is_some().into() {
break note;
}
} }
} }
@ -93,12 +99,12 @@ impl Note {
let fvk: FullViewingKey = (&sk).into(); let fvk: FullViewingKey = (&sk).into();
let recipient = fvk.default_address(); let recipient = fvk.default_address();
let note = Note { let note = Note::new(
recipient, recipient,
value: NoteValue::zero(), NoteValue::zero(),
rho: rho.unwrap_or_else(|| Nullifier::dummy(rng)), rho.unwrap_or_else(|| Nullifier::dummy(rng)),
rseed: RandomSeed::random(rng), rng,
}; );
(sk, fvk, note) (sk, fvk, note)
} }
@ -114,9 +120,22 @@ impl Note {
/// ///
/// [notes]: https://zips.z.cash/protocol/nu5.pdf#notes /// [notes]: https://zips.z.cash/protocol/nu5.pdf#notes
pub fn commitment(&self) -> NoteCommitment { pub fn commitment(&self) -> NoteCommitment {
// `Note` will always have a note commitment by construction.
self.commitment_inner().unwrap()
}
/// Derives the commitment to this note.
///
/// This is the internal fallible API, used to check at construction time that the
/// note has a commitment. Once you have a [`Note`] object, use `note.commitment()`
/// instead.
///
/// Defined in [Zcash Protocol Spec § 3.2: Notes][notes].
///
/// [notes]: https://zips.z.cash/protocol/nu5.pdf#notes
fn commitment_inner(&self) -> CtOption<NoteCommitment> {
let g_d = self.recipient.g_d(); let g_d = self.recipient.g_d();
// `Note` will always have a note commitment by construction.
NoteCommitment::derive( NoteCommitment::derive(
g_d.to_bytes(), g_d.to_bytes(),
self.recipient.pk_d().to_bytes(), self.recipient.pk_d().to_bytes(),
@ -125,7 +144,6 @@ impl Note {
self.rseed.psi(), self.rseed.psi(),
(&self.rseed).into(), (&self.rseed).into(),
) )
.unwrap()
} }
/// Derives the nullifier for this note. /// Derives the nullifier for this note.

View File

@ -11,7 +11,7 @@ use crate::{
}; };
/// A unique nullifier for a note. /// A unique nullifier for a note.
#[derive(Clone, Debug)] #[derive(Clone, Copy, Debug)]
pub struct Nullifier(pub(crate) pallas::Base); pub struct Nullifier(pub(crate) pallas::Base);
impl Nullifier { impl Nullifier {

View File

@ -18,7 +18,7 @@ use crate::{
const PRF_EXPAND_PERSONALIZATION: &[u8; 16] = b"Zcash_ExpandSeed"; const PRF_EXPAND_PERSONALIZATION: &[u8; 16] = b"Zcash_ExpandSeed";
/// A Pallas point that is guaranteed to not be the identity. /// A Pallas point that is guaranteed to not be the identity.
#[derive(Clone, Debug)] #[derive(Clone, Copy, Debug)]
pub(crate) struct NonIdentityPallasPoint(pallas::Point); pub(crate) struct NonIdentityPallasPoint(pallas::Point);
impl Deref for NonIdentityPallasPoint { impl Deref for NonIdentityPallasPoint {