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`.
### Added
- `sapling_crypto::Anchor`
- `sapling_crypto::BatchValidator` (moved from `zcash_proofs::sapling`).
- `sapling_crypto::SaplingVerificationContext` (moved from
`zcash_proofs::sapling`).

View File

@ -22,7 +22,7 @@ use crate::{
CommitmentSum, NoteValue, TrapdoorSum, ValueCommitTrapdoor, ValueCommitment, ValueSum,
},
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
@ -146,12 +146,12 @@ impl SpendInfo {
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 {
true
} else {
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>,
zip212_enforcement: Zip212Enforcement,
bundle_type: BundleType,
anchor: Node,
anchor: Anchor,
}
impl Builder {
pub fn new(
zip212_enforcement: Zip212Enforcement,
bundle_type: BundleType,
anchor: Node,
anchor: Anchor,
) -> Self {
Builder {
value_balance: ValueSum::zero(),
@ -502,7 +502,7 @@ pub fn bundle<SP: SpendProver, OP: OutputProver, R: RngCore, V: TryFrom<i64>>(
mut rng: R,
bundle_type: BundleType,
zip212_enforcement: Zip212Enforcement,
anchor: Node,
anchor: Anchor,
spends: Vec<SpendInfo>,
outputs: Vec<OutputInfo>,
) -> Result<Option<(UnauthorizedBundle<V>, SaplingMetadata)>, Error> {
@ -993,10 +993,10 @@ pub mod testing {
testing::{arb_node, arb_note},
value::testing::arb_positive_note_value,
zip32::testing::arb_extended_spending_key,
Node, NOTE_COMMITMENT_TREE_DEPTH,
Anchor, Node,
};
use incrementalmerkletree::{
frontier::testing::arb_commitment_tree, witness::IncrementalWitness, Hashable, Level,
frontier::testing::arb_commitment_tree, witness::IncrementalWitness,
};
use super::{Builder, BundleType};
@ -1029,10 +1029,10 @@ pub mod testing {
.first()
.zip(commitment_trees.first())
.map_or_else(
|| Node::empty_root(Level::from(NOTE_COMMITMENT_TREE_DEPTH)),
|| Anchor::empty_tree(),
|(note, tree)| {
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);

View File

@ -34,7 +34,8 @@ pub use bundle::Bundle;
pub use keys::{Diversifier, NullifierDerivingKey, ProofGenerationKey, SaplingIvk, ViewingKey};
pub use note::{nullifier::Nullifier, Note, Rseed};
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};

View File

@ -67,6 +67,43 @@ fn merkle_hash_field(depth: usize, lhs: &[u8; 32], rhs: &[u8; 32]) -> jubjub::Ba
.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.
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct Node(jubjub::Base);