mirror of https://github.com/zcash/orchard.git
Expose constructors required for ZIP-225 parsing.
This commit is contained in:
parent
e8f65a2158
commit
e743198a50
|
@ -16,7 +16,7 @@ use crate::{
|
||||||
primitives::redpallas::{self, Binding, SpendAuth},
|
primitives::redpallas::{self, Binding, SpendAuth},
|
||||||
tree::{Anchor, MerklePath},
|
tree::{Anchor, MerklePath},
|
||||||
value::{self, NoteValue, ValueCommitTrapdoor, ValueCommitment, ValueSum},
|
value::{self, NoteValue, ValueCommitTrapdoor, ValueCommitment, ValueSum},
|
||||||
Address, EncryptedNote, Note,
|
Address, TransmittedNoteCiphertext, Note,
|
||||||
};
|
};
|
||||||
|
|
||||||
const MIN_ACTIONS: usize = 2;
|
const MIN_ACTIONS: usize = 2;
|
||||||
|
@ -137,7 +137,11 @@ impl ActionInfo {
|
||||||
let cm_new = note.commitment();
|
let cm_new = note.commitment();
|
||||||
|
|
||||||
// TODO: Note encryption
|
// TODO: Note encryption
|
||||||
let encrypted_note = EncryptedNote;
|
let encrypted_note = TransmittedNoteCiphertext {
|
||||||
|
epk_bytes: [0u8; 32],
|
||||||
|
enc_ciphertext: [0u8; 580],
|
||||||
|
out_ciphertext: [0u8; 80],
|
||||||
|
};
|
||||||
|
|
||||||
(
|
(
|
||||||
Action::from_parts(
|
Action::from_parts(
|
||||||
|
|
|
@ -4,7 +4,7 @@ use nonempty::NonEmpty;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
circuit::{Instance, Proof},
|
circuit::{Instance, Proof},
|
||||||
note::{EncryptedNote, ExtractedNoteCommitment, Nullifier},
|
note::{ExtractedNoteCommitment, Nullifier, TransmittedNoteCiphertext},
|
||||||
primitives::redpallas::{self, Binding, SpendAuth},
|
primitives::redpallas::{self, Binding, SpendAuth},
|
||||||
tree::Anchor,
|
tree::Anchor,
|
||||||
value::{ValueCommitment, ValueSum},
|
value::{ValueCommitment, ValueSum},
|
||||||
|
@ -19,19 +19,19 @@ use crate::{
|
||||||
/// Internally, this may both consume a note and create a note, or it may do only one of
|
/// Internally, this may both consume a note and create a note, or it may do only one of
|
||||||
/// the two. TODO: Determine which is more efficient (circuit size vs bundle size).
|
/// the two. TODO: Determine which is more efficient (circuit size vs bundle size).
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Action<T> {
|
pub struct Action<A> {
|
||||||
/// The nullifier of the note being spent.
|
/// The nullifier of the note being spent.
|
||||||
nf: Nullifier,
|
nf: Nullifier,
|
||||||
/// The randomized verification key for the note being spent.
|
/// The randomized verification key for the note being spent.
|
||||||
rk: redpallas::VerificationKey<SpendAuth>,
|
rk: redpallas::VerificationKey<SpendAuth>,
|
||||||
/// A commitment to the new note being created.
|
/// A commitment to the new note being created.
|
||||||
cmx: ExtractedNoteCommitment,
|
cmx: ExtractedNoteCommitment,
|
||||||
/// The encrypted output note.
|
/// The transmitted note ciphertext
|
||||||
encrypted_note: EncryptedNote,
|
encrypted_note: TransmittedNoteCiphertext,
|
||||||
/// A commitment to the net value created or consumed by this action.
|
/// A commitment to the net value created or consumed by this action.
|
||||||
cv_net: ValueCommitment,
|
cv_net: ValueCommitment,
|
||||||
/// The authorization for this action.
|
/// The authorization for this action.
|
||||||
authorization: T,
|
authorization: A,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Action<T> {
|
impl<T> Action<T> {
|
||||||
|
@ -40,7 +40,7 @@ impl<T> Action<T> {
|
||||||
nf: Nullifier,
|
nf: Nullifier,
|
||||||
rk: redpallas::VerificationKey<SpendAuth>,
|
rk: redpallas::VerificationKey<SpendAuth>,
|
||||||
cmx: ExtractedNoteCommitment,
|
cmx: ExtractedNoteCommitment,
|
||||||
encrypted_note: EncryptedNote,
|
encrypted_note: TransmittedNoteCiphertext,
|
||||||
cv_net: ValueCommitment,
|
cv_net: ValueCommitment,
|
||||||
authorization: T,
|
authorization: T,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
@ -70,7 +70,7 @@ impl<T> Action<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the encrypted note ciphertext.
|
/// Returns the encrypted note ciphertext.
|
||||||
pub fn encrypted_note(&self) -> &EncryptedNote {
|
pub fn encrypted_note(&self) -> &TransmittedNoteCiphertext {
|
||||||
&self.encrypted_note
|
&self.encrypted_note
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,6 +172,35 @@ pub trait Authorization {
|
||||||
type SpendAuth;
|
type SpendAuth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Marker for an unauthorized bundle with no proofs or signatures.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Unauthorized {}
|
||||||
|
|
||||||
|
impl Authorization for Unauthorized {
|
||||||
|
type SpendAuth = ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Authorizing data for a bundle of actions, ready to be committed to the ledger.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Authorized {
|
||||||
|
proof: Proof,
|
||||||
|
binding_signature: redpallas::Signature<Binding>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Authorized {
|
||||||
|
/// Construct a new value with authorizing data.
|
||||||
|
pub fn new(proof: Proof, binding_signature: redpallas::Signature<Binding>) -> Self {
|
||||||
|
Authorized {
|
||||||
|
proof,
|
||||||
|
binding_signature,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Authorization for Authorized {
|
||||||
|
type SpendAuth = redpallas::Signature<SpendAuth>;
|
||||||
|
}
|
||||||
|
|
||||||
/// A bundle of actions to be applied to the ledger.
|
/// A bundle of actions to be applied to the ledger.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Bundle<T: Authorization> {
|
pub struct Bundle<T: Authorization> {
|
||||||
|
@ -287,13 +316,56 @@ impl<T: Authorization> Bundle<T> {
|
||||||
|
|
||||||
/// Authorizing data for a bundle of actions, ready to be committed to the ledger.
|
/// Authorizing data for a bundle of actions, ready to be committed to the ledger.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Authorized {
|
pub struct BundleAuth {
|
||||||
proof: Proof,
|
/// The authorizing data for the actions in a bundle
|
||||||
binding_signature: redpallas::Signature<Binding>,
|
pub action_authorizations: NonEmpty<<Authorized as Authorization>::SpendAuth>,
|
||||||
|
/// The authorizing data that covers the bundle as a whole
|
||||||
|
pub authorization: Authorized,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Authorization for Authorized {
|
/// Errors that may be generated in the process of constructing bundle authorizing data.
|
||||||
type SpendAuth = redpallas::Signature<SpendAuth>;
|
#[derive(Debug)]
|
||||||
|
pub enum BundleAuthError<E> {
|
||||||
|
/// An error produced by the underlying computation of authorizing data for a bundle
|
||||||
|
Wrapped(E),
|
||||||
|
/// Authorizing data for the bundle could not be matched to bundle contents.
|
||||||
|
AuthLengthMismatch(usize, usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Bundle<Unauthorized> {
|
||||||
|
/// Compute the authorizing data for a bundle and apply it to the bundle, returning the
|
||||||
|
/// authorized result.
|
||||||
|
pub fn with_auth<E, F: FnOnce(&Self) -> Result<BundleAuth, E>>(
|
||||||
|
self,
|
||||||
|
f: F,
|
||||||
|
) -> Result<Bundle<Authorized>, BundleAuthError<E>> {
|
||||||
|
let auth = f(&self).map_err(BundleAuthError::Wrapped)?;
|
||||||
|
let actions_len = self.actions.len();
|
||||||
|
|
||||||
|
if actions_len != auth.action_authorizations.len() {
|
||||||
|
Err(BundleAuthError::AuthLengthMismatch(
|
||||||
|
actions_len,
|
||||||
|
auth.action_authorizations.len(),
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
let actions = NonEmpty::from_vec(
|
||||||
|
self.actions
|
||||||
|
.into_iter()
|
||||||
|
.zip(auth.action_authorizations.into_iter())
|
||||||
|
.map(|(act, a)| act.map(|_| a))
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
.ok_or(BundleAuthError::AuthLengthMismatch(actions_len, 0))?;
|
||||||
|
|
||||||
|
Ok(Bundle {
|
||||||
|
actions,
|
||||||
|
flags: self.flags,
|
||||||
|
value_balance: self.value_balance,
|
||||||
|
anchor: self.anchor,
|
||||||
|
authorization: auth.authorization,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Authorized {
|
impl Authorized {
|
||||||
|
|
|
@ -156,6 +156,11 @@ impl Proof {
|
||||||
Err(plonk::Error::ConstraintSystemFailure)
|
Err(plonk::Error::ConstraintSystemFailure)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Construct a new Proof value.
|
||||||
|
pub fn new(bytes: Vec<u8>) -> Self {
|
||||||
|
Proof(bytes)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -174,6 +179,7 @@ mod tests {
|
||||||
value::{ValueCommitTrapdoor, ValueCommitment},
|
value::{ValueCommitTrapdoor, ValueCommitment},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO: recast as a proptest
|
||||||
#[test]
|
#[test]
|
||||||
fn round_trip() {
|
fn round_trip() {
|
||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
|
|
|
@ -29,4 +29,9 @@ mod tree;
|
||||||
pub mod value;
|
pub mod value;
|
||||||
|
|
||||||
pub use address::Address;
|
pub use address::Address;
|
||||||
pub use note::{EncryptedNote, Note, NoteCommitment, Nullifier};
|
pub use bundle::{Action, Authorization, Authorized, Bundle, Unauthorized};
|
||||||
|
pub use circuit::Proof;
|
||||||
|
pub use note::{
|
||||||
|
ExtractedNoteCommitment, Note, NoteCommitment, Nullifier, TransmittedNoteCiphertext,
|
||||||
|
};
|
||||||
|
pub use tree::Anchor;
|
||||||
|
|
10
src/note.rs
10
src/note.rs
|
@ -135,4 +135,12 @@ impl Note {
|
||||||
|
|
||||||
/// An encrypted note.
|
/// An encrypted note.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct EncryptedNote;
|
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],
|
||||||
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std::iter;
|
||||||
|
|
||||||
use bitvec::{array::BitArray, order::Lsb0};
|
use bitvec::{array::BitArray, order::Lsb0};
|
||||||
use ff::PrimeField;
|
use ff::PrimeField;
|
||||||
use pasta_curves::pallas;
|
use pasta_curves::{arithmetic::FieldExt, pallas};
|
||||||
use subtle::CtOption;
|
use subtle::CtOption;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -59,6 +59,13 @@ impl NoteCommitment {
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ExtractedNoteCommitment(pub(super) pallas::Base);
|
pub struct ExtractedNoteCommitment(pub(super) pallas::Base);
|
||||||
|
|
||||||
|
impl ExtractedNoteCommitment {
|
||||||
|
/// Deserialize the extracted note commitment from a byte array.
|
||||||
|
pub fn from_bytes(bytes: &[u8; 32]) -> CtOption<Self> {
|
||||||
|
pallas::Base::from_bytes(bytes).map(ExtractedNoteCommitment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<NoteCommitment> for ExtractedNoteCommitment {
|
impl From<NoteCommitment> for ExtractedNoteCommitment {
|
||||||
fn from(cm: NoteCommitment) -> Self {
|
fn from(cm: NoteCommitment) -> Self {
|
||||||
ExtractedNoteCommitment(extract_p(&cm.0))
|
ExtractedNoteCommitment(extract_p(&cm.0))
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
use group::Group;
|
use group::Group;
|
||||||
use halo2::arithmetic::CurveExt;
|
use halo2::arithmetic::CurveExt;
|
||||||
use pasta_curves::pallas;
|
use pasta_curves::{arithmetic::FieldExt, pallas};
|
||||||
use rand::RngCore;
|
use rand::RngCore;
|
||||||
|
use subtle::CtOption;
|
||||||
|
|
||||||
use super::NoteCommitment;
|
use super::NoteCommitment;
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -30,6 +31,11 @@ impl Nullifier {
|
||||||
Nullifier(extract_p(&pallas::Point::random(rng)))
|
Nullifier(extract_p(&pallas::Point::random(rng)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deserialize the nullifier from a byte array.
|
||||||
|
pub fn from_bytes(bytes: &[u8; 32]) -> CtOption<Self> {
|
||||||
|
pallas::Base::from_bytes(bytes).map(Nullifier)
|
||||||
|
}
|
||||||
|
|
||||||
/// $DeriveNullifier$.
|
/// $DeriveNullifier$.
|
||||||
///
|
///
|
||||||
/// Defined in [Zcash Protocol Spec § 4.16: Note Commitments and Nullifiers][commitmentsandnullifiers].
|
/// Defined in [Zcash Protocol Spec § 4.16: Note Commitments and Nullifiers][commitmentsandnullifiers].
|
||||||
|
|
|
@ -96,6 +96,12 @@ impl VerificationKey<SpendAuth> {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Signature<T: SigType>(reddsa::Signature<T>);
|
pub struct Signature<T: SigType>(reddsa::Signature<T>);
|
||||||
|
|
||||||
|
impl<T: SigType> From<[u8; 64]> for Signature<T> {
|
||||||
|
fn from(bytes: [u8; 64]) -> Self {
|
||||||
|
Signature(bytes.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) mod private {
|
pub(crate) mod private {
|
||||||
use super::{Binding, SpendAuth};
|
use super::{Binding, SpendAuth};
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ use rand::RngCore;
|
||||||
|
|
||||||
/// The root of an Orchard commitment tree.
|
/// The root of an Orchard commitment tree.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Anchor;
|
pub struct Anchor(pub [u8; 32]);
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct MerklePath;
|
pub struct MerklePath;
|
||||||
|
|
Loading…
Reference in New Issue