Support sr25519 agreement (#209)
* Support sr25519 ecdh agreement * Align version of curve25519-dalek Co-authored-by: Jaco <jacogr@gmail.com> * Reduce code size Co-authored-by: Jaco <jacogr@gmail.com> * Add explicit tests on sr25519 key agreement * Fix linting issues * Fix sr25519 key_agreement test Co-authored-by: Jaco <jacogr@gmail.com>
This commit is contained in:
Generated
+3
@@ -1,5 +1,7 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.13.0"
|
||||
@@ -659,6 +661,7 @@ version = "0.0.0"
|
||||
dependencies = [
|
||||
"blake2-rfc",
|
||||
"byteorder",
|
||||
"curve25519-dalek",
|
||||
"ed25519-dalek",
|
||||
"hex-literal",
|
||||
"hmac",
|
||||
|
||||
@@ -22,6 +22,7 @@ hmac = "0.7.0"
|
||||
# libsecp256k1 = "0.2.2"
|
||||
merlin = { version = "2.0", default-features = false }
|
||||
pbkdf2 = { version = "0.3.0", default-features = false }
|
||||
curve25519-dalek = { version = "2.1.0", default-features = false }
|
||||
schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated", "u64_backend"] }
|
||||
scrypt = { version = "0.2", default-features = false }
|
||||
sha2 = "0.8.1"
|
||||
|
||||
@@ -159,6 +159,17 @@ export const sr25519Verify = withWasm((wasm) =>
|
||||
}
|
||||
);
|
||||
|
||||
export const sr25519Agree = withWasm((wasm) =>
|
||||
(pubkey: Uint8Array, secret: Uint8Array): Uint8Array => {
|
||||
const [ptr0, len0] = allocU8a(pubkey);
|
||||
const [ptr1, len1] = allocU8a(secret);
|
||||
|
||||
wasm.ext_sr_agree(8, ptr0, len0, ptr1, len1);
|
||||
|
||||
return resultU8a();
|
||||
}
|
||||
);
|
||||
|
||||
export const vrfSign = withWasm((wasm) =>
|
||||
(secret: Uint8Array, context: Uint8Array, message: Uint8Array, extra: Uint8Array): Uint8Array => {
|
||||
const [ptr0, len0] = allocU8a(secret);
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
// which was adpated from the initial https://github.com/paritytech/schnorrkel-js/
|
||||
// forked at commit eff430ddc3090f56317c80654208b8298ef7ab3f
|
||||
|
||||
use curve25519_dalek::scalar::Scalar;
|
||||
use schnorrkel::{
|
||||
ExpansionMode, Keypair, MiniSecretKey, PublicKey, SecretKey, Signature,
|
||||
derive::{Derivation, ChainCode, CHAIN_CODE_LENGTH},
|
||||
@@ -134,6 +135,21 @@ pub fn ext_sr_verify(signature: &[u8], message: &[u8], pubkey: &[u8]) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
/// Key agreement between other's public key and self secret key.
|
||||
///
|
||||
/// * pubkey: UIntArray with 32 element
|
||||
/// * secret: UIntArray with 64 element
|
||||
///
|
||||
/// * returned vector is the generated secret of 32 bytes.
|
||||
#[wasm_bindgen]
|
||||
pub fn ext_sr_agree(pubkey: &[u8], secret: &[u8]) -> Vec<u8> {
|
||||
let secret = SecretKey::from_ed25519_bytes(secret).unwrap();
|
||||
// The first 32 bytes holds the canonical private key
|
||||
let mut key = [0u8; 32];
|
||||
key.copy_from_slice(&secret.to_bytes()[0..32]);
|
||||
(&Scalar::from_canonical_bytes(key).unwrap() * PublicKey::from_bytes(pubkey).unwrap().as_point()).compress().0.to_vec()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
extern crate rand;
|
||||
@@ -243,4 +259,32 @@ pub mod tests {
|
||||
|
||||
assert_eq!(public, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn key_agreement() {
|
||||
let self_seed = hex!("98b3d305d5a5eace562387e47e59badd4d77e3f72cabfb10a60f8a197059f0a8");
|
||||
let other_seed = hex!("9732eea001851ff862d949a1699c9971f3a26edbede2ad7922cbbe9a0701f366");
|
||||
let expected = hex!("b03a0b198c34c16f35cae933d88b16341b4cef3e84e851f20e664c6a30527f4e");
|
||||
let self_pair = ext_sr_from_seed(&self_seed);
|
||||
let self_sk = &self_pair[0..SECRET_KEY_LENGTH];
|
||||
let self_pk = &self_pair[SECRET_KEY_LENGTH..KEYPAIR_LENGTH];
|
||||
let other_pair = ext_sr_from_seed(&other_seed);
|
||||
let other_sk = &other_pair[0..SECRET_KEY_LENGTH];
|
||||
let other_pk = &other_pair[SECRET_KEY_LENGTH..KEYPAIR_LENGTH];
|
||||
|
||||
assert_eq!(ext_sr_agree(self_pk, other_sk), expected);
|
||||
assert_eq!(ext_sr_agree(other_pk, self_sk), expected);
|
||||
|
||||
let seed = generate_random_seed();
|
||||
let self_pair = ext_sr_from_seed(seed.as_slice());
|
||||
let self_sk = &self_pair[0..SECRET_KEY_LENGTH];
|
||||
let self_pk = &self_pair[SECRET_KEY_LENGTH..KEYPAIR_LENGTH];
|
||||
|
||||
let seed = generate_random_seed();
|
||||
let other_pair = ext_sr_from_seed(seed.as_slice());
|
||||
let other_sk = &other_pair[0..SECRET_KEY_LENGTH];
|
||||
let other_pk = &other_pair[SECRET_KEY_LENGTH..KEYPAIR_LENGTH];
|
||||
|
||||
assert_eq!(ext_sr_agree(self_pk, other_sk), ext_sr_agree(other_pk, self_sk));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ export interface WasmCryptoInstance {
|
||||
ext_sr_from_seed(a: number, b: number, c: number): void;
|
||||
ext_sr_sign(a: number, b: number, c: number, d: number, e: number, f: number, g: number): void;
|
||||
ext_sr_verify(a: number, b: number, c: number, d: number, e: number, f: number): number;
|
||||
ext_sr_agree(a: number, b: number, c: number, d: number, e: number): void;
|
||||
ext_vrf_sign(a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number): void;
|
||||
ext_vrf_verify(a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number): number;
|
||||
}
|
||||
|
||||
@@ -120,6 +120,23 @@ function sr25519_benchmark (wasm) {
|
||||
}
|
||||
}
|
||||
|
||||
function sr25519_key_agreement (wasm) {
|
||||
const pair1 = wasm.sr25519KeypairFromSeed(hexToU8a('0x3b44c558f9a8f3dc9690d53088558c1ba2529b677e316c6054d1852595b004af'));
|
||||
const pair2 = wasm.sr25519KeypairFromSeed(hexToU8a('0x923b80f79c6981fe756272128ec236eb510ae016dd20bdccbd77a9416b7ab94e'));
|
||||
const [, pk1, sk1] = extractKeys(pair1);
|
||||
const [, pk2, sk2] = extractKeys(pair2);
|
||||
|
||||
assert(u8aToHex(wasm.sr25519Agree(pk1, sk2)) === '0xfa7b90001b790fe42ff78b8cd86f6cf7a7c0a70b72f6b4c771b5d67536450222', 'Unmatched agreement keys');
|
||||
assert(u8aToHex(wasm.sr25519Agree(pk2, sk1)) === '0xfa7b90001b790fe42ff78b8cd86f6cf7a7c0a70b72f6b4c771b5d67536450222', 'Unmatched agreement keys');
|
||||
|
||||
for (let i = 0; i < 256; i++) {
|
||||
const [, pk1, sk1] = randomPair(wasm);
|
||||
const [, pk2, sk2] = randomPair(wasm);
|
||||
|
||||
assert(u8aToHex(wasm.sr25519Agree(pk1, sk2)) === u8aToHex(wasm.sr25519Agree(pk2, sk1)), 'Unmatched agreement keys');
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
sr25519_benchmark,
|
||||
sr25519_deriveHard,
|
||||
@@ -128,6 +145,7 @@ module.exports = {
|
||||
sr25519_deriveSoftKnown,
|
||||
sr25519_deriveSoftPubkey,
|
||||
sr25519_devFromSeed,
|
||||
sr25519_key_agreement,
|
||||
sr25519_pairFromSeed,
|
||||
sr25519_signAndVerify,
|
||||
sr25519_sign_deterministic,
|
||||
|
||||
Reference in New Issue
Block a user