You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
We present a minimal example canister smart contract for showcasing the [threshold ECDSA](https://internetcomputer.org/docs/current/developer-docs/integrations/t-ecdsa) API.
3
+
We present a minimal example canister smart contract for showcasing the [threshold ECDSA](https://internetcomputer.org/docs/building-apps/network-features/signatures/t-ecdsa) API.
4
4
5
5
The example canister is a signing oracle that creates ECDSA signatures with keys derived from an input string.
6
6
@@ -12,59 +12,13 @@ More specifically:
12
12
13
13
This tutorial gives a complete overview of the development, starting with downloading the [IC SDK](https://internetcomputer.org/docs/current/developer-docs/getting-started/install), up to the deployment and trying out the code on the IC mainnet.
14
14
15
-
> [!TIP]
16
-
> This walkthrough focuses on the version of the sample canister code written in [Motoko](https://internetcomputer.org/docs/current/developer-docs/backend/motoko/index.md) programming language, but no specific knowledge of Motoko is needed to follow along. There is also a [Rust](https://github.com/dfinity/examples/tree/master/rust/threshold-ecdsa) version available in the same repo and follows the same commands for deploying.
If you open the URL in a web browser, you will see a web UI that shows the public methods the canister exposes. Since the canister exposes `public_key` and `sign` methods, those are rendered in the web UI.
53
-
54
-
## Deploying the canister on the mainnet
55
-
56
-
To deploy this canister to the mainnet, one needs to do two things:
57
-
58
-
- Acquire cycles (the equivalent of "gas" on other blockchains). This is necessary for all canisters.
59
-
- Update the sample source code to have the right key ID. This is unique to this canister.
60
-
61
-
### Acquire cycles to deploy
62
-
63
-
Deploying to the Internet Computer requires [cycles](https://internetcomputer.org/docs/current/developer-docs/getting-started/tokens-and-cycles) (the equivalent of "gas" on other blockchains).
64
-
65
-
### Update source code with the right key ID
66
-
67
-
To deploy the sample code, the canister needs the right key ID for the right environment. Specifically, one needs to replace the value of the `key_id` in the `src/ecdsa_example_motoko/main.mo` file of the sample code. Before deploying to the mainnet, one should modify the code to use the right name of the `key_id`.
21
+
To deploy the sample code from ICP Ninja, the canister needs the right key ID for the right environment. Specifically, one needs to replace the value of the `key_id` in the `src/ecdsa_example_motoko/main.mo` file of the sample code. Before deploying to the mainnet from ICP Ninja, one should modify the code to use the right name of the `key_id`.
> To deploy to IC mainnet, one needs to replace the value in `key_id` fields with the values `"dfx_test_key"` to instead have either `"test_key_1"` or `"key_1"` depending on the desired intent.
99
53
100
-
### Deploying
101
-
102
-
To [deploy via mainnet](https://internetcomputer.org/docs/current/developer-docs/setup/deploy-mainnet.md), run the following commands:
103
-
104
-
```bash
105
-
npm install
106
-
dfx deploy --network ic
107
-
```
108
-
If successful, you should see something like this:
In the example above, `ecdsa_example_motoko` has the URL https://a3gq9-oaaaa-aaaab-qaa4q-cai.raw.icp0.io/?id=736w4-cyaaa-aaaal-qb3wq-caiand serves up the Candid web UI for this particular canister deployed on mainnet.
55
+
## Build and deploy from the command-line
118
56
119
-
##Obtaining public keys
57
+
### 1. [Download and install the IC SDK.](https://internetcomputer.org/docs/building-apps/getting-started/install)
120
58
121
-
### Using the Candid UI
59
+
### 2. Download your project from ICP Ninja using the 'Download files' button on the upper left corner, or [clone the GitHub examples repository.](https://github.com/dfinity/examples/)
122
60
123
-
If you deployed your canister locally or to the mainnet, you should have a URL to the Candid web UI where you can access the public methods. We can call the `public-key` method.
61
+
### 3. Navigate into the project's directory.
124
62
125
-
In the example below, the method returns `03c22bef676644dba524d4a24132ea8463221a55540a27fc86d690fda8e688e31a` as the public key.
63
+
### 4. Deploy the project to your local environment:
Open the file `main.mo`, which will show the following Motoko code that demonstrates how to obtain an ECDSA public key.
139
-
140
-
```motoko
141
-
//declare "ic" to be the management canister, which is evoked by `actor("aaaaa-aa")`. This is how we will obtain an ECDSA public key
142
-
let ic : IC = actor("aaaaa-aa");
143
-
144
-
public shared (msg) func public_key() : async { #Ok : { public_key: Blob }; #Err : Text } {
145
-
let caller = Principal.toBlob(msg.caller);
146
-
147
-
try {
148
-
149
-
//request the management canister to compute an ECDSA public key
150
-
let { public_key } = await ic.ecdsa_public_key({
151
-
152
-
//When `null`, it defaults to getting the public key of the canister that makes this call
153
-
canister_id = null;
154
-
derivation_path = [ caller ];
155
-
//this code uses the mainnet test key
156
-
key_id = { curve = #secp256k1; name = "test_key_1" };
157
-
});
158
-
159
-
#Ok({ public_key })
160
-
161
-
} catch (err) {
162
-
163
-
#Err(Error.message(err))
164
-
165
-
}
166
-
167
-
};
66
+
dfx start --background --clean && dfx deploy
168
67
```
169
68
170
-
In the code above, the canister calls the `ecdsa_public_key` method of the [IC management canister](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-management-canister) (`aaaaa-aa`).
171
-
69
+
## Obtaining public keys
172
70
173
-
**The [IC management canister](https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-management-canister) is just a facade; it does not exist as a canister (with isolated state, Wasm code, etc.). It is an ergonomic way for canisters to call the system API of the IC (as if it were a single canister). In the code below, we use the management canister to create an ECDSA publickey. `let ic : IC = actor("aaaaa-aa")` declares the IC management canister in the code above.**
71
+
If you deployed your canister locally or to the mainnet, you should have a URL to the Candid web UI where you can access the public methods. We can call the `public-key` method.
174
72
175
73
### Canister root public key
176
74
@@ -185,24 +83,6 @@ For obtaining the canister's root public key, the derivation path in the API can
185
83
186
84
Computing threshold ECDSA signatures is the core functionality of this feature. **Canisters do not hold ECDSA keys themselves**, but keys are derived from a master key held by dedicated subnets. A canister can request the computation of a signature through the management canister API. The request is then routed to a subnet holding the specified key and the subnet computes the requested signature using threshold cryptography. Thereby, it derives the canister root key or a key obtained through further derivation, as part of the signature protocol, from a shared secret and the requesting canister's principal identifier. Thus, a canister can only request signatures to be created for its canister root key or a key derived from it. This means that canisters "control" their private ECDSA keys in that they decide when signatures are to be created with them, but don't hold a private key themselves.
187
85
188
-
```motoko
189
-
public shared (msg) func sign(message_hash: Blob) : async { #Ok : { signature: Blob }; #Err : Text } {
190
-
assert(message_hash.size() == 32);
191
-
let caller = Principal.toBlob(msg.caller);
192
-
try {
193
-
Cycles.add(10_000_000_000);
194
-
let { signature } = await ic.sign_with_ecdsa({
195
-
message_hash;
196
-
derivation_path = [ caller ];
197
-
key_id = { curve = #secp256k1; name = "dfx_test_key" };
198
-
});
199
-
#Ok({ signature })
200
-
} catch (err) {
201
-
#Err(Error.message(err))
202
-
}
203
-
};
204
-
```
205
-
206
86
## Signature verification
207
87
208
88
For completeness of the example, we show that the created signatures can be verified with the public key corresponding to the same canister and derivation path.
@@ -223,10 +103,6 @@ The call to `ecdsaVerify` function should always return `true`.
223
103
224
104
Similar verifications can be done in many other languages with the help of cryptographic libraries that support the `secp256k1` curve.
225
105
226
-
## Conclusion
227
-
228
-
In this walkthrough, we deployed a sample smart contract that:
106
+
## Security considerations and best practices
229
107
230
-
* Signed with private ECDSA keys even though **canisters do not hold ECDSA keys themselves**.
231
-
* Requested a public key.
232
-
* Performed signature verification.
108
+
If you base your application on this example, it is recommended that you familiarize yourself with and adhere to the [security best practices](https://internetcomputer.org/docs/building-apps/security/overview) for developing on ICP. This example may not implement all the best practices.
0 commit comments