Skip to content

Commit 1d3b9a9

Browse files
feat: add signMessage noAuxRand option for kaspa wasm (#587)
* feat: add signMessageWithoutRand method for kaspa wasm * enhance: sign message api * fix: unit test fail * chore: update noAuxRand of ISignMessage * chore: add sign message demo for noAuxRand
1 parent 116dfb0 commit 1d3b9a9

File tree

4 files changed

+60
-9
lines changed

4 files changed

+60
-9
lines changed

cli/src/modules/message.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use kaspa_addresses::Version;
22
use kaspa_bip32::secp256k1::XOnlyPublicKey;
3+
use kaspa_wallet_core::message::SignMessageOptions;
34
use kaspa_wallet_core::{
45
account::{BIP32_ACCOUNT_KIND, KEYPAIR_ACCOUNT_KIND},
56
message::{sign_message, verify_message, PersonalMessage},
@@ -87,8 +88,9 @@ impl Message {
8788

8889
let pm = PersonalMessage(message);
8990
let privkey = self.get_address_private_key(&ctx, kaspa_address).await?;
91+
let sign_options = SignMessageOptions { no_aux_rand: false };
9092

91-
let sig_result = sign_message(&pm, &privkey);
93+
let sig_result = sign_message(&pm, &privkey, &sign_options);
9294

9395
match sig_result {
9496
Ok(signature) => {

wallet/core/src/message.rs

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,28 @@ impl AsRef<[u8]> for PersonalMessage<'_> {
1515
}
1616
}
1717

18+
#[derive(Clone)]
19+
pub struct SignMessageOptions {
20+
/// The auxiliary randomness exists only to mitigate specific kinds of power analysis
21+
/// side-channel attacks. Providing it definitely improves security, but omitting it
22+
/// should not be considered dangerous, as most legacy signature schemes don't provide
23+
/// mitigations against such attacks. To read more about the relevant discussions that
24+
/// arose in adding this randomness please see: https://github.com/sipa/bips/issues/195
25+
pub no_aux_rand: bool,
26+
}
27+
1828
/// Sign a message with the given private key
19-
pub fn sign_message(msg: &PersonalMessage, privkey: &[u8; 32]) -> Result<Vec<u8>, Error> {
29+
pub fn sign_message(msg: &PersonalMessage, privkey: &[u8; 32], options: &SignMessageOptions) -> Result<Vec<u8>, Error> {
2030
let hash = calc_personal_message_hash(msg);
2131

2232
let msg = secp256k1::Message::from_digest_slice(hash.as_bytes().as_slice())?;
2333
let schnorr_key = secp256k1::Keypair::from_seckey_slice(secp256k1::SECP256K1, privkey)?;
24-
let sig: [u8; 64] = *schnorr_key.sign_schnorr(msg).as_ref();
34+
35+
let sig: [u8; 64] = if options.no_aux_rand {
36+
*secp256k1::SECP256K1.sign_schnorr_no_aux_rand(&msg, &schnorr_key).as_ref()
37+
} else {
38+
*schnorr_key.sign_schnorr(msg).as_ref()
39+
};
2540

2641
Ok(sig.to_vec())
2742
}
@@ -74,7 +89,26 @@ mod tests {
7489
])
7590
.unwrap();
7691

77-
verify_message(&pm, &sign_message(&pm, &privkey).expect("sign_message failed"), &pubkey).expect("verify_message failed");
92+
let sign_with_aux_rand = SignMessageOptions { no_aux_rand: false };
93+
let sign_with_no_aux_rand = SignMessageOptions { no_aux_rand: true };
94+
verify_message(&pm, &sign_message(&pm, &privkey, &sign_with_aux_rand).expect("sign_message failed"), &pubkey)
95+
.expect("verify_message failed");
96+
verify_message(&pm, &sign_message(&pm, &privkey, &sign_with_no_aux_rand).expect("sign_message failed"), &pubkey)
97+
.expect("verify_message failed");
98+
}
99+
100+
#[test]
101+
fn test_basic_sign_without_rand_twice_should_get_same_signature() {
102+
let pm = PersonalMessage("Hello Kaspa!");
103+
let privkey: [u8; 32] = [
104+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
105+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
106+
];
107+
108+
let sign_with_no_aux_rand = SignMessageOptions { no_aux_rand: true };
109+
let signature = sign_message(&pm, &privkey, &sign_with_no_aux_rand).expect("sign_message failed");
110+
let signature_twice = sign_message(&pm, &privkey, &sign_with_no_aux_rand).expect("sign_message failed");
111+
assert_eq!(signature, signature_twice);
78112
}
79113

80114
#[test]
@@ -90,7 +124,12 @@ mod tests {
90124
])
91125
.unwrap();
92126

93-
verify_message(&pm, &sign_message(&pm, &privkey).expect("sign_message failed"), &pubkey).expect("verify_message failed");
127+
let sign_with_aux_rand = SignMessageOptions { no_aux_rand: false };
128+
let sign_with_no_aux_rand = SignMessageOptions { no_aux_rand: true };
129+
verify_message(&pm, &sign_message(&pm, &privkey, &sign_with_aux_rand).expect("sign_message failed"), &pubkey)
130+
.expect("verify_message failed");
131+
verify_message(&pm, &sign_message(&pm, &privkey, &sign_with_no_aux_rand).expect("sign_message failed"), &pubkey)
132+
.expect("verify_message failed");
94133
}
95134

96135
#[test]
@@ -110,7 +149,12 @@ Ut omnis magnam et accusamus earum rem impedit provident eum commodi repellat qu
110149
])
111150
.unwrap();
112151

113-
verify_message(&pm, &sign_message(&pm, &privkey).expect("sign_message failed"), &pubkey).expect("verify_message failed");
152+
let sign_with_aux_rand = SignMessageOptions { no_aux_rand: false };
153+
let sign_with_no_aux_rand = SignMessageOptions { no_aux_rand: true };
154+
verify_message(&pm, &sign_message(&pm, &privkey, &sign_with_aux_rand).expect("sign_message failed"), &pubkey)
155+
.expect("verify_message failed");
156+
verify_message(&pm, &sign_message(&pm, &privkey, &sign_with_no_aux_rand).expect("sign_message failed"), &pubkey)
157+
.expect("verify_message failed");
114158
}
115159

116160
#[test]

wallet/core/src/wasm/message.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const TS_MESSAGE_TYPES: &'static str = r#"
1414
export interface ISignMessage {
1515
message: string;
1616
privateKey: PrivateKey | string;
17+
noAuxRand?: boolean;
1718
}
1819
"#;
1920

@@ -30,10 +31,12 @@ pub fn js_sign_message(value: ISignMessage) -> Result<HexString, Error> {
3031
if let Some(object) = Object::try_from(&value) {
3132
let private_key = object.cast_into::<PrivateKey>("privateKey")?;
3233
let raw_msg = object.get_string("message")?;
34+
let no_aux_rand = object.get_bool("noAuxRand").unwrap_or(false);
3335
let mut privkey_bytes = [0u8; 32];
3436
privkey_bytes.copy_from_slice(&private_key.secret_bytes());
3537
let pm = PersonalMessage(&raw_msg);
36-
let sig_vec = sign_message(&pm, &privkey_bytes)?;
38+
let sign_options = SignMessageOptions { no_aux_rand };
39+
let sig_vec = sign_message(&pm, &privkey_bytes, &sign_options)?;
3740
privkey_bytes.zeroize();
3841
Ok(faster_hex::hex_string(sig_vec.as_slice()).into())
3942
} else {

wasm/examples/nodejs/javascript/general/message-signing.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ let message = 'Hello Kaspa!';
1212
let privkey = 'b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da56a784d9045190cfef';
1313
let pubkey = 'dff1d77f2a671c5f36183726db2341be58feae1da2deced843240f7b502ba659';
1414

15-
function runDemo(message, privateKey, publicKey) {
16-
let signature = signMessage({message, privateKey});
15+
function runDemo(message, privateKey, publicKey, noAuxRand) {
16+
let signature = signMessage({message, privateKey, noAuxRand});
1717

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

@@ -26,5 +26,7 @@ function runDemo(message, privateKey, publicKey) {
2626

2727
// Using strings:
2828
runDemo(message, privkey, pubkey);
29+
runDemo(message, privkey, pubkey, true);
2930
// Using Objects:
3031
runDemo(message, new PrivateKey(privkey), new PublicKey(pubkey));
32+
runDemo(message, new PrivateKey(privkey), new PublicKey(pubkey), true);

0 commit comments

Comments
 (0)