11"""Transaction building and parsing for the Zero Network.
22
3- Transaction format (100 bytes total):
4- from_pubkey[32] + to_pubkey[32] + amount[4] + nonce[4] + signature[28 ]
3+ Transaction format (136 bytes total):
4+ from_pubkey[32] + to_pubkey[32] + amount[4] + nonce[4] + signature[64 ]
55
6- The signature covers the first 72 bytes (from + to + amount + nonce) and is
7- truncated to 28 bytes from the standard Ed25519 64-byte signature. This matches
8- the wire format used by the Zero Network's Rust/tweetnacl implementations .
6+ The Ed25519 signature covers the first 72 bytes (from + to + amount + nonce).
7+ The full 64-byte signature is appended, matching the wire format required by
8+ the Zero Network validators .
99"""
1010
1111from __future__ import annotations
@@ -71,17 +71,17 @@ def build_transfer(
7171
7272
7373def sign_transfer (unsigned_tx : bytes , signing_key : SigningKey ) -> bytes :
74- """Sign an unsigned transaction and return the complete 100 -byte tx.
74+ """Sign an unsigned transaction and return the complete 136 -byte tx.
7575
76- The Ed25519 signature is computed over the 72-byte unsigned payload,
77- then truncated to 28 bytes to fit the wire format .
76+ The Ed25519 signature is computed over the 72-byte unsigned payload.
77+ The full 64-byte signature is appended .
7878
7979 Args:
8080 unsigned_tx: 72-byte unsigned transaction from build_transfer().
8181 signing_key: Ed25519 signing key (nacl.signing.SigningKey).
8282
8383 Returns:
84- 100 -byte signed transaction ready for submission.
84+ 136 -byte signed transaction ready for submission.
8585
8686 Raises:
8787 ValueError: If unsigned_tx is not 72 bytes.
@@ -90,33 +90,35 @@ def sign_transfer(unsigned_tx: bytes, signing_key: SigningKey) -> bytes:
9090 raise ValueError (f"unsigned_tx must be 72 bytes, got { len (unsigned_tx )} " )
9191
9292 signed = signing_key .sign (unsigned_tx )
93- # signed.signature is the 64-byte Ed25519 signature
94- # Truncate to 28 bytes for the wire format
95- sig_truncated = signed .signature [:28 ]
96-
97- return unsigned_tx + sig_truncated
93+ # signed.signature is the full 64-byte Ed25519 signature
94+ return unsigned_tx + signed .signature
9895
9996
10097def parse_transfer (tx_bytes : bytes ) -> Transfer :
101- """Parse a 100-byte transaction into its components.
98+ """Parse a signed transaction into its components.
99+
100+ Accepts 136-byte (full signature) or 100-byte (legacy) format.
102101
103102 Args:
104- tx_bytes: 100-byte signed transaction.
103+ tx_bytes: Signed transaction bytes .
105104
106105 Returns:
107106 Transfer dataclass with parsed fields.
108107
109108 Raises:
110- ValueError: If tx_bytes is not 100 bytes.
109+ ValueError: If tx_bytes is not 136 or 100 bytes.
111110 """
112- if len (tx_bytes ) != TX_SIZE :
113- raise ValueError (f"tx_bytes must be { TX_SIZE } bytes, got { len (tx_bytes )} " )
111+ LEGACY_TX_SIZE = 100
112+ if len (tx_bytes ) != TX_SIZE and len (tx_bytes ) != LEGACY_TX_SIZE :
113+ raise ValueError (
114+ f"tx_bytes must be { TX_SIZE } or { LEGACY_TX_SIZE } bytes, got { len (tx_bytes )} "
115+ )
114116
115117 from_pubkey = tx_bytes [0 :32 ]
116118 to_pubkey = tx_bytes [32 :64 ]
117119 amount_units = struct .unpack ("<I" , tx_bytes [64 :68 ])[0 ]
118120 nonce = struct .unpack ("<I" , tx_bytes [68 :72 ])[0 ]
119- signature = tx_bytes [72 :100 ]
121+ signature = tx_bytes [72 :]
120122
121123 return Transfer (
122124 from_pubkey = from_pubkey ,
0 commit comments