docs: document consensus rules from 4.4 Spend Descriptions (#3460)
This commit is contained in:
parent
2f33300c08
commit
3bbb8f0531
|
@ -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.
|
||||
///
|
||||
|
|
|
@ -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.
|
||||
///
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue