Summary
CIP-30 signData returns a DataSignature of { signature, key }, where key is the CBOR-encoded COSE_Key needed to verify the signature. SignData.signData produces both, but the wallet's signMessage returns only { payload, signature } and drops the key, and the SignedMessage interface has no key field. A consumer therefore cannot verify a message signed via the wallet API without obtaining the public key some other way, which breaks self-contained CIP-30 verification. No security impact: the dropped value is a public key, so nothing is leaked or made forgeable — it is a functional / spec-compliance gap.
Affected
packages/evolution/src/sdk/client/internal/Signing.ts
- signMessage (L363-381): returns
{ payload, signature } at L380, dropping signed.key
packages/evolution/src/sdk/wallet/Wallet.ts
- SignedMessage interface (L37-39): has payload + signature, no
key
contrast: packages/evolution/src/cose/SignData.ts SignedMessage (L39-41) already carries { signature, key }
Fix
Add a key field to the wallet SignedMessage interface and return Bytes.toHex(signed.key) from signMessage. Ensure the CIP-30 api-wallet path carries the key through as well, so both wallet types return a complete DataSignature.
Regression test
- given: a message signed via
wallet.signMessage
- before fix: result has no
key field; verifyData cannot be called without externally supplying the public key
- after fix: result includes the COSE_Key hex, and
verifyData(address, keyHash, payload, { signature, key }) verifies
Must FAIL on main today and PASS after the fix.
Reference
Reported informally (signMessage drops COSE_Key). Standard basis: CIP-30 DataSignature = { signature, key }.
Summary
CIP-30
signDatareturns aDataSignatureof{ signature, key }, wherekeyis the CBOR-encoded COSE_Key needed to verify the signature.SignData.signDataproduces both, but the wallet'ssignMessagereturns only{ payload, signature }and drops the key, and theSignedMessageinterface has nokeyfield. A consumer therefore cannot verify a message signed via the wallet API without obtaining the public key some other way, which breaks self-contained CIP-30 verification. No security impact: the dropped value is a public key, so nothing is leaked or made forgeable — it is a functional / spec-compliance gap.Affected
packages/evolution/src/sdk/client/internal/Signing.ts
{ payload, signature }at L380, droppingsigned.keypackages/evolution/src/sdk/wallet/Wallet.ts
keycontrast: packages/evolution/src/cose/SignData.ts SignedMessage (L39-41) already carries
{ signature, key }Fix
Add a
keyfield to the walletSignedMessageinterface and returnBytes.toHex(signed.key)fromsignMessage. Ensure the CIP-30 api-wallet path carries the key through as well, so both wallet types return a complete DataSignature.Regression test
wallet.signMessagekeyfield;verifyDatacannot be called without externally supplying the public keyverifyData(address, keyHash, payload, { signature, key })verifiesMust FAIL on main today and PASS after the fix.
Reference
Reported informally (signMessage drops COSE_Key). Standard basis: CIP-30 DataSignature =
{ signature, key }.