Skip to content

Commit eca422a

Browse files
authored
fix(crypto): basic_bls_signing example: use persistent actor and Motoko core (#233)
Adapts the basic_bls_signing example so that it works again with ICP Ninja, which recently upgraded to DFX 0.29.1, which ships with a new motoko compiler (0.16.1). The necessary changes for this were * Declaring the actor as `persistent` * Changing the `signatures` map to the stable mo:core/Map As the examples was touched anyway, the PR switches from the outdated `mo:base` to the new `mo:core` and fixes all compiler issues. The Github workflow sets the `DFX_VERSION` environment variable, so that only this example uses the new DFX version 0.29.1. This also required to change the bind host from `localhost` to `127.0.0.1` as otherwise this new DFX version hits the following error: ``` Error: The replica returned an HTTP Error: Http Error: status 400 Bad Request, content type "text/plain; charset=utf-8", content: error: no_authority details: The request is missing the required authority information (e.g. 'Host' header). ``` The changes were tested in ICP Ninja with the following link: [![](https://icp.ninja/assets/open.svg)](http://icp.ninja/editor?g=https://github.com/dfinity/vetkeys/tree/franzstefan/CRP-2924-bls-signing/examples/basic_bls_signing/motoko)
1 parent 7f0abce commit eca422a

File tree

5 files changed

+35
-61
lines changed

5 files changed

+35
-61
lines changed

.github/workflows/examples-basic-bls-signing.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ on:
1212
concurrency:
1313
group: ${{ github.workflow }}-${{ github.ref }}
1414
cancel-in-progress: true
15+
env:
16+
DFX_VERSION: 0.29.1
1517
jobs:
1618
examples-basic-bls-signing-rust-darwin:
1719
runs-on: macos-15

examples/basic_bls_signing/motoko/backend/src/Main.mo

Lines changed: 30 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
1-
import Principal "mo:base/Principal";
2-
import Text "mo:base/Text";
3-
import Blob "mo:base/Blob";
4-
import Nat64 "mo:base/Nat64";
5-
import Time "mo:base/Time";
6-
import HashMap "mo:base/HashMap";
7-
import Array "mo:base/Array";
8-
import Buffer "mo:base/Buffer";
9-
import Nat8 "mo:base/Nat8";
10-
import Nat32 "mo:base/Nat32";
11-
import Debug "mo:base/Debug";
12-
import Nat "mo:base/Nat";
1+
import Principal "mo:core/Principal";
2+
import Text "mo:core/Text";
3+
import Blob "mo:core/Blob";
4+
import Nat64 "mo:core/Nat64";
5+
import Time "mo:core/Time";
6+
import Map "mo:core/Map";
7+
import Array "mo:core/Array";
8+
import List "mo:core/List";
9+
import Nat8 "mo:core/Nat8";
10+
import Runtime "mo:core/Runtime";
11+
import Nat "mo:core/Nat";
1312
import VetKeys "mo:ic-vetkeys";
14-
import Sha256 "mo:sha2/Sha256";
13+
import Order "mo:core/Order";
1514

16-
shared actor class (keyName : Text) = {
15+
shared persistent actor class (keyName : Text) = {
1716
// Types
1817
type Signature = {
1918
message : Text;
@@ -31,43 +30,16 @@ shared actor class (keyName : Text) = {
3130
name : Text;
3231
};
3332

34-
// Hash and equality functions for SignatureKey
35-
private func signatureKeyEqual(a : SignatureKey, b : SignatureKey) : Bool {
36-
Principal.equal(a.signer, b.signer) and a.timestamp == b.timestamp
37-
};
38-
39-
private func signatureKeyHash(key : SignatureKey) : Nat32 {
40-
let signerBytes = Blob.toArray(Principal.toBlob(key.signer));
41-
let timestampBytes = nat64ToBytes(key.timestamp);
42-
let bytes = Array.append<Nat8>(signerBytes, timestampBytes);
43-
let hashBlob = Sha256.fromArray(#sha256, bytes);
44-
blobToNat32(hashBlob);
45-
};
46-
47-
func nat64ToBytes(n : Nat64) : [Nat8] {
48-
let byteMask : Nat64 = 0xff;
49-
func byte(x : Nat64) : Nat8 {
50-
Nat8.fromNat(Nat64.toNat(x));
51-
};
52-
[
53-
byte(((byteMask << 56) & n) >> 56),
54-
byte(((byteMask << 48) & n) >> 48),
55-
byte(((byteMask << 40) & n) >> 40),
56-
byte(((byteMask << 32) & n) >> 32),
57-
byte(((byteMask << 24) & n) >> 24),
58-
byte(((byteMask << 16) & n) >> 16),
59-
byte(((byteMask << 8) & n) >> 8),
60-
byte(((byteMask << 0) & n) >> 0),
61-
];
62-
};
63-
64-
private func blobToNat32(blob : Blob) : Nat32 {
65-
let bytes = Blob.toArray(blob);
66-
(Nat32.fromNat(Nat8.toNat(bytes[0])) << 24) + (Nat32.fromNat(Nat8.toNat(bytes[1])) << 16) + (Nat32.fromNat(Nat8.toNat(bytes[2])) << 8) + Nat32.fromNat(Nat8.toNat(bytes[3]));
33+
// Compare function for SignatureKey
34+
private func signatureKeyCompare(a : SignatureKey, b : SignatureKey) : Order.Order {
35+
switch (Principal.compare(a.signer, b.signer)) {
36+
case (#equal) { Nat64.compare(a.timestamp, b.timestamp) };
37+
case (other) { other };
38+
}
6739
};
6840

6941
// Stable storage for signatures
70-
private var signatures : HashMap.HashMap<SignatureKey, Signature> = HashMap.HashMap(0, signatureKeyEqual, signatureKeyHash);
42+
private var signatures = Map.empty<SignatureKey, Signature>();
7143

7244
// Helper function to get current timestamp
7345
private func getTimestamp() : Nat64 {
@@ -84,8 +56,8 @@ shared actor class (keyName : Text) = {
8456
let signerBytes = Principal.toBlob(signer);
8557
let signerArray = Blob.toArray(signerBytes);
8658

87-
let contextArray = Array.append<Nat8>(
88-
Array.append<Nat8>(domainSeparatorLength, domainSeparator),
59+
let contextArray = Array.concat<Nat8>(
60+
Array.concat<Nat8>(domainSeparatorLength, domainSeparator),
8961
signerArray,
9062
);
9163

@@ -113,10 +85,10 @@ shared actor class (keyName : Text) = {
11385
let SIGNATURE_SIZE : Nat = 48;
11486

11587
if (bytes.size() != BYTES_SIZE) {
116-
Debug.trap("Expected " # Nat.toText(BYTES_SIZE) # " signature bytes, but got " # Nat.toText(bytes.size()));
88+
Runtime.trap("Expected " # Nat.toText(BYTES_SIZE) # " signature bytes, but got " # Nat.toText(bytes.size()));
11789
};
11890

119-
let signatureBytes = Blob.fromArray(Array.subArray<Nat8>(Blob.toArray(bytes), BYTES_SIZE - SIGNATURE_SIZE, SIGNATURE_SIZE));
91+
let signatureBytes = Blob.fromArray(Array.sliceToArray<Nat8>(Blob.toArray(bytes), BYTES_SIZE - SIGNATURE_SIZE, BYTES_SIZE));
12092

12193
let timestamp = getTimestamp();
12294
let signature : Signature = {
@@ -127,26 +99,26 @@ shared actor class (keyName : Text) = {
12799

128100
// Handle potential timestamp collisions by incrementing until we find a free slot
129101
var timestampForMapKey = timestamp;
130-
while (signatures.get({ signer = caller; timestamp = timestampForMapKey }) != null) {
102+
while (Map.get(signatures, signatureKeyCompare, { signer = caller; timestamp = timestampForMapKey }) != null) {
131103
timestampForMapKey += 1;
132104
};
133105

134-
signatures.put({ signer = caller; timestamp = timestampForMapKey }, signature);
106+
ignore Map.insert(signatures, signatureKeyCompare, { signer = caller; timestamp = timestampForMapKey }, signature);
135107

136108
signatureBytes;
137109
};
138110

139111
// Get all signatures for the current caller
140112
public shared query ({ caller }) func get_my_signatures() : async [Signature] {
141-
let callerSignatures = Buffer.Buffer<Signature>(0);
113+
var callerSignatures = List.empty<Signature>();
142114

143-
for ((key, value) in signatures.entries()) {
115+
for ((key, value) in Map.entries(signatures)) {
144116
if (Principal.equal(key.signer, caller)) {
145-
callerSignatures.add(value);
117+
List.add(callerSignatures, value);
146118
};
147119
};
148120

149-
Buffer.toArray(callerSignatures);
121+
List.toArray(callerSignatures);
150122
};
151123

152124
// Get verification key for the current caller

examples/basic_bls_signing/motoko/dfx.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
},
4545
"networks": {
4646
"local": {
47-
"bind": "localhost:8000",
47+
"bind": "127.0.0.1:8000",
4848
"type": "ephemeral"
4949
}
5050
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
[dependencies]
2-
base = "0.14.8"
2+
core = "1.0.0"
33
ic-vetkeys = "0.3.0"
44
sha2 = "0.1.2"

examples/basic_bls_signing/rust/dfx.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
},
3939
"networks": {
4040
"local": {
41-
"bind": "localhost:8000",
41+
"bind": "127.0.0.1:8000",
4242
"type": "ephemeral"
4343
}
4444
}

0 commit comments

Comments
 (0)