zcash_primitives: Rework Sapling parsers to be plain functions

Once `zcash_primitives::sapling` is extracted to `sapling-crypto`, these
would have become orphan impls.
This commit is contained in:
Jack Grigg 2023-11-09 23:25:54 +00:00
parent 54eb03e34e
commit e1a5539094
4 changed files with 163 additions and 149 deletions

View File

@ -124,6 +124,13 @@ and this library adheres to Rust's notion of
### Removed
- `zcash_primitives::constants`:
- All `const` values (moved to `zcash_primitives::sapling::constants`).
- `zcash_primitives::sapling::bundle`:
- `SpendDescription::{read, read_nullifier, read_rk, read_spend_auth_sig}`
- `SpendDescription::{write_v4, write_v5_without_witness_data}`
- `SpendDescriptionV5::read`
- `OutputDescription::read`
- `OutputDescription::{write_v4, write_v5_without_proof}`
- `OutputDescriptionV5::read`
- `zcash_primitives::transaction::components::sapling`:
- The following types were removed from this module (moved into
`zcash_primitives::sapling::bundle`):

View File

@ -68,153 +68,159 @@ pub fn read_zkproof<R: Read>(mut reader: R) -> io::Result<GrothProofBytes> {
Ok(zkproof)
}
impl SpendDescription<Authorized> {
pub fn read_nullifier<R: Read>(mut reader: R) -> io::Result<Nullifier> {
let mut nullifier = Nullifier([0u8; 32]);
reader.read_exact(&mut nullifier.0)?;
Ok(nullifier)
}
/// Consensus rules (§4.4):
/// - Canonical encoding is enforced here.
/// - "Not small order" is enforced in SaplingVerificationContext::check_spend()
pub fn read_rk<R: Read>(mut reader: R) -> io::Result<PublicKey> {
PublicKey::read(&mut reader)
}
/// Consensus rules (§4.4):
/// - Canonical encoding is enforced here.
/// - Signature validity is enforced in SaplingVerificationContext::check_spend()
pub fn read_spend_auth_sig<R: Read>(mut reader: R) -> io::Result<Signature> {
Signature::read(&mut reader)
}
pub fn read<R: Read>(mut reader: R) -> io::Result<Self> {
// Consensus rules (§4.4) & (§4.5):
// - Canonical encoding is enforced here.
// - "Not small order" is enforced in SaplingVerificationContext::(check_spend()/check_output())
// (located in zcash_proofs::sapling::verifier).
let cv = read_value_commitment(&mut reader)?;
// Consensus rules (§7.3) & (§7.4):
// - Canonical encoding is enforced here
let anchor = read_base(&mut reader, "anchor")?;
let nullifier = Self::read_nullifier(&mut reader)?;
let rk = Self::read_rk(&mut reader)?;
let zkproof = read_zkproof(&mut reader)?;
let spend_auth_sig = Self::read_spend_auth_sig(&mut reader)?;
Ok(SpendDescription::from_parts(
cv,
anchor,
nullifier,
rk,
zkproof,
spend_auth_sig,
))
}
pub fn write_v4<W: Write>(&self, mut writer: W) -> io::Result<()> {
writer.write_all(&self.cv().to_bytes())?;
writer.write_all(self.anchor().to_repr().as_ref())?;
writer.write_all(&self.nullifier().0)?;
self.rk().write(&mut writer)?;
writer.write_all(self.zkproof())?;
self.spend_auth_sig().write(&mut writer)
}
pub fn write_v5_without_witness_data<W: Write>(&self, mut writer: W) -> io::Result<()> {
writer.write_all(&self.cv().to_bytes())?;
writer.write_all(&self.nullifier().0)?;
self.rk().write(&mut writer)
}
pub(crate) fn read_nullifier<R: Read>(mut reader: R) -> io::Result<Nullifier> {
let mut nullifier = Nullifier([0u8; 32]);
reader.read_exact(&mut nullifier.0)?;
Ok(nullifier)
}
impl SpendDescriptionV5 {
pub fn read<R: Read>(mut reader: &mut R) -> io::Result<Self> {
let cv = read_value_commitment(&mut reader)?;
let nullifier = SpendDescription::read_nullifier(&mut reader)?;
let rk = SpendDescription::read_rk(&mut reader)?;
Ok(SpendDescriptionV5::from_parts(cv, nullifier, rk))
}
/// Consensus rules (§4.4):
/// - Canonical encoding is enforced here.
/// - "Not small order" is enforced in SaplingVerificationContext::check_spend()
pub(crate) fn read_rk<R: Read>(mut reader: R) -> io::Result<PublicKey> {
PublicKey::read(&mut reader)
}
impl OutputDescription<GrothProofBytes> {
pub fn read<R: Read>(mut reader: &mut R) -> io::Result<Self> {
// Consensus rules (§4.5):
// - Canonical encoding is enforced here.
// - "Not small order" is enforced in SaplingVerificationContext::check_output()
// (located in zcash_proofs::sapling::verifier).
let cv = read_value_commitment(&mut reader)?;
// Consensus rule (§7.4): Canonical encoding is enforced here
let cmu = read_cmu(&mut reader)?;
// Consensus rules (§4.5):
// - Canonical encoding is enforced in librustzcash_sapling_check_output by zcashd
// - "Not small order" is enforced in SaplingVerificationContext::check_output()
let mut ephemeral_key = EphemeralKeyBytes([0u8; 32]);
reader.read_exact(&mut ephemeral_key.0)?;
let mut enc_ciphertext = [0u8; 580];
let mut out_ciphertext = [0u8; 80];
reader.read_exact(&mut enc_ciphertext)?;
reader.read_exact(&mut out_ciphertext)?;
let zkproof = read_zkproof(&mut reader)?;
Ok(OutputDescription::from_parts(
cv,
cmu,
ephemeral_key,
enc_ciphertext,
out_ciphertext,
zkproof,
))
}
pub fn write_v4<W: Write>(&self, mut writer: W) -> io::Result<()> {
writer.write_all(&self.cv().to_bytes())?;
writer.write_all(self.cmu().to_bytes().as_ref())?;
writer.write_all(self.ephemeral_key().as_ref())?;
writer.write_all(self.enc_ciphertext())?;
writer.write_all(self.out_ciphertext())?;
writer.write_all(self.zkproof())
}
pub fn write_v5_without_proof<W: Write>(&self, mut writer: W) -> io::Result<()> {
writer.write_all(&self.cv().to_bytes())?;
writer.write_all(self.cmu().to_bytes().as_ref())?;
writer.write_all(self.ephemeral_key().as_ref())?;
writer.write_all(self.enc_ciphertext())?;
writer.write_all(self.out_ciphertext())
}
/// Consensus rules (§4.4):
/// - Canonical encoding is enforced here.
/// - Signature validity is enforced in SaplingVerificationContext::check_spend()
pub(crate) fn read_spend_auth_sig<R: Read>(mut reader: R) -> io::Result<Signature> {
Signature::read(&mut reader)
}
impl OutputDescriptionV5 {
pub fn read<R: Read>(mut reader: &mut R) -> io::Result<Self> {
let cv = read_value_commitment(&mut reader)?;
let cmu = read_cmu(&mut reader)?;
pub(crate) fn read_spend_v4<R: Read>(mut reader: R) -> io::Result<SpendDescription<Authorized>> {
// Consensus rules (§4.4) & (§4.5):
// - Canonical encoding is enforced here.
// - "Not small order" is enforced in SaplingVerificationContext::(check_spend()/check_output())
// (located in zcash_proofs::sapling::verifier).
let cv = read_value_commitment(&mut reader)?;
// Consensus rules (§7.3) & (§7.4):
// - Canonical encoding is enforced here
let anchor = read_base(&mut reader, "anchor")?;
let nullifier = read_nullifier(&mut reader)?;
let rk = read_rk(&mut reader)?;
let zkproof = read_zkproof(&mut reader)?;
let spend_auth_sig = read_spend_auth_sig(&mut reader)?;
// Consensus rules (§4.5):
// - Canonical encoding is enforced in librustzcash_sapling_check_output by zcashd
// - "Not small order" is enforced in SaplingVerificationContext::check_output()
let mut ephemeral_key = EphemeralKeyBytes([0u8; 32]);
reader.read_exact(&mut ephemeral_key.0)?;
Ok(SpendDescription::from_parts(
cv,
anchor,
nullifier,
rk,
zkproof,
spend_auth_sig,
))
}
let mut enc_ciphertext = [0u8; 580];
let mut out_ciphertext = [0u8; 80];
reader.read_exact(&mut enc_ciphertext)?;
reader.read_exact(&mut out_ciphertext)?;
pub(crate) fn write_spend_v4<W: Write>(
mut writer: W,
spend: &SpendDescription<Authorized>,
) -> io::Result<()> {
writer.write_all(&spend.cv().to_bytes())?;
writer.write_all(spend.anchor().to_repr().as_ref())?;
writer.write_all(&spend.nullifier().0)?;
spend.rk().write(&mut writer)?;
writer.write_all(spend.zkproof())?;
spend.spend_auth_sig().write(&mut writer)
}
Ok(OutputDescriptionV5::from_parts(
cv,
cmu,
ephemeral_key,
enc_ciphertext,
out_ciphertext,
))
}
pub(crate) fn write_spend_v5_without_witness_data<W: Write>(
mut writer: W,
spend: &SpendDescription<Authorized>,
) -> io::Result<()> {
writer.write_all(&spend.cv().to_bytes())?;
writer.write_all(&spend.nullifier().0)?;
spend.rk().write(&mut writer)
}
pub(crate) fn read_spend_v5<R: Read>(mut reader: &mut R) -> io::Result<SpendDescriptionV5> {
let cv = read_value_commitment(&mut reader)?;
let nullifier = read_nullifier(&mut reader)?;
let rk = read_rk(&mut reader)?;
Ok(SpendDescriptionV5::from_parts(cv, nullifier, rk))
}
pub(crate) fn read_output_v4<R: Read>(
mut reader: &mut R,
) -> io::Result<OutputDescription<GrothProofBytes>> {
// Consensus rules (§4.5):
// - Canonical encoding is enforced here.
// - "Not small order" is enforced in SaplingVerificationContext::check_output()
// (located in zcash_proofs::sapling::verifier).
let cv = read_value_commitment(&mut reader)?;
// Consensus rule (§7.4): Canonical encoding is enforced here
let cmu = read_cmu(&mut reader)?;
// Consensus rules (§4.5):
// - Canonical encoding is enforced in librustzcash_sapling_check_output by zcashd
// - "Not small order" is enforced in SaplingVerificationContext::check_output()
let mut ephemeral_key = EphemeralKeyBytes([0u8; 32]);
reader.read_exact(&mut ephemeral_key.0)?;
let mut enc_ciphertext = [0u8; 580];
let mut out_ciphertext = [0u8; 80];
reader.read_exact(&mut enc_ciphertext)?;
reader.read_exact(&mut out_ciphertext)?;
let zkproof = read_zkproof(&mut reader)?;
Ok(OutputDescription::from_parts(
cv,
cmu,
ephemeral_key,
enc_ciphertext,
out_ciphertext,
zkproof,
))
}
pub(crate) fn write_output_v4<W: Write>(
mut writer: W,
output: &OutputDescription<GrothProofBytes>,
) -> io::Result<()> {
writer.write_all(&output.cv().to_bytes())?;
writer.write_all(output.cmu().to_bytes().as_ref())?;
writer.write_all(output.ephemeral_key().as_ref())?;
writer.write_all(output.enc_ciphertext())?;
writer.write_all(output.out_ciphertext())?;
writer.write_all(output.zkproof())
}
pub(crate) fn write_output_v5_without_proof<W: Write>(
mut writer: W,
output: &OutputDescription<GrothProofBytes>,
) -> io::Result<()> {
writer.write_all(&output.cv().to_bytes())?;
writer.write_all(output.cmu().to_bytes().as_ref())?;
writer.write_all(output.ephemeral_key().as_ref())?;
writer.write_all(output.enc_ciphertext())?;
writer.write_all(output.out_ciphertext())
}
pub(crate) fn read_output_v5<R: Read>(mut reader: &mut R) -> io::Result<OutputDescriptionV5> {
let cv = read_value_commitment(&mut reader)?;
let cmu = read_cmu(&mut reader)?;
// Consensus rules (§4.5):
// - Canonical encoding is enforced in librustzcash_sapling_check_output by zcashd
// - "Not small order" is enforced in SaplingVerificationContext::check_output()
let mut ephemeral_key = EphemeralKeyBytes([0u8; 32]);
reader.read_exact(&mut ephemeral_key.0)?;
let mut enc_ciphertext = [0u8; 580];
let mut out_ciphertext = [0u8; 80];
reader.read_exact(&mut enc_ciphertext)?;
reader.read_exact(&mut out_ciphertext)?;
Ok(OutputDescriptionV5::from_parts(
cv,
cmu,
ephemeral_key,
enc_ciphertext,
out_ciphertext,
))
}
#[cfg(any(test, feature = "test-dependencies"))]

View File

@ -26,7 +26,7 @@ use crate::{
consensus::{BlockHeight, BranchId},
sapling::{
self, builder as sapling_builder,
bundle::{OutputDescription, OutputDescriptionV5, SpendDescription, SpendDescriptionV5},
bundle::{OutputDescription, SpendDescription},
redjubjub,
},
};
@ -606,10 +606,10 @@ impl Transaction {
let vb = Self::read_amount(&mut reader)?;
#[allow(clippy::redundant_closure)]
let ss: Vec<SpendDescription<sapling::bundle::Authorized>> =
Vector::read(&mut reader, |r| SpendDescription::read(r))?;
Vector::read(&mut reader, |r| sapling_serialization::read_spend_v4(r))?;
#[allow(clippy::redundant_closure)]
let so: Vec<OutputDescription<sapling::bundle::GrothProofBytes>> =
Vector::read(&mut reader, |r| OutputDescription::read(r))?;
Vector::read(&mut reader, |r| sapling_serialization::read_output_v4(r))?;
(vb, ss, so)
} else {
(Amount::zero(), vec![], vec![])
@ -750,8 +750,8 @@ impl Transaction {
fn read_v5_sapling<R: Read>(
mut reader: R,
) -> io::Result<Option<sapling::Bundle<sapling::bundle::Authorized>>> {
let sd_v5s = Vector::read(&mut reader, SpendDescriptionV5::read)?;
let od_v5s = Vector::read(&mut reader, OutputDescriptionV5::read)?;
let sd_v5s = Vector::read(&mut reader, sapling_serialization::read_spend_v5)?;
let od_v5s = Vector::read(&mut reader, sapling_serialization::read_output_v5)?;
let n_spends = sd_v5s.len();
let n_outputs = od_v5s.len();
let value_balance = if n_spends > 0 || n_outputs > 0 {
@ -770,7 +770,7 @@ impl Transaction {
sapling_serialization::read_zkproof(r)
})?;
let v_spend_auth_sigs = Array::read(&mut reader, n_spends, |r| {
SpendDescription::read_spend_auth_sig(r)
sapling_serialization::read_spend_auth_sig(r)
})?;
let v_output_proofs = Array::read(&mut reader, n_outputs, |r| {
sapling_serialization::read_zkproof(r)
@ -859,14 +859,14 @@ impl Transaction {
self.sapling_bundle
.as_ref()
.map_or(&[], |b| b.shielded_spends()),
|w, e| e.write_v4(w),
|w, e| sapling_serialization::write_spend_v4(w, e),
)?;
Vector::write(
&mut writer,
self.sapling_bundle
.as_ref()
.map_or(&[], |b| b.shielded_outputs()),
|w, e| e.write_v4(w),
|w, e| sapling_serialization::write_output_v4(w, e),
)?;
} else if self.sapling_bundle.is_some() {
return Err(io::Error::new(
@ -955,11 +955,11 @@ impl Transaction {
) -> io::Result<()> {
if let Some(bundle) = sapling_bundle {
Vector::write(&mut writer, bundle.shielded_spends(), |w, e| {
e.write_v5_without_witness_data(w)
sapling_serialization::write_spend_v5_without_witness_data(w, e)
})?;
Vector::write(&mut writer, bundle.shielded_outputs(), |w, e| {
e.write_v5_without_proof(w)
sapling_serialization::write_output_v5_without_proof(w, e)
})?;
if !(bundle.shielded_spends().is_empty() && bundle.shielded_outputs().is_empty()) {

View File

@ -11,6 +11,7 @@ use crate::{
use super::{
components::{
sapling as sapling_serialization,
sprout::JsDescription,
transparent::{self, TxIn, TxOut},
},
@ -123,7 +124,7 @@ fn shielded_spends_hash<
fn shielded_outputs_hash(shielded_outputs: &[OutputDescription<GrothProofBytes>]) -> Blake2bHash {
let mut data = Vec::with_capacity(shielded_outputs.len() * 948);
for s_out in shielded_outputs {
s_out.write_v4(&mut data).unwrap();
sapling_serialization::write_output_v4(&mut data, s_out).unwrap();
}
Blake2bParams::new()
.hash_length(32)