docs: document consensus rules from 4.4 Spend Descriptions (#3460)

This commit is contained in:
Conrado Gouvea 2022-02-08 06:56:59 -03:00 committed by GitHub
parent 2f33300c08
commit 3bbb8f0531
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 97 additions and 6 deletions

View File

@ -314,6 +314,8 @@ impl TryFrom<ValueCommitment> for NotSmallOrderValueCommitment {
///
/// Returns an error if the point is of small order.
///
/// # Consensus
///
/// > cv and rk [MUST NOT be of small order][1], i.e. [h_J]cv MUST NOT be 𝒪_J
/// > and [h_J]rk MUST NOT be 𝒪_J.
///

View File

@ -1101,6 +1101,8 @@ impl TryFrom<redjubjub::VerificationKey<SpendAuth>> for ValidatingKey {
///
/// Returns an error if the key is malformed or [is of small order][1].
///
/// # Consensus
///
/// > Check that a Spend description's cv and rk are not of small order,
/// > i.e. [h_J]cv MUST NOT be 𝒪_J and [h_J]rk MUST NOT be 𝒪_J.
///

View File

@ -186,15 +186,38 @@ impl ZcashDeserialize for Spend<PerSpendAnchor> {
///
/// The "anchor encoding for v4 transactions" is implemented here.
fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
// # Consensus
//
// > Elements of a Spend description MUST be valid encodings of the types given above.
//
// https://zips.z.cash/protocol/protocol.pdf#spenddesc
//
// See comments below for each specific type.
Ok(Spend {
// Type is `ValueCommit^{Sapling}.Output`, i.e. J
// https://zips.z.cash/protocol/protocol.pdf#abstractcommit
// See [`commitment::NotSmallOrderValueCommitment::zcash_deserialize`].
cv: commitment::NotSmallOrderValueCommitment::zcash_deserialize(&mut reader)?,
// Type is `B^{[_{Sapling}_{Merkle}]}`, i.e. 32 bytes
per_spend_anchor: tree::Root(reader.read_32_bytes()?),
// Type is `B^Y^{[_{PRFnfSapling}/8]}`, i.e. 32 bytes
nullifier: note::Nullifier::from(reader.read_32_bytes()?),
// Type is `SpendAuthSig^{Sapling}.Public`, i.e. J
// https://zips.z.cash/protocol/protocol.pdf#concretereddsa
// See [`ValidatingKey::try_from`].
rk: reader
.read_32_bytes()?
.try_into()
.map_err(SerializationError::Parse)?,
// Type is `ZKSpend.Proof`, described in
// https://zips.z.cash/protocol/protocol.pdf#grothencoding
// It is not enforced here; this just reads 192 bytes.
// The type is validated when validating the proof, see
// [`groth16::Item::try_from`]. In #3179 we plan to validate here instead.
zkproof: Groth16Proof::zcash_deserialize(&mut reader)?,
// Type is SpendAuthSig^{Sapling}.Signature, i.e.
// B^Y^{[ceiling(_G/8) + ceiling(bitlength(𝑟_G)/8)]} i.e. 64 bytes
// https://zips.z.cash/protocol/protocol.pdf#concretereddsa
spend_auth_sig: reader.read_64_bytes()?.into(),
})
}
@ -217,9 +240,23 @@ impl ZcashSerialize for SpendPrefixInTransactionV5 {
impl ZcashDeserialize for SpendPrefixInTransactionV5 {
fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
// # Consensus
//
// > Elements of a Spend description MUST be valid encodings of the types given above.
//
// https://zips.z.cash/protocol/protocol.pdf#spenddesc
//
// See comments below for each specific type.
Ok(SpendPrefixInTransactionV5 {
// Type is `ValueCommit^{Sapling}.Output`, i.e. J
// https://zips.z.cash/protocol/protocol.pdf#abstractcommit
// See [`commitment::NotSmallOrderValueCommitment::zcash_deserialize`].
cv: commitment::NotSmallOrderValueCommitment::zcash_deserialize(&mut reader)?,
// Type is `B^Y^{[_{PRFnfSapling}/8]}`, i.e. 32 bytes
nullifier: note::Nullifier::from(reader.read_32_bytes()?),
// Type is `SpendAuthSig^{Sapling}.Public`, i.e. J
// https://zips.z.cash/protocol/protocol.pdf#concretereddsa
// See [`ValidatingKey::try_from`].
rk: reader
.read_32_bytes()?
.try_into()

View File

@ -191,6 +191,14 @@ impl ZcashDeserialize for Option<sapling::ShieldedData<SharedAnchor>> {
let value_balance = (&mut reader).zcash_deserialize_into()?;
// anchorSapling
//
// # Consensus
//
// > Elements of a Spend description MUST be valid encodings of the types given above.
//
// https://zips.z.cash/protocol/protocol.pdf#spenddesc
//
// Type is `B^{[_{Sapling}_{Merkle}]}`, i.e. 32 bytes
let shared_anchor = if spends_count > 0 {
Some(reader.read_32_bytes()?.into())
} else {
@ -198,8 +206,32 @@ impl ZcashDeserialize for Option<sapling::ShieldedData<SharedAnchor>> {
};
// vSpendProofsSapling
//
// # Consensus
//
// > Elements of a Spend description MUST be valid encodings of the types given above.
//
// https://zips.z.cash/protocol/protocol.pdf#spenddesc
//
// Type is `ZKSpend.Proof`, described in
// https://zips.z.cash/protocol/protocol.pdf#grothencoding
// It is not enforced here; this just reads 192 bytes.
// The type is validated when validating the proof, see
// [`groth16::Item::try_from`]. In #3179 we plan to validate here instead.
let spend_proofs = zcash_deserialize_external_count(spends_count, &mut reader)?;
// vSpendAuthSigsSapling
//
// # Consensus
//
// > Elements of a Spend description MUST be valid encodings of the types given above.
//
// https://zips.z.cash/protocol/protocol.pdf#spenddesc
//
// Type is SpendAuthSig^{Sapling}.Signature, i.e.
// B^Y^{[ceiling(_G/8) + ceiling(bitlength(𝑟_G)/8)]} i.e. 64 bytes
// https://zips.z.cash/protocol/protocol.pdf#concretereddsa
// See [`redjubjub::Signature<SpendAuth>::zcash_deserialize`].
let spend_sigs = zcash_deserialize_external_count(spends_count, &mut reader)?;
// vOutputProofsSapling

View File

@ -763,9 +763,13 @@ where
if let Some(sapling_shielded_data) = sapling_shielded_data {
for spend in sapling_shielded_data.spends_per_anchor() {
// Consensus rule: The proof π_ZKSpend MUST be valid
// given a primary input formed from the other
// fields except spendAuthSig.
// # Consensus
//
// > The proof π_ZKSpend MUST be valid
// > given a primary input formed from the other
// > fields except spendAuthSig.
//
// https://zips.z.cash/protocol/protocol.pdf#spenddesc
//
// Queue the verification of the Groth16 spend proof
// for each Spend description while adding the
@ -778,9 +782,23 @@ where
.oneshot(DescriptionWrapper(&spend).try_into()?),
);
// Consensus rule: The spend authorization signature
// MUST be a valid SpendAuthSig signature over
// SigHash using rk as the validating key.
// # Consensus
//
// > The spend authorization signature
// > MUST be a valid SpendAuthSig signature over
// > SigHash using rk as the validating key.
//
// This is validated by the verifier.
//
// > [NU5 onward] As specified in § 5.4.7 RedDSA, RedJubjub,
// > and RedPallas on p. 88, the validation of the 𝑅
// > component of the signature changes to prohibit non-canonical encodings.
//
// This is validated by the verifier, inside the `redjubjub` crate.
// It calls [`jubjub::AffinePoint::from_bytes`] to parse R and
// that enforces the canonical encoding.
//
// https://zips.z.cash/protocol/protocol.pdf#spenddesc
//
// Queue the validation of the RedJubjub spend
// authorization signature for each Spend