Merge pull request #2 from zcash/crate-skeleton

Crate skeleton
This commit is contained in:
ebfull 2021-02-09 08:37:34 -07:00 committed by GitHub
commit 744b39db9f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 359 additions and 0 deletions

8
src/address.rs Normal file
View File

@ -0,0 +1,8 @@
use crate::keys::Diversifier;
/// A shielded payment address.
#[derive(Debug)]
pub struct Address {
d: Diversifier,
pk_d: (),
}

86
src/bundle.rs Normal file
View File

@ -0,0 +1,86 @@
//! Structs related to bundles of Orchard actions.
use crate::{
circuit::Proof,
note::{EncryptedNote, NoteCommitment, Nullifier},
primitives::redpallas::{self, Binding, SpendAuth},
tree::Anchor,
value::{ValueCommitment, ValueSum},
};
/// An action applied to the global ledger.
///
/// Externally, this both creates a note (adding a commitment to the global ledger),
/// and consumes some note created prior to this action (adding a nullifier to the
/// global ledger).
///
/// 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).
#[derive(Debug)]
pub struct Action {
/// The nullifier of the note being spent.
nf_old: Nullifier,
/// The randomized verification key for the note being spent.
rk: redpallas::VerificationKey<SpendAuth>,
/// A commitment to the new note being created.
cm_new: NoteCommitment,
/// The encrypted output note.
encrypted_note: EncryptedNote,
/// A commitment to the net value created or consumed by this action.
cv_net: ValueCommitment,
}
/// A bundle of actions to be applied to the ledger.
///
/// TODO: Will this ever exist independently of its signatures, outside of a builder?
#[derive(Debug)]
pub struct Bundle {
anchor: Anchor,
actions: Vec<Action>,
value_balance: ValueSum,
proof: Proof,
}
impl Bundle {
/// Computes a commitment to the effects of this bundle, suitable for inclusion within
/// a transaction ID.
pub fn commitment(&self) -> BundleCommitment {
todo!()
}
}
/// An authorized bundle of actions, ready to be committed to the ledger.
#[derive(Debug)]
pub struct SignedBundle {
bundle: Bundle,
action_signatures: Vec<redpallas::Signature<SpendAuth>>,
binding_signature: redpallas::Signature<Binding>,
}
impl SignedBundle {
/// Computes a commitment to the effects of this bundle, suitable for inclusion within
/// a transaction ID.
///
/// This is equivalent to [`Bundle::commitment`].
pub fn commitment(&self) -> BundleCommitment {
self.bundle.commitment()
}
/// Computes a commitment to the authorizing data within for this bundle.
///
/// This together with `SignedBundle::commitment` bind the entire bundle.
pub fn authorizing_commitment(&self) -> BundleAuthorizingCommitment {
todo!()
}
}
/// A commitment to a bundle of actions.
///
/// This commitment is non-malleable, in the sense that a bundle's commitment will only
/// change if the effects of the bundle are altered.
#[derive(Debug)]
pub struct BundleCommitment;
/// A commitment to the authorizing data within a bundle of actions.
#[derive(Debug)]
pub struct BundleAuthorizingCommitment;

2
src/circuit.rs Normal file
View File

@ -0,0 +1,2 @@
#[derive(Debug)]
pub struct Proof(Vec<u8>);

109
src/keys.rs Normal file
View File

@ -0,0 +1,109 @@
//! Key structures for Orchard.
use crate::address::Address;
/// A spending key, from which all key material is derived.
///
/// TODO: In Sapling we never actually used this, instead deriving everything via ZIP 32,
/// so that we could maintain Bitcoin-like HD keys with properties like non-hardened
/// derivation. If we decide that we don't actually require non-hardened derivation, then
/// we could greatly simplify the HD structure and use this struct directly.
#[derive(Debug)]
pub struct SpendingKey;
#[derive(Debug)]
pub(crate) struct SpendAuthorizingKey;
impl From<&SpendingKey> for SpendAuthorizingKey {
fn from(_: &SpendingKey) -> Self {
todo!()
}
}
/// TODO: This is its protocol spec name for Sapling, but I'd prefer a different name.
#[derive(Debug)]
pub(crate) struct AuthorizingKey;
impl From<&SpendAuthorizingKey> for AuthorizingKey {
fn from(_: &SpendAuthorizingKey) -> Self {
todo!()
}
}
#[derive(Debug)]
pub(crate) struct NullifierDerivingKey;
impl From<&SpendingKey> for NullifierDerivingKey {
fn from(_: &SpendingKey) -> Self {
todo!()
}
}
/// A key that provides the capability to view incoming and outgoing transactions.
///
/// This key is useful anywhere you need to maintain accurate balance, but do not want the
/// ability to spend funds (such as a view-only wallet).
///
/// TODO: Should we just define the FVK to include extended stuff like the diversifier key?
#[derive(Debug)]
pub struct FullViewingKey {
ak: AuthorizingKey,
nk: NullifierDerivingKey,
rivk: (),
}
impl From<&SpendingKey> for FullViewingKey {
fn from(_: &SpendingKey) -> Self {
todo!()
}
}
impl FullViewingKey {
/// Returns the payment address for this key corresponding to the given diversifier.
pub fn address(&self, d: Diversifier) -> Address {
IncomingViewingKey::from(self).address(d)
}
}
/// A diversifier that can be used to derive a specific [`Address`] from a
/// [`FullViewingKey`] or [`IncomingViewingKey`].
#[derive(Debug)]
pub struct Diversifier([u8; 11]);
/// A key that provides the capability to detect and decrypt incoming notes from the block
/// chain, without being able to spend the notes or detect when they are spent.
///
/// This key is useful in situations where you only need the capability to detect inbound
/// payments, such as merchant terminals.
///
/// This key is not suitable for use on its own in a wallet, as it cannot maintain
/// accurate balance. You should use a [`FullViewingKey`] instead.
#[derive(Debug)]
pub struct IncomingViewingKey;
impl From<&FullViewingKey> for IncomingViewingKey {
fn from(_: &FullViewingKey) -> Self {
todo!()
}
}
impl IncomingViewingKey {
/// Returns the payment address for this key corresponding to the given diversifier.
pub fn address(&self, _: Diversifier) -> Address {
todo!()
}
}
/// A key that provides the capability to recover outgoing transaction information from
/// the block chain.
///
/// This key is not suitable for use on its own in a wallet, as it cannot maintain
/// accurate balance. You should use a [`FullViewingKey`] instead.
#[derive(Debug)]
pub struct OutgoingViewingKey;
impl From<&FullViewingKey> for OutgoingViewingKey {
fn from(_: &FullViewingKey) -> Self {
todo!()
}
}

View File

@ -6,3 +6,15 @@
#![deny(missing_debug_implementations)]
#![deny(missing_docs)]
#![deny(unsafe_code)]
mod address;
pub mod bundle;
mod circuit;
pub mod keys;
mod note;
pub mod primitives;
mod tree;
pub mod value;
pub use address::Address;
pub use note::{EncryptedNote, Note, NoteCommitment, Nullifier};

61
src/note.rs Normal file
View File

@ -0,0 +1,61 @@
use crate::{keys::FullViewingKey, value::NoteValue, Address};
/// The ZIP 212 seed randomness for a note.
#[derive(Debug)]
struct RandomSeed([u8; 32]);
impl RandomSeed {
fn psi(&self) -> () {
todo!()
}
fn rcm(&self) -> () {
todo!()
}
fn esk(&self) -> () {
todo!()
}
}
/// A discrete amount of funds received by an address.
#[derive(Debug)]
pub struct Note {
/// The recipient of the funds.
recipient: Address,
/// The value of this note.
value: NoteValue,
/// 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,
}
impl Note {
/// Derives the commitment to this note.
pub fn commitment(&self) -> NoteCommitment {
todo!()
}
/// Derives the nullifier for this note.
pub fn nullifier(&self, _: &FullViewingKey) -> Nullifier {
todo!()
}
}
/// An encrypted note.
#[derive(Debug)]
pub struct EncryptedNote;
/// A commitment to a note.
#[derive(Debug)]
pub struct NoteCommitment;
/// A unique nullifier for a note.
#[derive(Debug)]
pub struct Nullifier;

7
src/primitives.rs Normal file
View File

@ -0,0 +1,7 @@
//! Primitives used in the Orchard protocol.
// TODO:
// - DH stuff
// - EphemeralPublicKey
// - EphemeralSecretKey
pub mod redpallas;

View File

@ -0,0 +1,45 @@
//! TODO
use std::fmt;
use std::marker::PhantomData;
/// A RedPallas signature type.
pub trait SigType: private::Sealed + fmt::Debug {}
/// A type variable corresponding to an Orchard spend authorization signature.
#[derive(Debug)]
pub enum SpendAuth {}
impl SigType for SpendAuth {}
/// A type variable corresponding to an Orchard binding signature.
#[derive(Debug)]
pub enum Binding {}
impl SigType for Binding {}
/// A RedPallas signing key.
#[derive(Debug)]
pub struct SigningKey<T: SigType> {
_t: PhantomData<T>,
}
/// A RedPallas verification key.
#[derive(Debug)]
pub struct VerificationKey<T: SigType> {
_t: PhantomData<T>,
}
/// A RedPallas signature.
#[derive(Debug)]
pub struct Signature<T: SigType> {
_t: PhantomData<T>,
}
pub(crate) mod private {
use super::{Binding, SpendAuth};
pub trait Sealed {}
impl Sealed for SpendAuth {}
impl Sealed for Binding {}
}

3
src/tree.rs Normal file
View File

@ -0,0 +1,3 @@
/// The root of an Orchard commitment tree.
#[derive(Debug)]
pub struct Anchor;

26
src/value.rs Normal file
View File

@ -0,0 +1,26 @@
//! Monetary values within the Orchard shielded pool.
//!
//! Values are represented in two places within Orchard:
//! - The value of an individual note, which is unsigned.
//! - The sum of note values within an Orchard [`Action`] or [`Bundle`], which is signed.
//!
//! We give these separate types within this crate. Users should map these types to their
//! own general "amount" type as appropriate.
//!
//! Inside the circuit, values are constrained to be 63-bit integers.
//! - TODO: Should this be constrained further to 53 bits? To Zcash's MAX_MONEY?
//!
//! [`Action`]: crate::bundle::Action
//! [`Bundle`]: crate::bundle::Bundle
/// The value of an individual Orchard note.
#[derive(Debug)]
pub struct NoteValue(u64);
/// A sum of Orchard note values.
#[derive(Debug)]
pub struct ValueSum(i64);
/// A commitment to a [`ValueSum`].
#[derive(Debug)]
pub struct ValueCommitment;