index.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. "use strict";
  2. const assert = require("assert");
  3. const brorand = require("brorand");
  4. const hashjs = require("hash.js");
  5. const elliptic = require("elliptic");
  6. const addressCodec = require("ripple-address-codec");
  7. const secp256k1_1 = require("./secp256k1");
  8. const utils = require("./utils");
  9. const Ed25519 = elliptic.eddsa('ed25519');
  10. const Secp256k1 = elliptic.ec('secp256k1');
  11. const { hexToBytes } = utils;
  12. const { bytesToHex } = utils;
  13. function generateSeed(options = {}) {
  14. assert.ok(!options.entropy || options.entropy.length >= 16, 'entropy too short');
  15. const entropy = options.entropy ? options.entropy.slice(0, 16) : brorand(16);
  16. const type = options.algorithm === 'ed25519' ? 'ed25519' : 'secp256k1';
  17. return addressCodec.encodeSeed(Buffer.from(entropy), type);
  18. }
  19. function hash(message) {
  20. return hashjs.sha512().update(message).digest().slice(0, 32);
  21. }
  22. const secp256k1 = {
  23. deriveKeypair(entropy, options) {
  24. const prefix = '00';
  25. const privateKey = prefix + (0, secp256k1_1.derivePrivateKey)(entropy, options).toString(16, 64).toUpperCase();
  26. const publicKey = bytesToHex(Secp256k1.keyFromPrivate(privateKey.slice(2))
  27. .getPublic()
  28. .encodeCompressed());
  29. return { privateKey, publicKey };
  30. },
  31. sign(message, privateKey) {
  32. return bytesToHex(Secp256k1.sign(hash(message), hexToBytes(privateKey), {
  33. canonical: true,
  34. }).toDER());
  35. },
  36. verify(message, signature, publicKey) {
  37. return Secp256k1.verify(hash(message), signature, hexToBytes(publicKey));
  38. },
  39. };
  40. const ed25519 = {
  41. deriveKeypair(entropy) {
  42. const prefix = 'ED';
  43. const rawPrivateKey = hash(entropy);
  44. const privateKey = prefix + bytesToHex(rawPrivateKey);
  45. const publicKey = prefix + bytesToHex(Ed25519.keyFromSecret(rawPrivateKey).pubBytes());
  46. return { privateKey, publicKey };
  47. },
  48. sign(message, privateKey) {
  49. // caution: Ed25519.sign interprets all strings as hex, stripping
  50. // any non-hex characters without warning
  51. assert.ok(Array.isArray(message), 'message must be array of octets');
  52. return bytesToHex(Ed25519.sign(message, hexToBytes(privateKey).slice(1)).toBytes());
  53. },
  54. verify(message, signature, publicKey) {
  55. return Ed25519.verify(message, hexToBytes(signature), hexToBytes(publicKey).slice(1));
  56. },
  57. };
  58. function select(algorithm) {
  59. const methods = { 'ecdsa-secp256k1': secp256k1, ed25519 };
  60. return methods[algorithm];
  61. }
  62. function deriveKeypair(seed, options) {
  63. const decoded = addressCodec.decodeSeed(seed);
  64. const algorithm = decoded.type === 'ed25519' ? 'ed25519' : 'ecdsa-secp256k1';
  65. const method = select(algorithm);
  66. const keypair = method.deriveKeypair(decoded.bytes, options);
  67. const messageToVerify = hash('This test message should verify.');
  68. const signature = method.sign(messageToVerify, keypair.privateKey);
  69. /* istanbul ignore if */
  70. if (method.verify(messageToVerify, signature, keypair.publicKey) !== true) {
  71. throw new Error('derived keypair did not generate verifiable signature');
  72. }
  73. return keypair;
  74. }
  75. function getAlgorithmFromKey(key) {
  76. const bytes = hexToBytes(key);
  77. return bytes.length === 33 && bytes[0] === 0xed
  78. ? 'ed25519'
  79. : 'ecdsa-secp256k1';
  80. }
  81. function sign(messageHex, privateKey) {
  82. const algorithm = getAlgorithmFromKey(privateKey);
  83. return select(algorithm).sign(hexToBytes(messageHex), privateKey);
  84. }
  85. function verify(messageHex, signature, publicKey) {
  86. const algorithm = getAlgorithmFromKey(publicKey);
  87. return select(algorithm).verify(hexToBytes(messageHex), signature, publicKey);
  88. }
  89. function deriveAddressFromBytes(publicKeyBytes) {
  90. return addressCodec.encodeAccountID(utils.computePublicKeyHash(publicKeyBytes));
  91. }
  92. function deriveAddress(publicKey) {
  93. return deriveAddressFromBytes(Buffer.from(hexToBytes(publicKey)));
  94. }
  95. function deriveNodeAddress(publicKey) {
  96. const generatorBytes = addressCodec.decodeNodePublic(publicKey);
  97. const accountPublicBytes = (0, secp256k1_1.accountPublicFromPublicGenerator)(generatorBytes);
  98. return deriveAddressFromBytes(accountPublicBytes);
  99. }
  100. const { decodeSeed } = addressCodec;
  101. module.exports = {
  102. generateSeed,
  103. deriveKeypair,
  104. sign,
  105. verify,
  106. deriveAddress,
  107. deriveNodeAddress,
  108. decodeSeed,
  109. };
  110. //# sourceMappingURL=index.js.map