Add `Anchor` type for symmetry with Orchard.

This commit is contained in:
Kris Nuttycombe 2023-12-20 20:36:21 -07:00
parent 43d4133af4
commit 954a27ee9b
4 changed files with 50 additions and 11 deletions

View File

@ -10,6 +10,7 @@ The entries below are relative to the `zcash_primitives::sapling` module as of
`zcash_primitives 0.13.0`. `zcash_primitives 0.13.0`.
### Added ### Added
- `sapling_crypto::Anchor`
- `sapling_crypto::BatchValidator` (moved from `zcash_proofs::sapling`). - `sapling_crypto::BatchValidator` (moved from `zcash_proofs::sapling`).
- `sapling_crypto::SaplingVerificationContext` (moved from - `sapling_crypto::SaplingVerificationContext` (moved from
`zcash_proofs::sapling`). `zcash_proofs::sapling`).

View File

@ -22,7 +22,7 @@ use crate::{
CommitmentSum, NoteValue, TrapdoorSum, ValueCommitTrapdoor, ValueCommitment, ValueSum, CommitmentSum, NoteValue, TrapdoorSum, ValueCommitTrapdoor, ValueCommitment, ValueSum,
}, },
zip32::ExtendedSpendingKey, zip32::ExtendedSpendingKey,
Diversifier, MerklePath, Node, Note, PaymentAddress, ProofGenerationKey, SaplingIvk, Anchor, Diversifier, MerklePath, Node, Note, PaymentAddress, ProofGenerationKey, SaplingIvk,
}; };
/// If there are any shielded inputs, always have at least two shielded outputs, padding /// If there are any shielded inputs, always have at least two shielded outputs, padding
@ -146,12 +146,12 @@ impl SpendInfo {
self.note.value() self.note.value()
} }
fn has_matching_anchor(&self, anchor: &Node) -> bool { fn has_matching_anchor(&self, anchor: &Anchor) -> bool {
if self.note.value() == NoteValue::ZERO { if self.note.value() == NoteValue::ZERO {
true true
} else { } else {
let node = Node::from_cmu(&self.note.cmu()); let node = Node::from_cmu(&self.note.cmu());
&self.merkle_path.root(node) == anchor &Anchor::from(self.merkle_path.root(node)) == anchor
} }
} }
@ -384,14 +384,14 @@ pub struct Builder {
outputs: Vec<OutputInfo>, outputs: Vec<OutputInfo>,
zip212_enforcement: Zip212Enforcement, zip212_enforcement: Zip212Enforcement,
bundle_type: BundleType, bundle_type: BundleType,
anchor: Node, anchor: Anchor,
} }
impl Builder { impl Builder {
pub fn new( pub fn new(
zip212_enforcement: Zip212Enforcement, zip212_enforcement: Zip212Enforcement,
bundle_type: BundleType, bundle_type: BundleType,
anchor: Node, anchor: Anchor,
) -> Self { ) -> Self {
Builder { Builder {
value_balance: ValueSum::zero(), value_balance: ValueSum::zero(),
@ -502,7 +502,7 @@ pub fn bundle<SP: SpendProver, OP: OutputProver, R: RngCore, V: TryFrom<i64>>(
mut rng: R, mut rng: R,
bundle_type: BundleType, bundle_type: BundleType,
zip212_enforcement: Zip212Enforcement, zip212_enforcement: Zip212Enforcement,
anchor: Node, anchor: Anchor,
spends: Vec<SpendInfo>, spends: Vec<SpendInfo>,
outputs: Vec<OutputInfo>, outputs: Vec<OutputInfo>,
) -> Result<Option<(UnauthorizedBundle<V>, SaplingMetadata)>, Error> { ) -> Result<Option<(UnauthorizedBundle<V>, SaplingMetadata)>, Error> {
@ -993,10 +993,10 @@ pub mod testing {
testing::{arb_node, arb_note}, testing::{arb_node, arb_note},
value::testing::arb_positive_note_value, value::testing::arb_positive_note_value,
zip32::testing::arb_extended_spending_key, zip32::testing::arb_extended_spending_key,
Node, NOTE_COMMITMENT_TREE_DEPTH, Anchor, Node,
}; };
use incrementalmerkletree::{ use incrementalmerkletree::{
frontier::testing::arb_commitment_tree, witness::IncrementalWitness, Hashable, Level, frontier::testing::arb_commitment_tree, witness::IncrementalWitness,
}; };
use super::{Builder, BundleType}; use super::{Builder, BundleType};
@ -1029,10 +1029,10 @@ pub mod testing {
.first() .first()
.zip(commitment_trees.first()) .zip(commitment_trees.first())
.map_or_else( .map_or_else(
|| Node::empty_root(Level::from(NOTE_COMMITMENT_TREE_DEPTH)), || Anchor::empty_tree(),
|(note, tree)| { |(note, tree)| {
let node = Node::from_cmu(&note.cmu()); let node = Node::from_cmu(&note.cmu());
Node::from_scalar(*tree.root(node).inner()) Anchor::from(*tree.root(node).inner())
}, },
); );
let mut builder = Builder::new(zip212_enforcement, BundleType::DEFAULT, anchor); let mut builder = Builder::new(zip212_enforcement, BundleType::DEFAULT, anchor);

View File

@ -34,7 +34,8 @@ pub use bundle::Bundle;
pub use keys::{Diversifier, NullifierDerivingKey, ProofGenerationKey, SaplingIvk, ViewingKey}; pub use keys::{Diversifier, NullifierDerivingKey, ProofGenerationKey, SaplingIvk, ViewingKey};
pub use note::{nullifier::Nullifier, Note, Rseed}; pub use note::{nullifier::Nullifier, Note, Rseed};
pub use tree::{ pub use tree::{
merkle_hash, CommitmentTree, IncrementalWitness, MerklePath, Node, NOTE_COMMITMENT_TREE_DEPTH, merkle_hash, Anchor, CommitmentTree, IncrementalWitness, MerklePath, Node,
NOTE_COMMITMENT_TREE_DEPTH,
}; };
pub use verifier::{BatchValidator, SaplingVerificationContext}; pub use verifier::{BatchValidator, SaplingVerificationContext};

View File

@ -67,6 +67,43 @@ fn merkle_hash_field(depth: usize, lhs: &[u8; 32], rhs: &[u8; 32]) -> jubjub::Ba
.get_u() .get_u()
} }
/// The root of a Sapling commitment tree.
#[derive(Eq, PartialEq, Clone, Copy, Debug)]
pub struct Anchor(jubjub::Base);
impl From<jubjub::Base> for Anchor {
fn from(anchor_field: jubjub::Base) -> Anchor {
Anchor(anchor_field)
}
}
impl From<Node> for Anchor {
fn from(anchor: Node) -> Anchor {
Anchor(anchor.0)
}
}
impl Anchor {
/// The anchor of the empty Orchard note commitment tree.
///
/// This anchor does not correspond to any valid anchor for a spend, so it
/// may only be used for coinbase bundles or in circumstances where Orchard
/// functionality is not active.
pub fn empty_tree() -> Anchor {
Anchor(Node::empty_root(NOTE_COMMITMENT_TREE_DEPTH.into()).0)
}
/// Parses an Orchard anchor from a byte encoding.
pub fn from_bytes(bytes: [u8; 32]) -> CtOption<Anchor> {
jubjub::Base::from_repr(bytes).map(Self)
}
/// Returns the byte encoding of this anchor.
pub fn to_bytes(self) -> [u8; 32] {
self.0.to_repr()
}
}
/// A node within the Sapling commitment tree. /// A node within the Sapling commitment tree.
#[derive(Clone, Copy, PartialEq, Eq)] #[derive(Clone, Copy, PartialEq, Eq)]
pub struct Node(jubjub::Base); pub struct Node(jubjub::Base);