1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
use tokio::task::JoinSet;
use rand::Rng;
use rand_chacha::ChaCha20Rng;
use rand_core::SeedableRng;
use k256::ecdsa::{RecoveryId, VerifyingKey};
use dkls23::sign;
use sl_mpc_mate::coord::SimpleMessageRelay;
mod common;
#[tokio::main]
async fn main() {
// Logic: The relayer follows the Actor model: It spawns from the caller task, does the assigned task
// independently and return the result in the main task. For the purpose of that example there is no real
// networking, but instead a combination of shared state between rust tasks and message channel passing where
// receiver and sender channels are interleaved for p2p and broadcast communication. That is a SimpleMessageRelay. async
// In a real setup the relayer can be an independent network entity, where all the nodes can talk to. It
// can be implemented with a variety of existing networking protocols such as websockets; as long as it follows the
// underlying pull logic : Each receiver knows what message to subscribe for and so it asks the relayer to deliver it
// as long as it arrives from the expected sender.
// Rust: SimpleMessageRelay::new() creates an Arc<Mutex> object to be shared among all tasks. The objects does message
// accounting in hashmap : messages: HashMap<MsgId, MsgEntry>
let coord = SimpleMessageRelay::new();
// We locally generate some key shares in order to test the signing procedure.
let shares = common::shared::gen_keyshares(2, 3).await;
//fetch the public verification key from one of the keyshares
let vk = VerifyingKey::from_affine(shares[0].public_key().to_affine())
.unwrap();
//define a chain path for the signature: m is the default one
let chain_path = "m";
// Here the parties are simulated as in a real world example but locally as a set of rust async tasks:
// One task for each node to run the dkls23 ecdsa sign algorithm
let mut parties = JoinSet::new();
// For each node in the protocol a setup msg should be created tailored for that sign protocol. The setupmsg
// contains information about the public parameters of the protocol: number of nodes = n, minimum threshold = t dictating
// the minimum required nodes that need to be online in order to compute the distributed signature, a unique instance id for the sign protocol
// a unique id that identifies that key share id that will be created common for all nodes in order to distinguish from
// other key shares that will be potentially created, the public signature keys of each other node in order to
// verify authenticity and integrity of p2p and broadcast messages, and the secret signing key of the node boostraping the protocol which is
// unique and different per node.
for setup in common::shared::setup_dsg(&shares[0..2], chain_path) {
let mut rng = ChaCha20Rng::from_entropy();
// Each task representing a different node is "connecting" to the coordinator relayer: a new mpsc channel is created
// in a new per node relay, whereby each relay shares the same Arc<Mutex> messages object which has been created outside the loop
let relay = coord.connect();
// At that point we have created the correct setup msgs for each party with the aforementioned helper function, which
// in real world does not exist but the consumers of the library node should create. The next step is to execute each
// task in an async fashion. That function in a real world example runs by each node independently who want to compute the final
// signature.
parties.spawn(sign::run(setup, rng.gen(), relay));
}
// After all the tasks have finished we extract the signature and verify it against the public key
while let Some(fini) = parties.join_next().await {
let fini = fini.unwrap();
if let Err(ref err) = fini {
println!("error {err:?}");
}
let (sign, recid) = fini.unwrap();
let hash = [1u8; 32];
let recid2 =
RecoveryId::trial_recovery_from_prehash(&vk, &hash, &sign)
.unwrap();
assert_eq!(recid, recid2);
}
}