mirror of https://github.com/zcash/orchard.git
Merge pull request #344 from zingolabs/publicize_note_and_diversifier_construction
Publicize necessary functionality for creating diversifiers and notes from data
This commit is contained in:
commit
b81d0d1198
|
@ -6,6 +6,12 @@ and this project adheres to Rust's notion of
|
||||||
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
### Added
|
||||||
|
- `orchard::address::Address::diversifier`
|
||||||
|
- `orchard::keys::Diversifier::from_bytes`
|
||||||
|
- `orchard::note`:
|
||||||
|
- `RandomSeed`
|
||||||
|
- `Note::{from_parts, rseed}`
|
||||||
|
|
||||||
## [0.2.0] - 2022-06-24
|
## [0.2.0] - 2022-06-24
|
||||||
### Added
|
### Added
|
||||||
|
|
|
@ -30,7 +30,8 @@ impl Address {
|
||||||
Address { d, pk_d }
|
Address { d, pk_d }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn diversifier(&self) -> Diversifier {
|
/// Returns the [`Diversifier`] for this `Address`.
|
||||||
|
pub fn diversifier(&self) -> Diversifier {
|
||||||
self.d
|
self.d
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -552,7 +552,8 @@ impl DiversifierKey {
|
||||||
pub struct Diversifier([u8; 11]);
|
pub struct Diversifier([u8; 11]);
|
||||||
|
|
||||||
impl Diversifier {
|
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)
|
Diversifier(d)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1049,7 +1050,8 @@ mod tests {
|
||||||
NoteValue::from_raw(tv.note_v),
|
NoteValue::from_raw(tv.note_v),
|
||||||
rho,
|
rho,
|
||||||
RandomSeed::from_bytes(tv.note_rseed, &rho).unwrap(),
|
RandomSeed::from_bytes(tv.note_rseed, &rho).unwrap(),
|
||||||
);
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let cmx: ExtractedNoteCommitment = note.commitment().into();
|
let cmx: ExtractedNoteCommitment = note.commitment().into();
|
||||||
assert_eq!(cmx.to_bytes(), tv.note_cmx);
|
assert_eq!(cmx.to_bytes(), tv.note_cmx);
|
||||||
|
|
46
src/note.rs
46
src/note.rs
|
@ -21,7 +21,7 @@ pub use self::nullifier::Nullifier;
|
||||||
|
|
||||||
/// The ZIP 212 seed randomness for a note.
|
/// The ZIP 212 seed randomness for a note.
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub(crate) struct RandomSeed([u8; 32]);
|
pub struct RandomSeed([u8; 32]);
|
||||||
|
|
||||||
impl RandomSeed {
|
impl RandomSeed {
|
||||||
pub(crate) fn random(rng: &mut impl RngCore, rho: &Nullifier) -> Self {
|
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<Self> {
|
/// 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<Self> {
|
||||||
let rseed = RandomSeed(rseed);
|
let rseed = RandomSeed(rseed);
|
||||||
let esk = rseed.esk_inner(rho);
|
let esk = rseed.esk_inner(rho);
|
||||||
CtOption::new(rseed, esk.is_some())
|
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
|
&self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,18 +112,33 @@ impl PartialEq for Note {
|
||||||
impl Eq for Note {}
|
impl Eq for Note {}
|
||||||
|
|
||||||
impl 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,
|
recipient: Address,
|
||||||
value: NoteValue,
|
value: NoteValue,
|
||||||
rho: Nullifier,
|
rho: Nullifier,
|
||||||
rseed: RandomSeed,
|
rseed: RandomSeed,
|
||||||
) -> Self {
|
) -> CtOption<Self> {
|
||||||
Note {
|
let note = Note {
|
||||||
recipient,
|
recipient,
|
||||||
value,
|
value,
|
||||||
rho,
|
rho,
|
||||||
rseed,
|
rseed,
|
||||||
}
|
};
|
||||||
|
CtOption::new(note, note.commitment_inner().is_some())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates a new note.
|
/// Generates a new note.
|
||||||
|
@ -134,14 +153,9 @@ impl Note {
|
||||||
mut rng: impl RngCore,
|
mut rng: impl RngCore,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
loop {
|
loop {
|
||||||
let note = Note {
|
let note = Note::from_parts(recipient, value, rho, RandomSeed::random(&mut rng, &rho));
|
||||||
recipient,
|
if note.is_some().into() {
|
||||||
value,
|
break note.unwrap();
|
||||||
rho,
|
|
||||||
rseed: RandomSeed::random(&mut rng, &rho),
|
|
||||||
};
|
|
||||||
if note.commitment_inner().is_some().into() {
|
|
||||||
break note;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -180,7 +194,7 @@ impl Note {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the rseed value of this note.
|
/// Returns the rseed value of this note.
|
||||||
pub(crate) fn rseed(&self) -> &RandomSeed {
|
pub fn rseed(&self) -> &RandomSeed {
|
||||||
&self.rseed
|
&self.rseed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,7 @@ where
|
||||||
let pk_d = get_validated_pk_d(&diversifier)?;
|
let pk_d = get_validated_pk_d(&diversifier)?;
|
||||||
|
|
||||||
let recipient = Address::from_parts(diversifier, pk_d);
|
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))
|
Some((note, recipient))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -401,7 +401,7 @@ mod tests {
|
||||||
assert_eq!(ock.as_ref(), tv.ock);
|
assert_eq!(ock.as_ref(), tv.ock);
|
||||||
|
|
||||||
let recipient = Address::from_parts(d, pk_d);
|
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);
|
assert_eq!(ExtractedNoteCommitment::from(note.commitment()), cmx);
|
||||||
|
|
||||||
let action = Action::from_parts(
|
let action = Action::from_parts(
|
||||||
|
|
Loading…
Reference in New Issue