tezos-sign
Version:
Offline tool for tezos
244 lines (220 loc) • 6.96 kB
JavaScript
/*!
* tezos-sign 1.4.0 (https://github.com/yugasun/tezos-sign)
* API https://github.com/yugasun/tezos-sign/blob/master/doc/api.md
* Copyright 2017-2019 yugasun. All Rights Reserved
* Licensed under MIT (https://github.com/yugasun/tezos-sign/blob/master/LICENSE)
*/
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var sodium = _interopDefault(require('libsodium-wrappers'));
var bs58check = _interopDefault(require('bs58check'));
var bip39 = _interopDefault(require('bip39'));
var prefix = {
tz1: new Uint8Array([6, 161, 159]),
edsk: new Uint8Array([43, 246, 78, 7]),
edsk2: new Uint8Array([13, 15, 58, 7]),
edpk: new Uint8Array([13, 15, 37, 217]),
edsig: new Uint8Array([9, 245, 205, 134, 18]),
o: new Uint8Array([5, 116])
};
var utility = {
b58cencode: function b58cencode(payload, prefix) {
var n = new Uint8Array(prefix.length + payload.length);
n.set(prefix);
n.set(payload, prefix.length);
return bs58check.encode(Buffer.from(n, 'hex'));
},
b58cdecode: function b58cdecode(enc, prefix) {
return bs58check.decode(enc).slice(prefix.length);
},
buf2hex: function buf2hex(buffer) {
var byteArray = new Uint8Array(buffer);
var hexParts = [];
for (var i = 0; i < byteArray.length; i += 1) {
var hex = byteArray[i].toString(16);
var paddedHex = ('00' + hex).slice(-2);
hexParts.push(paddedHex);
}
return hexParts.join('');
},
hex2buf: function hex2buf(hex) {
var t = hex.match(/[\da-f]{2}/gi).map(function (h) {
return parseInt(h, 16);
});
var b = new Uint8Array(t);
return b;
},
mergebuf: function mergebuf(b1, b2) {
var r = new Uint8Array(b1.length + b2.length);
r.set(b1);
r.set(b2, b1.length);
return r;
},
generateMnemonic: function generateMnemonic() {
return bip39.generateMnemonic(160);
}
};
/**
* generate keys
*
* @param {string} name passphrase
* @return {object}
*/
function generateKeys(name) {
try {
var m = utility.generateMnemonic();
var s = bip39.mnemonicToSeed(m, name).slice(0, 32);
var kp = sodium.crypto_sign_seed_keypair(s);
var sk = utility.b58cencode(kp.privateKey, prefix.edsk);
var pk = utility.b58cencode(kp.publicKey, prefix.edpk);
var hash = sodium.crypto_generichash(20, kp.publicKey);
var pkh = utility.b58cencode(hash, prefix.tz1);
return {
mnemonic: m,
passphrase: name,
sk: sk,
pk: pk,
pkh: pkh
};
} catch (e) {
throw new Error('Generate failed: ' + e.message);
}
}
/**
* generate keys without seed
*
* @return {object}
*/
function generateKeysNoSeed() {
try {
var kp = sodium.crypto_sign_keypair();
var sk = utility.b58cencode(kp.privateKey, prefix.edsk);
var pk = utility.b58cencode(kp.publicKey, prefix.edpk);
var hash = sodium.crypto_generichash(20, kp.publicKey);
var pkh = utility.b58cencode(hash, prefix.tz1);
return {
sk: sk,
pk: pk,
pkh: pkh
};
} catch (e) {
throw new Error('Generate failed: ' + e.message);
}
}
/**
* extract keys
*
* @param {string} sk private key
* @return {object}
*/
function extractKeys(sk) {
try {
var pref = sk.substr(0, 4);
switch (pref) {
case 'edsk':
if (sk.length === 98) {
var decodeEdsk = utility.b58cdecode(sk, prefix.edsk).slice(32);
var pk = utility.b58cencode(decodeEdsk, prefix.edpk);
var hash = sodium.crypto_generichash(20, decodeEdsk);
var pkh = utility.b58cencode(hash, prefix.tz1);
return {
pk: pk,
pkh: pkh,
sk: sk
};
}
if (sk.length === 54) {
// seed
var s = utility.b58cdecode(sk, prefix.edsk2);
var kp = sodium.crypto_sign_seed_keypair(s);
var _hash = sodium.crypto_generichash(20, kp.publicKey);
var sk1 = utility.b58cencode(kp.privateKey, prefix.edsk);
var _pk = utility.b58cencode(kp.publicKey, prefix.edpk);
var _pkh = utility.b58cencode(_hash, prefix.tz1);
return {
sk: sk1,
pk: _pk,
pkh: _pkh
};
}
break;
default:
return false;
}
} catch (e) {
throw new Error('Extract private key failed: ' + e.message);
}
}
/**
* tezos offline sign
*
* @param {string} bytes operation bytes
* @param {string} sk private key
* @return {object}
*/
function sign(bytes, sk) {
try {
var bb = utility.hex2buf(bytes);
var wm = new Uint8Array([3]);
if (typeof wm !== 'undefined') bb = utility.mergebuf(wm, bb);
var chash = sodium.crypto_generichash(32, bb);
var edsk = utility.b58cdecode(sk, prefix.edsk);
var sig = sodium.crypto_sign_detached(chash, edsk, 'uint8array');
var edsig = utility.b58cencode(sig, prefix.edsig);
var sbytes = bytes + utility.buf2hex(sig);
return {
bytes: bytes,
sig: sig,
edsig: edsig,
sbytes: sbytes
};
} catch (e) {
throw new Error('Sign failed: ' + e.message);
}
}
/**
* validate address
*
* @param {string} a address
* @return {bool}
*/
function checkAddress(a) {
try {
utility.b58cdecode(a, prefix.tz1);
return true;
} catch (e) {
return false;
}
}
/**
* generate tx hash
*
* @param {string} sbytes signed op bytes
* @return {string}
*/
function generateTxHash(sbytes) {
try {
var hexBuffer = utility.hex2buf(sbytes);
var soHash = sodium.crypto_generichash(32, hexBuffer);
var hash = utility.b58cencode(soHash, prefix.o);
return hash;
} catch (e) {
throw new Error('Generate transaction hash failed: ' + e.message);
}
}
var index = {
generateKeys: generateKeys,
generateKeysNoSeed: generateKeysNoSeed,
extractKeys: extractKeys,
sign: sign,
checkAddress: checkAddress,
generateTxHash: generateTxHash
};
exports.generateKeys = generateKeys;
exports.generateKeysNoSeed = generateKeysNoSeed;
exports.extractKeys = extractKeys;
exports.sign = sign;
exports.checkAddress = checkAddress;
exports.generateTxHash = generateTxHash;
exports.default = index;