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:
parent
1896943f62
commit
b7b62af2f2
|
|
@ -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)?,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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, .. } => {
|
||||
|
|
|
|||
|
|
@ -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)?;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue