Skip to content

Commit 4c76dee

Browse files
Merge pull request #1187 from dfinity/jessiemongeon1-patch-18
add: Deploy to ICP Ninja + Standardize README
2 parents e551978 + 1fa06ef commit 4c76dee

File tree

1 file changed

+15
-139
lines changed

1 file changed

+15
-139
lines changed

motoko/threshold-ecdsa/README.md

Lines changed: 15 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Threshold ECDSA sample
22

3-
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.
44

55
The example canister is a signing oracle that creates ECDSA signatures with keys derived from an input string.
66

@@ -12,59 +12,13 @@ More specifically:
1212

1313
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.
1414

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.
15+
## Deploying from ICP Ninja
1716

18-
## Local development
17+
[![](https://icp.ninja/assets/open.svg)](https://icp.ninja/editor?g=https://github.com/dfinity/examples/tree/master/motoko/threshold-ecdsa)
1918

20-
### Prerequisites
21-
This example requires an installation of:
19+
### 1. Update source code with the right key ID
2220

23-
- [x] Install the [IC SDK](https://internetcomputer.org/docs/current/developer-docs/getting-started/install) v0.11.0 or newer.
24-
- [x] Clone the example dapp project: `git clone https://github.com/dfinity/examples`
25-
26-
Begin by opening a terminal window.
27-
28-
### Step 1: Setup the project environment
29-
30-
Navigate into the folder containing the project's files and start a local instance of the Internet Computer with the commands:
31-
32-
```bash
33-
cd examples/motoko/threshold-ecdsa
34-
dfx start --background
35-
```
36-
37-
### Step 2: Deploy the canisters
38-
39-
```bash
40-
dfx deploy
41-
```
42-
43-
If successful, you should see something like this:
44-
45-
```bash
46-
Deployed canisters.
47-
URLs:
48-
Backend canister via Candid interface:
49-
ecdsa_example_motoko: http://127.0.0.1:4943/?canisterId=t6rzw-2iaaa-aaaaa-aaama-cai&id=st75y-vaaaa-aaaaa-aaalq-cai
50-
```
51-
52-
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`.
6822

6923
There are three options:
7024

@@ -97,80 +51,24 @@ let { signature } = await ic.sign_with_ecdsa({
9751
> [!WARNING]
9852
> 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.
9953
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:
109-
110-
```bash
111-
Deployed canisters.
112-
URLs:
113-
Backend canister via Candid interface:
114-
ecdsa_example_motoko: https://a3gq9-oaaaa-aaaab-qaa4q-cai.raw.icp0.io/?id=736w4-cyaaa-aaaal-qb3wq-cai
115-
```
11654

117-
In the example above, `ecdsa_example_motoko` has the URL https://a3gq9-oaaaa-aaaab-qaa4q-cai.raw.icp0.io/?id=736w4-cyaaa-aaaal-qb3wq-cai and serves up the Candid web UI for this particular canister deployed on mainnet.
55+
## Build and deploy from the command-line
11856

119-
## Obtaining public keys
57+
### 1. [Download and install the IC SDK.](https://internetcomputer.org/docs/building-apps/getting-started/install)
12058

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/)
12260

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.
12462

125-
In the example below, the method returns `03c22bef676644dba524d4a24132ea8463221a55540a27fc86d690fda8e688e31a` as the public key.
63+
### 4. Deploy the project to your local environment:
12664

127-
```json
128-
{
129-
"Ok":
130-
{
131-
"public_key_hex": "03c22bef676644dba524d4a24132ea8463221a55540a27fc86d690fda8e688e31a"
132-
}
133-
}
13465
```
135-
136-
137-
### Code walkthrough
138-
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
16867
```
16968

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
17270

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 public key. `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.
17472

17573
### Canister root public key
17674

@@ -185,24 +83,6 @@ For obtaining the canister's root public key, the derivation path in the API can
18583

18684
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.
18785

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-
20686
## Signature verification
20787

20888
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`.
223103

224104
Similar verifications can be done in many other languages with the help of cryptographic libraries that support the `secp256k1` curve.
225105

226-
## Conclusion
227-
228-
In this walkthrough, we deployed a sample smart contract that:
106+
## Security considerations and best practices
229107

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

Comments
 (0)