Remove Chain and value::Constraint traits

There was push-back on having this crate require these traits, due to the
additional complexity within this crate. My rationale for including them
was to make it simpler to reason about what is responsible for enforcing
chain-specific constraints, and to reduce duplication (by enabling the
wrapping chain implementation to use type definitions and leverage all
built-in behaviour, instead of newtypes and needing to add a bunch of
wrapping logic and boilerplate, some of which would encode chain-specific
logic).

We'll try working within the requirement that this crate enforces minimal
base constraints and hard-codes any constants, and then have the wrapping
chain provide encoding prefixes and additional value constraints where
necessary.
This commit is contained in:
Jack Grigg 2021-01-21 12:16:50 +00:00
parent ae252f57a8
commit a564ba76ce
6 changed files with 45 additions and 76 deletions

View File

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

View File

@ -1,14 +1,11 @@
//! Structs related to bundles of Orchard actions.
use std::marker::PhantomData;
use crate::{
circuit::Proof,
note::{EncryptedNote, NoteCommitment, Nullifier},
primitives::redpallas::{self, Binding, SpendAuth},
tree::Anchor,
value::{ValueCommitment, ValueSum},
Chain,
};
/// An action applied to the global ledger.
@ -37,15 +34,14 @@ pub struct Action {
///
/// TODO: Will this ever exist independently of its signatures, outside of a builder?
#[derive(Debug)]
pub struct Bundle<C: Chain> {
pub struct Bundle {
anchor: Anchor,
actions: Vec<Action>,
value_balance: ValueSum<C::Value>,
value_balance: ValueSum,
proof: Proof,
_chain: PhantomData<C>,
}
impl<C: Chain> Bundle<C> {
impl Bundle {
/// Computes a commitment to the effects of this bundle, suitable for inclusion within
/// a transaction ID.
pub fn commitment(&self) -> BundleCommitment {
@ -55,13 +51,13 @@ impl<C: Chain> Bundle<C> {
/// An authorized bundle of actions, ready to be committed to the ledger.
#[derive(Debug)]
pub struct SignedBundle<C: Chain> {
bundle: Bundle<C>,
pub struct SignedBundle {
bundle: Bundle,
action_signatures: Vec<redpallas::Signature<SpendAuth>>,
binding_signature: redpallas::Signature<Binding>,
}
impl<C: Chain> SignedBundle<C> {
impl SignedBundle {
/// Computes a commitment to the effects of this bundle, suitable for inclusion within
/// a transaction ID.
///

View File

@ -1,17 +1,6 @@
//! Key structures for Orchard.
//!
//! TODO: Should we have the concept of a Network here? Or make these standalone without
//! defined string encodings, and use newtypes in Zcash?
//! - The latter might get messy, but would maintain the crate abstraction.
//! - One approach might be to make all these types take a type parameter that provides
//! encoding and decoding support, and then instantiate it in Zcash inside newtypes.
//! - We will need to encode some decisions here (like the size of the diversifier), which
//! depend on the encoding, so another alternative is we just require Bech32 and then
//! have the constrained type provide the HRP.
use std::marker::PhantomData;
use crate::{address::Address, Chain};
use crate::address::Address;
/// A spending key, from which all key material is derived.
///
@ -20,32 +9,32 @@ use crate::{address::Address, Chain};
/// 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<C: Chain>(PhantomData<C>);
pub struct SpendingKey;
#[derive(Debug)]
pub(crate) struct SpendAuthorizingKey<C: Chain>(PhantomData<C>);
pub(crate) struct SpendAuthorizingKey;
impl<C: Chain> From<&SpendingKey<C>> for SpendAuthorizingKey<C> {
fn from(_: &SpendingKey<C>) -> Self {
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<C: Chain>(PhantomData<C>);
pub(crate) struct AuthorizingKey;
impl<C: Chain> From<&SpendAuthorizingKey<C>> for AuthorizingKey<C> {
fn from(_: &SpendAuthorizingKey<C>) -> Self {
impl From<&SpendAuthorizingKey> for AuthorizingKey {
fn from(_: &SpendAuthorizingKey) -> Self {
todo!()
}
}
#[derive(Debug)]
pub(crate) struct NullifierDerivingKey<C: Chain>(PhantomData<C>);
pub(crate) struct NullifierDerivingKey;
impl<C: Chain> From<&SpendingKey<C>> for NullifierDerivingKey<C> {
fn from(_: &SpendingKey<C>) -> Self {
impl From<&SpendingKey> for NullifierDerivingKey {
fn from(_: &SpendingKey) -> Self {
todo!()
}
}
@ -53,10 +42,10 @@ impl<C: Chain> From<&SpendingKey<C>> for NullifierDerivingKey<C> {
/// A key that provides the capability to recover outgoing transaction information from
/// the block chain.
#[derive(Debug)]
pub struct OutgoingViewingKey<C: Chain>(PhantomData<C>);
pub struct OutgoingViewingKey;
impl<C: Chain> From<&SpendingKey<C>> for OutgoingViewingKey<C> {
fn from(_: &SpendingKey<C>) -> Self {
impl From<&SpendingKey> for OutgoingViewingKey {
fn from(_: &SpendingKey) -> Self {
todo!()
}
}
@ -71,21 +60,21 @@ impl<C: Chain> From<&SpendingKey<C>> for OutgoingViewingKey<C> {
///
/// TODO: Should we just define the FVK to include extended stuff like the diversifier key?
#[derive(Debug)]
pub struct FullViewingKey<C: Chain> {
ak: AuthorizingKey<C>,
nk: NullifierDerivingKey<C>,
ovk: OutgoingViewingKey<C>,
pub struct FullViewingKey {
ak: AuthorizingKey,
nk: NullifierDerivingKey,
ovk: OutgoingViewingKey,
}
impl<C: Chain> From<&SpendingKey<C>> for FullViewingKey<C> {
fn from(_: &SpendingKey<C>) -> Self {
impl From<&SpendingKey> for FullViewingKey {
fn from(_: &SpendingKey) -> Self {
todo!()
}
}
impl<C: Chain> FullViewingKey<C> {
impl FullViewingKey {
/// Returns the payment address for this key corresponding to the given diversifier.
pub fn address(&self, d: Diversifier<C>) -> Address<C> {
pub fn address(&self, d: Diversifier) -> Address {
IncomingViewingKey::from(self).address(d)
}
}
@ -96,7 +85,7 @@ impl<C: Chain> FullViewingKey<C> {
// This is a newtype around a `u128` for simplicity, and enforces the diversifier size
// during all operations.
#[derive(Debug)]
pub struct Diversifier<C: Chain>(u128, PhantomData<C>);
pub struct Diversifier(u128);
/// 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.
@ -107,17 +96,17 @@ pub struct Diversifier<C: Chain>(u128, PhantomData<C>);
/// This key is not suitable for use in a wallet, as it cannot maintain accurate balance.
/// You should use a [`FullViewingKey`] instead.
#[derive(Debug)]
pub struct IncomingViewingKey<C: Chain>(PhantomData<C>);
pub struct IncomingViewingKey;
impl<C: Chain> From<&FullViewingKey<C>> for IncomingViewingKey<C> {
fn from(_: &FullViewingKey<C>) -> Self {
impl From<&FullViewingKey> for IncomingViewingKey {
fn from(_: &FullViewingKey) -> Self {
todo!()
}
}
impl<C: Chain> IncomingViewingKey<C> {
impl IncomingViewingKey {
/// Returns the payment address for this key corresponding to the given diversifier.
pub fn address(&self, _: Diversifier<C>) -> Address<C> {
pub fn address(&self, _: Diversifier) -> Address {
todo!()
}
}

View File

@ -18,12 +18,3 @@ pub mod value;
pub use address::Address;
pub use note::{EncryptedNote, Note, NoteCommitment, Nullifier};
/// Chain-specific constants and constraints for Orchard.
///
/// The purpose of this trait is to encapsulate things like the human-readable prefixes
/// for encoded addresses, or the range of allowable values for notes.
pub trait Chain {
/// Constraints on values within this chain.
type Value: value::Constraint;
}

View File

@ -1,22 +1,22 @@
use crate::{keys::FullViewingKey, value::NoteValue, Address, Chain};
use crate::{keys::FullViewingKey, value::NoteValue, Address};
/// A discrete amount of funds received by an address.
#[derive(Debug)]
pub struct Note<C: Chain> {
pub struct Note {
/// The recipient of the funds.
recipient: Address<C>,
recipient: Address,
/// The value of this note.
value: NoteValue<C::Value>,
value: NoteValue,
}
impl<C: Chain> Note<C> {
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<C>) -> Nullifier {
pub fn nullifier(&self, _: &FullViewingKey) -> Nullifier {
todo!()
}
}

View File

@ -13,19 +13,13 @@
//! [`Action`]: crate::bundle::Action
//! [`Bundle`]: crate::bundle::Bundle
use std::fmt;
use std::marker::PhantomData;
/// The constraints applied to Orchard values.
pub trait Constraint: fmt::Debug {}
/// The value of an individual Orchard note.
#[derive(Debug)]
pub struct NoteValue<C: Constraint>(u64, PhantomData<C>);
pub struct NoteValue(u64);
/// A sum of Orchard note values.
#[derive(Debug)]
pub struct ValueSum<C: Constraint>(i64, PhantomData<C>);
pub struct ValueSum(i64);
/// A commitment to a [`ValueSum`].
#[derive(Debug)]