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:
@@ -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
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+102
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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(ðereum_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
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(ðereum_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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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
|
||||
};
|
||||
@@ -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
|
||||
};
|
||||
@@ -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
|
||||
};
|
||||
@@ -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;
|
||||
@@ -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
|
||||
};
|
||||
@@ -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,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,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
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user