Skip to content
This repository has been archived by the owner on Nov 19, 2024. It is now read-only.

[FINAL] Management canister API for tSchnorr signatures #288

Merged
merged 10 commits into from
Jul 23, 2024
30 changes: 30 additions & 0 deletions spec/_attachments/ic.did
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ type ecdsa_curve = variant {
secp256k1;
};

type schnorr_algorithm = variant {
bip340secp256k1;
ed25519;
};

fspreiss marked this conversation as resolved.
Show resolved Hide resolved
type satoshi = nat64;

type bitcoin_network = variant {
Expand Down Expand Up @@ -284,6 +289,27 @@ type sign_with_ecdsa_result = record {
signature : blob;
};

type schnorr_public_key_args = record {
canister_id : opt canister_id;
derivation_path : vec blob;
key_id : record { algorithm : schnorr_algorithm; name : text };
};

type schnorr_public_key_result = record {
public_key : blob;
chain_code : blob;
};

type sign_with_schnorr_args = record {
message : blob;
derivation_path : vec blob;
key_id : record { algorithm : schnorr_algorithm; name : text };
};

type sign_with_schnorr_result = record {
signature : blob;
};

type node_metrics_history_args = record {
subnet_id : principal;
start_at_timestamp_nanos : nat64;
Expand Down Expand Up @@ -344,6 +370,10 @@ service ic : {
ecdsa_public_key : (ecdsa_public_key_args) -> (ecdsa_public_key_result);
sign_with_ecdsa : (sign_with_ecdsa_args) -> (sign_with_ecdsa_result);

// Threshold Schnorr signature
schnorr_public_key : (schnorr_public_key_args) -> (schnorr_public_key_result);
sign_with_schnorr : (sign_with_schnorr_args) -> (sign_with_schnorr_result);

// bitcoin interface
bitcoin_get_balance : (bitcoin_get_balance_args) -> (bitcoin_get_balance_result);
bitcoin_get_balance_query : (bitcoin_get_balance_query_args) -> (bitcoin_get_balance_query_result) query;
Expand Down
36 changes: 33 additions & 3 deletions spec/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2145,19 +2145,49 @@ This method takes no input and returns 32 pseudo-random bytes to the caller. The

### IC method `ecdsa_public_key` {#ic-ecdsa_public_key}

This method returns a [SEC1](https://www.secg.org/sec1-v2.pdf) encoded ECDSA public key for the given canister using the given derivation path. If the `canister_id` is unspecified, it will default to the canister id of the caller. The `derivation_path` is a vector of variable length byte strings. Each byte string may be of arbitrary length, including empty. The total number of byte strings in the `derivation_path` must be at most 255. The `key_id` is a struct specifying both a curve and a name. The availability of a particular `key_id` depends on implementation.
This method returns a [SEC1](https://www.secg.org/sec1-v2.pdf) encoded ECDSA public key for the given canister using the given derivation path. If the `canister_id` is unspecified, it will default to the canister id of the caller. The `derivation_path` is a vector of variable length byte strings. Each byte string may be of arbitrary length, including empty. The total number of byte strings in the `derivation_path` must be at most 255. The `key_id` is a struct specifying both a curve and a name. The availability of a particular `key_id` depends on the implementation.

For curve `secp256k1`, the public key is derived using a generalization of BIP32 (see [ia.cr/2021/1330, Appendix D](https://ia.cr/2021/1330)). To derive (non-hardened) [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)-compatible public keys, each byte string (`blob`) in the `derivation_path` must be a 4-byte big-endian encoding of an unsigned integer less than 2<sup>31</sup>. If the `derivation_path` contains a byte string that is not a 4-byte big-endian encoding of an unsigned integer less than 2<sup>31</sup>, then a derived public key will be returned, but that key derivation process will not be compatible with the [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) standard.

The return result is an extended public key consisting of an ECDSA `public_key`, encoded in [SEC1](https://www.secg.org/sec1-v2.pdf) compressed form, and a `chain_code`, which can be used to deterministically derive child keys of the `public_key`.
The return value is an extended public key consisting of an ECDSA `public_key`, encoded in [SEC1](https://www.secg.org/sec1-v2.pdf) compressed form, and a `chain_code`, which can be used to deterministically derive child keys of the `public_key`.

This call requires that an ECDSA key with ID `key_id` was generated by the IC. Otherwise, the call is rejected.

### IC method `sign_with_ecdsa` {#ic-sign_with_ecdsa}

This method returns a new [ECDSA](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf) signature of the given `message_hash` that can be separately verified against a derived ECDSA public key. This public key can be obtained by calling `ecdsa_public_key` with the caller's `canister_id`, and the same `derivation_path` and `key_id` used here.

The signatures are encoded as the concatenation of the [SEC1](https://www.secg.org/sec1-v2.pdf) encodings of the two values r and s. For curve `secp256k1`, this corresponds to 32-byte big-endian encoding.

This call requires that the ECDSA feature is enabled, the caller is a canister, and `message_hash` is 32 bytes long. Otherwise it will be rejected.
This call requires that an ECDSA key with ID `key_id` was generated by the IC, the signing functionality for that key was enabled, the caller is a canister, and `message_hash` is 32 bytes long. Otherwise, the call is is rejected.

### IC method `schnorr_public_key` {#ic-schnorr_public_key}

This method returns a (derived) Schnorr public key for the given canister using the given derivation path. If the `canister_id` is unspecified, it will default to the canister id of the caller. The `derivation_path` is a vector of variable length byte strings. Each byte string may be of arbitrary length, including empty. The total number of byte strings in the `derivation_path` must be at most 255. The `key_id` is a struct specifying both an algorithm and a name. The availability of a particular `key_id` depends on the implementation.

The return value is an extended Schnorr public key consisting of a Schnorr `public_key` and a `chain_code`. The chain code can be used to deterministically derive child keys of the `public_key`. Both the derivation and the encoding of the public key depends on the key ID's `algorithm`:

- For algorithm `bip340secp256k1`, the public key is derived using the generalization of BIP32 defined in [ia.cr/2021/1330, Appendix D](https://ia.cr/2021/1330). To derive (non-hardened) [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)-compatible public keys, each byte string (`blob`) in the `derivation_path` must be a 4-byte big-endian encoding of an unsigned integer less than 2<sup>31</sup>. If the `derivation_path` contains a byte string that is not a 4-byte big-endian encoding of an unsigned integer less than 2<sup>31</sup>, then a derived public key will be returned, but that key derivation process will not be compatible with the [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) standard.

The public key is encoded in [SEC1](https://www.secg.org/sec1-v2.pdf) compressed form. To use BIP32 public keys to verify BIP340 Schnorr signatures, the first byte of the (33-byte) SEC1-encoded public key must be removed (see [BIP-340, Public Key Conversion](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki#public-key-conversion)).

- For algorithm `ed25519`, the public key is derived using the [Ed25519 hierarchical key derivation scheme specified in the Internet Computer Developer Docs](https://2xf6o-laaaa-aaaam-abrla-cai.icp0.io/docs/current/references/t-schnorr-how-it-works#ed25519-hierarchical-key-derivation).

The public key is encoded in standard 32-byte compressed form (see [RFC8032, 5.1.2 Encoding](https://datatracker.ietf.org/doc/html/rfc8032#section-5.1.2)).

This call requires that a Schnorr key with ID `key_id` was generated by the IC. Otherwise, the call is rejected.

### IC method `sign_with_schnorr` {#ic-sign_with_schnorr}

This method returns a Schnorr signature of the given `message` that can be verified against a (derived) public key obtained by calling `schnorr_public_key` using the caller's `canister_id` and the given `derivation_path` and `key_id`.

The encoding of the signature depends on the key ID's `algorithm`:

- For algorithm `bip340secp256k1`, the signature is encoded in 64 bytes according to [BIP340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki).

- For algorithm `ed25519`, the signature is encoded in 64 bytes according to [RFC8032, 5.1.6 Sign](https://datatracker.ietf.org/doc/html/rfc8032#section-5.1.6).

This call requires that a Schnorr key with ID `key_id` was generated by the IC, the signing functionality for that key was enabled, and the caller is a canister. Otherwise, the call is is rejected.

### IC method `http_request` {#ic-http_request}

Expand Down
Loading