From b7b62af2f25be369f29a3820b6280de18cd99ca9 Mon Sep 17 00:00:00 2001 From: Conrado Gouvea Date: Mon, 21 Feb 2022 20:49:32 -0300 Subject: [PATCH] Document consensus rules from 4.6 Action Descriptions (#3549) * docs: document consensus rules from 4.6 Action Descriptions * Apply suggestions from code review Co-authored-by: Marek * Apply suggestions from code review Co-authored-by: Marek Co-authored-by: Marek --- zebra-chain/src/orchard/action.rs | 34 +++++++++++++++++++ zebra-chain/src/primitives/redpallas/batch.rs | 16 +++++++++ zebra-chain/src/transaction/serialize.rs | 17 ++++++++++ zebra-consensus/src/transaction.rs | 24 ++++++++++--- 4 files changed, 86 insertions(+), 5 deletions(-) diff --git a/zebra-chain/src/orchard/action.rs b/zebra-chain/src/orchard/action.rs index a4136ba1..9e1270d4 100644 --- a/zebra-chain/src/orchard/action.rs +++ b/zebra-chain/src/orchard/action.rs @@ -59,13 +59,47 @@ impl ZcashSerialize for Action { impl ZcashDeserialize for Action { fn zcash_deserialize(mut reader: R) -> Result { + // # Consensus + // + // > Elements of an Action description MUST be canonical encodings of the types given above. + // + // https://zips.z.cash/protocol/protocol.pdf#actiondesc + // + // > LEOS2IP_{256}(cmx) MUST be less than ๐‘ž_โ„™. + // + // https://zips.z.cash/protocol/protocol.pdf#actionencodingandconsensus + // + // See comments below for each specific type. Ok(Action { + // Type is ValueCommit^{Orchard}.Output, i.e. โ„™. + // https://zips.z.cash/protocol/protocol.pdf#abstractcommit + // See [`ValueCommitment::zcash_deserialize`]. cv: ValueCommitment::zcash_deserialize(&mut reader)?, + // Type is `{0 .. ๐‘ž_โ„™ โˆ’ 1}`. See [`Nullifier::try_from`]. nullifier: Nullifier::try_from(reader.read_32_bytes()?)?, + // Type is SpendAuthSig^{Orchard}.Public, i.e. โ„™. + // https://zips.z.cash/protocol/protocol.pdf#concretespendauthsig + // https://zips.z.cash/protocol/protocol.pdf#concretereddsa + // This only reads the 32-byte buffer. The type is enforced + // on signature verification; see [`redpallas::batch`] rk: reader.read_32_bytes()?.into(), + // Type is `{0 .. ๐‘ž_โ„™ โˆ’ 1}`. Note that the second rule quoted above + // is also enforced here and it is technically redundant with the first. + // See [`pallas::Base::zcash_deserialize`]. cm_x: pallas::Base::zcash_deserialize(&mut reader)?, + // Denoted by `epk` in the spec. Type is KA^{Orchard}.Public, i.e. โ„™^*. + // https://zips.z.cash/protocol/protocol.pdf#concreteorchardkeyagreement + // See [`keys::EphemeralPublicKey::zcash_deserialize`]. ephemeral_key: keys::EphemeralPublicKey::zcash_deserialize(&mut reader)?, + // Type is `Sym.C`, i.e. `๐”น^Y^{[N]}`, i.e. arbitrary-sized byte arrays + // https://zips.z.cash/protocol/protocol.pdf#concretesym but fixed to + // 580 bytes in https://zips.z.cash/protocol/protocol.pdf#outputencodingandconsensus + // See [`note::EncryptedNote::zcash_deserialize`]. enc_ciphertext: note::EncryptedNote::zcash_deserialize(&mut reader)?, + // Type is `Sym.C`, i.e. `๐”น^Y^{[N]}`, i.e. arbitrary-sized byte arrays + // https://zips.z.cash/protocol/protocol.pdf#concretesym but fixed to + // 80 bytes in https://zips.z.cash/protocol/protocol.pdf#outputencodingandconsensus + // See [`note::WrappedNoteKey::zcash_deserialize`]. out_ciphertext: note::WrappedNoteKey::zcash_deserialize(&mut reader)?, }) } diff --git a/zebra-chain/src/primitives/redpallas/batch.rs b/zebra-chain/src/primitives/redpallas/batch.rs index d275c144..8126cd00 100644 --- a/zebra-chain/src/primitives/redpallas/batch.rs +++ b/zebra-chain/src/primitives/redpallas/batch.rs @@ -143,6 +143,14 @@ impl Item { Inner::Binding { vk_bytes, sig, c } => VerificationKey::::try_from(vk_bytes) .and_then(|vk| vk.verify_prehashed(&sig, c)), Inner::SpendAuth { vk_bytes, sig, c } => { + // # Consensus + // + // > Elements of an Action description MUST be canonical encodings of the types given above. + // + // https://zips.z.cash/protocol/protocol.pdf#actiondesc + // + // This validates the `rk` element, whose type is + // SpendAuthSig^{Orchard}.Public, i.e. โ„™. VerificationKey::::try_from(vk_bytes) .and_then(|vk| vk.verify_prehashed(&sig, c)) } @@ -244,6 +252,14 @@ impl Verifier { let VK = match item.inner { Inner::SpendAuth { vk_bytes, .. } => { + // # Consensus + // + // > Elements of an Action description MUST be canonical encodings of the types given above. + // + // https://zips.z.cash/protocol/protocol.pdf#actiondesc + // + // This validates the `rk` element, whose type is + // SpendAuthSig^{Orchard}.Public, i.e. โ„™. VerificationKey::::try_from(vk_bytes.bytes)?.point } Inner::Binding { vk_bytes, .. } => { diff --git a/zebra-chain/src/transaction/serialize.rs b/zebra-chain/src/transaction/serialize.rs index c11aca49..7c321f76 100644 --- a/zebra-chain/src/transaction/serialize.rs +++ b/zebra-chain/src/transaction/serialize.rs @@ -388,19 +388,36 @@ impl ZcashDeserialize for Option { return Ok(None); } + // # Consensus + // + // > Elements of an Action description MUST be canonical encodings of the types given above. + // + // https://zips.z.cash/protocol/protocol.pdf#actiondesc + // + // Some Action elements are validated in this function; they are described below. + // Denoted as `flagsOrchard` in the spec. + // Consensus: type of each flag is ๐”น, i.e. a bit. This is enforced implicitly + // in [`Flags::zcash_deserialized`]. let flags: orchard::Flags = (&mut reader).zcash_deserialize_into()?; // Denoted as `valueBalanceOrchard` in the spec. let value_balance: amount::Amount = (&mut reader).zcash_deserialize_into()?; // Denoted as `anchorOrchard` in the spec. + // Consensus: type is `{0 .. ๐‘ž_โ„™ โˆ’ 1}`. See [`orchard::tree::Root::zcash_deserialize`]. let shared_anchor: orchard::tree::Root = (&mut reader).zcash_deserialize_into()?; // Denoted as `sizeProofsOrchard` and `proofsOrchard` in the spec. + // Consensus: type is `ZKAction.Proof`, i.e. a byte sequence. + // https://zips.z.cash/protocol/protocol.pdf#halo2encoding let proof: Halo2Proof = (&mut reader).zcash_deserialize_into()?; // Denoted as `vSpendAuthSigsOrchard` in the spec. + // Consensus: this validates the `spendAuthSig` elements, whose type is + // SpendAuthSig^{Orchard}.Signature, i.e. + // B^Y^{[ceiling(โ„“_G/8) + ceiling(bitlength(๐‘Ÿ_G)/8)]} i.e. 64 bytes + // See [`Signature::zcash_deserialize`]. let sigs: Vec> = zcash_deserialize_external_count(actions.len(), &mut reader)?; diff --git a/zebra-consensus/src/transaction.rs b/zebra-consensus/src/transaction.rs index 2091c7c1..3d536454 100644 --- a/zebra-consensus/src/transaction.rs +++ b/zebra-consensus/src/transaction.rs @@ -907,8 +907,10 @@ where for authorized_action in orchard_shielded_data.actions.iter().cloned() { let (action, spend_auth_sig) = authorized_action.into_parts(); - // Consensus rule: The proof ๐œ‹ MUST be valid given a primary - // input (cv, rtOrchard, nf, rk, cm๐‘ฅ, enableSpends, enableOutputs) + // # Consensus + // + // > The proof ๐œ‹ MUST be valid given a primary input (cv, rt^{Orchard}, + // > nf, rk, cm_x, enableSpends, enableOutputs) // // https://zips.z.cash/protocol/protocol.pdf#actiondesc // @@ -922,9 +924,21 @@ where .oneshot(primitives::halo2::Item::from(orchard_shielded_data)), ); - // Consensus rule: The spend authorization signature - // MUST be a valid SpendAuthSig signature over - // SigHash using rk as the validating key. + // # Consensus + // + // > - Let SigHash be the SIGHASH transaction hash of this transaction, not + // > associated with an input, as defined in ยง 4.10 using SIGHASH_ALL. + // > - The spend authorization signature MUST be a valid SpendAuthSig^{Orchard} + // > signature over SigHash using rk as the validating key โ€” i.e. + // > SpendAuthSig^{Orchard}.Validate_{rk}(SigHash, spendAuthSig) = 1. + // > As specified in ยง 5.4.7, validation of the ๐‘… component of the + // > signature prohibits non-canonical encodings. + // + // https://zips.z.cash/protocol/protocol.pdf#actiondesc + // + // This is validated by the verifier, inside the [`primitives::redpallas`] module. + // It calls [`pallas::Affine::from_bytes`] to parse R and + // that enforces the canonical encoding. // // Queue the validation of the RedPallas spend // authorization signature for each Action