mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-29 17:48:10 +00:00
move interface fns to post.js, add web worker & browserify test
This commit is contained in:
parent
da0a2f8662
commit
3c0176a304
@ -1,15 +1,19 @@
|
|||||||
EMFLAGS = \
|
EMFLAGS = \
|
||||||
-O2 --closure 1 \
|
-Os --closure 1 \
|
||||||
--memory-init-file 0 \
|
--memory-init-file 0 \
|
||||||
--pre-js pre.js --post-js post.js \
|
--pre-js pre.js --post-js post.js \
|
||||||
-s EXPORTED_FUNCTIONS='["_hdnode_public_ckd", "_ecdsa_get_address"]' \
|
-s EXPORTED_FUNCTIONS='["_hdnode_public_ckd", "_ecdsa_get_address"]'
|
||||||
|
|
||||||
SRC = ../bignum.c ../ecdsa.c ../secp256k1.c ../hmac.c ../bip32.c \
|
SRC = ../bignum.c ../ecdsa.c ../secp256k1.c ../hmac.c ../bip32.c \
|
||||||
../base58.c ../ripemd160.c ../sha2.c ../rand.c
|
../base58.c ../ripemd160.c ../sha2.c ../rand.c
|
||||||
|
|
||||||
test: node_modules trezor-crypto.js
|
test-node: node_modules trezor-crypto.js test.js
|
||||||
node test.js
|
node test.js
|
||||||
|
|
||||||
|
test-browserify.js: node_modules trezor-crypto.js test.js
|
||||||
|
browserify test.js -o $@ --noparse=`pwd`/trezor-crypto.js
|
||||||
|
@echo "open test.html in your favourite browser"
|
||||||
|
|
||||||
trezor-crypto.js: $(SRC)
|
trezor-crypto.js: $(SRC)
|
||||||
emcc $(EMFLAGS) -o $@ $^
|
emcc $(EMFLAGS) -o $@ $^
|
||||||
|
|
||||||
@ -17,4 +21,4 @@ node_modules:
|
|||||||
npm install
|
npm install
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f trezor-crypto.js
|
rm -f trezor-crypto.js test-browserify.js
|
||||||
|
@ -1 +1,113 @@
|
|||||||
module.exports = Module;
|
/*
|
||||||
|
typedef struct {
|
||||||
|
uint32_t depth;
|
||||||
|
uint32_t fingerprint;
|
||||||
|
uint32_t child_num;
|
||||||
|
uint8_t chain_code[32];
|
||||||
|
uint8_t private_key[32];
|
||||||
|
uint8_t public_key[33];
|
||||||
|
} HDNode;
|
||||||
|
*/
|
||||||
|
|
||||||
|
var HEAPU8 = Module['HEAPU8'];
|
||||||
|
var _malloc = Module['_malloc'];
|
||||||
|
var _hdnode_public_ckd = Module['_hdnode_public_ckd'];
|
||||||
|
var _ecdsa_get_address = Module['_ecdsa_get_address'];
|
||||||
|
var Pointer_stringify = Module['Pointer_stringify'];
|
||||||
|
|
||||||
|
// HDNode struct global
|
||||||
|
var HDNODE_SIZE = 4 + 4 + 4 + 32 + 32 + 33;
|
||||||
|
var _hdnode = _malloc(HDNODE_SIZE);
|
||||||
|
|
||||||
|
// address string global
|
||||||
|
var ADDRESS_SIZE = 40; // maximum size
|
||||||
|
var _address = _malloc(ADDRESS_SIZE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* public library interface
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {HDNode} node HDNode struct, see the definition above
|
||||||
|
* @return {Uint8Array}
|
||||||
|
*/
|
||||||
|
function serializeNode(node) {
|
||||||
|
var b = new ArrayBuffer(HDNODE_SIZE);
|
||||||
|
|
||||||
|
var u32 = new Uint32Array(b, 0, 12);
|
||||||
|
u32[0] = node['depth'];
|
||||||
|
u32[1] = node['fingerprint'];
|
||||||
|
u32[2] = node['child_num'];
|
||||||
|
|
||||||
|
var u8 = new Uint8Array(b, 0, HDNODE_SIZE);
|
||||||
|
u8.set(node['chain_code'], 12);
|
||||||
|
u8.set(node['public_key'], 12 + 32 + 32);
|
||||||
|
|
||||||
|
return u8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Uint8Array} sn serialized node, see `serializeNode`
|
||||||
|
* @param {Number} index BIP32 index of the address
|
||||||
|
* @param {Number} version address version byte
|
||||||
|
* @return {String}
|
||||||
|
*/
|
||||||
|
function deriveAddress(sn, index, version) {
|
||||||
|
HEAPU8.set(sn, _hdnode);
|
||||||
|
_hdnode_public_ckd(_hdnode, index);
|
||||||
|
_ecdsa_get_address(_hdnode + 12 + 32 + 32, version, _address, ADDRESS_SIZE);
|
||||||
|
return Pointer_stringify(_address);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {HDNode} node HDNode struct, see the definition above
|
||||||
|
* @param {Number} from index of the first address
|
||||||
|
* @param {Number} to index of the last address
|
||||||
|
* @param {Number} version address version byte
|
||||||
|
* @return {Array<String>}
|
||||||
|
*/
|
||||||
|
function deriveAddressRange(node, from, to, version) {
|
||||||
|
var addresses = [];
|
||||||
|
var sn = serializeNode(node);
|
||||||
|
var i;
|
||||||
|
for (i = from; i <= to; i++) {
|
||||||
|
addresses.push(deriveAddress(sn, i, version));
|
||||||
|
}
|
||||||
|
return addresses;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof module !== 'undefined') {
|
||||||
|
module['exports'] = {
|
||||||
|
'serializeNode': serializeNode,
|
||||||
|
'deriveAddress': deriveAddress,
|
||||||
|
'deriveAddressRange': deriveAddressRange
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Web worker processing
|
||||||
|
*/
|
||||||
|
|
||||||
|
function processMessage(event) {
|
||||||
|
var data = event['data'];
|
||||||
|
var type = data['type'];
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case 'deriveAddressRange':
|
||||||
|
var response = deriveAddressRange(
|
||||||
|
data['node'],
|
||||||
|
data['from'],
|
||||||
|
data['to'],
|
||||||
|
data['version']
|
||||||
|
);
|
||||||
|
postMessage(response);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Error('Unknown message type: ' + type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ENVIRONMENT_IS_WORKER) {
|
||||||
|
this['onmessage'] = processMessage;
|
||||||
|
}
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
// stub importScripts for the faulty detection of web worker env
|
||||||
|
if (typeof importScripts === 'undefined'
|
||||||
|
&& typeof WorkerGlobalScope !== 'undefined'
|
||||||
|
&& this instanceof WorkerGlobalScope
|
||||||
|
) {
|
||||||
|
this.importScripts = function () {
|
||||||
|
throw new Error('importScripts is a stub');
|
||||||
|
};
|
||||||
|
}
|
8
emscripten/test.html
Normal file
8
emscripten/test.html
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script async src="test-browserify.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -1,67 +1,98 @@
|
|||||||
var crypto = require('./trezor-crypto');
|
var crypto = require('./trezor-crypto');
|
||||||
|
|
||||||
/* typedef struct {
|
|
||||||
uint32_t depth;
|
|
||||||
uint32_t fingerprint;
|
|
||||||
uint32_t child_num;
|
|
||||||
uint8_t chain_code[32];
|
|
||||||
uint8_t private_key[32];
|
|
||||||
uint8_t public_key[33];
|
|
||||||
} HDNode;
|
|
||||||
*/
|
|
||||||
|
|
||||||
var HDNODE_SIZE = 4 + 4 + 4 + 32 + 32 + 33;
|
|
||||||
var hdnode = crypto._malloc(HDNODE_SIZE);
|
|
||||||
|
|
||||||
var ADDRESS_SIZE = 40; // maximum size
|
|
||||||
var address = crypto._malloc(ADDRESS_SIZE);
|
|
||||||
|
|
||||||
function prepareNode(n) {
|
|
||||||
var b = new ArrayBuffer(HDNODE_SIZE);
|
|
||||||
var u8 = new Uint8Array(b, 0, HDNODE_SIZE);
|
|
||||||
var u32 = new Uint32Array(b, 0, 12);
|
|
||||||
|
|
||||||
u32[0] = n.depth;
|
|
||||||
u32[1] = n.parentFingerprint;
|
|
||||||
u32[2] = n.index;
|
|
||||||
u8.set(n.chainCode, 12);
|
|
||||||
u8.set(n.pubKey.toBuffer(), 12 + 32 + 32);
|
|
||||||
|
|
||||||
return u8;
|
|
||||||
}
|
|
||||||
|
|
||||||
function deriveAddress(pn, i, version) {
|
|
||||||
crypto.HEAPU8.set(pn, hdnode);
|
|
||||||
crypto._hdnode_public_ckd(hdnode, i);
|
|
||||||
crypto._ecdsa_get_address(hdnode + 12 + 32 + 32, version, address, ADDRESS_SIZE);
|
|
||||||
return crypto.Pointer_stringify(address);
|
|
||||||
}
|
|
||||||
|
|
||||||
// benching code
|
|
||||||
|
|
||||||
var bitcoin = require('bitcoinjs-lib');
|
var bitcoin = require('bitcoinjs-lib');
|
||||||
|
|
||||||
var node = bitcoin.HDNode.fromBase58(
|
var XPUB =
|
||||||
'xpub6AHA9hZDN11k2ijHMeS5QqHx2KP9aMBRhTDqANMnwVtdyw2TDYRm' +
|
'xpub6AHA9hZDN11k2ijHMeS5QqHx2KP9aMBRhTDqANMnwVtdyw2TDYRm' +
|
||||||
'F8PjpvwUFcL1Et8Hj59S3gTSMcUQ5gAqTz3Wd8EsMTmF3DChhqPQBnU'
|
'F8PjpvwUFcL1Et8Hj59S3gTSMcUQ5gAqTz3Wd8EsMTmF3DChhqPQBnU';
|
||||||
).derive(0);
|
var node = bitcoin.HDNode.fromBase58(XPUB).derive(0);
|
||||||
|
|
||||||
timeBitcoinjs(node);
|
var nodeStruct = {
|
||||||
timeTrezorCrypto(node);
|
depth: node.depth,
|
||||||
|
child_num: node.index,
|
||||||
|
fingerprint: node.parentFingerprint,
|
||||||
|
chain_code: node.chainCode,
|
||||||
|
public_key: node.pubKey.toBuffer()
|
||||||
|
};
|
||||||
|
var nodeSerialized = crypto.serializeNode(nodeStruct);
|
||||||
|
|
||||||
function timeBitcoinjs(n) {
|
var suite;
|
||||||
console.time('bitcoinjs')
|
var worker;
|
||||||
for (var i = 0; i < 1000; i++) {
|
|
||||||
n.derive(i).getAddress()
|
if (typeof Worker !== 'undefined') {
|
||||||
}
|
console.log('enabling web worker benchmark');
|
||||||
console.timeEnd('bitcoinjs')
|
worker = new Worker('./trezor-crypto.js');
|
||||||
|
worker.onerror = function (error) {
|
||||||
|
console.error('worker:', error);
|
||||||
|
};
|
||||||
|
suite = [
|
||||||
|
// benchBitcoinJS,
|
||||||
|
// benchBrowserify,
|
||||||
|
benchWorker
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
suite = [
|
||||||
|
benchBitcoinJS,
|
||||||
|
benchBrowserify
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
function timeTrezorCrypto(n) {
|
benchmark(suite, 1000, 1000);
|
||||||
var nP = prepareNode(n);
|
|
||||||
console.time('trezor-crypto')
|
function benchmark(suite, delay, ops) {
|
||||||
for (var i = 0; i < 1000; i++) {
|
(function cycle(i) {
|
||||||
deriveAddress(nP, i, 0);
|
setTimeout(function () {
|
||||||
|
var benchmark = suite[i];
|
||||||
|
runBenchmark(benchmark, ops, function (runtime) {
|
||||||
|
printResult(benchmark, ops, runtime);
|
||||||
|
cycle(i+1 < suite.length ? i+1 : 0);
|
||||||
|
});
|
||||||
|
}, delay);
|
||||||
|
}(0));
|
||||||
}
|
}
|
||||||
console.timeEnd('trezor-crypto')
|
|
||||||
|
function benchBitcoinJS(ops, fn) {
|
||||||
|
var i;
|
||||||
|
for (i = 0; i < ops; i++) {
|
||||||
|
node.derive(i).getAddress();
|
||||||
|
}
|
||||||
|
fn();
|
||||||
|
}
|
||||||
|
|
||||||
|
function benchBrowserify(ops, fn) {
|
||||||
|
var i;
|
||||||
|
for (i = 0; i < ops; i++) {
|
||||||
|
crypto.deriveAddress(nodeSerialized, i, 0);
|
||||||
|
}
|
||||||
|
fn();
|
||||||
|
}
|
||||||
|
|
||||||
|
function benchWorker(ops, fn) {
|
||||||
|
worker.onmessage = function (event) {
|
||||||
|
fn();
|
||||||
|
};
|
||||||
|
worker.postMessage({
|
||||||
|
type: 'deriveAddressRange',
|
||||||
|
node: nodeStruct,
|
||||||
|
from: 0,
|
||||||
|
to: ops - 1,
|
||||||
|
version: 0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function runBenchmark(benchmark, ops, fn) {
|
||||||
|
var start = new Date();
|
||||||
|
benchmark(ops, function () {
|
||||||
|
var end = new Date();
|
||||||
|
fn(end - start);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function printResult(benchmark, ops, runtime) {
|
||||||
|
var opssec = (ops / runtime) * 1000;
|
||||||
|
console.log(
|
||||||
|
benchmark.name,
|
||||||
|
'ops #', ops,
|
||||||
|
'runtime', runtime / 1000,
|
||||||
|
'sec, ops/sec', opssec
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user