1
1
from typing import Optional , Union
2
2
3
+ from cbor2 import CBORTag , dumps
3
4
from cose .algorithms import EdDSA
4
5
from cose .headers import KID , Algorithm
5
6
from cose .keys import CoseKey
10
11
from cose .messages import CoseMessage , Sign1Message
11
12
12
13
from pycardano .address import Address
14
+ from pycardano .crypto import BIP32ED25519PublicKey
13
15
from pycardano .key import (
16
+ ExtendedSigningKey ,
17
+ ExtendedVerificationKey ,
14
18
PaymentVerificationKey ,
15
19
SigningKey ,
16
20
StakeExtendedSigningKey ,
17
21
StakeSigningKey ,
18
22
StakeVerificationKey ,
19
- VerificationKey ,
20
23
)
21
24
from pycardano .network import Network
22
25
25
28
26
29
def sign (
27
30
message : str ,
28
- signing_key : SigningKey ,
31
+ signing_key : Union [ ExtendedSigningKey , SigningKey ] ,
29
32
attach_cose_key : bool = False ,
30
33
network : Network = Network .MAINNET ,
31
34
) -> Union [str , dict ]:
@@ -45,7 +48,9 @@ def sign(
45
48
"""
46
49
47
50
# derive the verification key
48
- verification_key = VerificationKey .from_signing_key (signing_key )
51
+ verification_key = signing_key .to_verification_key ()
52
+ if isinstance (verification_key , ExtendedVerificationKey ):
53
+ verification_key = verification_key .to_non_extended ()
49
54
50
55
if isinstance (signing_key , StakeSigningKey ) or isinstance (
51
56
signing_key , StakeExtendedSigningKey
@@ -85,7 +90,20 @@ def sign(
85
90
86
91
msg .key = cose_key # attach the key to the message
87
92
88
- encoded = msg .encode ()
93
+ if isinstance (signing_key , ExtendedSigningKey ):
94
+ _message = [
95
+ msg .phdr_encoded ,
96
+ msg .uhdr_encoded ,
97
+ msg .payload ,
98
+ signing_key .sign (msg ._sig_structure ),
99
+ ]
100
+
101
+ encoded = dumps (
102
+ CBORTag (msg .cbor_tag , _message ), default = msg ._custom_cbor_encoder
103
+ )
104
+
105
+ else :
106
+ encoded = msg .encode ()
89
107
90
108
# turn the enocded message into a hex string and remove the first byte
91
109
# which is always "d2"
@@ -108,7 +126,8 @@ def sign(
108
126
109
127
110
128
def verify (
111
- signed_message : Union [str , dict ], attach_cose_key : Optional [bool ] = None
129
+ signed_message : Union [str , dict ],
130
+ attach_cose_key : Optional [bool ] = None ,
112
131
) -> dict :
113
132
"""Verify the signature of a COSESign1 message and decode its contents following CIP-0008.
114
133
Supports messages signed by browser wallets or `Message.sign()`.
@@ -175,7 +194,16 @@ def verify(
175
194
# attach the key to the decoded message
176
195
decoded_message .key = cose_key
177
196
178
- signature_verified = decoded_message .verify_signature ()
197
+ if len (verification_key ) > 32 :
198
+ vk = BIP32ED25519PublicKey (
199
+ public_key = verification_key [:32 ], chain_code = verification_key [32 :]
200
+ )
201
+ vk .verify (
202
+ signature = decoded_message .signature , message = decoded_message ._sig_structure
203
+ )
204
+ signature_verified = True
205
+ else :
206
+ signature_verified = decoded_message .verify_signature ()
179
207
180
208
message = decoded_message .payload .decode ("utf-8" )
181
209
0 commit comments