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 <mail@marek.onl>

* Apply suggestions from code review

Co-authored-by: Marek <mail@marek.onl>

Co-authored-by: Marek <mail@marek.onl>
This commit is contained in:
Conrado Gouvea 2022-02-21 20:49:32 -03:00 committed by GitHub
parent 1896943f62
commit b7b62af2f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 86 additions and 5 deletions

View File

@ -59,13 +59,47 @@ impl ZcashSerialize for Action {
impl ZcashDeserialize for Action {
fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
// # 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)?,
})
}

View File

@ -143,6 +143,14 @@ impl Item {
Inner::Binding { vk_bytes, sig, c } => VerificationKey::<Binding>::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::<SpendAuth>::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::<SpendAuth>::try_from(vk_bytes.bytes)?.point
}
Inner::Binding { vk_bytes, .. } => {

View File

@ -388,19 +388,36 @@ impl ZcashDeserialize for Option<orchard::ShieldedData> {
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<Signature<SpendAuth>> =
zcash_deserialize_external_count(actions.len(), &mut reader)?;

View File

@ -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