Add asm.js generation with CRYPTO_ASM env var (#23)

* Add asm.js generation, import via index-asm.js

* Less sed-y, more babel-y

* Throw error when some failed

* CRYPTO_ASM env flag

* CHANGELOG
This commit is contained in:
Jaco Greeff
2019-07-18 15:38:50 +02:00
committed by GitHub
parent 62066e8dcd
commit 72d4ec56b5
21 changed files with 428 additions and 347 deletions
+1
View File
@@ -17,5 +17,6 @@ cc-test-reporter
lerna-debug.log*
npm-debug.log*
package-lock.json
report.*.json
yarn-debug.log*
yarn-error.log*
+4
View File
@@ -1,3 +1,7 @@
# 0.13.x
- Added a build-time optional asm.js fallback for the WASM libraries when WebAssembly is not available, i.e. on React Native. To enable this, add `CRYPTO_ASM=1` to your environment config. (i.e. `CRYPTO_ASM=1 yarn build`)
# 0.12.1
- Remove deprecated `@polkadot/wasm-schnorrkel` & `@polkadot/wasm-dalek-ed25519` source (all combined in `@polkadot/wasm-crypto`, was kept for historical purposes)
+1 -1
View File
@@ -22,6 +22,6 @@
"devDependencies": {
"@babel/core": "^7.5.4",
"@polkadot/dev": "^0.30.0-beta.22",
"@polkadot/util": "^0.94.0-beta.12"
"@polkadot/util": "^0.94.0-beta.15"
}
}
-21
View File
@@ -1,21 +0,0 @@
#!/usr/bin/env bash
set -e
# shortcuts for files
echo "*** Adjusting output"
SRC=build/wasm.js
# We don't want inline requires
sed -i -e 's/var wasm;/const crypto = require('\''crypto'\''); let wasm; const requires = { crypto };/g' $SRC
sed -i -e 's/return addHeapObject(require(varg0));/return addHeapObject(requires[varg0]);/g' $SRC
# this creates issues in both the browser and RN (@polkadot/util has a polyfill)
sed -i -e 's/const TextEncoder = require('\''util'\'')\.TextEncoder;/const { stringToU8a } = require('\''@polkadot\/util'\'');/g' $SRC
sed -i -e 's/let cachedTextEncoder = new /\/\/ let cachedTextEncoder = new /g' $SRC
sed -i -e 's/cachedTextEncoder\.encode/stringToU8a/g' $SRC
# this creates issues in both the browser and RN (@polkadot/util has a polyfill)
sed -i -e 's/const TextDecoder = require('\''util'\'')\.TextDecoder;/const { u8aToString } = require('\''@polkadot\/util'\'');/g' $SRC
sed -i -e 's/let cachedTextDecoder = new /\/\/ let cachedTextDecoder = new /g' $SRC
sed -i -e 's/cachedTextDecoder\.decode/u8aToString/g' $SRC
+1
View File
@@ -8,6 +8,7 @@
"index.js",
"wasm.d.ts",
"wasm.js",
"wasm_asm.js",
"wasm_bg.js",
"wasm_wasm.js"
],
+49
View File
@@ -0,0 +1,49 @@
/* eslint-disable @typescript-eslint/no-var-requires */
// 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.
const { assert } = require('@polkadot/util');
const INIT_ERRROR = '@polkadot/wasm-crypto has not been initialized';
module.exports = function (stubbed) {
const wrapReady = (fn) =>
(...params) => {
assert(stubbed.isReady(), INIT_ERRROR);
return fn(...params);
};
return {
bip39Generate: wrapReady(stubbed.ext_bip39_generate),
bip39ToEntropy: wrapReady(stubbed.ext_bip39_to_entropy),
bip39ToMiniSecret: wrapReady(stubbed.ext_bip39_to_mini_secret),
bip39ToSeed: wrapReady(stubbed.ext_bip39_to_seed),
bip39Validate: wrapReady(stubbed.ext_bip39_validate),
ed25519KeypairFromSeed: wrapReady(stubbed.ext_ed_from_seed),
ed25519Sign: wrapReady(stubbed.ext_ed_sign),
ed25519Verify: wrapReady(stubbed.ext_ed_verify),
sr25519DeriveKeypairHard: wrapReady(stubbed.ext_sr_derive_keypair_hard),
sr25519DeriveKeypairSoft: wrapReady(stubbed.ext_sr_derive_keypair_soft),
sr25519DerivePublicSoft: wrapReady(stubbed.ext_sr_derive_public_soft),
sr25519KeypairFromSeed: wrapReady(stubbed.ext_sr_from_seed),
sr25519Sign: wrapReady(stubbed.ext_sr_sign),
sr25519Verify: wrapReady(stubbed.ext_sr_verify),
blake2b: wrapReady(stubbed.ext_blake2b),
keccak256: wrapReady(stubbed.ext_keccak256),
pbkdf2: wrapReady(stubbed.ext_pbkdf2),
// secp256k1IsRecoverable: wrapReady(stubbed.ext_secp256k1_is_recoverable);
// secp256k1Recover: wrapReady(stubbed.ext_secp256k1_recover);
sha512: wrapReady(stubbed.ext_sha512),
twox: wrapReady(stubbed.ext_twox),
isReady: stubbed.isReady,
waitReady: stubbed.waitReady
};
};
+8
View File
@@ -0,0 +1,8 @@
/* eslint-disable @typescript-eslint/no-var-requires */
// 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.
const stubbed = require('./asm');
module.exports = require('./exports')(stubbed);
+1 -37
View File
@@ -3,42 +3,6 @@
// 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');
const INIT_ERRROR = '@polkadot/wasm-crypto has not been initialized';
const wrapReady = (fn) =>
(...params) => {
assert(stubbed.isReady(), INIT_ERRROR);
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;
module.exports = require('./exports')(stubbed);
+33 -34
View File
@@ -7,53 +7,52 @@
const { assert, u8aToHex } = require('@polkadot/util');
// @ts-ignore
const wasm = require('../../build/index');
module.exports = function (wasm) {
function bip39_generate () {
const RESULT = wasm.bip39Generate(21);
function bip39_generate () {
const RESULT = wasm.bip39Generate(21);
console.log('\tPHR', RESULT);
console.log('\tPHR', RESULT);
assert(RESULT.split(' ').length === 21, 'ERROR: Invalid bip39 Phase length');
}
assert(RESULT.split(' ').length === 21, 'ERROR: Invalid bip39 Phase length');
}
function bip39_validate () {
const RESULT = wasm.bip39Validate(wasm.bip39Generate(12));
function bip39_validate () {
const RESULT = wasm.bip39Validate(wasm.bip39Generate(12));
console.log('\tVAL', RESULT);
console.log('\tVAL', RESULT);
assert(RESULT, 'ERROR: Invalid bip39 validation');
}
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'));
function bip39_toEntropy () {
const RESULT = u8aToHex(wasm.bip39ToEntropy('legal winner thank year wave sausage worth useful legal winner thank yellow'));
console.log('\tENT', RESULT);
console.log('\tENT', RESULT);
assert(RESULT === '0x7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f', 'ERROR: Invalid bip39 entropy');
}
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'));
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);
console.log('\tMIN', RESULT);
assert(RESULT === '0x4313249608fe8ac10fd5886c92c4579007272cb77c21551ee5b8d60b78041685', 'ERROR: Invalid bip39 mini secret');
}
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', ''));
function bip39_toSeed () {
const RESULT = u8aToHex(wasm.bip39ToSeed('seed sock milk update focus rotate barely fade car face mechanic mercy', ''));
console.log('\tSEE', RESULT);
console.log('\tSEE', RESULT);
assert(RESULT === '0x3c121e20de068083b49c2315697fb59a2d9e8643c24e5ea7628132c58969a027', 'ERROR: Invalid bip39 mini secret');
}
assert(RESULT === '0x3c121e20de068083b49c2315697fb59a2d9e8643c24e5ea7628132c58969a027', 'ERROR: Invalid bip39 mini secret');
}
module.exports = {
bip39_generate,
bip39_validate,
bip39_toEntropy,
bip39_toMiniSecret,
bip39_toSeed
return {
bip39_generate,
bip39_validate,
bip39_toEntropy,
bip39_toMiniSecret,
bip39_toSeed
};
};
+51 -52
View File
@@ -8,58 +8,57 @@
const crypto = require('crypto');
const { assert, hexToU8a, stringToU8a, u8aToHex } = require('@polkadot/util');
// @ts-ignore
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 = function (wasm) {
function extractKeys (pair) {
return [pair, pair.slice(32), pair.slice(0, 32)];
}
}
module.exports = {
ed25519_pairFromSeed,
ed25519_signAndVerify,
ed25519_verifyExisting,
ed25519_benchmark
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');
}
}
return {
ed25519_pairFromSeed,
ed25519_signAndVerify,
ed25519_verifyExisting,
ed25519_benchmark
};
};
+44 -45
View File
@@ -7,67 +7,66 @@
const { assert, stringToU8a, u8aToHex } = require('@polkadot/util');
// @ts-ignore
const wasm = require('../../build/index');
module.exports = function (wasm) {
function blake2bHash () {
const hash = u8aToHex(wasm.blake2b(stringToU8a('abc'), new Uint8Array(), 64));
function blake2bHash () {
const hash = u8aToHex(wasm.blake2b(stringToU8a('abc'), new Uint8Array(), 64));
console.log('\tRES', hash);
console.log('\tRES', hash);
assert(hash === '0xba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923', 'ERROR: blake2bHash does not match');
}
assert(hash === '0xba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923', 'ERROR: blake2bHash does not match');
}
function keccak256 () {
const hash = u8aToHex(wasm.keccak256(stringToU8a('test value')));
function keccak256 () {
const hash = u8aToHex(wasm.keccak256(stringToU8a('test value')));
console.log('\tRES', hash);
console.log('\tRES', hash);
assert(hash === '0x2d07364b5c231c56ce63d49430e085ea3033c750688ba532b24029124c26ca5e', 'ERROR: keccak256 does not match');
}
assert(hash === '0x2d07364b5c231c56ce63d49430e085ea3033c750688ba532b24029124c26ca5e', 'ERROR: keccak256 does not match');
}
function pbkdf2Hash () {
const hash = u8aToHex(wasm.pbkdf2(stringToU8a('hello world'), stringToU8a('this is a salt'), 2048));
function pbkdf2Hash () {
const hash = u8aToHex(wasm.pbkdf2(stringToU8a('hello world'), stringToU8a('this is a salt'), 2048));
console.log('\tRES', hash);
console.log('\tRES', hash);
assert(hash === '0x5fcbe04f05300a3ecc5c35d18ea0b78f3f6853d2ae5f3fca374f69a7d1f78b5def5c60dae1a568026c7492511e0c53521e8bb6e03a650e1263265fee92722270', 'ERROR: pbkdf2Hash does not match');
}
assert(hash === '0x5fcbe04f05300a3ecc5c35d18ea0b78f3f6853d2ae5f3fca374f69a7d1f78b5def5c60dae1a568026c7492511e0c53521e8bb6e03a650e1263265fee92722270', 'ERROR: pbkdf2Hash does not match');
}
// function secp256k1Recover () {
// const pk = u8aToHex(wasm.keccak256(wasm.secp256k1Recover(
// hexToU8a('0x2bbfa926ee947dfac384d981f8913b4e0992e52d7b6711e0ec3d9f8b0f752648'),
// hexToU8a('0x7505f2880114da51b3f5d535f8687953c0ab9af4ab81e592eaebebf53b728d2b6dfd9b5bcd70fee412b1f31360e7c2774009305cb84fc50c1d0ff8034dfa5fff1c')
// )));
// function secp256k1Recover () {
// const pk = u8aToHex(wasm.keccak256(wasm.secp256k1Recover(
// hexToU8a('0x2bbfa926ee947dfac384d981f8913b4e0992e52d7b6711e0ec3d9f8b0f752648'),
// hexToU8a('0x7505f2880114da51b3f5d535f8687953c0ab9af4ab81e592eaebebf53b728d2b6dfd9b5bcd70fee412b1f31360e7c2774009305cb84fc50c1d0ff8034dfa5fff1c')
// )));
// console.log('\tPUB', pk);
// console.log('\tPUB', pk);
// assert(pk === '0x91d366769d44a7c7690428bfdf67ec7eae23d2459694685257b6fc59d1baa1fe', 'ERROR: secp256k1Recover does not match');
// }
// assert(pk === '0x91d366769d44a7c7690428bfdf67ec7eae23d2459694685257b6fc59d1baa1fe', 'ERROR: secp256k1Recover does not match');
// }
function sha512Hash () {
const hash = u8aToHex(wasm.sha512(stringToU8a('hello world')));
function sha512Hash () {
const hash = u8aToHex(wasm.sha512(stringToU8a('hello world')));
console.log('\tRES', hash);
console.log('\tRES', hash);
assert(hash === '0x309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca86d4cd86f989dd35bc5ff499670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f', 'ERROR: sha512Hash does not match');
}
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));
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);
console.log('\t64 ', hash64);
console.log('\t256', hash256);
assert(hash64 === '0x990977adf52cbc44' && hash256 === '0x990977adf52cbc440889329981caa9bef7da5770b2b8a05303b75d95360dd62b', 'ERROR: twoxHash does not match');
}
assert(hash64 === '0x990977adf52cbc44' && hash256 === '0x990977adf52cbc440889329981caa9bef7da5770b2b8a05303b75d95360dd62b', 'ERROR: twoxHash does not match');
}
module.exports = {
blake2bHash,
keccak256,
pbkdf2Hash,
// secp256k1Recover,
sha512Hash,
twoxHash
return {
blake2bHash,
keccak256,
pbkdf2Hash,
// secp256k1Recover,
sha512Hash,
twoxHash
};
};
+38 -19
View File
@@ -4,29 +4,48 @@
// of the Apache-2.0 license. See the LICENSE file for details.
// @ts-check
// @ts-ignore
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 = function (wasm) {
const tests = {
...bip39(wasm),
...ed25519(wasm),
...hashing(wasm),
...sr25519(wasm)
};
module.exports.beforeAll = async function beforeAll () {
return wasm.waitReady();
return {
beforeAll: async function beforeAll () {
return wasm.waitReady();
},
runAll: function runAll () {
const failed = [];
let count = 0;
Object.keys(tests).forEach((name) => {
count++;
try {
console.time(name);
console.log();
console.log(name);
tests[name]();
console.timeEnd(name);
} catch (error) {
console.error(error);
failed.push(name);
}
});
if (failed.length) {
throw new Error(`Failed: ${failed.length} of ${count}: ${failed.concat(', ')}`);
}
},
tests
};
};
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;
+114 -115
View File
@@ -8,121 +8,120 @@
const crypto = require('crypto');
const { assert, hexToU8a, stringToU8a, u8aToHex } = require('@polkadot/util');
// @ts-ignore
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('0xb4bfa1f7a5166695eb75299fd1c4c03ea212871c342f2c5dfea0902b2c246918');
const MESSAGE = stringToU8a('Verifying that I am the owner of 5G9hQLdsKQswNPgB499DeA5PkFBbgkLPJWkkS6FAM6xGQ8xD. Hash: 221455a3\n');
const SIGNATURE = hexToU8a('0x5a9755f069939f45d96aaf125cf5ce7ba1db998686f87f2fb3cbdea922078741a73891ba265f70c31436e18a9acd14d189d73c12317ab6c313285cd938453202');
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 = function (wasm) {
function extractKeys (pair) {
return [pair, pair.slice(64), pair.slice(0, 64)];
}
}
module.exports = {
sr25519_pairFromSeed,
sr25519_devFromSeed,
sr25519_deriveHard,
sr25519_deriveHardKnown,
sr25519_deriveSoft,
sr25519_deriveSoftKnown,
sr25519_deriveSoftPubkey,
sr25519_signAndVerify,
sr25519_verifyExisting,
sr25519_benchmark
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('0xb4bfa1f7a5166695eb75299fd1c4c03ea212871c342f2c5dfea0902b2c246918');
const MESSAGE = stringToU8a('Verifying that I am the owner of 5G9hQLdsKQswNPgB499DeA5PkFBbgkLPJWkkS6FAM6xGQ8xD. Hash: 221455a3\n');
const SIGNATURE = hexToU8a('0x5a9755f069939f45d96aaf125cf5ce7ba1db998686f87f2fb3cbdea922078741a73891ba265f70c31436e18a9acd14d189d73c12317ab6c313285cd938453202');
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');
}
}
return {
sr25519_pairFromSeed,
sr25519_devFromSeed,
sr25519_deriveHard,
sr25519_deriveHardKnown,
sr25519_deriveSoft,
sr25519_deriveSoftKnown,
sr25519_deriveSoftPubkey,
sr25519_signAndVerify,
sr25519_verifyExisting,
sr25519_benchmark
};
};
+14 -1
View File
@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-var-requires */
// 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.
@@ -6,4 +7,16 @@
// @ts-ignore
global.WebAssembly = null;
require('./wasm');
// @ts-ignore
const asm = require('../build/index');
const { beforeAll, runAll } = require('./all')(asm);
(async () => {
await beforeAll();
runAll();
})().catch((error) => {
console.error(error);
process.exit(-1);
});
+3 -1
View File
@@ -7,7 +7,9 @@
// @ts-ignore
require('../build/crypto-polyfill');
const { beforeAll, tests } = require('./all');
// @ts-ignore
const wasm = require('../build/index');
const { beforeAll, tests } = require('./all')(wasm);
describe('schnorrkel-js', () => {
beforeEach(beforeAll);
+9 -2
View File
@@ -4,9 +4,16 @@
// of the Apache-2.0 license. See the LICENSE file for details.
// @ts-check
const { beforeAll, runAll } = require('./all');
// @ts-ignore
const wasm = require('../build/index');
const { beforeAll, runAll } = require('./all')(wasm);
(async () => {
await beforeAll();
runAll();
})();
})().catch((error) => {
console.error(error);
process.exit(-1);
});
+49 -13
View File
@@ -16,11 +16,13 @@ mv pkg build
# shortcuts for files
echo "*** Adjusting output"
BGJ=build/wasm_bg.js
SRC=build/wasm.js
SRC_ASM=build/asm.js
SRC_WASM=build/wasm.js
DEF=build/wasm.d.ts
WSM=build/wasm_bg.wasm
OPT=build/wasm_opt.wasm
ASM=build/wasm_asm.js
TMP=build/wasm_tmp.js
# optimise
echo "*** Optimising WASM output"
@@ -29,7 +31,15 @@ echo "*** Optimising WASM output"
# build asmjs version from the input (optimised) WASM
# echo "*** Building asm.js version"
# ../../binaryen/bin/wasm2js --no-validation --output $ASM $OPT
echo "*** Building asm.js version"
../../binaryen/bin/wasm2js --no-validation --output $TMP $OPT
# cleanup asm
sed -i -e 's/\.\/wasm/\.\/asm/g' $TMP
# get babel to take care of making it sane
NODE_OPTIONS=--max_old_space_size=8192 yarn babel $TMP --presets @babel/preset-env --out-file=$ASM
rm -rf $TMP
# convert wasm to base64 structure
echo "*** Packing WASM into base64"
@@ -39,16 +49,26 @@ node ../../scripts/pack-wasm-base64.js
echo "*** Copying package sources"
cp src/js/* build/
# cleanup asm
# sed -i -e 's/import {/\/\/ import {/g' $ASM
# sed -i -e 's/function asmFunc/var schnorrkel = require('\''\.\/wasm'\''); function asmFunc/g' $ASM
# sed -i -e 's/export const /module\.exports\./g' $ASM
# sed -i -e 's/{abort.*},memasmFunc/schnorrkel, memasmFunc/g' $ASM
# we are swapping to a async interface for webpack support (wasm limits)
sed -i -e 's/wasm = require/\/\/ wasm = require/g' $SRC
sed -i -e 's/wasm = require/\/\/ wasm = require/g' $SRC_WASM
# construct our promise and add ready helpers
# We don't want inline requires
sed -i -e 's/var wasm;/const crypto = require('\''crypto'\''); let wasm; const requires = { crypto };/g' $SRC_WASM
sed -i -e 's/return addHeapObject(require(varg0));/return addHeapObject(requires[varg0]);/g' $SRC_WASM
# this creates issues in both the browser and RN (@polkadot/util has a polyfill)
sed -i -e 's/const TextEncoder = require('\''util'\'')\.TextEncoder;/const { stringToU8a } = require('\''@polkadot\/util'\'');/g' $SRC_WASM
sed -i -e 's/let cachedTextEncoder = new /\/\/ let cachedTextEncoder = new /g' $SRC_WASM
sed -i -e 's/cachedTextEncoder\.encode/stringToU8a/g' $SRC_WASM
# this creates issues in both the browser and RN (@polkadot/util has a polyfill)
sed -i -e 's/const TextDecoder = require('\''util'\'')\.TextDecoder;/const { u8aToString } = require('\''@polkadot\/util'\'');/g' $SRC_WASM
sed -i -e 's/let cachedTextDecoder = new /\/\/ let cachedTextDecoder = new /g' $SRC_WASM
sed -i -e 's/cachedTextDecoder\.decode/u8aToString/g' $SRC_WASM
cp -f $SRC_WASM $SRC_ASM
# construct our promise and add ready helpers (WASM)
echo "
module.exports.abort = function () { throw new Error('abort'); };
@@ -59,7 +79,20 @@ module.exports.isReady = function () { return !!wasm; }
module.exports.waitReady = function () { return wasmPromise.then(() => !!wasm); }
wasmPromise.then((_wasm) => { wasm = _wasm });
" >> $SRC
" >> $SRC_WASM
# construct our promise and add ready helpers (ASM)
echo "
module.exports.abort = function () { throw new Error('abort'); };
const asmjs = require('./wasm_asm');
const wasmPromise = Promise.resolve(asmjs);
module.exports.isReady = function () { return !!wasm; }
module.exports.waitReady = function () { return wasmPromise.then(() => !!wasm); }
wasmPromise.then((_wasm) => { wasm = _wasm });
" >> $SRC_ASM
# add extra methods to type definitions
echo "
@@ -79,9 +112,12 @@ module.exports = async function createExportPromise () {
};
if (!WebAssembly) {
console.error(\`ERROR: Unable to initialize \${pkg.name}, WebAssembly is not available in this environment\`);
if (process.env.CRYPTO_ASM) {
return require('./wasm_asm');
}
console.error(\`ERROR: Unable to initialize \${pkg.name}, WebAssembly is not available in this environment. If you requires an asm.js fallback, specify it with the 'CRYPTO_ASM' environment flag.\`);
// TODO: Return asm version when not detected
return null;
}
-1
View File
@@ -15,7 +15,6 @@ for PKG in "${PACKAGES[@]}"; do
cd $PKG
../../scripts/build-package.sh
./adjust.sh
../../scripts/test-package.sh
rm -rf build/*-e build/package.json build/README.md
+1 -1
View File
@@ -3,7 +3,7 @@
set -e
# wasm2js for wasm -> asm.js
BINARYEN=( "wasm-opt" )
BINARYEN=( "wasm-opt" "wasm2js" )
# install wasm-pack as required
if ! [ -x "$(command -v wasm-pack)" ]; then
+3
View File
@@ -10,5 +10,8 @@ RUST_BACKTRACE=full rustup run nightly cargo test --release -- --nocapture
echo "*** Testing WASM"
node ./test/wasm.js
echo "*** Testing ASM.js"
CRYPTO_ASM=1 node ./test/asm.js
echo "*** Testing via Jest"
yarn jest ./test/jest.spec.js
+4 -4
View File
@@ -1853,10 +1853,10 @@
typescript "^3.5.3"
vuepress "^1.0.2"
"@polkadot/util@^0.94.0-beta.12":
version "0.94.0-beta.12"
resolved "https://registry.yarnpkg.com/@polkadot/util/-/util-0.94.0-beta.12.tgz#c05fd3ccad761e691ef195fee508dc12cd97e8b6"
integrity sha512-5/xjHAZ5Eo4nhNC9f+vpTczL1QuFVdKrN2xhjJutAx/lpM+3X9qlp6AAKwiR8IVqcKwPZ1tPAr3do6Ku1Z7dkQ==
"@polkadot/util@^0.94.0-beta.15":
version "0.94.0-beta.15"
resolved "https://registry.yarnpkg.com/@polkadot/util/-/util-0.94.0-beta.15.tgz#c10656ee5b6bd8ed50387b9bff4e606a076a439d"
integrity sha512-sx3kWaqOf7oCMXhxg7Dd3d0GlboieyeVBOuShslwKBnEW720AMOCuh3XmQUyUPferTbxukzqudBv7ME8y7e/pg==
dependencies:
"@babel/runtime" "^7.5.4"
"@types/bn.js" "^4.11.5"