UNPKG

ripple-keypairs

Version:

Cryptographic key pairs for the XRP Ledger

113 lines (100 loc) 3.27 kB
import { decodeNodePublic, decodeSeed, encodeAccountID, encodeSeed, } from 'ripple-address-codec' import { ripemd160 } from '@xrplf/isomorphic/ripemd160' import { sha256 } from '@xrplf/isomorphic/sha256' import { hexToBytes, randomBytes } from '@xrplf/isomorphic/utils' import { accountPublicFromPublicGenerator } from './signing-schemes/secp256k1/utils' import Sha512 from './utils/Sha512' import assert from './utils/assert' import type { Algorithm, HexString, KeyPair, SigningScheme } from './types' import { getAlgorithmFromPrivateKey, getAlgorithmFromPublicKey, } from './utils/getAlgorithmFromKey' import secp256k1 from './signing-schemes/secp256k1' import ed25519 from './signing-schemes/ed25519' function getSigningScheme(algorithm: Algorithm): SigningScheme { const schemes = { 'ecdsa-secp256k1': secp256k1, ed25519 } return schemes[algorithm] } function generateSeed( options: { entropy?: Uint8Array algorithm?: Algorithm } = {}, ): string { assert.ok( !options.entropy || options.entropy.length >= 16, 'entropy too short', ) const entropy = options.entropy ? options.entropy.slice(0, 16) : randomBytes(16) const type = options.algorithm === 'ed25519' ? 'ed25519' : 'secp256k1' return encodeSeed(entropy, type) } function deriveKeypair( seed: string, options?: { algorithm?: Algorithm validator?: boolean accountIndex?: number }, ): KeyPair { const decoded = decodeSeed(seed) const proposedAlgorithm = options?.algorithm ?? decoded.type const algorithm = proposedAlgorithm === 'ed25519' ? 'ed25519' : 'ecdsa-secp256k1' const scheme = getSigningScheme(algorithm) const keypair = scheme.deriveKeypair(decoded.bytes, options) const messageToVerify = Sha512.half('This test message should verify.') const signature = scheme.sign(messageToVerify, keypair.privateKey) /* istanbul ignore if */ if (!scheme.verify(messageToVerify, signature, keypair.publicKey)) { throw new Error('derived keypair did not generate verifiable signature') } return keypair } function sign(messageHex: HexString, privateKey: HexString): HexString { const algorithm = getAlgorithmFromPrivateKey(privateKey) return getSigningScheme(algorithm).sign(hexToBytes(messageHex), privateKey) } function verify( messageHex: HexString, signature: HexString, publicKey: HexString, ): boolean { const algorithm = getAlgorithmFromPublicKey(publicKey) return getSigningScheme(algorithm).verify( hexToBytes(messageHex), signature, publicKey, ) } function computePublicKeyHash(publicKeyBytes: Uint8Array): Uint8Array { return ripemd160(sha256(publicKeyBytes)) } function deriveAddressFromBytes(publicKeyBytes: Uint8Array): string { return encodeAccountID(computePublicKeyHash(publicKeyBytes)) } function deriveAddress(publicKey: string): string { return deriveAddressFromBytes(hexToBytes(publicKey)) } function deriveNodeAddress(publicKey: string): string { const generatorBytes = decodeNodePublic(publicKey) const accountPublicBytes = accountPublicFromPublicGenerator(generatorBytes) return deriveAddressFromBytes(accountPublicBytes) } export { generateSeed, deriveKeypair, sign, verify, deriveAddress, deriveNodeAddress, decodeSeed, }