Combine all crypto into a single package (#15)

* Combine all crypto into a single package

* Disable build for daled & schnrorrkel (combined)

* Bump @polkadot/dev (for publish)

* yarn.lock

* Fix CHANGELOG
This commit is contained in:
Jaco Greeff
2019-03-30 17:35:43 +01:00
committed by GitHub
parent 768ec2c043
commit a1692ae1e6
25 changed files with 1285 additions and 507 deletions
+6
View File
@@ -1,3 +1,9 @@
# 0.8.1
- Pull ed25519 & sr25519 into wasm-crypto as well (smaller final size)
- Disable build/publish of `wasm-dalek-ed25519` & `wasm-schnorrkel` (single package)
- Improve error messaging, instead of `__wasm_malloc of null`
# 0.7.1
- Fix build scripts to properly attach errors in the log (dropped in 0.6.1)
+1 -1
View File
@@ -21,7 +21,7 @@
},
"devDependencies": {
"@babel/core": "^7.4.0",
"@polkadot/dev": "^0.28.1",
"@polkadot/dev": "^0.29.0-beta.0",
"@polkadot/util": "^0.76.0-beta.0"
}
}
+102
View File
@@ -93,6 +93,14 @@ name = "cfg-if"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "clear_on_drop"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cloudabi"
version = "0.0.3"
@@ -120,6 +128,18 @@ dependencies = [
"subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "curve25519-dalek"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"subtle 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "digest"
version = "0.8.0"
@@ -128,6 +148,18 @@ dependencies = [
"generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ed25519-dalek"
version = "1.0.0-pre.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"curve25519-dalek 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "failure"
version = "0.1.5"
@@ -201,6 +233,11 @@ dependencies = [
"digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "keccak"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lazy_static"
version = "1.3.0"
@@ -232,6 +269,17 @@ name = "memory_units"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "merlin"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "nodrop"
version = "0.1.13"
@@ -250,6 +298,14 @@ name = "opaque-debug"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "packed_simd"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "parking_lot"
version = "0.7.1"
@@ -316,6 +372,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
"packed_simd 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -427,6 +484,23 @@ dependencies = [
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "schnorrkel"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"curve25519-dalek 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"ed25519-dalek 1.0.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"merlin 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"sha3 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"subtle 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "scopeguard"
version = "0.3.3"
@@ -456,6 +530,18 @@ dependencies = [
"opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "sha3"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "smallvec"
version = "0.6.9"
@@ -466,6 +552,11 @@ name = "subtle"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "subtle"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "syn"
version = "0.15.29"
@@ -546,10 +637,12 @@ version = "0.0.0"
dependencies = [
"blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"ed25519-dalek 1.0.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)",
"hex-literal 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"hmac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"schnorrkel 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tiny-bip39 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -651,11 +744,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb"
"checksum cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)" = "c9ce8bb087aacff865633f0bd5aeaed910fe2fe55b55f4739527f2e023a2e53d"
"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4"
"checksum clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "97276801e127ffb46b66ce23f35cc96bd454fa311294bced4bbace7baa8b1d17"
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
"checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e"
"checksum crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a2f4a431c5c9f662e1200b7c7f02c34e91361150e382089a8f2dec3ba680cbda"
"checksum crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5"
"checksum curve25519-dalek 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e1f8a6fc0376eb52dc18af94915cc04dfdf8353746c0e8c550ae683a0815e5c1"
"checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c"
"checksum ed25519-dalek 1.0.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)" = "81956bcf7ef761fb4e1d88de3fa181358a0d26cbcb9755b587a08f9119824b86"
"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2"
"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1"
"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
@@ -665,14 +761,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum hex-literal 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ddc2928beef125e519d69ae1baa8c37ea2e0d3848545217f6db0179c5eb1d639"
"checksum hex-literal-impl 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "520870c3213943eb8d7803e80180d12a6c7ceb4ae74602544529d1643dc4ddda"
"checksum hmac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f127a908633569f208325f86f71255d3363c79721d7f9fe31cd5569908819771"
"checksum keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7"
"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
"checksum libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "aab692d7759f5cd8c859e169db98ae5b52c924add2af5fbbca11d12fefb567c1"
"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c"
"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
"checksum memory_units 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3"
"checksum merlin 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "83c2dda19c01176e8e7148f7bdb88bbdf215a8db0641f89fc40e4b81736aeda5"
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
"checksum once_cell 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "532c29a261168a45ce28948f9537ddd7a5dd272cc513b3017b1e82a88f962c37"
"checksum opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "93f5bb2e8e8dec81642920ccff6b61f1eb94fa3020c5a325c9851ff604152409"
"checksum packed_simd 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a85ea9fc0d4ac0deb6fe7911d38786b32fc11119afd9e9d38b84ff691ce64220"
"checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337"
"checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9"
"checksum pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9"
@@ -693,12 +792,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
"checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619"
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
"checksum schnorrkel 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a700659388785588c75b197cecda0f23c7112a9281ef703e8ffc651061ce014c"
"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
"checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d"
"checksum sha3 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "34a5e54083ce2b934bf059fdf38e7330a154177e029ab6c4e18638f2f624053a"
"checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be"
"checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee"
"checksum subtle 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "702662512f3ddeb74a64ce2fbbf3707ee1b6bb663d28bb054e0779bbc720d926"
"checksum syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1825685f977249735d510a242a6727b46efe914bb67e38d30c071b1b72b1d5c2"
"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015"
"checksum tiny-bip39 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f5388a470627f97a01a6e13389ced797a42b1611f9de7e0f6ca705675ac55297"
+2
View File
@@ -17,9 +17,11 @@ crate-type = ["cdylib", "rlib"]
[dependencies]
blake2-rfc = "0.2.18"
byteorder = "1.3.1"
ed25519-dalek = { version = "1.0.0-pre.1", features = ["nightly"] }
hmac = "0.7.0"
# libsecp256k1 = "0.2.2"
pbkdf2 = { version = "0.3.0", default-features = false }
schnorrkel = { version = "0.1.0", features = ["nightly"] }
sha2 = "0.8.0"
tiny-bip39 = { version = "0.6.1", default-features = false }
tiny-keccak = "1.4.2"
+127
View File
@@ -0,0 +1,127 @@
// Copyright 2019 @polkadot/wasm-crypto authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
use bip39::{Mnemonic, MnemonicType, Language, Seed};
use hmac::Hmac;
use pbkdf2::pbkdf2;
use sha2::Sha512;
use wasm_bindgen::prelude::*;
/// Generate a bip39 phrase
///
/// words: number of words, either 12, 15, 18 21 or 24
///
/// Returns the bip 39 phrase
#[wasm_bindgen]
pub fn ext_bip39_generate(words: u32) -> String {
Mnemonic::new(MnemonicType::for_word_count(words as usize).unwrap(), Language::English)
.into_phrase()
}
/// Create entropy from a bip39 phrase
///
/// * phrase: mnemonic phrase
///
/// Returns the entropy
#[wasm_bindgen]
pub fn ext_bip39_to_entropy(phrase: &str) -> Vec<u8> {
Mnemonic::from_phrase(phrase, Language::English)
.unwrap()
.entropy()
.to_vec()
}
/// Create a mini-secret from a bip39 phrase
///
/// * phrase: mnemonic phrase
///
/// Returns the 32-byte mini-secret via entropy
#[wasm_bindgen]
pub fn ext_bip39_to_mini_secret(phrase: &str, password: &str) -> Vec<u8> {
let salt = format!("mnemonic{}", password);
let mnemonic = Mnemonic::from_phrase(phrase, Language::English).unwrap();
let mut result = [0u8; 64];
pbkdf2::<Hmac<Sha512>>(mnemonic.entropy(), salt.as_bytes(), 2048, &mut result);
result[..32].to_vec()
}
/// Creates a see from a bip-39 phrase
///
/// @phrase: mnemonic phrase
///
/// Returns a 32-byte seed
#[wasm_bindgen]
pub fn ext_bip39_to_seed(phrase: &str, password: &str) -> Vec<u8> {
let mnemonic = Mnemonic::from_phrase(phrase, Language::English).unwrap();
Seed::new(&mnemonic, password)
.as_bytes()[..32]
.to_vec()
}
/// Validates a bip39 phrase
///
/// * phrase: mnemonic phrase
///
/// Returns the true/false
#[wasm_bindgen]
pub fn ext_bip39_validate(phrase: &str) -> bool {
match Mnemonic::validate(phrase, Language::English) {
Err(_) => false,
_ => true
}
}
#[cfg(test)]
pub mod tests {
use hex_literal::{hex, hex_impl};
use super::*;
#[test]
fn can_bip39_entropy() {
let phrase = "legal winner thank year wave sausage worth useful legal winner thank yellow";
let entropy = hex!("7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f");
let result = ext_bip39_to_entropy(phrase);
assert_eq!(result, entropy);
}
#[test]
fn can_bip39_mini_secret() {
let phrase = "legal winner thank year wave sausage worth useful legal winner thank yellow";
let password = "Substrate";
let mini = hex!("4313249608fe8ac10fd5886c92c4579007272cb77c21551ee5b8d60b78041685");
let result = ext_bip39_to_mini_secret(phrase, password);
assert_eq!(result[..], mini[..]);
}
#[test]
fn can_bip39_seed() {
let phrase = "seed sock milk update focus rotate barely fade car face mechanic mercy";
let seed = hex!("3c121e20de068083b49c2315697fb59a2d9e8643c24e5ea7628132c58969a027");
let result = ext_bip39_to_seed(phrase, "");
assert_eq!(result[..], seed[..]);
}
#[test]
fn can_bip39_generate() {
let phrase = ext_bip39_generate(12);
let is_valid = ext_bip39_validate(&phrase);
assert!(is_valid);
}
#[test]
fn can_bip39_validate() {
let is_valid = ext_bip39_validate("seed sock milk update focus rotate barely fade car face mechanic mercy");
let is_invalid = ext_bip39_validate("wine photo extra cushion basket dwarf humor cloud truck job boat submit");
assert_eq!(is_valid, true);
assert_eq!(is_invalid, false);
}
}
+164
View File
@@ -0,0 +1,164 @@
// Copyright 2019 @polkadot/wasm-dalek-ed25519 authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
use ed25519_dalek::{Keypair, PublicKey, SecretKey, Signature};
use wasm_bindgen::prelude::*;
/// Keypair helper function.
fn create_from_pair(pair: &[u8]) -> Keypair {
match Keypair::from_bytes(pair) {
Ok(pair) => return pair,
Err(_) => panic!("Provided pair is invalid.")
}
}
/// Keypair helper function
fn create_from_parts(public: &[u8], secret: &[u8]) -> Keypair {
let mut pair = vec![];
pair.extend_from_slice(secret);
pair.extend_from_slice(public);
create_from_pair(&pair)
}
/// Keypair helper function.
fn create_from_seed(seed: &[u8]) -> Keypair {
let secret = SecretKey::from_bytes(seed).unwrap();
let public: PublicKey = (&secret).into();
create_from_parts(public.as_bytes(), seed)
}
/// PublicKey helper
fn create_public(public: &[u8]) -> PublicKey {
match PublicKey::from_bytes(public) {
Ok(public) => return public,
Err(_) => panic!("Provided public key is invalid.")
}
}
/// Generate a key pair.
///
/// * seed: UIntArray with 32 element
///
/// returned vector is the concatenation of first the private key (64 bytes)
/// followed by the public key (32) bytes.
#[wasm_bindgen]
pub fn ext_ed_from_seed(seed: &[u8]) -> Vec<u8> {
create_from_seed(seed)
.to_bytes()
.to_vec()
}
/// Sign a message
///
/// The combination of both public and private key must be provided.
/// This is effectively equivalent to a keypair.
///
/// * public: UIntArray with 32 element
/// * private: UIntArray with 64 element
/// * message: Arbitrary length UIntArray
///
/// * returned vector is the signature consisting of 64 bytes.
#[wasm_bindgen]
pub fn ext_ed_sign(public: &[u8], secret: &[u8], message: &[u8]) -> Vec<u8> {
create_from_parts(public, secret)
.sign(message)
.to_bytes()
.to_vec()
}
/// Verify a message and its corresponding against a public key;
///
/// * signature: UIntArray with 64 element
/// * message: Arbitrary length UIntArray
/// * pubkey: UIntArray with 32 element
#[wasm_bindgen]
pub fn ext_ed_verify(signature: &[u8], message: &[u8], public: &[u8]) -> bool {
let signature = match Signature::from_bytes(signature) {
Ok(signature) => signature,
Err(_) => return false
};
create_public(public)
.verify(message, &signature)
.is_ok()
}
#[cfg(test)]
pub mod tests {
extern crate rand;
use hex_literal::{hex, hex_impl};
use super::*;
use ed25519_dalek::{SIGNATURE_LENGTH, KEYPAIR_LENGTH, SECRET_KEY_LENGTH};
fn generate_random_seed() -> Vec<u8> {
(0..32).map(|_| rand::random::<u8>() ).collect()
}
#[test]
fn can_create_keypair() {
let seed = generate_random_seed();
let keypair = ext_ed_from_seed(seed.as_slice());
assert!(keypair.len() == KEYPAIR_LENGTH);
}
#[test]
fn creates_pair_from_known() {
let seed = b"12345678901234567890123456789012";
let expected = hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee");
let keypair = ext_ed_from_seed(seed);
let public = &keypair[SECRET_KEY_LENGTH..KEYPAIR_LENGTH];
assert_eq!(public, expected);
}
#[test]
fn can_sign_message() {
let seed = generate_random_seed();
let keypair = ext_ed_from_seed(seed.as_slice());
let private = &keypair[0..SECRET_KEY_LENGTH];
let public = &keypair[SECRET_KEY_LENGTH..KEYPAIR_LENGTH];
let message = b"this is a message";
let signature = ext_ed_sign(public, private, message);
assert!(signature.len() == SIGNATURE_LENGTH);
}
#[test]
fn can_verify_message() {
let seed = generate_random_seed();
let keypair = ext_ed_from_seed(seed.as_slice());
let private = &keypair[0..SECRET_KEY_LENGTH];
let public = &keypair[SECRET_KEY_LENGTH..KEYPAIR_LENGTH];
let message = b"this is a message";
let signature = ext_ed_sign(public, private, message);
let is_valid = ext_ed_verify(&signature[..], message, public);
assert!(is_valid);
}
#[test]
fn can_verify_known() {
let public = hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee");
let message = b"this is a message";
let signature = hex!("90588f3f512496f2dd40571d162e8182860081c74e2085316e7c4396918f07da412ee029978e4dd714057fe973bd9e7d645148bf7b66680d67c93227cde95202");
let is_valid = ext_ed_verify(&signature, message, &public);
assert!(is_valid);
}
#[test]
fn can_verify_known_wrong() {
let public = hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee");
let message = b"this is a message";
let signature = &[0u8; 64];
let is_valid = ext_ed_verify(signature, message, &public);
assert_eq!(is_valid, false);
}
}
+244
View File
@@ -0,0 +1,244 @@
// Copyright 2019 @polkadot/wasm-crypto authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
use blake2_rfc::blake2b::blake2b;
use byteorder::{ByteOrder, LittleEndian};
use hmac::Hmac;
use pbkdf2::pbkdf2;
use sha2::{Digest, Sha512};
// use secp256k1;
use std::hash::Hasher;
use tiny_keccak::keccak256;
use twox_hash::XxHash;
use wasm_bindgen::prelude::*;
/// helper function for a single twox round with a seed
fn create_twox(data: &[u8], seed: u64) -> [u8; 8] {
let mut hasher = XxHash::with_seed(seed);
hasher.write(data);
let hash64 = hasher.finish();
let mut result = [0u8; 8];
LittleEndian::write_u64(&mut result, hash64);
result
}
/// blake2b hash for the specified input
///
/// * data: Arbitrary data to be hashed
/// * key: Key to add to the hashing (normally empty)
/// * size: Size in bytes of the resulting output
///
/// Returns a vector with the hash result
#[wasm_bindgen]
pub fn ext_blake2b(data: &[u8], key: &[u8], size: u32) -> Vec<u8> {
// we cast to usize here - due to the WASM, we'd rather have u32 inputs
blake2b(size as usize, key, data)
.as_bytes()
.to_vec()
}
/// Create a keccak256 hash for the specified input
///
// * data: Arbitrary data to be hashed
///
/// Returns the hash as a vector
#[wasm_bindgen]
pub fn ext_keccak256(data: &[u8]) -> Vec<u8> {
keccak256(data)
.to_vec()
}
/// pbkdf2 hash from an input, salt for the number of specified rounds
///
/// * data: Arbitrary data to be hashed
/// * salt: Salt for this hash
/// * rounds: The number of rounds to perform
///
/// Returns a vecor with the hash result
#[wasm_bindgen]
pub fn ext_pbkdf2(data: &[u8], salt: &[u8], rounds: u32) -> Vec<u8> {
let mut result = [0u8; 64];
// we cast to usize here - due to the WASM, we'd rather have u32 inputs
pbkdf2::<Hmac<Sha512>>(data, salt, rounds as usize, &mut result);
result.to_vec()
}
// /// Checks for the recoverability of a signature from message
// ///
// /// * message: The message
// /// * signature: The signature
// ///
// /// Returns 0 on success, or a specific error code
// #[wasm_bindgen]
// pub fn ext_secp256k1_is_recoverable(message: &[u8], signature: &[u8]) -> u32 {
// let rs = match secp256k1::Signature::parse_slice(&signature[0..64]) {
// Ok(rs) => rs,
// _ => return 1
// };
// let v = match secp256k1::RecoveryId::parse(if signature[64] > 26 { signature[64] - 27 } else { signature[64] } as u8) {
// Ok(v) => v,
// _ => return 2
// };
// let mut msg = [0u8; 32];
// msg.copy_from_slice(&message);
// match secp256k1::recover(&secp256k1::Message::parse(&msg), &rs, &v) {
// Ok(_) => 0,
// _ => 3
// }
// }
// /// Recovers the secp256k1 signature from the input
// ///
// /// * message: The message
// /// * signature: The signature
// ///
// /// Returns a vector with the recovered public key
// #[wasm_bindgen]
// pub fn ext_secp256k1_recover(message: &[u8], signature: &[u8]) -> Vec<u8> {
// let rs = match secp256k1::Signature::parse_slice(&signature[0..64]) {
// Ok(rs) => rs,
// _ => panic!("Unable to recover r,s")
// };
// let v = match secp256k1::RecoveryId::parse(if signature[64] > 26 { signature[64] - 27 } else { signature[64] } as u8) {
// Ok(v) => v,
// _ => panic!("Unable to recover v")
// };
// let mut msg = [0u8; 32];
// msg.copy_from_slice(&message);
// match secp256k1::recover(&secp256k1::Message::parse(&msg), &rs, &v) {
// Ok(pk) => return pk.serialize()[1..65].to_vec(),
// _ => panic!("Unable to recover publickey")
// }
// }
/// sha512 hash for the specified input
///
/// * data: Arbitrary data to be hashed
///
/// Returns a vecor with the hash result
#[wasm_bindgen]
pub fn ext_sha512(data: &[u8]) -> Vec<u8> {
let mut hasher = Sha512::new();
hasher.input(data);
hasher
.result()
.to_vec()
}
/// twox hash for the specified input and rounds
///
/// * data: Arbitrary data to be hashed
/// * rounds: Number of 8-byte rounds to add to the output
///
/// Returns a vecor with the hash result
#[wasm_bindgen]
pub fn ext_twox(data: &[u8], rounds: u32) -> Vec<u8> {
let mut vec = vec![];
for round in 0..rounds {
// we cast to u64 here - due to the WASM, we'd rather have u32 inputs
vec.extend_from_slice(&create_twox(data, round as u64));
}
vec
}
#[cfg(test)]
pub mod tests {
use hex_literal::{hex, hex_impl};
use super::*;
// // Constructs the message that Ethereum RPC's `personal_sign` and `eth_sign` would sign.
// fn ethereum_signable_message(data: &[u8]) -> Vec<u8> {
// let prefix = b"Pay DOTs to the Polkadot account:";
// let mut l = prefix.len() + data.len();
// let mut rev = Vec::new();
// let mut v = b"\x19Ethereum Signed Message:\n".to_vec();
// while l > 0 {
// rev.push(b'0' + (l % 10) as u8);
// l /= 10;
// }
// v.extend(rev.into_iter().rev());
// v.extend_from_slice(&prefix[..]);
// v.extend_from_slice(data);
// v
// }
#[test]
fn can_blake2b() {
let data = b"abc";
let expected_32 = hex!("bddd813c634239723171ef3fee98579b94964e3bb1cb3e427262c8c068d52319");
let expected_64 = hex!("ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923");
let hash_32 = ext_blake2b(data, &[], 32);
let hash_64 = ext_blake2b(data, &[], 64);
assert_eq!(hash_32[..], expected_32[..]);
assert_eq!(hash_64[..], expected_64[..]);
}
#[test]
fn can_keccak256() {
let data = b"test value";
let expected = hex!("2d07364b5c231c56ce63d49430e085ea3033c750688ba532b24029124c26ca5e");
let hash = ext_keccak256(data);
assert_eq!(hash[..], expected[..]);
}
#[test]
fn can_pbkdf2() {
let salt = b"this is a salt";
let data = b"hello world";
let expected = hex!("5fcbe04f05300a3ecc5c35d18ea0b78f3f6853d2ae5f3fca374f69a7d1f78b5def5c60dae1a568026c7492511e0c53521e8bb6e03a650e1263265fee92722270");
let hash = ext_pbkdf2(data, salt, 2048);
assert_eq!(hash[..], expected[..]);
}
// #[test]
// fn can_secp256k1_real_eth_sig() {
// let sig = hex!("7505f2880114da51b3f5d535f8687953c0ab9af4ab81e592eaebebf53b728d2b6dfd9b5bcd70fee412b1f31360e7c2774009305cb84fc50c1d0ff8034dfa5fff1c");
// let pk = hex!("DF67EC7EAe23D2459694685257b6FC59d1BAA1FE");
// let data = [42, 0, 0, 0, 0, 0, 0, 0];
// let msg = ext_keccak256(&ethereum_signable_message(&data));
// let result = ext_keccak256(&ext_secp256k1_recover(&msg[..], &sig[..]));
// assert_eq!(result[12..], pk[..]);
// }
#[test]
fn can_sha512() {
let data = b"hello world";
let expected = hex!("309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca86d4cd86f989dd35bc5ff499670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f");
let hash = ext_sha512(data);
assert_eq!(hash[..], expected[..]);
}
#[test]
fn can_twox() {
let data = b"abc";
let expected_64 = hex!("990977adf52cbc44");
let expected_256 = hex!("990977adf52cbc440889329981caa9bef7da5770b2b8a05303b75d95360dd62b");
let hash_64 = ext_twox(data, 1);
let hash_256 = ext_twox(data, 4);
assert_eq!(hash_64[..], expected_64[..]);
assert_eq!(hash_256[..], expected_256[..]);
}
}
+12
View File
@@ -7,6 +7,18 @@ export function bip39ToEntropy (phrase: string): Uint8Array;
export function bip39ToMiniSecret (phrase: string, password: string): Uint8Array;
export function bip39ToSeed (phrase: string, password: string): Uint8Array;
export function bip39Validate (phrase: string): boolean;
export function ed25519KeypairFromSeed (seed: Uint8Array): Uint8Array;
export function ed25519Sign (publicKey: Uint8Array, secretKey: Uint8Array, message: Uint8Array): Uint8Array;
export function ed25519Verify (signature: Uint8Array, message: Uint8Array, publicKey: Uint8Array): boolean;
export function sr25519DeriveKeypairHard (pair: Uint8Array, chainCode: Uint8Array): Uint8Array;
export function sr25519DeriveKeypairSoft (pair: Uint8Array, chainCode: Uint8Array): Uint8Array;
export function sr25519DerivePublicSoft (publicKey: Uint8Array, chainCode: Uint8Array): Uint8Array;
export function sr25519KeypairFromSeed (seed: Uint8Array): Uint8Array;
export function sr25519Sign (publicKey: Uint8Array, secretKey: Uint8Array, message: Uint8Array): Uint8Array;
export function sr25519Verify (signature: Uint8Array, message: Uint8Array, publicKey: Uint8Array): boolean;
export function blake2b (data: Uint8Array, key: Uint8Array, byteSize: number): Uint8Array;
export function keccak256 (data: Uint8Array): Uint8Array;
export function pbkdf2 (data: Uint8Array, salt: Uint8Array, rounds: number): Uint8Array;
+32 -12
View File
@@ -2,20 +2,40 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
const { assert } = require('@polkadot/util');
const stubbed = require('./wasm');
module.exports.bip39Generate = stubbed.ext_bip39_generate;
module.exports.bip39ToEntropy = stubbed.ext_bip39_to_entropy;
module.exports.bip39ToMiniSecret = stubbed.ext_bip39_to_mini_secret;
module.exports.bip39ToSeed = stubbed.ext_bip39_to_seed;
module.exports.bip39Validate = stubbed.ext_bip39_validate
module.exports.blake2b = stubbed.ext_blake2b;
module.exports.keccak256 = stubbed.ext_keccak256;
module.exports.pbkdf2 = stubbed.ext_pbkdf2;
// module.exports.secp256k1IsRecoverable = stubbed.ext_secp256k1_is_recoverable;
// module.exports.secp256k1Recover = stubbed.ext_secp256k1_recover;
module.exports.sha512 = stubbed.ext_sha512;
module.exports.twox = stubbed.ext_twox;
const wrapReady = (fn) =>
(...params) => {
assert(stubbed.isReady(), 'ERROR: @polkadot/wasm-crypto has not been initialized');
return fn(...params);
};
module.exports.bip39Generate = wrapReady(stubbed.ext_bip39_generate);
module.exports.bip39ToEntropy = wrapReady(stubbed.ext_bip39_to_entropy);
module.exports.bip39ToMiniSecret = wrapReady(stubbed.ext_bip39_to_mini_secret);
module.exports.bip39ToSeed = wrapReady(stubbed.ext_bip39_to_seed);
module.exports.bip39Validate = wrapReady(stubbed.ext_bip39_validate);
module.exports.ed25519KeypairFromSeed = wrapReady(stubbed.ext_ed_from_seed);
module.exports.ed25519Sign = wrapReady(stubbed.ext_ed_sign);
module.exports.ed25519Verify = wrapReady(stubbed.ext_ed_verify);
module.exports.sr25519DeriveKeypairHard = wrapReady(stubbed.ext_sr_derive_keypair_hard);
module.exports.sr25519DeriveKeypairSoft = wrapReady(stubbed.ext_sr_derive_keypair_soft);
module.exports.sr25519DerivePublicSoft = wrapReady(stubbed.ext_sr_derive_public_soft);
module.exports.sr25519KeypairFromSeed = wrapReady(stubbed.ext_sr_from_seed);
module.exports.sr25519Sign = wrapReady(stubbed.ext_sr_sign);
module.exports.sr25519Verify = wrapReady(stubbed.ext_sr_verify);
module.exports.blake2b = wrapReady(stubbed.ext_blake2b);
module.exports.keccak256 = wrapReady(stubbed.ext_keccak256);
module.exports.pbkdf2 = wrapReady(stubbed.ext_pbkdf2);
// module.exports.secp256k1IsRecoverable = wrapReady(stubbed.ext_secp256k1_is_recoverable);
// module.exports.secp256k1Recover = wrapReady(stubbed.ext_secp256k1_recover);
module.exports.sha512 = wrapReady(stubbed.ext_sha512);
module.exports.twox = wrapReady(stubbed.ext_twox);
module.exports.isReady = stubbed.isReady;
module.exports.waitReady = stubbed.waitReady;
+4 -353
View File
@@ -2,360 +2,11 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
use bip39::{Mnemonic, MnemonicType, Language, Seed};
use blake2_rfc::blake2b::blake2b;
use byteorder::{ByteOrder, LittleEndian};
use hmac::Hmac;
use pbkdf2::pbkdf2;
// use secp256k1;
use sha2::{Digest, Sha512};
use std::hash::Hasher;
use tiny_keccak::keccak256;
use twox_hash::XxHash;
use wasm_bindgen::prelude::*;
// Use `wee_alloc` as the global allocator.
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
/// helper function for a single twox round with a seed
fn create_twox(data: &[u8], seed: u64) -> [u8; 8] {
let mut hasher = XxHash::with_seed(seed);
hasher.write(data);
let hash64 = hasher.finish();
let mut result = [0u8; 8];
LittleEndian::write_u64(&mut result, hash64);
result
}
/// Generate a bip39 phrase
///
/// words: number of words, either 12, 15, 18 21 or 24
///
/// Returns the bip 39 phrase
#[wasm_bindgen]
pub fn ext_bip39_generate(words: u32) -> String {
Mnemonic::new(MnemonicType::for_word_count(words as usize).unwrap(), Language::English)
.into_phrase()
}
/// Create entropy from a bip39 phrase
///
/// * phrase: mnemonic phrase
///
/// Returns the entropy
#[wasm_bindgen]
pub fn ext_bip39_to_entropy(phrase: &str) -> Vec<u8> {
Mnemonic::from_phrase(phrase, Language::English)
.unwrap()
.entropy()
.to_vec()
}
/// Create a mini-secret from a bip39 phrase
///
/// * phrase: mnemonic phrase
///
/// Returns the 32-byte mini-secret via entropy
#[wasm_bindgen]
pub fn ext_bip39_to_mini_secret(phrase: &str, password: &str) -> Vec<u8> {
let salt = format!("mnemonic{}", password);
let mnemonic = Mnemonic::from_phrase(phrase, Language::English).unwrap();
let mut result = [0u8; 64];
pbkdf2::<Hmac<Sha512>>(mnemonic.entropy(), salt.as_bytes(), 2048, &mut result);
result[..32].to_vec()
}
/// Creates a see from a bip-39 phrase
///
/// @phrase: mnemonic phrase
///
/// Returns a 32-byte seed
#[wasm_bindgen]
pub fn ext_bip39_to_seed(phrase: &str, password: &str) -> Vec<u8> {
let mnemonic = Mnemonic::from_phrase(phrase, Language::English).unwrap();
Seed::new(&mnemonic, password)
.as_bytes()[..32]
.to_vec()
}
/// Validates a bip39 phrase
///
/// * phrase: mnemonic phrase
///
/// Returns the true/false
#[wasm_bindgen]
pub fn ext_bip39_validate(phrase: &str) -> bool {
match Mnemonic::validate(phrase, Language::English) {
Err(_) => false,
_ => true
}
}
/// blake2b hash for the specified input
///
/// * data: Arbitrary data to be hashed
/// * key: Key to add to the hashing (normally empty)
/// * size: Size in bytes of the resulting output
///
/// Returns a vector with the hash result
#[wasm_bindgen]
pub fn ext_blake2b(data: &[u8], key: &[u8], size: u32) -> Vec<u8> {
// we cast to usize here - due to the WASM, we'd rather have u32 inputs
blake2b(size as usize, key, data)
.as_bytes()
.to_vec()
}
/// Create a keccak256 hash for the specified input
///
// * data: Arbitrary data to be hashed
///
/// Returns the hash as a vector
#[wasm_bindgen]
pub fn ext_keccak256(data: &[u8]) -> Vec<u8> {
keccak256(data)
.to_vec()
}
/// pbkdf2 hash from an input, salt for the number of specified rounds
///
/// * data: Arbitrary data to be hashed
/// * salt: Salt for this hash
/// * rounds: The number of rounds to perform
///
/// Returns a vecor with the hash result
#[wasm_bindgen]
pub fn ext_pbkdf2(data: &[u8], salt: &[u8], rounds: u32) -> Vec<u8> {
let mut result = [0u8; 64];
// we cast to usize here - due to the WASM, we'd rather have u32 inputs
pbkdf2::<Hmac<Sha512>>(data, salt, rounds as usize, &mut result);
result.to_vec()
}
// /// Checks for the recoverability of a signature from message
// ///
// /// * message: The message
// /// * signature: The signature
// ///
// /// Returns 0 on success, or a specific error code
// #[wasm_bindgen]
// pub fn ext_secp256k1_is_recoverable(message: &[u8], signature: &[u8]) -> u32 {
// let rs = match secp256k1::Signature::parse_slice(&signature[0..64]) {
// Ok(rs) => rs,
// _ => return 1
// };
// let v = match secp256k1::RecoveryId::parse(if signature[64] > 26 { signature[64] - 27 } else { signature[64] } as u8) {
// Ok(v) => v,
// _ => return 2
// };
// let mut msg = [0u8; 32];
// msg.copy_from_slice(&message);
// match secp256k1::recover(&secp256k1::Message::parse(&msg), &rs, &v) {
// Ok(_) => 0,
// _ => 3
// }
// }
// /// Recovers the secp256k1 signature from the input
// ///
// /// * message: The message
// /// * signature: The signature
// ///
// /// Returns a vector with the recovered public key
// #[wasm_bindgen]
// pub fn ext_secp256k1_recover(message: &[u8], signature: &[u8]) -> Vec<u8> {
// let rs = match secp256k1::Signature::parse_slice(&signature[0..64]) {
// Ok(rs) => rs,
// _ => panic!("Unable to recover r,s")
// };
// let v = match secp256k1::RecoveryId::parse(if signature[64] > 26 { signature[64] - 27 } else { signature[64] } as u8) {
// Ok(v) => v,
// _ => panic!("Unable to recover v")
// };
// let mut msg = [0u8; 32];
// msg.copy_from_slice(&message);
// match secp256k1::recover(&secp256k1::Message::parse(&msg), &rs, &v) {
// Ok(pk) => return pk.serialize()[1..65].to_vec(),
// _ => panic!("Unable to recover publickey")
// }
// }
/// sha512 hash for the specified input
///
/// * data: Arbitrary data to be hashed
///
/// Returns a vecor with the hash result
#[wasm_bindgen]
pub fn ext_sha512(data: &[u8]) -> Vec<u8> {
let mut hasher = Sha512::new();
hasher.input(data);
hasher
.result()
.to_vec()
}
/// twox hash for the specified input and rounds
///
/// * data: Arbitrary data to be hashed
/// * rounds: Number of 8-byte rounds to add to the output
///
/// Returns a vecor with the hash result
#[wasm_bindgen]
pub fn ext_twox(data: &[u8], rounds: u32) -> Vec<u8> {
let mut vec = vec![];
for round in 0..rounds {
// we cast to u64 here - due to the WASM, we'd rather have u32 inputs
vec.extend_from_slice(&create_twox(data, round as u64));
}
vec
}
#[cfg(test)]
pub mod tests {
use hex_literal::{hex, hex_impl};
use super::*;
// // Constructs the message that Ethereum RPC's `personal_sign` and `eth_sign` would sign.
// fn ethereum_signable_message(data: &[u8]) -> Vec<u8> {
// let prefix = b"Pay DOTs to the Polkadot account:";
// let mut l = prefix.len() + data.len();
// let mut rev = Vec::new();
// let mut v = b"\x19Ethereum Signed Message:\n".to_vec();
// while l > 0 {
// rev.push(b'0' + (l % 10) as u8);
// l /= 10;
// }
// v.extend(rev.into_iter().rev());
// v.extend_from_slice(&prefix[..]);
// v.extend_from_slice(data);
// v
// }
#[test]
fn can_bip39_entropy() {
let phrase = "legal winner thank year wave sausage worth useful legal winner thank yellow";
let entropy = hex!("7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f");
let result = ext_bip39_to_entropy(phrase);
assert_eq!(result, entropy);
}
#[test]
fn can_bip39_mini_secret() {
let phrase = "legal winner thank year wave sausage worth useful legal winner thank yellow";
let password = "Substrate";
let mini = hex!("4313249608fe8ac10fd5886c92c4579007272cb77c21551ee5b8d60b78041685");
let result = ext_bip39_to_mini_secret(phrase, password);
assert_eq!(result[..], mini[..]);
}
#[test]
fn can_bip39_seed() {
let phrase = "seed sock milk update focus rotate barely fade car face mechanic mercy";
let seed = hex!("3c121e20de068083b49c2315697fb59a2d9e8643c24e5ea7628132c58969a027");
let result = ext_bip39_to_seed(phrase, "");
assert_eq!(result[..], seed[..]);
}
#[test]
fn can_bip39_generate() {
let phrase = ext_bip39_generate(12);
let is_valid = ext_bip39_validate(&phrase);
assert!(is_valid);
}
#[test]
fn can_bip39_validate() {
let is_valid = ext_bip39_validate("seed sock milk update focus rotate barely fade car face mechanic mercy");
let is_invalid = ext_bip39_validate("wine photo extra cushion basket dwarf humor cloud truck job boat submit");
assert_eq!(is_valid, true);
assert_eq!(is_invalid, false);
}
#[test]
fn can_blake2b() {
let data = b"abc";
let expected_32 = hex!("bddd813c634239723171ef3fee98579b94964e3bb1cb3e427262c8c068d52319");
let expected_64 = hex!("ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923");
let hash_32 = ext_blake2b(data, &[], 32);
let hash_64 = ext_blake2b(data, &[], 64);
assert_eq!(hash_32[..], expected_32[..]);
assert_eq!(hash_64[..], expected_64[..]);
}
#[test]
fn can_keccak256() {
let data = b"test value";
let expected = hex!("2d07364b5c231c56ce63d49430e085ea3033c750688ba532b24029124c26ca5e");
let hash = ext_keccak256(data);
assert_eq!(hash[..], expected[..]);
}
#[test]
fn can_pbkdf2() {
let salt = b"this is a salt";
let data = b"hello world";
let expected = hex!("5fcbe04f05300a3ecc5c35d18ea0b78f3f6853d2ae5f3fca374f69a7d1f78b5def5c60dae1a568026c7492511e0c53521e8bb6e03a650e1263265fee92722270");
let hash = ext_pbkdf2(data, salt, 2048);
assert_eq!(hash[..], expected[..]);
}
// #[test]
// fn can_secp256k1_real_eth_sig() {
// let sig = hex!("7505f2880114da51b3f5d535f8687953c0ab9af4ab81e592eaebebf53b728d2b6dfd9b5bcd70fee412b1f31360e7c2774009305cb84fc50c1d0ff8034dfa5fff1c");
// let pk = hex!("DF67EC7EAe23D2459694685257b6FC59d1BAA1FE");
// let data = [42, 0, 0, 0, 0, 0, 0, 0];
// let msg = ext_keccak256(&ethereum_signable_message(&data));
// let result = ext_keccak256(&ext_secp256k1_recover(&msg[..], &sig[..]));
// assert_eq!(result[12..], pk[..]);
// }
#[test]
fn can_sha512() {
let data = b"hello world";
let expected = hex!("309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca86d4cd86f989dd35bc5ff499670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f");
let hash = ext_sha512(data);
assert_eq!(hash[..], expected[..]);
}
#[test]
fn can_twox() {
let data = b"abc";
let expected_64 = hex!("990977adf52cbc44");
let expected_256 = hex!("990977adf52cbc440889329981caa9bef7da5770b2b8a05303b75d95360dd62b");
let hash_64 = ext_twox(data, 1);
let hash_256 = ext_twox(data, 4);
assert_eq!(hash_64[..], expected_64[..]);
assert_eq!(hash_256[..], expected_256[..]);
}
}
pub mod bip39;
pub mod ed25519;
pub mod hashing;
pub mod sr25519;
+238
View File
@@ -0,0 +1,238 @@
// Copyright 2019 Paritytech via https://github.com/paritytech/schnorrkel-js/
// Copyright 2019 @polkadot/wasm-schnorrkel authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
// Originally developed (as a fork) in https://github.com/polkadot-js/schnorrkel-js/
// which was adpated from the initial https://github.com/paritytech/schnorrkel-js/
// forked at commit eff430ddc3090f56317c80654208b8298ef7ab3f
use schnorrkel::{
Keypair, MiniSecretKey, PublicKey, SecretKey, Signature,
derive::{Derivation, ChainCode, CHAIN_CODE_LENGTH},
};
use wasm_bindgen::prelude::*;
// We must make sure that this is the same as declared in the substrate source code.
const SIGNING_CTX: &'static [u8] = b"substrate";
/// ChainCode construction helper
fn create_cc(data: &[u8]) -> ChainCode {
let mut cc = [0u8; CHAIN_CODE_LENGTH];
cc.copy_from_slice(&data);
ChainCode(cc)
}
/// Keypair helper function.
fn create_from_seed(seed: &[u8]) -> Keypair {
match MiniSecretKey::from_bytes(seed) {
Ok(mini) => return mini.expand_to_keypair(),
Err(_) => panic!("Provided seed is invalid.")
}
}
/// Keypair helper function.
fn create_from_pair(pair: &[u8]) -> Keypair {
match Keypair::from_bytes(pair) {
Ok(pair) => return pair,
Err(_) => panic!("Provided pair is invalid.")
}
}
/// PublicKey helper
fn create_public(public: &[u8]) -> PublicKey {
match PublicKey::from_bytes(public) {
Ok(public) => return public,
Err(_) => panic!("Provided public key is invalid.")
}
}
/// SecretKey helper
fn create_secret(secret: &[u8]) -> SecretKey {
match SecretKey::from_bytes(secret) {
Ok(secret) => return secret,
Err(_) => panic!("Provided private key is invalid.")
}
}
/// Perform a derivation on a secret
///
/// * secret: UIntArray with 64 bytes
/// * cc: UIntArray with 32 bytes
///
/// returned vector the derived keypair as a array of 96 bytes
#[wasm_bindgen]
pub fn ext_sr_derive_keypair_hard(pair: &[u8], cc: &[u8]) -> Vec<u8> {
create_from_pair(pair).secret
.hard_derive_mini_secret_key(Some(create_cc(cc)), &[]).0
.expand_to_keypair()
.to_bytes()
.to_vec()
}
/// Perform a derivation on a secret
///
/// * secret: UIntArray with 64 bytes
/// * cc: UIntArray with 32 bytes
///
/// returned vector the derived keypair as a array of 96 bytes
#[wasm_bindgen]
pub fn ext_sr_derive_keypair_soft(pair: &[u8], cc: &[u8]) -> Vec<u8> {
create_from_pair(pair)
.derived_key_simple(create_cc(cc), &[]).0
.to_bytes()
.to_vec()
}
/// Perform a derivation on a publicKey
///
/// * pubkey: UIntArray with 32 bytes
/// * cc: UIntArray with 32 bytes
///
/// returned vector is the derived publicKey as a array of 32 bytes
#[wasm_bindgen]
pub fn ext_sr_derive_public_soft(public: &[u8], cc: &[u8]) -> Vec<u8> {
create_public(public)
.derived_key_simple(create_cc(cc), &[]).0
.to_bytes().to_vec()
}
/// Generate a key pair.
///
/// * seed: UIntArray with 32 element
///
/// returned vector is the concatenation of first the private key (64 bytes)
/// followed by the public key (32) bytes.
#[wasm_bindgen]
pub fn ext_sr_from_seed(seed: &[u8]) -> Vec<u8> {
create_from_seed(seed)
.to_bytes()
.to_vec()
}
/// Sign a message
///
/// The combination of both public and private key must be provided.
/// This is effectively equivalent to a keypair.
///
/// * public: UIntArray with 32 element
/// * private: UIntArray with 64 element
/// * message: Arbitrary length UIntArray
///
/// * returned vector is the signature consisting of 64 bytes.
#[wasm_bindgen]
pub fn ext_sr_sign(public: &[u8], secret: &[u8], message: &[u8]) -> Vec<u8> {
create_secret(secret)
.sign_simple(SIGNING_CTX, message, &create_public(public))
.to_bytes()
.to_vec()
}
/// Verify a message and its corresponding against a public key;
///
/// * signature: UIntArray with 64 element
/// * message: Arbitrary length UIntArray
/// * pubkey: UIntArray with 32 element
#[wasm_bindgen]
pub fn ext_sr_verify(signature: &[u8], message: &[u8], public: &[u8]) -> bool {
let signature = match Signature::from_bytes(signature) {
Ok(signature) => signature,
Err(_) => return false
};
create_public(public)
.verify_simple(SIGNING_CTX, message, &signature)
}
#[cfg(test)]
pub mod tests {
extern crate rand;
extern crate schnorrkel;
use hex_literal::{hex, hex_impl};
use super::*;
use schnorrkel::{SIGNATURE_LENGTH, KEYPAIR_LENGTH, SECRET_KEY_LENGTH};
fn generate_random_seed() -> Vec<u8> {
(0..32).map(|_| rand::random::<u8>() ).collect()
}
#[test]
fn can_create_keypair() {
let seed = generate_random_seed();
let keypair = ext_sr_from_seed(seed.as_slice());
assert!(keypair.len() == KEYPAIR_LENGTH);
}
#[test]
fn creates_pair_from_known() {
let seed = hex!("fac7959dbfe72f052e5a0c3c8d6530f202b02fd8f9f5ca3580ec8deb7797479e");
let expected = hex!("46ebddef8cd9bb167dc30878d7113b7e168e6f0646beffd77d69d39bad76b47a");
let keypair = ext_sr_from_seed(&seed);
let public = &keypair[SECRET_KEY_LENGTH..KEYPAIR_LENGTH];
assert_eq!(public, expected);
}
#[test]
fn can_sign_message() {
let seed = generate_random_seed();
let keypair = ext_sr_from_seed(seed.as_slice());
let private = &keypair[0..SECRET_KEY_LENGTH];
let public = &keypair[SECRET_KEY_LENGTH..KEYPAIR_LENGTH];
let message = b"this is a message";
let signature = ext_sr_sign(public, private, message);
assert!(signature.len() == SIGNATURE_LENGTH);
}
#[test]
fn can_verify_message() {
let seed = generate_random_seed();
let keypair = ext_sr_from_seed(seed.as_slice());
let private = &keypair[0..SECRET_KEY_LENGTH];
let public = &keypair[SECRET_KEY_LENGTH..KEYPAIR_LENGTH];
let message = b"this is a message";
let signature = ext_sr_sign(public, private, message);
let is_valid = ext_sr_verify(&signature[..], message, public);
assert!(is_valid);
}
#[test]
fn soft_derives_pair() {
let cc = hex!("0c666f6f00000000000000000000000000000000000000000000000000000000"); // foo
let seed = hex!("fac7959dbfe72f052e5a0c3c8d6530f202b02fd8f9f5ca3580ec8deb7797479e");
let expected = hex!("40b9675df90efa6069ff623b0fdfcf706cd47ca7452a5056c7ad58194d23440a");
let keypair = ext_sr_from_seed(&seed);
let derived = ext_sr_derive_keypair_soft(&keypair, &cc);
let public = &derived[SECRET_KEY_LENGTH..KEYPAIR_LENGTH];
assert_eq!(public, expected);
}
#[test]
fn soft_derives_public() {
let cc = hex!("0c666f6f00000000000000000000000000000000000000000000000000000000"); // foo
let public = hex!("46ebddef8cd9bb167dc30878d7113b7e168e6f0646beffd77d69d39bad76b47a");
let expected = hex!("40b9675df90efa6069ff623b0fdfcf706cd47ca7452a5056c7ad58194d23440a");
let derived = ext_sr_derive_public_soft(&public, &cc);
assert_eq!(derived, expected);
}
#[test]
fn hard_derives_pair() {
let cc = hex!("14416c6963650000000000000000000000000000000000000000000000000000"); // Alice
let seed = hex!("fac7959dbfe72f052e5a0c3c8d6530f202b02fd8f9f5ca3580ec8deb7797479e");
let expected = hex!("d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d");
let keypair = ext_sr_from_seed(&seed);
let derived = ext_sr_derive_keypair_hard(&keypair, &cc);
let public = &derived[SECRET_KEY_LENGTH..KEYPAIR_LENGTH];
assert_eq!(public, expected);
}
}
-132
View File
@@ -1,132 +0,0 @@
// Copyright 2019 @polkadot/wasm-crypto authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
// @ts-check
const { assert, stringToU8a, u8aToHex } = require('@polkadot/util');
const crypto = require('../build/index');
function bip39Generate () {
const RESULT = crypto.bip39Generate(21);
console.log('\tPHR', RESULT);
assert(RESULT.split(' ').length === 21, 'ERROR: Invalid bip39 Phase length');
}
function bip39Validate () {
const RESULT = crypto.bip39Validate(crypto.bip39Generate(12));
console.log('\tVAL', RESULT);
assert(RESULT, 'ERROR: Invalid bip39 validation');
}
function bip39ToEntropy () {
const RESULT = u8aToHex(crypto.bip39ToEntropy('legal winner thank year wave sausage worth useful legal winner thank yellow'));
console.log('\tENT', RESULT);
assert(RESULT === '0x7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f', 'ERROR: Invalid bip39 entropy');
}
function bip39ToMiniSecret () {
const RESULT = u8aToHex(crypto.bip39ToMiniSecret('legal winner thank year wave sausage worth useful legal winner thank yellow', 'Substrate'));
console.log('\tMIN', RESULT);
assert(RESULT === '0x4313249608fe8ac10fd5886c92c4579007272cb77c21551ee5b8d60b78041685', 'ERROR: Invalid bip39 mini secret');
}
function bip39ToSeed () {
const RESULT = u8aToHex(crypto.bip39ToSeed('seed sock milk update focus rotate barely fade car face mechanic mercy', ''));
console.log('\SEE', RESULT);
assert(RESULT === '0x3c121e20de068083b49c2315697fb59a2d9e8643c24e5ea7628132c58969a027', 'ERROR: Invalid bip39 mini secret');
}
function blake2bHash () {
const hash = u8aToHex(crypto.blake2b(stringToU8a('abc'), new Uint8Array(), 64));
console.log('\tRES', hash);
assert(hash === '0xba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923', 'ERROR: blake2bHash does not match');
}
function keccak256 () {
const hash = u8aToHex(crypto.keccak256(stringToU8a('test value')));
console.log('\tRES', hash);
assert(hash === '0x2d07364b5c231c56ce63d49430e085ea3033c750688ba532b24029124c26ca5e', 'ERROR: keccak256 does not match');
}
function pbkdf2Hash () {
const hash = u8aToHex(crypto.pbkdf2(stringToU8a('hello world'), stringToU8a('this is a salt'), 2048));
console.log('\tRES', hash);
assert(hash === '0x5fcbe04f05300a3ecc5c35d18ea0b78f3f6853d2ae5f3fca374f69a7d1f78b5def5c60dae1a568026c7492511e0c53521e8bb6e03a650e1263265fee92722270', 'ERROR: pbkdf2Hash does not match');
}
// function secp256k1Recover () {
// const pk = u8aToHex(crypto.keccak256(crypto.secp256k1Recover(
// hexToU8a('0x2bbfa926ee947dfac384d981f8913b4e0992e52d7b6711e0ec3d9f8b0f752648'),
// hexToU8a('0x7505f2880114da51b3f5d535f8687953c0ab9af4ab81e592eaebebf53b728d2b6dfd9b5bcd70fee412b1f31360e7c2774009305cb84fc50c1d0ff8034dfa5fff1c')
// )));
// console.log('\tPUB', pk);
// assert(pk === '0x91d366769d44a7c7690428bfdf67ec7eae23d2459694685257b6fc59d1baa1fe', 'ERROR: secp256k1Recover does not match');
// }
function sha512Hash () {
const hash = u8aToHex(crypto.sha512(stringToU8a('hello world')));
console.log('\tRES', hash);
assert(hash === '0x309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca86d4cd86f989dd35bc5ff499670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f', 'ERROR: sha512Hash does not match');
}
function twoxHash () {
const hash64 = u8aToHex(crypto.twox(stringToU8a('abc'), 1));
const hash256 = u8aToHex(crypto.twox(stringToU8a('abc'), 4));
console.log('\t64 ', hash64);
console.log('\t256', hash256);
assert(hash64 === '0x990977adf52cbc44' && hash256 === '0x990977adf52cbc440889329981caa9bef7da5770b2b8a05303b75d95360dd62b', 'ERROR: twoxHash does not match');
}
const tests = {
bip39Generate,
bip39Validate,
bip39ToEntropy,
bip39ToMiniSecret,
bip39ToSeed,
blake2bHash,
keccak256,
pbkdf2Hash,
// secp256k1Recover,
sha512Hash,
twoxHash
};
module.exports.beforeAll = async function beforeAll () {
return crypto.waitReady();
}
module.exports.runAll = function runAll () {
Object.keys(tests).forEach((name) => {
console.time(name);
console.log();
console.log(name);
tests[name]();
console.timeEnd(name);
});
}
module.exports.tests = tests;
+56
View File
@@ -0,0 +1,56 @@
// Copyright 2019 @polkadot/wasm-crypto authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
// @ts-check
const { assert, u8aToHex } = require('@polkadot/util');
const wasm = require('../../build/index');
function bip39_generate () {
const RESULT = wasm.bip39Generate(21);
console.log('\tPHR', RESULT);
assert(RESULT.split(' ').length === 21, 'ERROR: Invalid bip39 Phase length');
}
function bip39_validate () {
const RESULT = wasm.bip39Validate(wasm.bip39Generate(12));
console.log('\tVAL', RESULT);
assert(RESULT, 'ERROR: Invalid bip39 validation');
}
function bip39_toEntropy () {
const RESULT = u8aToHex(wasm.bip39ToEntropy('legal winner thank year wave sausage worth useful legal winner thank yellow'));
console.log('\tENT', RESULT);
assert(RESULT === '0x7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f', 'ERROR: Invalid bip39 entropy');
}
function bip39_toMiniSecret () {
const RESULT = u8aToHex(wasm.bip39ToMiniSecret('legal winner thank year wave sausage worth useful legal winner thank yellow', 'Substrate'));
console.log('\tMIN', RESULT);
assert(RESULT === '0x4313249608fe8ac10fd5886c92c4579007272cb77c21551ee5b8d60b78041685', 'ERROR: Invalid bip39 mini secret');
}
function bip39_toSeed () {
const RESULT = u8aToHex(wasm.bip39ToSeed('seed sock milk update focus rotate barely fade car face mechanic mercy', ''));
console.log('\SEE', RESULT);
assert(RESULT === '0x3c121e20de068083b49c2315697fb59a2d9e8643c24e5ea7628132c58969a027', 'ERROR: Invalid bip39 mini secret');
}
module.exports = {
bip39_generate,
bip39_validate,
bip39_toEntropy,
bip39_toMiniSecret,
bip39_toSeed
};
+62
View File
@@ -0,0 +1,62 @@
// Copyright 2019 @polkadot/wasm-wasm-ed25519 authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
// @ts-check
const crypto = require('crypto');
const { assert, hexToU8a, stringToU8a, u8aToHex } = require('@polkadot/util');
const wasm = require('../../build/index');
function extractKeys (pair) {
return [pair, pair.slice(32), pair.slice(0, 32)];
}
function randomPair () {
return extractKeys(wasm.ed25519KeypairFromSeed(crypto.randomBytes(32)));
}
function ed25519_pairFromSeed () {
const [pair, pk, sk] = extractKeys(wasm.ed25519KeypairFromSeed(stringToU8a('12345678901234567890123456789012')));
console.log('\tSEC', u8aToHex(sk));
console.log('\tPUB', u8aToHex(pk));
assert(u8aToHex(pair) === '0x31323334353637383930313233343536373839303132333435363738393031322f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee', 'ERROR: pairFromSeed() does not match');
}
function ed25519_signAndVerify () {
const [, pk, sk] = randomPair();
const signature = wasm.ed25519Sign(pk, sk, stringToU8a('this is a message'));
const isValid = wasm.ed25519Verify(signature, stringToU8a('this is a message'), pk);
console.log('\tSIG', u8aToHex(signature));
console.log('\tRES', isValid);
assert(isValid, 'ERROR: Unable to verify signature');
}
function ed25519_verifyExisting () {
const isValid = wasm.ed25519Verify(hexToU8a('0x90588f3f512496f2dd40571d162e8182860081c74e2085316e7c4396918f07da412ee029978e4dd714057fe973bd9e7d645148bf7b66680d67c93227cde95202'), stringToU8a('this is a message'), hexToU8a('0x2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee'));
console.log('\tRES', isValid);
assert(isValid, 'ERROR: Unable to verify signature');
}
function ed25519_benchmark () {
const MESSAGE = stringToU8a('this is a message');
for (let i = 0; i < 256; i++) {
const [, pk, sk] = randomPair();
assert(wasm.ed25519Verify(wasm.ed25519Sign(pk, sk, MESSAGE), MESSAGE, pk), 'ERROR: Unable to verify signature');
}
}
module.exports = {
ed25519_pairFromSeed,
ed25519_signAndVerify,
ed25519_verifyExisting,
ed25519_benchmark
};
+70
View File
@@ -0,0 +1,70 @@
// Copyright 2019 @polkadot/wasm-crypto authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
// @ts-check
const { assert, stringToU8a, u8aToHex } = require('@polkadot/util');
const wasm = require('../../build/index');
function blake2bHash () {
const hash = u8aToHex(wasm.blake2b(stringToU8a('abc'), new Uint8Array(), 64));
console.log('\tRES', hash);
assert(hash === '0xba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923', 'ERROR: blake2bHash does not match');
}
function keccak256 () {
const hash = u8aToHex(wasm.keccak256(stringToU8a('test value')));
console.log('\tRES', hash);
assert(hash === '0x2d07364b5c231c56ce63d49430e085ea3033c750688ba532b24029124c26ca5e', 'ERROR: keccak256 does not match');
}
function pbkdf2Hash () {
const hash = u8aToHex(wasm.pbkdf2(stringToU8a('hello world'), stringToU8a('this is a salt'), 2048));
console.log('\tRES', hash);
assert(hash === '0x5fcbe04f05300a3ecc5c35d18ea0b78f3f6853d2ae5f3fca374f69a7d1f78b5def5c60dae1a568026c7492511e0c53521e8bb6e03a650e1263265fee92722270', 'ERROR: pbkdf2Hash does not match');
}
// function secp256k1Recover () {
// const pk = u8aToHex(wasm.keccak256(wasm.secp256k1Recover(
// hexToU8a('0x2bbfa926ee947dfac384d981f8913b4e0992e52d7b6711e0ec3d9f8b0f752648'),
// hexToU8a('0x7505f2880114da51b3f5d535f8687953c0ab9af4ab81e592eaebebf53b728d2b6dfd9b5bcd70fee412b1f31360e7c2774009305cb84fc50c1d0ff8034dfa5fff1c')
// )));
// console.log('\tPUB', pk);
// assert(pk === '0x91d366769d44a7c7690428bfdf67ec7eae23d2459694685257b6fc59d1baa1fe', 'ERROR: secp256k1Recover does not match');
// }
function sha512Hash () {
const hash = u8aToHex(wasm.sha512(stringToU8a('hello world')));
console.log('\tRES', hash);
assert(hash === '0x309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca86d4cd86f989dd35bc5ff499670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f', 'ERROR: sha512Hash does not match');
}
function twoxHash () {
const hash64 = u8aToHex(wasm.twox(stringToU8a('abc'), 1));
const hash256 = u8aToHex(wasm.twox(stringToU8a('abc'), 4));
console.log('\t64 ', hash64);
console.log('\t256', hash256);
assert(hash64 === '0x990977adf52cbc44' && hash256 === '0x990977adf52cbc440889329981caa9bef7da5770b2b8a05303b75d95360dd62b', 'ERROR: twoxHash does not match');
}
module.exports = {
blake2bHash,
keccak256,
pbkdf2Hash,
// secp256k1Recover,
sha512Hash,
twoxHash
};
+30
View File
@@ -0,0 +1,30 @@
// Copyright 2019 @polkadot/wasm-crypto authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
// @ts-check
const wasm = require('../../build/index');
const bip39 = require('./bip39');
const ed25519 = require('./ed25519');
const hashing = require('./hashing');
const sr25519 = require('./sr25519');
const tests = { ...bip39, ...ed25519, ...hashing, ...sr25519 };
module.exports.beforeAll = async function beforeAll () {
return wasm.waitReady();
}
module.exports.runAll = function runAll () {
Object.keys(tests).forEach((name) => {
console.time(name);
console.log();
console.log(name);
tests[name]();
console.timeEnd(name);
});
}
module.exports.tests = tests;
+126
View File
@@ -0,0 +1,126 @@
// Copyright 2019 @polkadot/wasm-schnorrkel authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
// @ts-check
const crypto = require('crypto');
const { assert, hexToU8a, stringToU8a, u8aToHex } = require('@polkadot/util');
const wasm = require('../../build/index');
function extractKeys (pair) {
return [pair, pair.slice(64), pair.slice(0, 64)];
}
function randomPair () {
return extractKeys(wasm.sr25519KeypairFromSeed(crypto.randomBytes(32)));
}
function sr25519_pairFromSeed () {
const pair = wasm.sr25519KeypairFromSeed(stringToU8a('12345678901234567890123456789012'));
console.log('\tSEC', u8aToHex(pair.slice(0, 64)));
console.log('\tPUB', u8aToHex(pair.slice(64)));
assert(u8aToHex(pair) === '0xf0106660c3dda23f16daa9ac5b811b963077f5bc0af89f85804f0de8e424f050f98d66f39442506ff947fd911f18c7a7a5da639a63e8d3b4e233f74143d951c1741c08a06f41c596608f6774259bd9043304adfa5d3eea62760bd9be97634d63', 'ERROR: pairFromSeed() does not match');
}
function sr25519_devFromSeed () {
const pair = wasm.sr25519KeypairFromSeed(hexToU8a('0xfac7959dbfe72f052e5a0c3c8d6530f202b02fd8f9f5ca3580ec8deb7797479e'));
console.log('\tSEC', u8aToHex(pair.slice(0, 64)));
console.log('\tPUB', u8aToHex(pair.slice(64)));
assert(u8aToHex(pair) === '0x28b0ae221c6bb06856b287f60d7ea0d98552ea5a16db16956849aa371db3eb51fd190cce74df356432b410bd64682309d6dedb27c76845daf388557cbac3ca3446ebddef8cd9bb167dc30878d7113b7e168e6f0646beffd77d69d39bad76b47a', 'ERROR: devFromSeed() does not match');
}
function sr25519_verifyExisting () {
const PK = hexToU8a('0x741c08a06f41c596608f6774259bd9043304adfa5d3eea62760bd9be97634d63');
const MESSAGE = stringToU8a('this is a message');
const SIGNATURE = hexToU8a('0xdecef12cf20443e7c7a9d406c237e90bcfcf145860722622f92ebfd5eb4b5b3990b6443934b5cba8f925a0ae75b3a77d35b8490cbb358dd850806e58eaf72904'
);
const isValid = wasm.sr25519Verify(SIGNATURE, MESSAGE, PK);
console.log('\tRES', isValid);
assert(isValid, 'ERROR: Unable to verify signature');
}
function sr25519_signAndVerify () {
const [, pk, sk] = randomPair();
const signature = wasm.sr25519Sign(pk, sk, stringToU8a('this is a message'));
const isValid = wasm.sr25519Verify(signature, stringToU8a('this is a message'), pk);
console.log('\tSIG', u8aToHex(signature));
console.log('\tRES', isValid);
assert(isValid, 'ERROR: Unable to verify signature');
}
function sr25519_deriveHard () {
const [pair] = randomPair();
const derived = wasm.sr25519DeriveKeypairHard(pair, hexToU8a('0x0c666f6f00000000000000000000000000000000000000000000000000000000'));
console.log('\tSEC', u8aToHex(derived.slice(0, 64)));
console.log('\tPUB', u8aToHex(derived.slice(64)));
}
function sr25519_deriveHardKnown () {
const derived = wasm.sr25519DeriveKeypairHard(hexToU8a('0x28b0ae221c6bb06856b287f60d7ea0d98552ea5a16db16956849aa371db3eb51fd190cce74df356432b410bd64682309d6dedb27c76845daf388557cbac3ca3446ebddef8cd9bb167dc30878d7113b7e168e6f0646beffd77d69d39bad76b47a'), hexToU8a('0x14416c6963650000000000000000000000000000000000000000000000000000'));
const publicKey = u8aToHex(derived.slice(64));
console.log('\tSEC', u8aToHex(derived.slice(0, 64)));
console.log('\tPUB', publicKey);
assert(publicKey === '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d', 'Unmatched resulting public keys');
}
function sr25519_deriveSoft () {
const [pair] = randomPair();
const derived = wasm.sr25519DeriveKeypairSoft(pair, hexToU8a('0x0c666f6f00000000000000000000000000000000000000000000000000000000'));
console.log('\tSEC', u8aToHex(derived.slice(0, 64)));
console.log('\tPUB', u8aToHex(derived.slice(64)));
}
function sr25519_deriveSoftKnown () {
const derived = wasm.sr25519DeriveKeypairSoft(hexToU8a('0x28b0ae221c6bb06856b287f60d7ea0d98552ea5a16db16956849aa371db3eb51fd190cce74df356432b410bd64682309d6dedb27c76845daf388557cbac3ca3446ebddef8cd9bb167dc30878d7113b7e168e6f0646beffd77d69d39bad76b47a'), hexToU8a('0x0c666f6f00000000000000000000000000000000000000000000000000000000'));
const publicKey = u8aToHex(derived.slice(64));
console.log('\tSEC', u8aToHex(derived.slice(0, 64)));
console.log('\tPUB', publicKey);
assert(publicKey === '0x40b9675df90efa6069ff623b0fdfcf706cd47ca7452a5056c7ad58194d23440a', 'Unmatched resulting public keys');
}
function sr25519_deriveSoftPubkey () {
const derived = u8aToHex(wasm.sr25519DerivePublicSoft( hexToU8a('0x46ebddef8cd9bb167dc30878d7113b7e168e6f0646beffd77d69d39bad76b47a'), hexToU8a('0x0c666f6f00000000000000000000000000000000000000000000000000000000')));
console.log('\tPUB', derived);
assert(derived === '0x40b9675df90efa6069ff623b0fdfcf706cd47ca7452a5056c7ad58194d23440a', 'Unmatched resulting public keys');
}
function sr25519_benchmark () {
const MESSAGE = stringToU8a('this is a message');
for (let i = 0; i < 256; i++) {
const [, pk, sk] = randomPair();
assert(wasm.sr25519Verify(wasm.sr25519Sign(pk, sk, MESSAGE), MESSAGE, pk), 'ERROR: Unable to verify signature');
}
}
module.exports = {
sr25519_pairFromSeed,
sr25519_devFromSeed,
sr25519_deriveHard,
sr25519_deriveHardKnown,
sr25519_deriveSoft,
sr25519_deriveSoftKnown,
sr25519_deriveSoftPubkey,
sr25519_signAndVerify,
sr25519_verifyExisting,
sr25519_benchmark
};
+1 -1
View File
@@ -5,7 +5,7 @@
require('../build/crypto-polyfill');
const { beforeAll, tests } = require('./all.js');
const { beforeAll, tests } = require('./all');
describe('schnorrkel-js', () => {
beforeEach(beforeAll);
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright 2019 @polkadot/wasm-schnorrkel authors & contributors
// Copyright 2019 @polkadot/wasm-dalek-ed25519 authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
// @ts-check
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright 2019 @polkadot/wasm-schnorrkel authors & contributors
// Copyright 2019 @polkadot/wasm-dalek-ed25519 authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
// @ts-check
@@ -1,4 +1,4 @@
// Copyright 2019 @polkadot/wasm-schnorrkel authors & contributors
// Copyright 2019 @polkadot/wasm-dalek-ed25519 authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
// @ts-check
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright 2019 @polkadot/wasm-schnorrkel authors & contributors
// Copyright 2019 @polkadot/wasm-dalek-ed25519 authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
// @ts-check
+4 -4
View File
@@ -1543,10 +1543,10 @@
universal-user-agent "^2.0.0"
url-template "^2.0.8"
"@polkadot/dev@^0.28.1":
version "0.28.1"
resolved "https://registry.yarnpkg.com/@polkadot/dev/-/dev-0.28.1.tgz#c9b53a5948252c4f11686a13cd5990d84687f9a6"
integrity sha512-x2Yh/KFaTfiQNOs2A1cBJyZRAA5sk/hKerghfj2BubnWm9M+Qx112aoApKUL+s0KMOyKU3ZQjiGSuGyGn6TtqA==
"@polkadot/dev@^0.29.0-beta.0":
version "0.29.0-beta.0"
resolved "https://registry.yarnpkg.com/@polkadot/dev/-/dev-0.29.0-beta.0.tgz#ec4296b7365b1fb2c788cf78ea2ed97d1631b9e1"
integrity sha512-kKhTshLED1XvpecJ3ECBQARFAmRRw3xPxvHvV5+EaPZvN0XTGn7DRi3QfP9IugAsDbT5kVWLokojkBgjgiFstg==
dependencies:
"@babel/cli" "^7.2.3"
"@babel/core" "^7.4.0"