From 495e1ec20f2272adb3fd2a1a1b33a1400768414c Mon Sep 17 00:00:00 2001 From: Conrado Gouvea Date: Mon, 14 Feb 2022 18:31:20 -0300 Subject: [PATCH] docs: document consensus rules from 4.5 Output Descriptions (#3462) * docs: document consensus rules from 4.4 Spend Descriptions * docs: document consensus rules from 4.5 Output Descriptions * cargo fmt Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- zebra-chain/src/sapling/keys.rs | 2 + zebra-chain/src/sapling/output.rs | 61 ++++++++++++++++++++++++ zebra-chain/src/transaction/serialize.rs | 32 +++++++++++++ zebra-consensus/src/transaction.rs | 10 ++-- 4 files changed, 102 insertions(+), 3 deletions(-) diff --git a/zebra-chain/src/sapling/keys.rs b/zebra-chain/src/sapling/keys.rs index a049f99b..d738c894 100644 --- a/zebra-chain/src/sapling/keys.rs +++ b/zebra-chain/src/sapling/keys.rs @@ -1052,6 +1052,8 @@ impl TryFrom<[u8; 32]> for EphemeralPublicKey { /// /// Returns an error if the key is non-canonical, or [it is of small order][1]. /// + /// # Consensus + /// /// > Check that a Output description's cv and epk are not of small order, /// > i.e. [h_J]cv MUST NOT be 𝒪_J and [h_J]epk MUST NOT be 𝒪_J. /// diff --git a/zebra-chain/src/sapling/output.rs b/zebra-chain/src/sapling/output.rs index 3d9ccb56..30e6f09c 100644 --- a/zebra-chain/src/sapling/output.rs +++ b/zebra-chain/src/sapling/output.rs @@ -134,12 +134,45 @@ impl ZcashSerialize for OutputInTransactionV4 { impl ZcashDeserialize for OutputInTransactionV4 { fn zcash_deserialize(mut reader: R) -> Result { + // # Consensus + // + // > Elements of a Output description MUST be valid encodings of the types given above. + // + // https://zips.z.cash/protocol/protocol.pdf#outputdesc + // + // > LEOS2IP_{256}(cmu) MUST be less than 𝑞_J. + // + // https://zips.z.cash/protocol/protocol.pdf#outputencodingandconsensus + // + // See comments below for each specific type. Ok(OutputInTransactionV4(Output { + // 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. + // However, the consensus rule above restricts it even more. + // See [`jubjub::Fq::zcash_deserialize`]. cm_u: jubjub::Fq::zcash_deserialize(&mut reader)?, + // Type is `KA^{Sapling}.Public`, i.e. J + // https://zips.z.cash/protocol/protocol.pdf#concretesaplingkeyagreement + // See [`keys::EphemeralPublicKey::zcash_deserialize`]. ephemeral_key: keys::EphemeralPublicKey::zcash_deserialize(&mut reader)?, + // Type is `Sym.C`, i.e. `B^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. `B^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)?, + // Type is `ZKOutput.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)?, })) } @@ -164,11 +197,39 @@ impl ZcashSerialize for OutputPrefixInTransactionV5 { impl ZcashDeserialize for OutputPrefixInTransactionV5 { fn zcash_deserialize(mut reader: R) -> Result { + // # Consensus + // + // > Elements of a Output description MUST be valid encodings of the types given above. + // + // https://zips.z.cash/protocol/protocol.pdf#outputdesc + // + // > LEOS2IP_{256}(cmu) MUST be less than 𝑞_J. + // + // https://zips.z.cash/protocol/protocol.pdf#outputencodingandconsensus + // + // See comments below for each specific type. Ok(OutputPrefixInTransactionV5 { + // 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. + // However, the consensus rule above restricts it even more. + // See [`jubjub::Fq::zcash_deserialize`]. cm_u: jubjub::Fq::zcash_deserialize(&mut reader)?, + // Type is `KA^{Sapling}.Public`, i.e. J + // https://zips.z.cash/protocol/protocol.pdf#concretesaplingkeyagreement + // See [`keys::EphemeralPublicKey::zcash_deserialize`]. ephemeral_key: keys::EphemeralPublicKey::zcash_deserialize(&mut reader)?, + // Type is `Sym.C`, i.e. `B^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. `B^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/transaction/serialize.rs b/zebra-chain/src/transaction/serialize.rs index f3b09be8..ac7def0c 100644 --- a/zebra-chain/src/transaction/serialize.rs +++ b/zebra-chain/src/transaction/serialize.rs @@ -206,6 +206,14 @@ impl ZcashDeserialize for Option> { // https://zips.z.cash/protocol/protocol.pdf#spenddesc // // Type is `B^{[ℓ_{Sapling}_{Merkle}]}`, i.e. 32 bytes + // + // # 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 { @@ -225,6 +233,18 @@ impl ZcashDeserialize for Option> { // 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. + // + // # 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)?; // Denoted as `vSpendAuthSigsSapling` in the spec. @@ -242,6 +262,18 @@ impl ZcashDeserialize for Option> { let spend_sigs = zcash_deserialize_external_count(spends_count, &mut reader)?; // Denoted as `vOutputProofsSapling` in the spec. + // + // # Consensus + // + // > Elements of a Output description MUST be valid encodings of the types given above. + // + // https://zips.z.cash/protocol/protocol.pdf#outputdesc + // + // Type is `ZKOutput.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 output_proofs = zcash_deserialize_external_count(outputs_count, &mut reader)?; // Denoted as `bindingSigSapling` in the spec. diff --git a/zebra-consensus/src/transaction.rs b/zebra-consensus/src/transaction.rs index 7f2852ca..2091c7c1 100644 --- a/zebra-consensus/src/transaction.rs +++ b/zebra-consensus/src/transaction.rs @@ -834,9 +834,13 @@ where } for output in sapling_shielded_data.outputs() { - // Consensus rule: The proof π_ZKOutput MUST be - // valid given a primary input formed from the other - // fields except C^enc and C^out. + // # Consensus + // + // > The proof π_ZKOutput MUST be + // > valid given a primary input formed from the other + // > fields except C^enc and C^out. + // + // https://zips.z.cash/protocol/protocol.pdf#outputdesc // // Queue the verification of the Groth16 output // proof for each Output description while adding