Skip to content

Commit d1cea43

Browse files
CIP-0008: Allow for signing with stake key directly
In the browser, if a user specifies the stake key as part of CIP-0030 the message returned in JSON has the COSE key as the staking key. The verify() method correctly detects this, but the sign() method does not. This change detects if a stake SigningKey type was passed in and if so, sign with a stake key. Sample behavior: [00:28:29 01/24 thaddeuss-mbp] hacker:~/workspaces/wildtangz/cardano-vending-machine$ python3 Python 3.8.1 (v3.8.1:1b293b6006, Dec 18 2019, 14:08:53) [Clang 6.0 (clang-600.0.57)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import pycardano >>> skey = pycardano.key.StakeSigningKey.load('/var/folders/qz/ldnst4y96_z436s0ptw0vyp40000gn/T/cardano-vm-test-eobtvu6g/buyers/buyer.stake.skey') >>> sign_addr = pycardano.cip.cip8.verify(pycardano.cip.cip8.sign('hello', skey, attach_cose_key=False, network=pycardano.network.Network.TESTNET))['signing_address'] >>> sign_addr stake_test1uq5xgs974dna05tjc5pr8sfq5cc4hzludaz7z4e4vpx6p0gkrzzmd The old behavior resulted in output of 'addr_test1vq5xgs974dna05tjc5pr8sfq5cc4hzludaz7z4e4vpx6p0gktu6v8' [ Documentation: pydoc updates ] [ Testing: python -m build, manual test in CLI ] [ Code Review: #154 ]
1 parent 3527aa4 commit d1cea43

File tree

2 files changed

+66
-3
lines changed

2 files changed

+66
-3
lines changed

pycardano/cip/cip8.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
from pycardano.key import (
1414
PaymentVerificationKey,
1515
SigningKey,
16+
StakeExtendedSigningKey,
17+
StakeSigningKey,
1618
StakeVerificationKey,
1719
VerificationKey,
1820
)
@@ -27,7 +29,9 @@ def sign(
2729
attach_cose_key: bool = False,
2830
network: Network = Network.MAINNET,
2931
) -> Union[str, dict]:
30-
"""Sign an arbitrary message with a payment key following CIP-0008.
32+
"""Sign an arbitrary message with a payment or stake key following CIP-0008.
33+
Note that a stake key passed in must be of type StakeSigningKey or
34+
StakeExtendedSigningKey to be detected.
3135
3236
Args:
3337
message (str): Message to be signed
@@ -43,11 +47,16 @@ def sign(
4347
# derive the verification key
4448
verification_key = VerificationKey.from_signing_key(signing_key)
4549

50+
if isinstance(signing_key, StakeSigningKey) or isinstance(signing_key, StakeExtendedSigningKey):
51+
address = Address(payment_part=None, staking_part=verification_key.hash(), network=network)
52+
else:
53+
address = Address(payment_part=verification_key.hash(), staking_part=None, network=network)
54+
4655
# create the message object, attach verification key to the header
4756
msg = Sign1Message(
4857
phdr={
4958
Algorithm: EdDSA,
50-
"address": Address(verification_key.hash(), network=network).to_primitive(),
59+
"address": address.to_primitive(),
5160
},
5261
payload=message.encode("utf-8"),
5362
)

test/pycardano/test_cip8.py

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from pycardano.cip.cip8 import sign, verify
2-
from pycardano.key import PaymentSigningKey, PaymentVerificationKey
2+
from pycardano.key import PaymentSigningKey, PaymentVerificationKey, StakeSigningKey, StakeVerificationKey
33
from pycardano.network import Network
44

55
SK = PaymentSigningKey.from_json(
@@ -18,6 +18,22 @@
1818
}"""
1919
)
2020

21+
STAKE_SK = StakeSigningKey.from_json(
22+
"""{
23+
"type": "StakeSigningKeyShelley_ed25519",
24+
"description": "Stake Signing Key",
25+
"cborHex": "5820ff3a330df8859e4e5f42a97fcaee73f6a00d0cf864f4bca902bd106d423f02c0"
26+
}"""
27+
)
28+
29+
STAKE_VK = StakeVerificationKey.from_json(
30+
"""{
31+
"type": "StakeVerificationKeyShelley_ed25519",
32+
"description": "Stake Verification Key",
33+
"cborHex": "58205edaa384c658c2bd8945ae389edac0a5bd452d0cfd5d1245e3ecd540030d1e3c"
34+
}"""
35+
)
36+
2137

2238
def test_verify_message():
2339

@@ -75,6 +91,18 @@ def test_sign_message():
7591
)
7692

7793

94+
def test_sign_message_with_stake():
95+
96+
message = "Pycardano is cool."
97+
signed_message = sign(
98+
message, signing_key=STAKE_SK, attach_cose_key=False, network=Network.TESTNET
99+
)
100+
assert (
101+
signed_message
102+
== "84584da301276761646472657373581de04828a2dadba97ca9fd0cdc99975899470c219bdc0d828cfa6ddf6d690458205edaa384c658c2bd8945ae389edac0a5bd452d0cfd5d1245e3ecd540030d1e3ca166686173686564f452507963617264616e6f20697320636f6f6c2e5840ba1dd643f0d2e844f0509b1a7161ae4a3650f1d553fcc6e517020c5703acb70dfeea1014f2a1513baefaa2279cb151e8ff2dada6b51269cf33127d3c05829502"
103+
)
104+
105+
78106
def test_sign_message_cosy_key_separate():
79107

80108
message = "Pycardano is cool."
@@ -109,3 +137,29 @@ def test_sign_and_verify():
109137
assert verification["verified"]
110138
assert verification["message"] == "Pycardano is cool."
111139
assert verification["signing_address"].payment_part == VK.hash()
140+
141+
142+
def test_sign_and_verify_stake():
143+
144+
# try first with no cose key attached
145+
message = "Pycardano is cool."
146+
signed_message = sign(
147+
message, signing_key=STAKE_SK, attach_cose_key=False, network=Network.TESTNET
148+
)
149+
150+
verification = verify(signed_message)
151+
assert verification["verified"]
152+
assert verification["message"] == "Pycardano is cool."
153+
assert verification["signing_address"].payment_part == None
154+
assert verification["signing_address"].staking_part == STAKE_VK.hash()
155+
156+
# try again but attach cose key
157+
signed_message = sign(
158+
message, signing_key=STAKE_SK, attach_cose_key=True, network=Network.TESTNET
159+
)
160+
161+
verification = verify(signed_message)
162+
assert verification["verified"]
163+
assert verification["message"] == "Pycardano is cool."
164+
assert verification["signing_address"].payment_part == None
165+
assert verification["signing_address"].staking_part == STAKE_VK.hash()

0 commit comments

Comments
 (0)