UNPKG

seele-sdk-javascript

Version:
122 lines (105 loc) 3.55 kB
const { randomBytes } = require('crypto') const createKeccakHash = require('keccak') const RLP = require('rlp') const secp256k1 = require('secp256k1') const maxShard = 4 /** @namespace*/ var key = { /** * @method * @param {number} targetShard Target shard * @return {object} PrivateKey and address from shard * @example * key.spawn(1) * // returns * // { * // address: '0xcc5d9fb5712c17222686b55cad068ecf1dd4f1f1', * // privateKey: '0x51ec37a9351c96a1886f2d951e7f51f3069d0b4f1373b74fb69f91db76623f63' * // } */ spawn : function generateKeypairByShard(targetShard){ targetShard = targetShard || 1; let keypair if ( 1 <= targetShard && targetShard <= maxShard ) { do{ keypair = generateKeypair() } while (this.shard(keypair.address) != targetShard) return keypair } else { throw "invalid shard" } }, /** * @method * @param {string} address Address whose shard will be calculated * @return {number} Shard of address * @example * key.shard('0xcc5d9fb5712c17222686b55cad068ecf1dd4f1f1') * // returns * // 1 */ shard : function shardOfAddress(address){ var sum = 0 var buf = Buffer.from(address.substring(2), 'hex') for (const pair of buf.entries()) {if (pair[0] < 18){sum += pair[1]}} sum += (buf.readUInt16BE(18) >> 4) return (sum % maxShard) + 1 }, /** * @method * @param {string} pri Privatekey whose address will be calculated * @return {string} Address of private key * @example * key.addof('0x51ec37a9351c96a1886f2d951e7f51f3069d0b4f1373b74fb69f91db76623f63') * // returns * // '0x51ec37a9351c96a1886f2d951e7f51f3069d0b4f1373b74fb69f91db76623f63' */ addof : function addressOf(pri){ var pub = privateToPublic(pri) var add = publicToAddress(pub) return add }, /** * @method * @param {string} add Address to be verified * @return {string} Validity of address * @example * key.valid('0x03bcaf796fe8cffd90d1245667921ab83a3a43e1') * // returns * // true */ valid : function addressValidity(add){ if (!(/^0x[0-9a-f]{39}1$/.test(add) || /^0x[0-9A-F]{39}1$/.test(add))) { return false; } return true } } function privateToPublic(privateKey){ if (privateKey.length!=66){throw "privatekey string should be of lenth 66"} if (privateKey.slice(0,2)!="0x"){throw "privateKey string should start with 0x"} const inbuf = Buffer.from(privateKey.slice(2), 'hex'); if (!secp256k1.privateKeyVerify(inbuf)){throw "invalid privateKey"} const oubuf = secp256k1.publicKeyCreate(inbuf, false).slice(1); return '0x'+oubuf.toString('hex') } function publicToAddress(pub){ var buf = Buffer.from(pub.slice(2), 'hex'); var add = "0x" + createKeccakHash('keccak256').update(RLP.encode(buf)).digest().slice(12).toString('hex').replace(/.$/i,"1") return add; } function generateKeypair(){ let privKey do { privKey = randomBytes(32) } while (!secp256k1.privateKeyVerify(privKey)) // get the public key in a compressed format let pubKey = secp256k1.publicKeyCreate(privKey) pubKey = secp256k1.publicKeyConvert(pubKey, false).slice(1) // Only take the lower 160bits of the hash let address = createKeccakHash('keccak256').update(RLP.encode(pubKey)).digest().slice(-20) address[19] = address[19]&0xF0|1 return { "address" : "0x" + address.toString('hex'), "privateKey" : "0x" + privKey.toString('hex'), } } module.exports = key