'use strict'; /** * SigningKey * * */ var secp256k1 = new (require('elliptic')).ec('secp256k1'); var utils = (function() { var convert = require('../utils/convert'); return { defineProperty: require('../utils/properties').defineProperty, arrayify: convert.arrayify, hexlify: convert.hexlify, padZeros: convert.padZeros, getAddress: require('../utils/address').getAddress, keccak256: require('../utils/keccak256') }; })(); var errors = require('../utils/errors'); function SigningKey(privateKey) { errors.checkNew(this, SigningKey); try { privateKey = utils.arrayify(privateKey); if (privateKey.length !== 32) { errors.throwError('exactly 32 bytes required', errors.INVALID_ARGUMENT, { value: privateKey }); } } catch(error) { var params = { arg: 'privateKey', reason: error.reason, value: '[REDACTED]' } if (error.value) { if(typeof(error.value.length) === 'number') { params.length = error.value.length; } params.type = typeof(error.value); } errors.throwError('invalid private key', error.code, params); } utils.defineProperty(this, 'privateKey', utils.hexlify(privateKey)) var keyPair = secp256k1.keyFromPrivate(privateKey); utils.defineProperty(this, 'publicKey', '0x' + keyPair.getPublic(true, 'hex')) var address = SigningKey.publicKeyToAddress('0x' + keyPair.getPublic(false, 'hex')); utils.defineProperty(this, 'address', address) utils.defineProperty(this, 'signDigest', function(digest) { var signature = keyPair.sign(utils.arrayify(digest), {canonical: true}); var r = '0x' + signature.r.toString(16); var s = '0x' + signature.s.toString(16); return { recoveryParam: signature.recoveryParam, r: utils.hexlify(utils.padZeros(r, 32)), s: utils.hexlify(utils.padZeros(s, 32)) } }); } utils.defineProperty(SigningKey, 'recover', function(digest, r, s, recoveryParam) { var signature = { r: utils.arrayify(r), s: utils.arrayify(s) }; var publicKey = secp256k1.recoverPubKey(utils.arrayify(digest), signature, recoveryParam); return SigningKey.publicKeyToAddress('0x' + publicKey.encode('hex', false)); }); utils.defineProperty(SigningKey, 'getPublicKey', function(value, compressed) { value = utils.arrayify(value); compressed = !!compressed; if (value.length === 32) { var keyPair = secp256k1.keyFromPrivate(value); return '0x' + keyPair.getPublic(compressed, 'hex'); } else if (value.length === 33) { var keyPair = secp256k1.keyFromPublic(value); return '0x' + keyPair.getPublic(compressed, 'hex'); } else if (value.length === 65) { var keyPair = secp256k1.keyFromPublic(value); return '0x' + keyPair.getPublic(compressed, 'hex'); } throw new Error('invalid value'); }); utils.defineProperty(SigningKey, 'publicKeyToAddress', function(publicKey) { publicKey = '0x' + SigningKey.getPublicKey(publicKey, false).slice(4); return utils.getAddress('0x' + utils.keccak256(publicKey).substring(26)); }); module.exports = SigningKey;