From 9c75104bd657b0c12172d2a520ee8896ddd3b905 Mon Sep 17 00:00:00 2001 From: renaud dubois Date: Wed, 11 Dec 2024 08:53:30 +0100 Subject: [PATCH] full session FROST tested OK --- src/libMPC/README.md | 16 ++++++- src/libMPC/SCL_frost.mjs | 11 +++-- src/libMPC/test_frost.mjs | 89 +++++++++++++++++++++++++++++++++++---- 3 files changed, 101 insertions(+), 15 deletions(-) diff --git a/src/libMPC/README.md b/src/libMPC/README.md index 4013db1..0dcf6db 100644 --- a/src/libMPC/README.md +++ b/src/libMPC/README.md @@ -191,10 +191,14 @@ Note: the protocol requires to broadcast onchain 4 values (2 locked tokens, then The element $t$ shall be as protected as a secret key, to prevent $B$ from stealing $A$ token. In the description, Alice has more duty regarding to the protection of this secret. -# Performing a Multisignature with libMPC FROST (WIP) +# Performing a Multisignature with libMPC FROST + + + +## Design notes The generation and distribution of FROST's shares are out of scope of its specification. However -[FROST-RFC] https://datatracker.ietf.org/doc/draft-irtf-cfrg-frost/15/ specifies a trusted key dealer generation which is the most obvious. The DKG is implemented in the class SCL_FROST_TDealer. +[FROST-RFC](https://datatracker.ietf.org/doc/draft-irtf-cfrg-frost/15/) specifies a trusted key dealer generation which is the most obvious. The DKG is implemented in the class SCL_trustedkeygen. In the future the more decentralized chill-DKG shall be implemented. @@ -224,6 +228,14 @@ Tests can be ran using the following command : The `file test_atomic_bitcoin.js` aims to provide a full onchain demonstration of a bridging. +## FROST + +Tests can be ran using the following command : +``` + node test_frost.mjs +``` + + # Product Roadmap - Musig2 can be used to provide protection against trappoored hardware [as explained here](https://docs.google.com/presentation/d/10JmRVq9qeoIouLyzIOMcMLnfQQbZlZoSP5eTOyXYUdI/edit#slide=id.g2bf9c14683d_1_265). Using Musig2 with account abstraction, it is possible to have a companion app handling a first key, the hardware wallet a second. diff --git a/src/libMPC/SCL_frost.mjs b/src/libMPC/SCL_frost.mjs index d9c812a..d412579 100644 --- a/src/libMPC/SCL_frost.mjs +++ b/src/libMPC/SCL_frost.mjs @@ -307,10 +307,10 @@ Nonce_hash(rand, pk, aggpk, i, msgPrefixed, extraIn) { } - Nonce_gen(sk,pk,aggpk, m,extra_in){ + Nonce_gen(sk,pk,group_pk, m,extra_in){ const rand =randomBytes(32);//note that if sk is well protected, leakage of the nonce doesn't break the scheme - - return this.Nonce_gen_internal(rand, sk,pk,aggpk, m,extra_in); + + return this.Nonce_gen_internal(rand, sk,pk,group_pk, m,extra_in); } @@ -327,7 +327,6 @@ Nonce_hash(rand, pk, aggpk, i, msgPrefixed, extraIn) { let Rj = this.curve.GetZero();//infinity neutral point for(let i=0;ithis.curve.order) { return false; @@ -540,6 +541,8 @@ Partial_sig_agg(psigs, ids, session_ctx){ //verify one of the partial signature provided by a participant Psig_verify(psig, id, pubnonce, pk, session_ctx){ + + let sessionV=this.Get_session_values(session_ctx);//(Q, gacc, _, b, R, e) let s = int_from_bytes(psig); let Q=sessionV[0]; diff --git a/src/libMPC/test_frost.mjs b/src/libMPC/test_frost.mjs index 142de5e..fc913d5 100644 --- a/src/libMPC/test_frost.mjs +++ b/src/libMPC/test_frost.mjs @@ -204,30 +204,100 @@ function test_partialSig(){ } + +function randomSubset(n, subsetSize) { + if (subsetSize > n) { + throw new Error("Subset size cannot be larger than n"); + } + + const subset = new Set(); + + // Randomly select `subsetSize` unique numbers + while (subset.size < subsetSize) { + const randomNumber = Math.floor(Math.random() * n); + subset.add(randomNumber); // Use a Set to avoid duplicates + } + + // Convert to array and sort in increasing order + return Array.from(subset).sort((a, b) => a - b); +} + //randomly generated full session function test_random_fullsession(Curvename){ console.log("/*************************** "); - console.log("Test Full session, random input on curve:", Curvename); + console.log("Test Full FROST session, random input on curve:", Curvename); + + let n=12; + let k=4; console.log("----------Generate Keys:"); let curve=new SCL_ecc(Curvename); let sk=curve.Get_Random_privateKey(); - let dealer=new SCL_trustedKeyGen( Curvename,sk, 12,4); - + let dealer=new SCL_trustedKeyGen( Curvename,sk, n,k); + let frost=new SCL_FROST(Curvename); + console.log(" Check key correctness:", dealer.Check_Shares()); - let rec_secret=dealer.Interpolate_group_seckey(dealer.secshares); - console.log(" Interpolating secret:", rec_secret==int_from_bytes(sk)); + + - let rec_public=Interpolate_group_pubkey(dealer.pubshares, dealer.ids, curve); - console.log(" Interpolating public keys", Buffer.from(rec_public).equals(dealer.pubkey)); + console.log("----------Signer Set:"); + let elements=randomSubset(n, k+1); + console.log("set:", elements); + let Ids = elements.map(index => dealer.ids[index]); + console.log("ids:", Ids); + let pubshares=elements.map(index => dealer.pubshares[index]);//pubshares as points + let b8_pubshares=elements.map(index => curve.PointCompress(dealer.pubshares[index])) + let secshares=elements.map(index => dealer.secshares[index]);//this is the view from the dealer and shall never happen to be computed in practice + + let group_pk=Interpolate_group_pubkey(pubshares, Ids, curve); + let x_group_pk=curve.ForceXonly(group_pk);//x-only version for noncegen, allways 32 + console.log(" Interpolating public key from pubkey set", Buffer.from(group_pk).equals(dealer.pubkey)); - console.log("----------Signer Set:"); + let rec_secret=dealer.Interpolate_group_seckey(secshares); + console.log(" Interpolating secret key from seckey set:", rec_secret==int_from_bytes(dealer.sk)); - + console.log("----------Generate message and nonces"); + + const msg=Buffer.from(randomBytes(32)); + const extra_in= Buffer.from(randomBytes(32)); + + let secnonces=[]; + let pubnonces=[]; + + for(let i=0;i