From a9661e2c2e7368fa2da832afcb5f0c9b44b9ba06 Mon Sep 17 00:00:00 2001 From: Boris Oncev Date: Wed, 28 Aug 2024 15:11:25 +0200 Subject: [PATCH] add sign and verify challenge to wasm lib --- wasm-wrappers/WASM-API.md | 12 +++++++++ wasm-wrappers/js-bindings/wasm_test.js | 23 ++++++++++++++++ wasm-wrappers/src/lib.rs | 36 ++++++++++++++++++++++++++ 3 files changed, 71 insertions(+) diff --git a/wasm-wrappers/WASM-API.md b/wasm-wrappers/WASM-API.md index 9e584ead0..abb2c228e 100644 --- a/wasm-wrappers/WASM-API.md +++ b/wasm-wrappers/WASM-API.md @@ -47,6 +47,18 @@ that derived the given public key. Note that this function is used for verifying messages related to spending, such as transaction input witness. +### Function: `sign_challenge` + +Given a message and a private key, create and sign a challenge with the given private key +This kind of signature is to be used when signing challenges. + +### Function: `verify_challenge` + +Given a signed challenge, an address and a message. Verify that +the signature is produced by signing the message with the private key +that derived the given public key. +Note that this function is used for verifying messages related challenges. + ### Function: `encode_output_transfer` Given a destination address, an amount and a network type (mainnet, testnet, etc), this function diff --git a/wasm-wrappers/js-bindings/wasm_test.js b/wasm-wrappers/js-bindings/wasm_test.js index 22d17a64c..6d55abfb9 100644 --- a/wasm-wrappers/js-bindings/wasm_test.js +++ b/wasm-wrappers/js-bindings/wasm_test.js @@ -41,6 +41,8 @@ import { effective_pool_balance, Amount, encode_output_issue_nft, + sign_challenge, + verify_challenge, } from "../pkg/wasm_wrappers.js"; function assert_eq_arrays(arr1, arr2) { @@ -103,6 +105,27 @@ export async function run_test() { console.log("Tested invalid menemonic successfully"); } + { + let challenge = sign_challenge(priv_key, message); + let address = pubkey_to_pubkeyhash_address(pub_key, Network.Testnet); + let result = verify_challenge(address, Network.Testnet, challenge, message); + if (!result) { + throw new Error("Invalid sing and verify challenge"); + } + + const different_priv_key = make_private_key(); + const different_pub_key = public_key_from_private_key(different_priv_key); + let different_address = pubkey_to_pubkeyhash_address(different_pub_key, Network.Testnet); + try { + verify_challenge(different_address, Network.Testnet, challenge, message); + } catch (e) { + if (!e.includes("Public key to address mismatch")) { + throw e; + } + console.log("Tested verify with different address successfully"); + } + } + try { make_receiving_address(bad_priv_key, 0); throw new Error("Invalid private key worked somehow!"); diff --git a/wasm-wrappers/src/lib.rs b/wasm-wrappers/src/lib.rs index f06225f05..d023d6e76 100644 --- a/wasm-wrappers/src/lib.rs +++ b/wasm-wrappers/src/lib.rs @@ -26,7 +26,9 @@ use common::{ output_value::OutputValue::{self, Coin, TokenV1}, signature::{ inputsig::{ + arbitrary_message::{produce_message_challenge, ArbitraryMessageSignature}, authorize_hashed_timelock_contract_spend::AuthorizedHashedTimelockContractSpend, + authorize_pubkeyhash_spend::AuthorizedPublicKeyHashSpend, classical_multisig::authorize_classical_multisig::{ sign_classical_multisig_spending, AuthorizedClassicalMultisigSpend, }, @@ -340,6 +342,40 @@ pub fn verify_signature_for_spending( Ok(verifcation_result) } +/// Given a message and a private key, create and sign a challenge with the given private key +/// This kind of signature is to be used when signing challenges. +#[wasm_bindgen] +pub fn sign_challenge(private_key: &[u8], message: &[u8]) -> Result, Error> { + let private_key = PrivateKey::decode_all(&mut &private_key[..]) + .map_err(|_| Error::InvalidPrivateKeyEncoding)?; + + let challenge = produce_message_challenge(message); + let public_key = PublicKey::from_private_key(&private_key); + + let signature = private_key.sign_message(&challenge.encode(), randomness::make_true_rng())?; + let signature = AuthorizedPublicKeyHashSpend::new(public_key, signature); + Ok(signature.encode()) +} + +/// Given a signed challenge, an address and a message. Verify that +/// the signature is produced by signing the message with the private key +/// that derived the given public key. +/// Note that this function is used for verifying messages related challenges. +#[wasm_bindgen] +pub fn verify_challenge( + address: &str, + network: Network, + signed_challenge: &[u8], + message: &[u8], +) -> Result { + let chain_config = Builder::new(network.into()).build(); + let destination = parse_addressable::(&chain_config, address)?; + let message_challenge = produce_message_challenge(message); + let sig = ArbitraryMessageSignature::from_data(signed_challenge.to_vec()); + sig.verify_signature(&chain_config, &destination, &message_challenge)?; + Ok(true) +} + fn parse_addressable( chain_config: &ChainConfig, address: &str,