From 13152bf351b10ab81de58eafb9a378c1e7ed49d8 Mon Sep 17 00:00:00 2001 From: peg Date: Wed, 29 Nov 2023 22:53:17 +0100 Subject: [PATCH] `entropy-protocol` - polkadot-js compatible sr25519 key generation for 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 --- .circleci/then.yml | 2 +- crypto/protocol/Cargo.toml | 3 +++ crypto/protocol/Makefile | 4 +++ crypto/protocol/nodejs-test/index.js | 4 +-- crypto/protocol/src/user/wasm.rs | 38 +++++++++++++++++----------- crypto/server/tests/protocol_wasm.rs | 34 ++++++++++--------------- 6 files changed, 46 insertions(+), 39 deletions(-) diff --git a/.circleci/then.yml b/.circleci/then.yml index bd66ccf06..336b540d4 100644 --- a/.circleci/then.yml +++ b/.circleci/then.yml @@ -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 ../../.. diff --git a/crypto/protocol/Cargo.toml b/crypto/protocol/Cargo.toml index 8bb632d13..6fe0a9891 100644 --- a/crypto/protocol/Cargo.toml +++ b/crypto/protocol/Cargo.toml @@ -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"] diff --git a/crypto/protocol/Makefile b/crypto/protocol/Makefile index 73ce5247b..0ce24ed19 100644 --- a/crypto/protocol/Makefile +++ b/crypto/protocol/Makefile @@ -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/ diff --git a/crypto/protocol/nodejs-test/index.js b/crypto/protocol/nodejs-test/index.js index aa940a867..b74bc836b 100644 --- a/crypto/protocol/nodejs-test/index.js +++ b/crypto/protocol/nodejs-test/index.js @@ -33,7 +33,7 @@ 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) @@ -41,7 +41,7 @@ switch(process.argv[2].toLowerCase()) { 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) diff --git a/crypto/protocol/src/user/wasm.rs b/crypto/protocol/src/user/wasm.rs index 7e33d1d6b..564ce165d 100644 --- a/crypto/protocol/src/user/wasm.rs +++ b/crypto/protocol/src/user/wasm.rs @@ -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; @@ -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, + user_signing_secret_key: Vec, x25519_private_key_vec: Vec, ) -> Result { 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 @@ -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, + user_signing_secret_key: Vec, x25519_private_key_vec: Vec, ) -> Result { let validators_info = parse_validator_info(validators_info_js)?; @@ -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 @@ -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) -> Result { + 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 })) +} diff --git a/crypto/server/tests/protocol_wasm.rs b/crypto/server/tests/protocol_wasm.rs index 9b0853587..71285aea8 100644 --- a/crypto/server/tests/protocol_wasm.rs +++ b/crypto/server/tests/protocol_wasm.rs @@ -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; @@ -124,12 +124,6 @@ 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), @@ -137,7 +131,7 @@ async fn test_wasm_sign_tx_user_participates() { &users_keyshare_option.clone().unwrap(), &sig_uid, validators_info.clone(), - eve_seed, + one.pair().to_raw_vec(), &one_x25519_sk, ), ) @@ -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; @@ -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, + user_sig_req_secret_key: Vec, x25519_private_key: Vec, sig_uid: String, key_share: String, @@ -265,7 +257,7 @@ struct UserParticipatesInSigningProtocolArgs { #[derive(Debug, Clone, Serialize, Deserialize)] struct UserParticipatesInDkgProtocolArgs { - user_sig_req_seed: Vec, + user_sig_req_secret_key: Vec, x25519_private_key: Vec, validators_info: Vec, } @@ -283,12 +275,12 @@ async fn spawn_user_participates_in_signing_protocol( key_share: &KeyShare, sig_uid: &str, validators_info: Vec, - user_sig_req_seed: [u8; 32], + user_sig_req_secret_key: Vec, 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 { @@ -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, - user_sig_req_seed: [u8; 32], + user_sig_req_secret_key: Vec, 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 {