Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changes to TXID generation to account for ZSA additions #22

Merged
merged 36 commits into from
Sep 19, 2024
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
e1674dd
updating zip_0244 functions to support generating both V5 and V6 dige…
vivek-arte May 4, 2024
e08b89c
adding V6 transaction class to transaction.py -- code reuse needs to …
vivek-arte May 4, 2024
97ba30d
changes to transaction.py and zip_0244.py
vivek-arte May 15, 2024
9fbb1b0
minor update
vivek-arte May 20, 2024
9f308ee
initial attempt at inheritance, to be improved
vivek-arte Jun 10, 2024
4744106
changing inheritance structure of TransactionV5 and TransactionV6, an…
vivek-arte Jun 14, 2024
26616ee
reverting zip_0244.py to only include V5 details
vivek-arte Jun 14, 2024
1130d66
separate txid vectors for zsa into separate files
vivek-arte Jun 14, 2024
aea6de2
adding ZSA version of zip 244 vectors
vivek-arte Jun 16, 2024
1a2a58e
renaming to NU7 and so on
vivek-arte Jun 17, 2024
c33d00a
still WIP, updating to work with librustzcash code
vivek-arte Jun 18, 2024
49aeb58
updating get_random_unicode_bytes to give a slightly wider range of v…
vivek-arte Jul 10, 2024
256c06f
changes to the transaction format serialization and the txid generati…
vivek-arte Jul 10, 2024
029cfae
updating the generated test vectors
vivek-arte Jul 10, 2024
cca44d8
some cleanup changes
vivek-arte Jul 22, 2024
2c5e31d
removing unichr option from get_random_unicode_bytes
vivek-arte Jul 27, 2024
6bd821d
cleaner import
vivek-arte Jul 27, 2024
2ebe23d
simple changes based on review comments
vivek-arte Jul 27, 2024
4ad2361
moving common transaction fields in a way that reduces code duplication
vivek-arte Jul 29, 2024
10ef794
reducing code duplication by creating an OrchardActionBase class whic…
vivek-arte Jul 29, 2024
59b0372
reducing code duplication in transaction, transaction_zsa, zip_0244 a…
vivek-arte Jul 30, 2024
df173c0
reducing code duplication inside the main function of zip_0244 and zi…
vivek-arte Jul 30, 2024
ea6e099
regenerating test vectors
vivek-arte Jul 30, 2024
0448e1e
minor spacing fix to reduce diff
vivek-arte Jul 30, 2024
7a48c13
resolving review comments, first pass
vivek-arte Aug 15, 2024
5cedbba
resolving review comments, second pass
vivek-arte Aug 18, 2024
fcc4f94
resolving review comments, third pass
vivek-arte Aug 24, 2024
62a239e
updating test vector files
vivek-arte Aug 24, 2024
ede0e0a
changing txn version back to V6
vivek-arte Aug 26, 2024
de12205
resolving review comments
vivek-arte Sep 5, 2024
ea48161
renaming rho to nf_old in note_encryption files
vivek-arte Sep 17, 2024
0409263
making changes based on review
vivek-arte Sep 18, 2024
0d1e967
further changes
vivek-arte Sep 18, 2024
1d936d1
adding Offsets class, other review changes
vivek-arte Sep 18, 2024
737b366
removing redundant import
vivek-arte Sep 18, 2024
ff64cde
based on review comments
vivek-arte Sep 19, 2024
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
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,4 @@ orchard_zsa_asset_base="zcash_test_vectors.orchard_zsa.asset_base:main"
orchard_zsa_issuance_auth_sig="zcash_test_vectors.orchard_zsa.issuance_auth_sig:main"
orchard_zsa_key_components = "zcash_test_vectors.orchard_zsa.key_components:main"
orchard_zsa_note_encryption = "zcash_test_vectors.orchard_zsa.note_encryption:main"
orchard_zsa_digests = "zcash_test_vectors.transaction_zsa:main"
1 change: 1 addition & 0 deletions regenerate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ tv_scripts=(
zip_0143
zip_0243
zip_0244
orchard_zsa_digests
zip_0316
zip_0320)

Expand Down
40 changes: 20 additions & 20 deletions test-vectors/json/orchard_zsa_asset_base.json

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions test-vectors/json/orchard_zsa_digests.json

Large diffs are not rendered by default.

20 changes: 10 additions & 10 deletions test-vectors/json/zip_0244.json

Large diffs are not rendered by default.

118 changes: 59 additions & 59 deletions test-vectors/rust/orchard_zsa_asset_base.rs

Large diffs are not rendered by default.

445 changes: 445 additions & 0 deletions test-vectors/rust/orchard_zsa_digests.rs

Large diffs are not rendered by default.

264 changes: 114 additions & 150 deletions test-vectors/rust/zip_0244.rs

Large diffs are not rendered by default.

40 changes: 20 additions & 20 deletions test-vectors/zcash/orchard_zsa_asset_base.json

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions test-vectors/zcash/orchard_zsa_digests.json

Large diffs are not rendered by default.

20 changes: 10 additions & 10 deletions test-vectors/zcash/zip_0244.json

Large diffs are not rendered by default.

14 changes: 6 additions & 8 deletions zcash_test_vectors/orchard_zsa/asset_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from hashlib import blake2b
from ..orchard.group_hash import group_hash
from ..output import render_args, render_tv, option
from ..output import render_args, render_tv


def native_asset():
Expand All @@ -29,13 +29,11 @@ def zsa_value_base(asset_digest_value):
return group_hash(b"z.cash:OrchardZSA", asset_digest_value)


def get_random_unicode_bytes(length):
try:
get_char = unichr
except NameError:
get_char = chr
def get_random_unicode_bytes(length, rand):
vivek-arte marked this conversation as resolved.
Show resolved Hide resolved

random.seed(0xabad533d)
get_char = chr

random.seed(rand.u8())
PaulLaux marked this conversation as resolved.
Show resolved Hide resolved

# Update this to include code point ranges to be sampled
include_ranges = [
Expand Down Expand Up @@ -84,7 +82,7 @@ def randbytes(l):
isk = IssuanceKeys(rand.b(32))

key_bytes = bytes(isk.ik)
description_bytes = get_random_unicode_bytes(512)
description_bytes = get_random_unicode_bytes(512, rand)
asset_base = zsa_value_base(asset_digest(encode_asset_id(key_bytes, description_bytes)))

test_vectors.append({
Expand Down
60 changes: 60 additions & 0 deletions zcash_test_vectors/orchard_zsa/digests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/usr/bin/env python3
import sys; assert sys.version_info[0] >= 3, "Python 3 required."

from hashlib import blake2b
import struct

NU7_VERSION_GROUP_ID = 0x124A69F8
NU7_TX_VERSION = 6


def orchard_zsa_burn_digest(tx):
digest = blake2b(digest_size=32, person=b'ZTxIdOrcBurnHash')

if len(tx.vAssetBurnOrchardZSA) > 0:
for desc in tx.vAssetBurnOrchardZSA:
digest.update(bytes(desc.assetBase))
digest.update(struct.pack('<Q', desc.valueBurn))

return digest.digest()


def issuance_digest(tx):
digest = blake2b(digest_size=32, person=b'ZTxIdSAIssueHash')

if len(tx.vIssueActions) > 0:
digest.update(issue_actions_digest(tx))
digest.update(tx.ik)

return digest.digest()


def issuance_auth_digest(tx):
digest = blake2b(digest_size=32, person=b'ZTxAuthZSAOrHash')
if len(tx.vIssueActions) > 0:
digest.update(tx.issueAuthSig)
return digest.digest()


def issue_actions_digest(tx):
digest = blake2b(digest_size=32, person=b'ZTxIdIssuActHash')

for action in tx.vIssueActions:
digest.update(issue_notes_digest(action))
digest.update(action.asset_desc)
digest.update(struct.pack('<B', action.flagsIssuance))

return digest.digest()


def issue_notes_digest(action):
digest = blake2b(digest_size=32, person=b'ZTxIdIAcNoteHash')

for note in action.vNotes:
digest.update(bytes(note.recipient))
digest.update(struct.pack('<Q', note.value))
digest.update(bytes(note.assetBase))
digest.update(bytes(note.rho))
digest.update(note.rseed)

return digest.digest()
75 changes: 50 additions & 25 deletions zcash_test_vectors/transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,16 +158,16 @@ def __bytes__(self):
bytes(self.proof)
)

class OrchardActionDescription(object):
def __init__(self, rand):
class OrchardActionBase(object):
def __init__(self, enc_ciphertext_size, rand):
# We don't need to take account of whether this is a coinbase transaction,
# because we're only generating random fields.
self.cv = pallas_group_hash(b'TVRandPt', rand.b(32))
self.nullifier = PallasBase(leos2ip(rand.b(32)))
self.rk = pallas_group_hash(b'TVRandPt', rand.b(32))
self.cmx = PallasBase(leos2ip(rand.b(32)))
self.ephemeralKey = pallas_group_hash(b'TVRandPt', rand.b(32))
self.encCiphertext = rand.b(ZC_SAPLING_ENCCIPHERTEXT_SIZE)
self.encCiphertext = rand.b(enc_ciphertext_size)
self.outCiphertext = rand.b(ZC_SAPLING_OUTCIPHERTEXT_SIZE)
self.spendAuthSig = RedPallasSignature(rand)

Expand All @@ -182,6 +182,10 @@ def __bytes__(self):
self.outCiphertext
)

class OrchardActionDescription(OrchardActionBase):
def __init__(self, rand):
super().__init__(ZC_SAPLING_ENCCIPHERTEXT_SIZE, rand)

class JoinSplit(object):
def __init__(self, rand, fUseGroth = False):
self.vpub_old = 0
Expand Down Expand Up @@ -411,20 +415,17 @@ def __bytes__(self):

return ret


class TransactionV5(object):
def __init__(self, rand, consensus_branch_id):
# Creating a base transaction class with common fields that V5 and subsequent versions can inherit.
class TransactionBase(object):
def __init__(self, rand, have_orchard=True):
# Decide which transaction parts will be generated.
flip_coins = rand.u8()
have_transparent_in = (flip_coins >> 0) % 2
have_transparent_out = (flip_coins >> 1) % 2
have_sapling = (flip_coins >> 2) % 2
have_orchard = (flip_coins >> 3) % 2
is_coinbase = (not have_transparent_in) and (flip_coins >> 4) % 2

# Common Transaction Fields
self.nVersionGroupId = NU5_VERSION_GROUP_ID
self.nConsensusBranchId = consensus_branch_id
self.nLockTime = rand.u32()
self.nExpiryHeight = rand.u32() % TX_EXPIRY_HEIGHT_THRESHOLD

Expand Down Expand Up @@ -462,15 +463,9 @@ def __init__(self, rand, consensus_branch_id):
# v^balanceSapling is defined to be 0.
self.valueBalanceSapling = 0

# Orchard Transaction Fields
# Orchard Transaction Fields that are present in both V5 and V6
self.vActionsOrchard = []
if have_orchard:
for _ in range(rand.u8() % 5):
self.vActionsOrchard.append(OrchardActionDescription(rand))
self.flagsOrchard = rand.u8() & 3 # Only two flag bits are currently defined.
if is_coinbase:
# set enableSpendsOrchard = 0
self.flagsOrchard &= 2
self.valueBalanceOrchard = rand.u64() % (MAX_MONEY + 1)
self.anchorOrchard = PallasBase(leos2ip(rand.b(32)))
self.proofsOrchard = rand.b(rand.u8() + 32) # Proof will always contain at least one element
Expand All @@ -482,21 +477,17 @@ def __init__(self, rand, consensus_branch_id):

assert is_coinbase == self.is_coinbase()

def version_bytes(self):
return NU5_TX_VERSION | (1 << 31)

def is_coinbase(self):
# <https://github.com/zcash/zcash/blob/d8c818bfa507adb845e527f5beb38345c490b330/src/primitives/transaction.h#L969-L972>
return len(self.vin) == 1 and bytes(self.vin[0].prevout.txid) == b'\x00'*32 and self.vin[0].prevout.n == 0xFFFFFFFF

# TODO: Update ZIP 225 to document endianness
def __bytes__(self):
def to_bytes(self, version_bytes, nVersionGroupId, nConsensusBranchId):
ret = b''

# Common Transaction Fields
ret += struct.pack('<I', self.version_bytes())
ret += struct.pack('<I', self.nVersionGroupId)
ret += struct.pack('<I', self.nConsensusBranchId)
ret += struct.pack('<I', version_bytes)
ret += struct.pack('<I', nVersionGroupId)
ret += struct.pack('<I', nConsensusBranchId)
ret += struct.pack('<I', self.nLockTime)
ret += struct.pack('<I', self.nExpiryHeight)

Expand Down Expand Up @@ -545,10 +536,44 @@ def __bytes__(self):
ret += self.proofsOrchard
for desc in self.vActionsOrchard:
ret += bytes(desc.spendAuthSig)
ret += bytes(self.bindingSigOrchard)

return ret

class TransactionV5(TransactionBase):
def __init__(self, rand, consensus_branch_id):
have_orchard = rand.bool()
# All Transparent, Sapling, and part of the Orchard Transaction Fields are initialized in the super class.
super().__init__(rand, have_orchard)

# Common Transaction Fields
self.nVersionGroupId = NU5_VERSION_GROUP_ID
self.nConsensusBranchId = consensus_branch_id

# Orchard Transaction Fields
if have_orchard:
for _ in range(rand.u8() % 5):
self.vActionsOrchard.append(OrchardActionDescription(rand))
self.flagsOrchard = rand.u8()
self.flagsOrchard &= 3 # Only two flag bits are currently defined.
if self.is_coinbase():
# set enableSpendsOrchard = 0
self.flagsOrchard &= 2

@staticmethod
def version_bytes():
return NU5_TX_VERSION | (1 << 31)

def __bytes__(self):
ret = b''

# Fields that are in TransactionBase: Common, Transparent, Sapling, most Orchard
ret += super().to_bytes(self.version_bytes(), self.nVersionGroupId, self.nConsensusBranchId)

# Orchard remaining Transaction Fields (if the Orchard bundle exists)
if len(self.vActionsOrchard) > 0:
PaulLaux marked this conversation as resolved.
Show resolved Hide resolved
ret += bytes(self.bindingSigOrchard)

return ret

class Transaction(object):
def __init__(self, rand, version, consensus_branch_id=None):
Expand Down
Loading
Loading