Skip to content

Commit

Permalink
entropy-protocol - polkadot-js compatible sr25519 key generation fo…
Browse files Browse the repository at this point in the history
…r wasm API (#533)

* entropy-protocol wasm api takes sr25519 secret key rather than seed

* Add wasm-test feature flag for testing with sp-core keypairs

* Update CI script

* Comment

* Use from_ed25519_bytes when testing

* Update test
  • Loading branch information
ameba23 authored Nov 29, 2023
1 parent bee9f71 commit 13152bf
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 39 deletions.
2 changes: 1 addition & 1 deletion .circleci/then.yml
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ jobs:
name: Build entropy-protocol nodejs package.
command: |
cd crypto/protocol
make build-nodejs
make build-nodejs-testing
cd nodejs-test
yarn
cd ../../..
Expand Down
3 changes: 3 additions & 0 deletions crypto/protocol/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -67,5 +67,8 @@ wasm=[
"dep:schnorrkel",
]

# Use sp-core compatible sr25519 keypairs on wasm, rather then polkadot JS. For testing only
wasm-test=["wasm"]

[lib]
crate-type=["cdylib", "rlib"]
4 changes: 4 additions & 0 deletions crypto/protocol/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ build-web ::
build-bundler ::
wasm-pack build --target bundler . --no-default-features -F wasm

# Builds a JS Module for nodejs with testing features
build-nodejs-testing ::
wasm-pack build --target nodejs . --no-default-features -F wasm-test

# Cleans out build artifacts.
clean ::
rm -rf pkg/ nodejs-test/node_modules/
4 changes: 2 additions & 2 deletions crypto/protocol/nodejs-test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@ try {

switch(process.argv[2].toLowerCase()) {
case 'register':
protocol.run_dkg_protocol(input.validators_info, input.user_sig_req_seed, input.x25519_private_key).then((keyShare) => {
protocol.run_dkg_protocol(input.validators_info, input.user_sig_req_secret_key, input.x25519_private_key).then((keyShare) => {
console.log(keyShare.toString())
}).catch((err) => {
console.error('ERR', err)
})
break
case 'sign':
let keyShare = protocol.KeyShare.fromString(input.key_share)
protocol.run_signing_protocol(keyShare, input.sig_uid, input.validators_info, input.user_sig_req_seed, input.x25519_private_key).then((output) => {
protocol.run_signing_protocol(keyShare, input.sig_uid, input.validators_info, input.user_sig_req_secret_key, input.x25519_private_key).then((output) => {
console.log(output)
}).catch((err) => {
console.error('ERR', err)
Expand Down
38 changes: 23 additions & 15 deletions crypto/protocol/src/user/wasm.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Wrappers around functions to run dkg and signing protocols for JS
use js_sys::Error;
use sp_core::{sr25519, Pair};
use sp_core::sr25519;
use subxt::utils::AccountId32;
use wasm_bindgen::prelude::*;
use wasm_bindgen_derive::TryFromJsValue;
Expand All @@ -12,17 +12,12 @@ use crate::KeyParams;
#[cfg_attr(feature = "wasm", wasm_bindgen)]
pub async fn run_dkg_protocol(
validators_info_js: ValidatorInfoArray,
user_signing_keypair_seed: Vec<u8>,
user_signing_secret_key: Vec<u8>,
x25519_private_key_vec: Vec<u8>,
) -> Result<KeyShare, Error> {
let validators_info = parse_validator_info(validators_info_js)?;

let user_signing_keypair = {
let seed: [u8; 32] = user_signing_keypair_seed
.try_into()
.map_err(|_| Error::new("User signing keypair seed must be 32 bytes"))?;
sr25519::Pair::from_seed(&seed)
};
let user_signing_keypair = sr25519_keypair_from_secret_key(user_signing_secret_key)?;

let x25519_private_key: x25519_dalek::StaticSecret = {
let x25519_private_key_raw: [u8; 32] = x25519_private_key_vec
Expand All @@ -49,7 +44,7 @@ pub async fn run_signing_protocol(
key_share: KeyShare,
sig_uid: String,
validators_info_js: ValidatorInfoArray,
user_signing_keypair_seed: Vec<u8>,
user_signing_secret_key: Vec<u8>,
x25519_private_key_vec: Vec<u8>,
) -> Result<String, Error> {
let validators_info = parse_validator_info(validators_info_js)?;
Expand All @@ -63,12 +58,7 @@ pub async fn run_signing_protocol(
sig_hash_vec.try_into().map_err(|_| Error::new("Message hash must be 32 bytes"))?
};

let user_signing_keypair = {
let seed: [u8; 32] = user_signing_keypair_seed
.try_into()
.map_err(|_| Error::new("User signing keypair seed must be 32 bytes"))?;
sr25519::Pair::from_seed(&seed)
};
let user_signing_keypair = sr25519_keypair_from_secret_key(user_signing_secret_key)?;

let x25519_private_key: x25519_dalek::StaticSecret = {
let x25519_private_key_raw: [u8; 32] = x25519_private_key_vec
Expand Down Expand Up @@ -225,3 +215,21 @@ impl KeyShare {
self.0.party_index()
}
}

// Make a sr25519 keypair given a secret key, using sp-core compatible key generation if
// in test mode, polkadot-js compatible otherwise
fn sr25519_keypair_from_secret_key(secret_key: Vec<u8>) -> Result<sr25519::Pair, Error> {
if secret_key.len() != 64 {
return Err(Error::new("Secret key must be 64 bytes"));
}

let secret = if cfg!(feature = "wasm-test") {
schnorrkel::SecretKey::from_bytes(secret_key.as_slice())
} else {
schnorrkel::SecretKey::from_ed25519_bytes(secret_key.as_slice())
}
.map_err(|err| Error::new(&err.to_string()))?;

let public = secret.to_public();
Ok(sr25519::Pair::from(schnorrkel::Keypair { secret, public }))
}
34 changes: 13 additions & 21 deletions crypto/server/tests/protocol_wasm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use std::{
};
use subxt::{
backend::legacy::LegacyRpcMethods,
ext::sp_core::{sr25519::Signature, Bytes},
ext::sp_core::{sr25519::Signature, Bytes, Pair},
Config, OnlineClient,
};
use synedrion::KeyShare;
Expand Down Expand Up @@ -124,20 +124,14 @@ async fn test_wasm_sign_tx_user_participates() {

let one_x25519_sk = derive_static_secret(&one.pair());

let eve_seed: [u8; 32] =
hex::decode("786ad0e2df456fe43dd1f91ebca22e235bc162e0bb8d53c633e8c85b2af68b7a")
.unwrap()
.try_into()
.unwrap();

// Submit transaction requests, and connect and participate in signing
let (mut test_user_res, user_sig) = future::join(
submit_transaction_requests(validator_ips_and_keys.clone(), generic_msg.clone(), one),
spawn_user_participates_in_signing_protocol(
&users_keyshare_option.clone().unwrap(),
&sig_uid,
validators_info.clone(),
eve_seed,
one.pair().to_raw_vec(),
&one_x25519_sk,
),
)
Expand Down Expand Up @@ -223,19 +217,17 @@ async fn test_wasm_register_with_private_key_visibility() {
})
.collect();

let one_seed: [u8; 32] =
hex::decode("3b3993c957ed9342cbb011eb9029c53fb253345114eff7da5951e98a41ba5ad5")
.unwrap()
.try_into()
.unwrap();

// Call the `user/new` endpoint, and connect and participate in the protocol
let (new_user_response_result, user_keyshare_json) = future::join(
client
.post("http://127.0.0.1:3002/user/new")
.body(onchain_user_request.clone().encode())
.send(),
spawn_user_participates_in_dkg_protocol(validators_info.clone(), one_seed, &one_x25519_sk),
spawn_user_participates_in_dkg_protocol(
validators_info.clone(),
one.pair().to_raw_vec(),
&one_x25519_sk,
),
)
.await;

Expand All @@ -256,7 +248,7 @@ async fn test_wasm_register_with_private_key_visibility() {

#[derive(Debug, Clone, Serialize, Deserialize)]
struct UserParticipatesInSigningProtocolArgs {
user_sig_req_seed: Vec<u8>,
user_sig_req_secret_key: Vec<u8>,
x25519_private_key: Vec<u8>,
sig_uid: String,
key_share: String,
Expand All @@ -265,7 +257,7 @@ struct UserParticipatesInSigningProtocolArgs {

#[derive(Debug, Clone, Serialize, Deserialize)]
struct UserParticipatesInDkgProtocolArgs {
user_sig_req_seed: Vec<u8>,
user_sig_req_secret_key: Vec<u8>,
x25519_private_key: Vec<u8>,
validators_info: Vec<ValidatorInfoParsed>,
}
Expand All @@ -283,12 +275,12 @@ async fn spawn_user_participates_in_signing_protocol(
key_share: &KeyShare<KeyParams>,
sig_uid: &str,
validators_info: Vec<ValidatorInfo>,
user_sig_req_seed: [u8; 32],
user_sig_req_secret_key: Vec<u8>,
x25519_private_key: &x25519_dalek::StaticSecret,
) -> String {
let args = UserParticipatesInSigningProtocolArgs {
sig_uid: sig_uid.to_string(),
user_sig_req_seed: user_sig_req_seed.to_vec(),
user_sig_req_secret_key,
validators_info: validators_info
.into_iter()
.map(|validator_info| ValidatorInfoParsed {
Expand All @@ -309,11 +301,11 @@ async fn spawn_user_participates_in_signing_protocol(
/// the protocol runnning parameters as JSON as a command line argument
async fn spawn_user_participates_in_dkg_protocol(
validators_info: Vec<ValidatorInfo>,
user_sig_req_seed: [u8; 32],
user_sig_req_secret_key: Vec<u8>,
x25519_private_key: &x25519_dalek::StaticSecret,
) -> String {
let args = UserParticipatesInDkgProtocolArgs {
user_sig_req_seed: user_sig_req_seed.to_vec(),
user_sig_req_secret_key,
validators_info: validators_info
.into_iter()
.map(|validator_info| ValidatorInfoParsed {
Expand Down

0 comments on commit 13152bf

Please sign in to comment.