From eecdca44327db1063dd012f71fc0bfa6bcc0cbba Mon Sep 17 00:00:00 2001 From: Mostafa Date: Wed, 18 Jun 2025 16:33:31 +0800 Subject: [PATCH 1/4] feat: add signature and public key for transactions --- examples/example_transfer_transaction_bls.py | 9 +++++++-- examples/example_transfer_transaction_ed25519.py | 6 ++++++ pactus/transaction/transaction.py | 10 ++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/examples/example_transfer_transaction_bls.py b/examples/example_transfer_transaction_bls.py index f03d86f..9b9bc8e 100644 --- a/examples/example_transfer_transaction_bls.py +++ b/examples/example_transfer_transaction_bls.py @@ -18,12 +18,17 @@ def main() -> None: sec = PrivateKey.from_string( "TSECRET1PZF33H72N9PHXZATY5URH5SS4M33VVDFAWYVESL5JTLT9A00TNWKQYNGM6Z" ) + pub = sec.public_key() tx = Transaction.create_transfer_tx(lock_time, sender, receiver, amount, fee, memo) - signed_tx = tx.sign(sec) + signed_data = tx.sign(sec) - print(f"Signed transaction hex: {signed_tx.hex()}") + if pub.verify(bytes(tx.sign_bytes()), tx.signature): + print("Signature verification succeeded") + else: + print("Signature verification failed") + print(f"Signed transaction hex: {signed_data.hex()}") if __name__ == "__main__": main() diff --git a/examples/example_transfer_transaction_ed25519.py b/examples/example_transfer_transaction_ed25519.py index f1c9d5a..c913257 100644 --- a/examples/example_transfer_transaction_ed25519.py +++ b/examples/example_transfer_transaction_ed25519.py @@ -18,10 +18,16 @@ def main() -> None: sec = PrivateKey.from_string( "TSECRET1RGLSGPYLQRVET27AZUVS9TSP8MPGF9LH4U4RKKARMCATFK9L0KUCS7DCC09" ) + pub = sec.public_key() tx = Transaction.create_transfer_tx(lock_time, sender, receiver, amount, fee, memo) signed_tx = tx.sign(sec) + if pub.verify(bytes(tx.sign_bytes()), tx.signature): + print("Signature verification succeeded") + else: + print("Signature verification failed") + print(f"Signed transaction hex: {signed_tx.hex()}") diff --git a/pactus/transaction/transaction.py b/pactus/transaction/transaction.py index 55e82fe..367b876 100644 --- a/pactus/transaction/transaction.py +++ b/pactus/transaction/transaction.py @@ -1,7 +1,9 @@ from pactus.amount import Amount from pactus.crypto.address import Address from pactus.crypto.private_key import PrivateKey +from pactus.crypto.public_key import PublicKey from pactus.encoding import encoding +from pactus.crypto.signature import Signature from ._payload import ( BondPayload, @@ -11,6 +13,8 @@ WithdrawPayload, ) +FLAG_STRIPPED_PUBLIC_KEY = 0x01 +FLAG_NOT_SIGNED = 0x02 class Transaction: def __init__( @@ -26,6 +30,8 @@ def __init__( self.version = 1 self.fee = fee self.payload = payload + self.public_key: PublicKey = None + self.signature: Signature = None @classmethod def create_transfer_tx( @@ -129,4 +135,8 @@ def sign(self, private_key: PrivateKey) -> bytes: encoding.append_fixed_bytes(buf, sig.raw_bytes()) encoding.append_fixed_bytes(buf, pub.raw_bytes()) + self.public_key = pub + self.signature = sig + self.flags |= FLAG_NOT_SIGNED + return buf From 00d58eae45a386688c367129eebcf999a4800b33 Mon Sep 17 00:00:00 2001 From: Mostafa Date: Wed, 18 Jun 2025 17:00:25 +0800 Subject: [PATCH 2/4] chore: fix linting issues --- examples/example_transfer_transaction_bls.py | 1 + pactus/transaction/transaction.py | 3 ++- ruff.toml | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/example_transfer_transaction_bls.py b/examples/example_transfer_transaction_bls.py index 9b9bc8e..391c136 100644 --- a/examples/example_transfer_transaction_bls.py +++ b/examples/example_transfer_transaction_bls.py @@ -30,5 +30,6 @@ def main() -> None: print(f"Signed transaction hex: {signed_data.hex()}") + if __name__ == "__main__": main() diff --git a/pactus/transaction/transaction.py b/pactus/transaction/transaction.py index 367b876..fba2459 100644 --- a/pactus/transaction/transaction.py +++ b/pactus/transaction/transaction.py @@ -2,8 +2,8 @@ from pactus.crypto.address import Address from pactus.crypto.private_key import PrivateKey from pactus.crypto.public_key import PublicKey -from pactus.encoding import encoding from pactus.crypto.signature import Signature +from pactus.encoding import encoding from ._payload import ( BondPayload, @@ -16,6 +16,7 @@ FLAG_STRIPPED_PUBLIC_KEY = 0x01 FLAG_NOT_SIGNED = 0x02 + class Transaction: def __init__( self, diff --git a/ruff.toml b/ruff.toml index a0c12b8..f1755b6 100644 --- a/ruff.toml +++ b/ruff.toml @@ -51,6 +51,7 @@ ignore = [ "D107", "D203", "D212", + "TC001", "COM812", "ISC001", "D205", From 3f55c031f5d0f0ade58e73002537f9c13657482a Mon Sep 17 00:00:00 2001 From: Mostafa Date: Mon, 23 Jun 2025 16:19:01 +0800 Subject: [PATCH 3/4] chore: fix linting issues --- pactus/amount.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pactus/amount.py b/pactus/amount.py index d7f492d..def8a40 100644 --- a/pactus/amount.py +++ b/pactus/amount.py @@ -26,6 +26,9 @@ def __eq__(self, other: "Amount") -> bool: return False + def __hash__(self) -> int: + return hash(self.value) + @classmethod def from_nano_pac(cls, a: int) -> "Amount": """Store the value as NanoPAC in the Amount instance.""" From cec8f5cf48624ab993f9db287293b53cf71ec949 Mon Sep 17 00:00:00 2001 From: Mostafa Date: Mon, 23 Jun 2025 16:38:38 +0800 Subject: [PATCH 4/4] test: error on signature verification --- examples/example_transfer_transaction_bls.py | 5 ++--- examples/example_transfer_transaction_ed25519.py | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/examples/example_transfer_transaction_bls.py b/examples/example_transfer_transaction_bls.py index 391c136..e590ee7 100644 --- a/examples/example_transfer_transaction_bls.py +++ b/examples/example_transfer_transaction_bls.py @@ -23,10 +23,9 @@ def main() -> None: tx = Transaction.create_transfer_tx(lock_time, sender, receiver, amount, fee, memo) signed_data = tx.sign(sec) - if pub.verify(bytes(tx.sign_bytes()), tx.signature): - print("Signature verification succeeded") - else: + if not pub.verify(bytes(tx.sign_bytes()), tx.signature): print("Signature verification failed") + exit(1) print(f"Signed transaction hex: {signed_data.hex()}") diff --git a/examples/example_transfer_transaction_ed25519.py b/examples/example_transfer_transaction_ed25519.py index c913257..f2b190b 100644 --- a/examples/example_transfer_transaction_ed25519.py +++ b/examples/example_transfer_transaction_ed25519.py @@ -23,10 +23,9 @@ def main() -> None: tx = Transaction.create_transfer_tx(lock_time, sender, receiver, amount, fee, memo) signed_tx = tx.sign(sec) - if pub.verify(bytes(tx.sign_bytes()), tx.signature): - print("Signature verification succeeded") - else: + if not pub.verify(bytes(tx.sign_bytes()), tx.signature): print("Signature verification failed") + exit(1) print(f"Signed transaction hex: {signed_tx.hex()}")