Skip to content

Commit

Permalink
CIP-0030: update to api.signData() (#148)
Browse files Browse the repository at this point in the history
* CIP-0030: update to api.signData()

The current specification of signData() suffers from several issues:
1) There is no way to get the verification keys to verify the signature
   returned without prior knowledge
2) The specification did not completely say what would be returned, if
   it was merely hex-encoded bytes of the signature or what.
3) The COSE_Sign1/COSE_Sign object would need to be constructed
   identically on both the wallet and dApp side which was not covered by
   the spec

This update should address these as for 1) the COSE_Sign1 object returned is specified to contain in the `kid` header the verification key. 2) is resolved as well as we no longer have untyped bytes, and 3) is also resolved by nature of explicitly returning it.

The endpoint as a result is simpler and does not cover more complex
CIP-0008/COSE situations but these are likely not needed for dApps, and
if they ever are, it would be better to simply add in another endpoint
to cover them as this should cover the standard case for verifying
ownership of an address(and associated payment key) in a simpler way.

Other alterntives were previously discussed in the original CIP-0030 PR:
#88

* CIP-30 signData - add address protected header

* CIP30: data sign add COSEKey to return value and change kid header

* CIP30 data sign: Use Address instead of cbor<address>
  • Loading branch information
rooooooooob authored Mar 16, 2022
1 parent dbca318 commit 3672786
Showing 1 changed file with 32 additions and 9 deletions.
41 changes: 32 additions & 9 deletions CIP-0030/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ The API specified in this document will count as version 0.1.0 for version-check

## Data Types

### Address

A string represnting an address in either bech32 format, or hex-encoded bytes. All return types containing `Address` must return the bech32 format, but must accept either format for inputs.

### Bytes

A hex-encoded string of the corresponding bytes.
Expand All @@ -37,6 +41,15 @@ A hex-encoded string of the corresponding bytes.
A hex-encoded string representing [CBOR](https://tools.ietf.org/html/rfc7049) corresponding to `T` defined via [CDDL](https://tools.ietf.org/html/rfc8610) either inside of the [Shelley Mult-asset binary spec](https://github.com/input-output-hk/cardano-ledger-specs/blob/0738804155245062f05e2f355fadd1d16f04cd56/shelley-ma/shelley-ma-test/cddl-files/shelley-ma.cddl) or, if not present there, from the [CIP-0008 signing spec](https://github.com/cardano-foundation/CIPs/blob/master/CIP-0008/CIP-0008.md).
This representation was chosen when possible as it is consistent across the Cardano ecosystem and widely used by other tools, such as [cardano-serialization-lib](https://github.com/Emurgo/cardano-serialization-lib), which has support to encode every type in the binary spec as CBOR bytes.

### DataSignature

```
type DataSignature = {|
signature:cbor\<COSE_Sign1>,
key: cbor\<COSE_Key>,
|};
```

### TransactionUnspentOutput

If we have CBOR specified by the following CDDL referencing the Shelley-MA CDDL:
Expand Down Expand Up @@ -93,7 +106,6 @@ DataSignErrorCode {
ProofGeneration: 1,
AddressNotPK: 2,
UserDeclined: 3,
InvalidFormat: 4,
}
type DataSignError = {
code: DataSignErrorCode,
Expand All @@ -104,7 +116,6 @@ type DataSignError = {
* ProofGeneration - Wallet could not sign the data (e.g. does not have the secret key associated with the address)
* AddressNotPK - Address was not a P2PK address and thus had no SK associated with it.
* UserDeclined - User declined to sign the data
* InvalidFormat - If a wallet enforces data format requirements, this error signifies that the data did not conform to valid formats.

### PaginateError

Expand Down Expand Up @@ -203,25 +214,25 @@ Errors: `APIError`

Returns the total balance available of the wallet. This is the same as summing the results of `api.getUtxos()`, but it is both useful to dApps and likely already maintained by the implementing wallet in a more efficient manner so it has been included in the API as well.

### api.getUsedAddresses(paginate: Paginate = undefined): Promise\<cbor\<address>[]>
### api.getUsedAddresses(paginate: Paginate = undefined): Promise\<Address[]>

Errors: `APIError`

Returns a list of all used (included in some on-chain transaction) addresses controlled by the wallet. The results can be further paginated by `paginate` if it is not `undefined`.

### api.getUnusedAddresses(): Promise\<cbor\<address>[]>
### api.getUnusedAddresses(): Promise\<Address[]>

Errors: `APIError`

Returns a list of unused addresses controlled by the wallet.

### api.getChangeAddress(): Promise\<cbor\<address>>
### api.getChangeAddress(): Promise\<Address>

Errors: `APIError`

Returns an address owned by the wallet that should be used as a change address to return leftover assets during transaction creation back to the connected wallet. This can be used as a generic receive address as well.

### api.getRewardAddresses(): Promise\<cbor\<address>[]>
### api.getRewardAddresses(): Promise\<Address[]>

Errors: `APIError`

Expand All @@ -233,13 +244,25 @@ Errors: `APIError`, `TxSignError`

Requests that a user sign the unsigned portions of the supplied transaction. The wallet should ask the user for permission, and if given, try to sign the supplied body and return a signed transaction. If `partialSign` is true, the wallet only tries to sign what it can. If `partialSign` is false and the wallet could not sign the entire transaction, `TxSignError` shall be returned with the `ProofGeneration` code. Likewise if the user declined in either case it shall return the `UserDeclined` code. Only the portions of the witness set that were signed as a result of this call are returned to encourage dApps to verify the contents returned by this endpoint while building the final transaction.

### api.signData(addr: cbor\<address>, sigStructure: cbor\<Sig_structure>): Promise\<Bytes>
### api.signData(addr: Address, payload: Bytes): Promise\<DataSignature>

Errors: `APIError`, `DataSignError`

This endpoint is due to be updated/finalized soon, see [discussion in the initial PR](https://github.com/cardano-foundation/CIPs/pull/88#issuecomment-954436243).
This endpoint utilizes the [CIP-0008 signing spec](https://github.com/cardano-foundation/CIPs/blob/master/CIP-0008/CIP-0008.md) for standardization/safety reasons. It allows the dApp to request the user to sign a payload conforming to said spec. The user's consent should be requested and the message to sign shown to the user. The payment key from `addr` will be used for base, enterprise and pointer addresses to determine the EdDSA25519 key used. The staking key will be used for reward addresses. This key will be used to sign the `COSE_Sign1`'s `Sig_structure` with the following headers set:

* `alg` (1) - must be set to `EdDSA` (-8)
* `kid` (4) - Optional, if present must be set to the same value as in the `COSE_key` specified below. It is recommended to be set to the same value as in the `"address"` header.
* `"address"` - must be set to the raw binary bytes of the address as per the binary spec, without the CBOR binary wrapper tag

The payload is not hashed and no `external_aad` is used.

If the payment key for `addr` is not a P2Pk address then `DataSignError` will be returned with code `AddressNotPK`. `ProofGeneration` shall be returned if the wallet cannot generate a signature (i.e. the wallet does not own the requested payment private key), and `UserDeclined` will be returned if the user refuses the request. The return shall be a `DataSignature` with `signature` set to the hex-encoded CBOR bytes of the `COSE_Sign1` object specified above and `key` shall be the hex-encoded CBOR bytes of a `COSE_Key` structure with the following headers set:

This endpoint utilizes the [CIP-0008 signing spec](https://github.com/cardano-foundation/CIPs/blob/master/CIP-0008/CIP-0008.md) for standardization/safety reasons. It allows the dApp to request the user to sign data conforming to said spec. The user's consent should be requested and the details of `sig_structure` shown to them in an informative way. The Please refer to the CIP-0008 spec for details on how to construct the sig structure.
* `kty` (1) - must be set to `OKP` (1)
* `kid` (2) - Optional, if present must be set to the same value as in the `COSE_Sign1` specified above.
* `alg` (3) - must be set to `EdDSA` (-8)
* `crv` (-1) - must be set to `Ed25519` (6)
* `x` (-2) - must be set to the public key bytes of the key used to sign the `Sig_structure`

### api.submitTx(tx: cbor\<transaction>): Promise\<hash32>

Expand Down

0 comments on commit 3672786

Please sign in to comment.