Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions test-vectors/json/orchard_zsa_digests.json

Large diffs are not rendered by default.

4,846 changes: 2,423 additions & 2,423 deletions test-vectors/rust/orchard_zsa_digests.rs

Large diffs are not rendered by default.

18 changes: 9 additions & 9 deletions test-vectors/zcash/orchard_zsa_digests.json

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions zcash_test_vectors/transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,10 @@ def to_bytes(self, version_bytes, nVersionGroupId, nConsensusBranchId):
ret += write_compact_size(len(self.vout))
for x in self.vout:
ret += bytes(x)
if version_bytes == NU7_TX_VERSION_BYTES:
for sighash_info in self.vSighashInfo:
ret += write_compact_size(len(sighash_info))
ret += bytes(sighash_info)

# Sapling Transaction Fields
hasSapling = len(self.vSpendsSapling) + len(self.vOutputsSapling) > 0
Expand Down
8 changes: 5 additions & 3 deletions zcash_test_vectors/transaction_v6.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,11 +149,13 @@ def __init__(self, rand, consensus_branch_id, sighash_info, have_orchard_zsa=Tru

# All Transparent, Sapling, and part of the Orchard Transaction Fields are initialized in the super class.
super().__init__(rand, have_orchard_zsa)
self.vSighashInfo = [sighash_info] * len(self.vin)
for desc in self.vSpendsSapling:
desc.spendAuthSigInfo = sighash_info
self.bindingSigSaplingInfo = sighash_info
self.bindingSigOrchardInfo = sighash_info

if hasattr(self, "bindingSigSapling"):
self.bindingSigSaplingInfo = sighash_info
if hasattr(self, "bindingSigOrchard"):
self.bindingSigOrchardInfo = sighash_info
Comment on lines +155 to +158
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Later, in

        for desc in tx.vOutputsSapling:
            digest.update(bytes(desc.proof))
        digest.update(write_compact_size(len(tx.bindingSigSaplingInfo)))
        digest.update(bytes(tx.bindingSigSaplingInfo))
        digest.update(bytes(tx.bindingSigSapling))

what happens if tx.bindingSigSaplingInfo in None?

Copy link
Copy Markdown
Author

@ConstanceBeguier ConstanceBeguier Nov 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

def sapling_auth_digest_v6(tx):
    digest = blake2b(digest_size=32, person=SAPLING_AUTH_DIGEST_PERSONALIZAION)

    if len(tx.vSpendsSapling) + len(tx.vOutputsSapling) > 0:
        for desc in tx.vSpendsSapling:
            digest.update(bytes(desc.proof))
        for desc in tx.vSpendsSapling:
            digest.update(write_compact_size(len(desc.spendAuthSigInfo)))
            digest.update(bytes(desc.spendAuthSigInfo))
            digest.update(bytes(desc.spendAuthSig))
        for desc in tx.vOutputsSapling:
            digest.update(bytes(desc.proof))
        digest.update(write_compact_size(len(tx.bindingSigSaplingInfo)))
        digest.update(bytes(tx.bindingSigSaplingInfo))
        digest.update(bytes(tx.bindingSigSapling))

    return digest.digest()

If tx.bindingSigSaplingInfo is None and we try to access it, an exception will be raised.
The function sapling_auth_digest_v6 is only called for v6 transaction.
In this function, tx.bindingSigSaplingInfo and tx.bindingSigSapling are accessed only when the transaction includes a Sapling element.
For v6 transactions, whenever a Sapling element is present, both of these fields are populated.


# Common Transaction Fields
self.nVersionGroupId = NU7_VERSION_GROUP_ID
Expand Down
15 changes: 13 additions & 2 deletions zcash_test_vectors/zip_0244.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,22 @@ def transparent_digest(tx):

return digest.digest()

TRANSPARENT_AUTH_DIGEST_PERSONALIZAION = b'ZTxAuthTransHash'

def transparent_scripts_digest(tx):
digest = blake2b(digest_size=32, person=b'ZTxAuthTransHash')
digest = blake2b(digest_size=32, person=TRANSPARENT_AUTH_DIGEST_PERSONALIZAION)
for x in tx.vin:
digest.update(bytes(x.scriptSig))
return digest.digest()

def transparent_scripts_digest_v6(tx):
digest = blake2b(digest_size=32, person=TRANSPARENT_AUTH_DIGEST_PERSONALIZAION)
for (sighash_info, vin) in zip(tx.vSighashInfo, tx.vin):
digest.update(write_compact_size(len(sighash_info)))
digest.update(bytes(sighash_info))
digest.update(bytes(vin.scriptSig))
return digest.digest()

# Sapling

def sapling_digest(tx):
Expand Down Expand Up @@ -243,12 +253,13 @@ def auth_digest(tx):
person=b'ZTxAuthHash_' + struct.pack('<I', tx.nConsensusBranchId),
)

digest.update(transparent_scripts_digest(tx))
if tx.version_bytes() == NU7_TX_VERSION_BYTES:
digest.update(transparent_scripts_digest_v6(tx))
digest.update(sapling_auth_digest_v6(tx))
digest.update(orchard_zsa_auth_digest(tx))
digest.update(issuance_auth_digest(tx))
else:
digest.update(transparent_scripts_digest(tx))
digest.update(sapling_auth_digest(tx))
digest.update(orchard_auth_digest(tx))

Expand Down