Skip to content

Commit

Permalink
Merge branch 'kaspanet:master' into legacy
Browse files Browse the repository at this point in the history
  • Loading branch information
aspect authored Oct 26, 2023
2 parents a84719d + 11cc019 commit 5a3e7b0
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 11 deletions.
6 changes: 6 additions & 0 deletions consensus/wasm/src/keypair.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,3 +246,9 @@ impl TryFrom<JsValue> for PublicKey {
}
}
}

impl From<PublicKey> for XOnlyPublicKey {
fn from(value: PublicKey) -> Self {
value.xonly_public_key
}
}
24 changes: 13 additions & 11 deletions wallet/core/src/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,6 @@ pub fn sign_message(msg: &PersonalMessage, privkey: &[u8; 32]) -> Result<Vec<u8>
Ok(sig.to_vec())
}

pub fn sign_message_with_aux_rand(msg: &PersonalMessage, privkey: &[u8; 32], aux_rand: &[u8; 32]) -> Result<Vec<u8>, Error> {
let hash = calc_personal_message_hash(msg);

let msg = secp256k1::Message::from_slice(hash.as_bytes().as_slice())?;
let schnorr_key = secp256k1::KeyPair::from_seckey_slice(secp256k1::SECP256K1, privkey)?;
let curve = secp256k1::Secp256k1::new();
let sig: [u8; 64] = *curve.sign_schnorr_with_aux_rand(&msg, &schnorr_key, aux_rand).as_ref();

Ok(sig.to_vec())
}

/// Ok(()) if the signature matches the given message and pubkey
/// Error if any of the inputs are incorrect, or the signature is invalid
pub fn verify_message(msg: &PersonalMessage, signature: &Vec<u8>, pubkey: &XOnlyPublicKey) -> Result<(), Error> {
Expand All @@ -50,6 +39,19 @@ fn calc_personal_message_hash(msg: &PersonalMessage) -> Hash {
mod tests {
use super::*;

/// Sign message equivalent that's only used for tests
/// Necessary only because of KIP test vectors
fn sign_message_with_aux_rand(msg: &PersonalMessage, privkey: &[u8; 32], aux_rand: &[u8; 32]) -> Result<Vec<u8>, Error> {
let hash = calc_personal_message_hash(msg);

let msg = secp256k1::Message::from_slice(hash.as_bytes().as_slice())?;
let schnorr_key = secp256k1::KeyPair::from_seckey_slice(secp256k1::SECP256K1, privkey)?;
let curve = secp256k1::Secp256k1::new();
let sig: [u8; 64] = *curve.sign_schnorr_with_aux_rand(&msg, &schnorr_key, aux_rand).as_ref();

Ok(sig.to_vec())
}

#[test]
fn test_basic_sign_and_verify_sign() {
let pm = PersonalMessage("Hello Kaspa!");
Expand Down
45 changes: 45 additions & 0 deletions wallet/core/src/wasm/message.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use crate::imports::*;
use crate::message::*;
use kaspa_consensus_wasm::{PrivateKey, PublicKey};

/// Signs a message with the given private key
/// @param {object} value - an object containing { message: String, privateKey: String|PrivateKey }
/// @returns {String} the signature, in hex string format
#[wasm_bindgen(js_name = signMessage, skip_jsdoc)]
pub fn js_sign_message(value: JsValue) -> Result<String, Error> {
if let Some(object) = Object::try_from(&value) {
let private_key = object.get::<PrivateKey>("privateKey")?;
let raw_msg = object.get_string("message")?;
let mut privkey_bytes = [0u8; 32];

privkey_bytes.copy_from_slice(&private_key.secret_bytes());

let pm = PersonalMessage(&raw_msg);

let sig_vec = sign_message(&pm, &privkey_bytes)?;

Ok(faster_hex::hex_string(sig_vec.as_slice()))
} else {
Err(Error::custom("Failed to parse input"))
}
}

/// Verifies with a public key the signature of the given message
/// @param {object} value - an object containing { message: String, signature: String, publicKey: String|PublicKey }
/// @returns {bool} true if the signature can be verified with the given public key and message, false otherwise
#[wasm_bindgen(js_name = verifyMessage, skip_jsdoc)]
pub fn js_verify_message(value: JsValue) -> Result<bool, Error> {
if let Some(object) = Object::try_from(&value) {
let public_key = object.get::<PublicKey>("publicKey")?;
let raw_msg = object.get_string("message")?;
let signature = object.get_string("signature")?;

let pm = PersonalMessage(&raw_msg);
let mut signature_bytes = [0u8; 64];
faster_hex::hex_decode(signature.as_bytes(), &mut signature_bytes)?;

Ok(verify_message(&pm, &signature_bytes.to_vec(), &public_key.into()).is_ok())
} else {
Err(Error::custom("Failed to parse input"))
}
}
2 changes: 2 additions & 0 deletions wallet/core/src/wasm/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod balance;
pub mod message;
pub mod tx;
pub mod utils;
pub mod utxo;
Expand All @@ -7,6 +8,7 @@ pub mod xprivatekey;
pub mod xpublickey;

pub use balance::*;
pub use message::*;
pub use tx::*;
pub use utils::*;
pub use utxo::*;
Expand Down
30 changes: 30 additions & 0 deletions wasm/nodejs/message_signing.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
let kaspa = require('./kaspa/kaspa_wasm');
let {
PrivateKey,
PublicKey,
signMessage,
verifyMessage,
} = kaspa;

kaspa.initConsolePanicHook();

let message = 'Hello Kaspa!';
let privkey = 'B7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEF';
let pubkey = 'DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659';

function runDemo(message, privateKey, publicKey) {
let signature = signMessage({message, privateKey});

console.info(`Message: ${message} => Signature: ${signature}`);

if (verifyMessage({message, signature, publicKey})) {
console.info('Signature verified!');
} else {
console.info('Signature is invalid!');
}
}

// Using strings:
runDemo(message, privkey, pubkey);
// Using Objects:
runDemo(message, new PrivateKey(privkey), new PublicKey(pubkey));

0 comments on commit 5a3e7b0

Please sign in to comment.