Skip to content

Commit 6ab878c

Browse files
authored
feat: CRP-2844 CRP-2850 CRP-2853 add Motoko basic IBE backend and enable its use in ICP Ninja (#158)
Also: * Adds helper functions for the management canister VetKD API and signing with BLS. * Removes the frontend declarations from the repo, since they are generated upon deployment.
1 parent 1a98e96 commit 6ab878c

36 files changed

Lines changed: 4588 additions & 346 deletions

.github/workflows/examples-basic-ibe.yml

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,34 +19,65 @@ concurrency:
1919
group: ${{ github.workflow }}-${{ github.ref }}
2020
cancel-in-progress: true
2121
jobs:
22-
examples-basic-ibe-darwin:
22+
examples-basic-ibe-rust-darwin:
2323
runs-on: macos-15
2424
steps:
2525
- uses: actions/checkout@v4
2626
- name: Provision Darwin
2727
run: |
2828
bash .github/workflows/provision-darwin.sh
29-
- name: Deploy Basic IBE Darwin
29+
- name: Deploy Basic IBE Rust Darwin
3030
run: |
3131
set -eExuo pipefail
3232
cargo install candid-extractor
3333
npm i
34-
pushd examples/basic_ibe
35-
./deploy_locally.sh
34+
pushd examples/basic_ibe/rust
35+
dfx start --background && dfx deploy
3636
cd frontend
3737
npm run lint
38-
examples-basic-ibe-linux:
38+
examples-basic-ibe-rust-linux:
3939
runs-on: ubuntu-24.04
4040
steps:
4141
- uses: actions/checkout@v4
4242
- name: Provision Linux
4343
run: bash .github/workflows/provision-linux.sh
44-
- name: Deploy Basic IBE Linux
44+
- name: Deploy Basic IBE Rust Linux
4545
run: |
4646
set -eExuo pipefail
4747
cargo install candid-extractor
4848
npm i
49-
pushd examples/basic_ibe
50-
./deploy_locally.sh
49+
pushd examples/basic_ibe/rust
50+
dfx start --background && dfx deploy
51+
cd frontend
52+
npm run lint
53+
examples-basic-ibe-motoko-darwin:
54+
runs-on: macos-15
55+
steps:
56+
- uses: actions/checkout@v4
57+
- name: Provision Darwin
58+
run: |
59+
bash .github/workflows/provision-darwin.sh
60+
- name: Deploy Basic IBE Motoko Darwin
61+
run: |
62+
set -eExuo pipefail
63+
cargo install candid-extractor
64+
npm i
65+
pushd examples/basic_ibe/motoko
66+
dfx start --background && dfx deploy
67+
cd frontend
68+
npm run lint
69+
examples-basic-ibe-motoko-linux:
70+
runs-on: ubuntu-24.04
71+
steps:
72+
- uses: actions/checkout@v4
73+
- name: Provision Linux
74+
run: bash .github/workflows/provision-linux.sh
75+
- name: Deploy Basic IBE Motoko Linux
76+
run: |
77+
set -eExuo pipefail
78+
cargo install candid-extractor
79+
npm i
80+
pushd examples/basic_ibe/motoko
81+
dfx start --background && dfx deploy
5182
cd frontend
5283
npm run lint

Cargo.lock

Lines changed: 0 additions & 16 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ members = [
55
"backend/rs/canisters/ic_vetkeys_encrypted_maps_canister",
66
"backend/rs/canisters/ic_vetkeys_manager_canister",
77
"backend/rs/canisters/tests",
8-
"examples/basic_ibe/backend",
98
"examples/password_manager_with_metadata/backend"
109
]
1110
resolver = "2"

backend/mo/ic_vetkeys/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Change Log
22

3+
## [Unreleased]
4+
5+
### Adds
6+
- Sign with BLS and VetKD helper functions.
7+
38
## [0.2.0] - 2025-06-18
49

510
### Fixes
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import Blob "mo:base/Blob";
2+
3+
module {
4+
public type VetKdKeyid = {
5+
curve : { #bls12_381_g2 };
6+
name : Text;
7+
};
8+
9+
public type VetkdSystemApi = actor {
10+
vetkd_public_key : ({
11+
canister_id : ?Principal;
12+
context : Blob;
13+
key_id : VetKdKeyid;
14+
}) -> async ({ public_key : Blob });
15+
vetkd_derive_key : ({
16+
context : Blob;
17+
input : Blob;
18+
key_id : VetKdKeyid;
19+
transport_public_key : Blob;
20+
}) -> async ({ encrypted_key : Blob });
21+
};
22+
23+
public func vetKdDeriveKey(input : Blob, context : Blob, keyId : VetKdKeyid, transportPublicKey : Blob) : async Blob {
24+
let request = {
25+
context;
26+
input;
27+
key_id = keyId;
28+
transport_public_key = transportPublicKey;
29+
};
30+
let (reply) = await (with cycles = 26_153_846_153) (actor ("aaaaa-aa") : VetkdSystemApi).vetkd_derive_key(request);
31+
reply.encrypted_key;
32+
};
33+
34+
public func vetKdPublicKey(canisterId : ?Principal, context : Blob, VetKdKeyid : VetKdKeyid) : async Blob {
35+
let request = {
36+
canister_id = canisterId;
37+
context;
38+
key_id = VetKdKeyid;
39+
};
40+
let (reply) = await (actor ("aaaaa-aa") : VetkdSystemApi).vetkd_public_key(request);
41+
reply.public_key;
42+
};
43+
44+
public func signWithBls(message : Blob, context : Blob, VetKdKeyid : VetKdKeyid) : async Blob {
45+
// Encryption with the G1 identity element produces unencrypted vetKeys
46+
let pointAtInfinity : Blob = Blob.fromArray([192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
47+
await vetKdDeriveKey(message, context, VetKdKeyid, pointAtInfinity);
48+
};
49+
50+
public func blsPublicKey(canisterId : ?Principal, context : Blob, VetKdKeyid : VetKdKeyid) : async Blob {
51+
await vetKdPublicKey(canisterId, context, VetKdKeyid);
52+
};
53+
};

backend/mo/ic_vetkeys/src/key_manager/KeyManager.mo

Lines changed: 4 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ import Result "mo:base/Result";
4747
import Types "../Types";
4848
import Text "mo:base/Text";
4949
import Nat8 "mo:base/Nat8";
50+
import ManagementCanister "../ManagementCanister";
5051

5152
module {
5253
/// The public verification key used to verify the authenticity of derived vetKeys.
@@ -70,20 +71,6 @@ module {
7071
/// The public transport key used to encrypt vetKeys for secure transmission.
7172
public type TransportKey = Blob;
7273

73-
type VetkdSystemApi = actor {
74-
vetkd_public_key : ({
75-
canister_id : ?Principal;
76-
context : Blob;
77-
key_id : { curve : { #bls12_381_g2 }; name : Text };
78-
}) -> async ({ public_key : Blob });
79-
vetkd_derive_key : ({
80-
context : Blob;
81-
input : Blob;
82-
key_id : { curve : { #bls12_381_g2 }; name : Text };
83-
transport_public_key : Blob;
84-
}) -> async ({ encrypted_key : Blob });
85-
};
86-
8774
func compareKeyIds(a : KeyId, b : KeyId) : { #less; #greater; #equal } {
8875
let ownersCompare = Principal.compare(a.0, b.0);
8976
if (ownersCompare == #equal) {
@@ -102,7 +89,7 @@ module {
10289
};
10390

10491
/// See the module documentation for more information.
105-
public class KeyManager<T>(key_id : { curve : { #bls12_381_g2 }; name : Text }, domainSeparator : Text, accessRightsOperations : Types.AccessControlOperations<T>) {
92+
public class KeyManager<T>(vetKdKeyId : ManagementCanister.VetKdKeyid, domainSeparator : Text, accessRightsOperations : Types.AccessControlOperations<T>) {
10693
public var accessControl : OrderedMap.Map<Principal, [(KeyId, T)]> = accessControlMapOps().empty();
10794
public var sharedKeys : OrderedMap.Map<KeyId, [Principal]> = sharedKeysMapOps().empty();
10895
let domainSeparatorBytes = Text.encodeUtf8(domainSeparator);
@@ -154,16 +141,7 @@ module {
154141
/// Retrieves the vetKD verification key for this canister.
155142
/// This key is used to verify the authenticity of derived vetKeys.
156143
public func getVetkeyVerificationKey() : async VetKeyVerificationKey {
157-
let context = domainSeparatorBytes;
158-
159-
let request = {
160-
canister_id = null;
161-
context;
162-
key_id;
163-
};
164-
165-
let (reply) = await (actor ("aaaaa-aa") : VetkdSystemApi).vetkd_public_key(request);
166-
reply.public_key;
144+
await ManagementCanister.vetKdPublicKey(null, domainSeparatorBytes, vetKdKeyId);
167145
};
168146

169147
/// Retrieves an encrypted vetKey for caller and key id.
@@ -180,17 +158,7 @@ module {
180158
Blob.toArray(keyId.1),
181159
]);
182160

183-
let context = domainSeparatorBytes;
184-
185-
let request = {
186-
input = Blob.fromArray(input);
187-
context;
188-
key_id;
189-
transport_public_key = transportKey;
190-
};
191-
192-
let (reply) = await (with cycles = 26_153_846_153) (actor ("aaaaa-aa") : VetkdSystemApi).vetkd_derive_key(request);
193-
#ok(reply.encrypted_key);
161+
#ok(await ManagementCanister.vetKdDeriveKey(Blob.fromArray(input), domainSeparatorBytes, vetKdKeyId, transportKey));
194162
};
195163
};
196164
};

backend/mo/ic_vetkeys/src/lib.mo

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import KeyManagerModule "key_manager/KeyManager";
22
import EncryptedMapsModule "encrypted_maps/EncryptedMaps";
3+
import ManagementCanisterModule "ManagementCanister";
34
import Types "Types";
45

56
module {
@@ -9,4 +10,6 @@ module {
910

1011
public let KeyManager = KeyManagerModule;
1112
public let EncryptedMaps = EncryptedMapsModule;
13+
14+
public let ManagementCanister = ManagementCanisterModule;
1215
};

examples/basic_ibe/README.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,13 @@ npm install
3232

3333
### Deploy the Canisters
3434

35-
Run the local deployment script, which starts the local development environment (`dfx`) if necessary, builds both backend and frontend (asset) canisters, and installs them locally.
35+
If you want to deploy this project locally with a Motoko backend, then run:
3636
```bash
37-
bash deploy_locally.sh
37+
dfx start --background && dfx deploy
3838
```
39+
from the `motoko` folder.
40+
41+
To use the Rust backend instead of Motoko, run the same command in the `rust` folder.
3942

4043
## Example Components
4144

@@ -50,7 +53,7 @@ The backend consists of a canister that:
5053

5154
The frontend is a vanilla typescript application providing a simple interface for sending, receiving, and deleting encrypted messages.
5255

53-
To run the frontend in development mode with hot reloading (after running `deploy_locally.sh`):
56+
To run the frontend in development mode with hot reloading (after running `dfx deploy`):
5457

5558
```bash
5659
npm run dev

examples/basic_ibe/backend/Cargo.toml

Lines changed: 0 additions & 24 deletions
This file was deleted.

examples/basic_ibe/deploy_locally.sh

Lines changed: 0 additions & 18 deletions
This file was deleted.

0 commit comments

Comments
 (0)