diff --git a/CHANGELOG.md b/CHANGELOG.md index 5077477b..7ae89ad8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to Rust's notion of [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added +- `orchard::address::Address::diversifier` +- `orchard::keys::Diversifier::from_bytes` +- `orchard::note`: + - `RandomSeed` + - `Note::{from_parts, rseed}` ## [0.2.0] - 2022-06-24 ### Added diff --git a/src/address.rs b/src/address.rs index 67804e11..6b643ad3 100644 --- a/src/address.rs +++ b/src/address.rs @@ -30,7 +30,8 @@ impl Address { Address { d, pk_d } } - pub(crate) fn diversifier(&self) -> Diversifier { + /// Returns the [`Diversifier`] for this `Address`. + pub fn diversifier(&self) -> Diversifier { self.d } diff --git a/src/keys.rs b/src/keys.rs index 0504dfa4..e277264d 100644 --- a/src/keys.rs +++ b/src/keys.rs @@ -552,7 +552,8 @@ impl DiversifierKey { pub struct Diversifier([u8; 11]); impl Diversifier { - pub(crate) fn from_bytes(d: [u8; 11]) -> Self { + /// Reads a diversifier from a byte array. + pub fn from_bytes(d: [u8; 11]) -> Self { Diversifier(d) } @@ -1049,7 +1050,8 @@ mod tests { NoteValue::from_raw(tv.note_v), rho, RandomSeed::from_bytes(tv.note_rseed, &rho).unwrap(), - ); + ) + .unwrap(); let cmx: ExtractedNoteCommitment = note.commitment().into(); assert_eq!(cmx.to_bytes(), tv.note_cmx); diff --git a/src/note.rs b/src/note.rs index 6bd3f778..522b137f 100644 --- a/src/note.rs +++ b/src/note.rs @@ -21,7 +21,7 @@ pub use self::nullifier::Nullifier; /// The ZIP 212 seed randomness for a note. #[derive(Copy, Clone, Debug)] -pub(crate) struct RandomSeed([u8; 32]); +pub struct RandomSeed([u8; 32]); impl RandomSeed { pub(crate) fn random(rng: &mut impl RngCore, rho: &Nullifier) -> Self { @@ -35,13 +35,17 @@ impl RandomSeed { } } - pub(crate) fn from_bytes(rseed: [u8; 32], rho: &Nullifier) -> CtOption { + /// Reads a note's random seed from bytes, given the note's nullifier. + /// + /// Returns `None` if the nullifier is not for the same note as the seed. + pub fn from_bytes(rseed: [u8; 32], rho: &Nullifier) -> CtOption { let rseed = RandomSeed(rseed); let esk = rseed.esk_inner(rho); CtOption::new(rseed, esk.is_some()) } - pub(crate) fn as_bytes(&self) -> &[u8; 32] { + /// Returns the byte array corresponding to this seed. + pub fn as_bytes(&self) -> &[u8; 32] { &self.0 } @@ -108,18 +112,33 @@ impl PartialEq for Note { impl Eq for Note {} impl Note { - pub(crate) fn from_parts( + /// Creates a `Note` from its component parts. + /// + /// Returns `None` if a valid [`NoteCommitment`] cannot be derived from the note. + /// + /// # Caveats + /// + /// This low-level constructor enforces that the provided arguments produce an + /// internally valid `Note`. However, it allows notes to be constructed in a way that + /// violates required security checks for note decryption, as specified in + /// [Section 4.19] of the Zcash Protocol Specification. Users of this constructor + /// should only call it with note components that have been fully validated by + /// decrypting a received note according to [Section 4.19]. + /// + /// [Section 4.19]: https://zips.z.cash/protocol/protocol.pdf#saplingandorchardinband + pub fn from_parts( recipient: Address, value: NoteValue, rho: Nullifier, rseed: RandomSeed, - ) -> Self { - Note { + ) -> CtOption { + let note = Note { recipient, value, rho, rseed, - } + }; + CtOption::new(note, note.commitment_inner().is_some()) } /// Generates a new note. @@ -134,14 +153,9 @@ impl Note { mut rng: impl RngCore, ) -> Self { loop { - let note = Note { - recipient, - value, - rho, - rseed: RandomSeed::random(&mut rng, &rho), - }; - if note.commitment_inner().is_some().into() { - break note; + let note = Note::from_parts(recipient, value, rho, RandomSeed::random(&mut rng, &rho)); + if note.is_some().into() { + break note.unwrap(); } } } @@ -180,7 +194,7 @@ impl Note { } /// Returns the rseed value of this note. - pub(crate) fn rseed(&self) -> &RandomSeed { + pub fn rseed(&self) -> &RandomSeed { &self.rseed } diff --git a/src/note_encryption.rs b/src/note_encryption.rs index c6572312..0b249eec 100644 --- a/src/note_encryption.rs +++ b/src/note_encryption.rs @@ -75,7 +75,7 @@ where let pk_d = get_validated_pk_d(&diversifier)?; let recipient = Address::from_parts(diversifier, pk_d); - let note = Note::from_parts(recipient, value, domain.rho, rseed); + let note = Option::from(Note::from_parts(recipient, value, domain.rho, rseed))?; Some((note, recipient)) } @@ -401,7 +401,7 @@ mod tests { assert_eq!(ock.as_ref(), tv.ock); let recipient = Address::from_parts(d, pk_d); - let note = Note::from_parts(recipient, value, rho, rseed); + let note = Note::from_parts(recipient, value, rho, rseed).unwrap(); assert_eq!(ExtractedNoteCommitment::from(note.commitment()), cmx); let action = Action::from_parts(