Be more explicit about empty sapling & orchard hashes.
This commit is contained in:
parent
b93c503263
commit
0253442af0
|
@ -950,7 +950,6 @@ impl Transaction {
|
||||||
orchard_serialization::write_action_without_auth(w, a)
|
orchard_serialization::write_action_without_auth(w, a)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
if !bundle.actions().is_empty() {
|
|
||||||
orchard_serialization::write_flags(&mut writer, &bundle.flags())?;
|
orchard_serialization::write_flags(&mut writer, &bundle.flags())?;
|
||||||
writer.write_all(&bundle.value_balance().to_i64_le_bytes())?;
|
writer.write_all(&bundle.value_balance().to_i64_le_bytes())?;
|
||||||
orchard_serialization::write_anchor(&mut writer, bundle.anchor())?;
|
orchard_serialization::write_anchor(&mut writer, bundle.anchor())?;
|
||||||
|
@ -967,7 +966,6 @@ impl Transaction {
|
||||||
writer.write_all(&<[u8; 64]>::from(
|
writer.write_all(&<[u8; 64]>::from(
|
||||||
bundle.authorization().binding_signature(),
|
bundle.authorization().binding_signature(),
|
||||||
))?;
|
))?;
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
CompactSize::write(&mut writer, 0)?;
|
CompactSize::write(&mut writer, 0)?;
|
||||||
}
|
}
|
||||||
|
@ -1013,8 +1011,8 @@ pub struct TzeDigests<A> {
|
||||||
pub struct TxDigests<A> {
|
pub struct TxDigests<A> {
|
||||||
pub header_digest: A,
|
pub header_digest: A,
|
||||||
pub transparent_digests: Option<TransparentDigests<A>>,
|
pub transparent_digests: Option<TransparentDigests<A>>,
|
||||||
pub sapling_digest: A,
|
pub sapling_digest: Option<A>,
|
||||||
pub orchard_digest: A,
|
pub orchard_digest: Option<A>,
|
||||||
#[cfg(feature = "zfuture")]
|
#[cfg(feature = "zfuture")]
|
||||||
pub tze_digests: Option<TzeDigests<A>>,
|
pub tze_digests: Option<TzeDigests<A>>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -253,11 +253,8 @@ fn hash_transparent_txid_data(t_digests: Option<&TransparentDigests<Blake2bHash>
|
||||||
h.finalize()
|
h.finalize()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hash_sapling_txid_data<A: sapling::Authorization>(
|
fn hash_sapling_txid_data<A: sapling::Authorization>(bundle: &sapling::Bundle<A>) -> Blake2bHash {
|
||||||
sapling_bundle: Option<&sapling::Bundle<A>>,
|
|
||||||
) -> Blake2bHash {
|
|
||||||
let mut h = hasher(ZCASH_SAPLING_HASH_PERSONALIZATION);
|
let mut h = hasher(ZCASH_SAPLING_HASH_PERSONALIZATION);
|
||||||
if let Some(bundle) = sapling_bundle {
|
|
||||||
if !(bundle.shielded_spends.is_empty() && bundle.shielded_outputs.is_empty()) {
|
if !(bundle.shielded_spends.is_empty() && bundle.shielded_outputs.is_empty()) {
|
||||||
h.write_all(hash_sapling_spends(&bundle.shielded_spends).as_bytes())
|
h.write_all(hash_sapling_spends(&bundle.shielded_spends).as_bytes())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -268,10 +265,13 @@ fn hash_sapling_txid_data<A: sapling::Authorization>(
|
||||||
h.write_all(&bundle.value_balance.to_i64_le_bytes())
|
h.write_all(&bundle.value_balance.to_i64_le_bytes())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
h.finalize()
|
h.finalize()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn hash_sapling_txid_empty() -> Blake2bHash {
|
||||||
|
hasher(ZCASH_SAPLING_HASH_PERSONALIZATION).finalize()
|
||||||
|
}
|
||||||
|
|
||||||
/// Write disjoint parts of each Orchard shielded action as 3 separate hashes:
|
/// Write disjoint parts of each Orchard shielded action as 3 separate hashes:
|
||||||
/// * \[(nullifier, cmx, ephemeral_key, enc_ciphertext\[..52\])*\] personalized
|
/// * \[(nullifier, cmx, ephemeral_key, enc_ciphertext\[..52\])*\] personalized
|
||||||
/// with ZCASH_ORCHARD_ACTIONS_COMPACT_HASH_PERSONALIZATION
|
/// with ZCASH_ORCHARD_ACTIONS_COMPACT_HASH_PERSONALIZATION
|
||||||
|
@ -283,10 +283,9 @@ fn hash_sapling_txid_data<A: sapling::Authorization>(
|
||||||
/// Then, hash these together along with (flags, value_balance_orchard, anchor_orchard),
|
/// Then, hash these together along with (flags, value_balance_orchard, anchor_orchard),
|
||||||
/// personalized with ZCASH_ORCHARD_ACTIONS_HASH_PERSONALIZATION
|
/// personalized with ZCASH_ORCHARD_ACTIONS_HASH_PERSONALIZATION
|
||||||
fn hash_orchard_txid_data<A: orchard::Authorization>(
|
fn hash_orchard_txid_data<A: orchard::Authorization>(
|
||||||
orchard_bundle: Option<&orchard::Bundle<A, Amount>>,
|
bundle: &orchard::Bundle<A, Amount>,
|
||||||
) -> Blake2bHash {
|
) -> Blake2bHash {
|
||||||
let mut h = hasher(ZCASH_ORCHARD_HASH_PERSONALIZATION);
|
let mut h = hasher(ZCASH_ORCHARD_HASH_PERSONALIZATION);
|
||||||
if let Some(bundle) = orchard_bundle {
|
|
||||||
let mut ch = hasher(ZCASH_ORCHARD_ACTIONS_COMPACT_HASH_PERSONALIZATION);
|
let mut ch = hasher(ZCASH_ORCHARD_ACTIONS_COMPACT_HASH_PERSONALIZATION);
|
||||||
let mut mh = hasher(ZCASH_ORCHARD_ACTIONS_MEMOS_HASH_PERSONALIZATION);
|
let mut mh = hasher(ZCASH_ORCHARD_ACTIONS_MEMOS_HASH_PERSONALIZATION);
|
||||||
let mut nh = hasher(ZCASH_ORCHARD_ACTIONS_NONCOMPACT_HASH_PERSONALIZATION);
|
let mut nh = hasher(ZCASH_ORCHARD_ACTIONS_NONCOMPACT_HASH_PERSONALIZATION);
|
||||||
|
@ -316,10 +315,13 @@ fn hash_orchard_txid_data<A: orchard::Authorization>(
|
||||||
h.write_all(&bundle.value_balance().to_i64_le_bytes())
|
h.write_all(&bundle.value_balance().to_i64_le_bytes())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
ser_orch::write_anchor(&mut h, bundle.anchor()).unwrap();
|
ser_orch::write_anchor(&mut h, bundle.anchor()).unwrap();
|
||||||
}
|
|
||||||
h.finalize()
|
h.finalize()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn hash_orchard_txid_empty() -> Blake2bHash {
|
||||||
|
hasher(ZCASH_ORCHARD_HASH_PERSONALIZATION).finalize()
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "zfuture")]
|
#[cfg(feature = "zfuture")]
|
||||||
fn hash_tze_txid_data(tze_digests: Option<&TzeDigests<Blake2bHash>>) -> Blake2bHash {
|
fn hash_tze_txid_data(tze_digests: Option<&TzeDigests<Blake2bHash>>) -> Blake2bHash {
|
||||||
let mut h = hasher(ZCASH_TZE_HASH_PERSONALIZATION);
|
let mut h = hasher(ZCASH_TZE_HASH_PERSONALIZATION);
|
||||||
|
@ -343,8 +345,8 @@ pub struct TxIdDigester;
|
||||||
impl<A: Authorization> TransactionDigest<A> for TxIdDigester {
|
impl<A: Authorization> TransactionDigest<A> for TxIdDigester {
|
||||||
type HeaderDigest = Blake2bHash;
|
type HeaderDigest = Blake2bHash;
|
||||||
type TransparentDigest = Option<TransparentDigests<Blake2bHash>>;
|
type TransparentDigest = Option<TransparentDigests<Blake2bHash>>;
|
||||||
type SaplingDigest = Blake2bHash;
|
type SaplingDigest = Option<Blake2bHash>;
|
||||||
type OrchardDigest = Blake2bHash;
|
type OrchardDigest = Option<Blake2bHash>;
|
||||||
|
|
||||||
#[cfg(feature = "zfuture")]
|
#[cfg(feature = "zfuture")]
|
||||||
type TzeDigest = Option<TzeDigests<Blake2bHash>>;
|
type TzeDigest = Option<TzeDigests<Blake2bHash>>;
|
||||||
|
@ -372,14 +374,14 @@ impl<A: Authorization> TransactionDigest<A> for TxIdDigester {
|
||||||
&self,
|
&self,
|
||||||
sapling_bundle: Option<&sapling::Bundle<A::SaplingAuth>>,
|
sapling_bundle: Option<&sapling::Bundle<A::SaplingAuth>>,
|
||||||
) -> Self::SaplingDigest {
|
) -> Self::SaplingDigest {
|
||||||
hash_sapling_txid_data(sapling_bundle)
|
sapling_bundle.map(hash_sapling_txid_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn digest_orchard(
|
fn digest_orchard(
|
||||||
&self,
|
&self,
|
||||||
orchard_bundle: Option<&orchard::Bundle<A::OrchardAuth, Amount>>,
|
orchard_bundle: Option<&orchard::Bundle<A::OrchardAuth, Amount>>,
|
||||||
) -> Self::OrchardDigest {
|
) -> Self::OrchardDigest {
|
||||||
hash_orchard_txid_data(orchard_bundle)
|
orchard_bundle.map(hash_orchard_txid_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "zfuture")]
|
#[cfg(feature = "zfuture")]
|
||||||
|
@ -406,13 +408,13 @@ impl<A: Authorization> TransactionDigest<A> for TxIdDigester {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_hash(
|
pub(crate) fn to_hash(
|
||||||
_txversion: TxVersion,
|
_txversion: TxVersion,
|
||||||
consensus_branch_id: BranchId,
|
consensus_branch_id: BranchId,
|
||||||
header_digest: Blake2bHash,
|
header_digest: Blake2bHash,
|
||||||
transparent_digests: Option<&TransparentDigests<Blake2bHash>>,
|
transparent_digests: Option<&TransparentDigests<Blake2bHash>>,
|
||||||
sapling_digest: Blake2bHash,
|
sapling_digest: Option<Blake2bHash>,
|
||||||
orchard_digest: Blake2bHash,
|
orchard_digest: Option<Blake2bHash>,
|
||||||
#[cfg(feature = "zfuture")] tze_digests: Option<&TzeDigests<Blake2bHash>>,
|
#[cfg(feature = "zfuture")] tze_digests: Option<&TzeDigests<Blake2bHash>>,
|
||||||
) -> Blake2bHash {
|
) -> Blake2bHash {
|
||||||
let mut personal = [0; 16];
|
let mut personal = [0; 16];
|
||||||
|
@ -425,8 +427,18 @@ pub fn to_hash(
|
||||||
h.write_all(header_digest.as_bytes()).unwrap();
|
h.write_all(header_digest.as_bytes()).unwrap();
|
||||||
h.write_all(hash_transparent_txid_data(transparent_digests).as_bytes())
|
h.write_all(hash_transparent_txid_data(transparent_digests).as_bytes())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
h.write_all(sapling_digest.as_bytes()).unwrap();
|
h.write_all(
|
||||||
h.write_all(orchard_digest.as_bytes()).unwrap();
|
sapling_digest
|
||||||
|
.unwrap_or_else(hash_sapling_txid_empty)
|
||||||
|
.as_bytes(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
h.write_all(
|
||||||
|
orchard_digest
|
||||||
|
.unwrap_or_else(hash_orchard_txid_empty)
|
||||||
|
.as_bytes(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
#[cfg(feature = "zfuture")]
|
#[cfg(feature = "zfuture")]
|
||||||
if _txversion.has_tze() {
|
if _txversion.has_tze() {
|
||||||
|
|
Loading…
Reference in New Issue