refactor: remove import * where able (#2550)

refactor: remove `import *` where able to

BREAKING CHANGE: Moved all methods that were on `Utils` in
`@xrplf/secret-numbers` are now individually exported. This affects:
- Utils.randomEntropy,
- Utils.randomSecret
- Utils.entropyToSecret
- Utils.secretToEntropy
- Utils.calculateChecksum
- Utils.checkChecksum
- Utils.parseSecretString
This commit is contained in:
Caleb Kniffen
2023-11-01 16:30:59 -05:00
parent 3f1739895a
commit 83b9780b5b
8 changed files with 90 additions and 70 deletions

View File

@@ -1,4 +1,4 @@
import * as enums from './definitions.json' import enums from './definitions.json'
import { import {
XrplDefinitionsBase, XrplDefinitionsBase,
FieldInstance, FieldInstance,

View File

@@ -1,19 +1,26 @@
import assert from 'assert' import assert from 'assert'
import * as fixtures from './fixtures/api.json' import * as fixtures from './fixtures/api.json'
import * as api from '../src' import {
decodeSeed,
deriveAddress,
deriveKeypair,
deriveNodeAddress,
generateSeed,
sign,
verify,
} from '../src'
const decodeSeed = api.decodeSeed
const entropy = new Uint8Array([ const entropy = new Uint8Array([
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
]) ])
describe('api', () => { describe('api', () => {
it('generateSeed - secp256k1', () => { it('generateSeed - secp256k1', () => {
assert.strictEqual(api.generateSeed({ entropy }), fixtures.secp256k1.seed) assert.strictEqual(generateSeed({ entropy }), fixtures.secp256k1.seed)
}) })
it('generateSeed - secp256k1, random', () => { it('generateSeed - secp256k1, random', () => {
const seed = api.generateSeed() const seed = generateSeed()
assert(seed.startsWith('s')) assert(seed.startsWith('s'))
const { type, bytes } = decodeSeed(seed) const { type, bytes } = decodeSeed(seed)
assert(type === 'secp256k1') assert(type === 'secp256k1')
@@ -22,13 +29,13 @@ describe('api', () => {
it('generateSeed - ed25519', () => { it('generateSeed - ed25519', () => {
assert.strictEqual( assert.strictEqual(
api.generateSeed({ entropy, algorithm: 'ed25519' }), generateSeed({ entropy, algorithm: 'ed25519' }),
fixtures.ed25519.seed, fixtures.ed25519.seed,
) )
}) })
it('generateSeed - ed25519, random', () => { it('generateSeed - ed25519, random', () => {
const seed = api.generateSeed({ algorithm: 'ed25519' }) const seed = generateSeed({ algorithm: 'ed25519' })
assert(seed.startsWith('sEd')) assert(seed.startsWith('sEd'))
const { type, bytes } = decodeSeed(seed) const { type, bytes } = decodeSeed(seed)
assert(type === 'ed25519') assert(type === 'ed25519')
@@ -36,36 +43,36 @@ describe('api', () => {
}) })
it('deriveKeypair - secp256k1', () => { it('deriveKeypair - secp256k1', () => {
const keypair = api.deriveKeypair(fixtures.secp256k1.seed) const keypair = deriveKeypair(fixtures.secp256k1.seed)
assert.deepEqual(keypair, fixtures.secp256k1.keypair) assert.deepEqual(keypair, fixtures.secp256k1.keypair)
}) })
it('deriveKeypair - ed25519', () => { it('deriveKeypair - ed25519', () => {
const keypair = api.deriveKeypair(fixtures.ed25519.seed) const keypair = deriveKeypair(fixtures.ed25519.seed)
assert.deepEqual(keypair, fixtures.ed25519.keypair) assert.deepEqual(keypair, fixtures.ed25519.keypair)
}) })
it('deriveKeypair - secp256k1 - validator', () => { it('deriveKeypair - secp256k1 - validator', () => {
const keypair = api.deriveKeypair(fixtures.secp256k1.seed, { const keypair = deriveKeypair(fixtures.secp256k1.seed, {
validator: true, validator: true,
}) })
assert.deepEqual(keypair, fixtures.secp256k1.validatorKeypair) assert.deepEqual(keypair, fixtures.secp256k1.validatorKeypair)
}) })
it('deriveKeypair - ed25519 - validator', () => { it('deriveKeypair - ed25519 - validator', () => {
const keypair = api.deriveKeypair(fixtures.ed25519.seed, { const keypair = deriveKeypair(fixtures.ed25519.seed, {
validator: true, validator: true,
}) })
assert.deepEqual(keypair, fixtures.ed25519.validatorKeypair) assert.deepEqual(keypair, fixtures.ed25519.validatorKeypair)
}) })
it('deriveAddress - secp256k1 public key', () => { it('deriveAddress - secp256k1 public key', () => {
const address = api.deriveAddress(fixtures.secp256k1.keypair.publicKey) const address = deriveAddress(fixtures.secp256k1.keypair.publicKey)
assert.strictEqual(address, fixtures.secp256k1.address) assert.strictEqual(address, fixtures.secp256k1.address)
}) })
it('deriveAddress - ed25519 public key', () => { it('deriveAddress - ed25519 public key', () => {
const address = api.deriveAddress(fixtures.ed25519.keypair.publicKey) const address = deriveAddress(fixtures.ed25519.keypair.publicKey)
assert.strictEqual(address, fixtures.ed25519.address) assert.strictEqual(address, fixtures.ed25519.address)
}) })
@@ -73,7 +80,7 @@ describe('api', () => {
const privateKey = fixtures.secp256k1.keypair.privateKey const privateKey = fixtures.secp256k1.keypair.privateKey
const message = fixtures.secp256k1.message const message = fixtures.secp256k1.message
const messageHex = Buffer.from(message, 'utf8').toString('hex') const messageHex = Buffer.from(message, 'utf8').toString('hex')
const signature = api.sign(messageHex, privateKey) const signature = sign(messageHex, privateKey)
assert.strictEqual(signature, fixtures.secp256k1.signature) assert.strictEqual(signature, fixtures.secp256k1.signature)
}) })
@@ -82,14 +89,14 @@ describe('api', () => {
const publicKey = fixtures.secp256k1.keypair.publicKey const publicKey = fixtures.secp256k1.keypair.publicKey
const message = fixtures.secp256k1.message const message = fixtures.secp256k1.message
const messageHex = Buffer.from(message, 'utf8').toString('hex') const messageHex = Buffer.from(message, 'utf8').toString('hex')
assert(api.verify(messageHex, signature, publicKey)) assert(verify(messageHex, signature, publicKey))
}) })
it('sign - ed25519', () => { it('sign - ed25519', () => {
const privateKey = fixtures.ed25519.keypair.privateKey const privateKey = fixtures.ed25519.keypair.privateKey
const message = fixtures.ed25519.message const message = fixtures.ed25519.message
const messageHex = Buffer.from(message, 'utf8').toString('hex') const messageHex = Buffer.from(message, 'utf8').toString('hex')
const signature = api.sign(messageHex, privateKey) const signature = sign(messageHex, privateKey)
assert.strictEqual(signature, fixtures.ed25519.signature) assert.strictEqual(signature, fixtures.ed25519.signature)
}) })
@@ -98,19 +105,19 @@ describe('api', () => {
const publicKey = fixtures.ed25519.keypair.publicKey const publicKey = fixtures.ed25519.keypair.publicKey
const message = fixtures.ed25519.message const message = fixtures.ed25519.message
const messageHex = Buffer.from(message, 'utf8').toString('hex') const messageHex = Buffer.from(message, 'utf8').toString('hex')
assert(api.verify(messageHex, signature, publicKey)) assert(verify(messageHex, signature, publicKey))
}) })
it('deriveNodeAddress', () => { it('deriveNodeAddress', () => {
const addrX = 'n9KHn8NfbBsZV5q8bLfS72XyGqwFt5mgoPbcTV4c6qKiuPTAtXYk' const addrX = 'n9KHn8NfbBsZV5q8bLfS72XyGqwFt5mgoPbcTV4c6qKiuPTAtXYk'
const addrY = 'rU7bM9ENDkybaxNrefAVjdLTyNLuue1KaJ' const addrY = 'rU7bM9ENDkybaxNrefAVjdLTyNLuue1KaJ'
assert.strictEqual(api.deriveNodeAddress(addrX), addrY) assert.strictEqual(deriveNodeAddress(addrX), addrY)
}) })
it('Random Address', () => { it('Random Address', () => {
const seed = api.generateSeed() const seed = generateSeed()
const keypair = api.deriveKeypair(seed) const keypair = deriveKeypair(seed)
const address = api.deriveAddress(keypair.publicKey) const address = deriveAddress(keypair.publicKey)
assert(address.startsWith('r')) assert(address.startsWith('r'))
}) })
}) })

View File

@@ -2,6 +2,11 @@
Subscribe to [the **xrpl-announce** mailing list](https://groups.google.com/g/xrpl-announce) for release announcements. We recommend that `@xrplf/secret-numbers` users stay up-to-date with the latest stable release. Subscribe to [the **xrpl-announce** mailing list](https://groups.google.com/g/xrpl-announce) for release announcements. We recommend that `@xrplf/secret-numbers` users stay up-to-date with the latest stable release.
## Unreleased
### BREAKING CHANGES:
- Moved all methods that were on `Utils` are now individually exported.
## 1.0.0 Beta 1 (2023-10-19) ## 1.0.0 Beta 1 (2023-10-19)
* Add `xrpl-secret-numbers` by @WietseWind to the mono repo. * Add `xrpl-secret-numbers` by @WietseWind to the mono repo.

View File

@@ -1,8 +1,2 @@
/* Methods ==================================================================== */ export * from './schema/Account'
import Account from './schema/Account' export * from './utils'
import * as Utils from './utils'
/* Types ==================================================================== */
/* Export ==================================================================== */
export { Account, Utils }

View File

@@ -1,10 +1,14 @@
import * as keypairs from 'ripple-keypairs' import { deriveAddress, deriveKeypair, generateSeed } from 'ripple-keypairs'
import * as utils from '../utils' import {
entropyToSecret,
parseSecretString,
randomSecret,
secretToEntropy,
} from '../utils'
/* Types ==================================================================== */ /* Types ==================================================================== */
// eslint-disable-next-line import/no-unused-modules -- it is returned by Account.getKeypair
export interface Keypair { export interface Keypair {
publicKey: string publicKey: string
privateKey: string privateKey: string
@@ -18,7 +22,7 @@ interface AccountData {
/* Class ==================================================================== */ /* Class ==================================================================== */
export default class Account { export class Account {
private readonly _secret: string[] private readonly _secret: string[]
private readonly _account: AccountData = { private readonly _account: AccountData = {
familySeed: '', familySeed: '',
@@ -31,13 +35,13 @@ export default class Account {
constructor(secretNumbers?: string[] | string | Buffer) { constructor(secretNumbers?: string[] | string | Buffer) {
if (typeof secretNumbers === 'string') { if (typeof secretNumbers === 'string') {
this._secret = utils.parseSecretString(secretNumbers) this._secret = parseSecretString(secretNumbers)
} else if (Array.isArray(secretNumbers)) { } else if (Array.isArray(secretNumbers)) {
this._secret = secretNumbers this._secret = secretNumbers
} else if (Buffer.isBuffer(secretNumbers)) { } else if (Buffer.isBuffer(secretNumbers)) {
this._secret = utils.entropyToSecret(secretNumbers) this._secret = entropyToSecret(secretNumbers)
} else { } else {
this._secret = utils.randomSecret() this._secret = randomSecret()
} }
validateLengths(this._secret) validateLengths(this._secret)
@@ -70,12 +74,10 @@ export default class Account {
private derive(): void { private derive(): void {
try { try {
const entropy = utils.secretToEntropy(this._secret) const entropy = secretToEntropy(this._secret)
this._account.familySeed = keypairs.generateSeed({ entropy }) this._account.familySeed = generateSeed({ entropy })
this._account.keypair = keypairs.deriveKeypair(this._account.familySeed) this._account.keypair = deriveKeypair(this._account.familySeed)
this._account.address = keypairs.deriveAddress( this._account.address = deriveAddress(this._account.keypair.publicKey)
this._account.keypair.publicKey,
)
} catch (error) { } catch (error) {
let message = 'Unknown Error' let message = 'Unknown Error'
if (error instanceof Error) { if (error instanceof Error) {

View File

@@ -1,16 +1,16 @@
import * as keypairs from 'ripple-keypairs' import { deriveAddress, deriveKeypair, generateSeed } from 'ripple-keypairs'
import { Account, Utils } from '../src' import { Account, secretToEntropy } from '../src'
describe('API: XRPL Secret Numbers', () => { describe('API: XRPL Secret Numbers', () => {
describe('Generate new account', () => { describe('Generate new account', () => {
const account = new Account() const account = new Account()
it('Output sanity checks', () => { it('Output sanity checks', () => {
expect(account.getAddress()).toMatch(/^r[a-zA-Z0-9]{19,}$/u) expect(account.getAddress()).toMatch(/^r[a-zA-Z0-9]{19,}$/u)
const entropy = Utils.secretToEntropy(`${account.toString()}`.split(' ')) const entropy = secretToEntropy(`${account.toString()}`.split(' '))
const familySeed = keypairs.generateSeed({ entropy }) const familySeed = generateSeed({ entropy })
const keypair = keypairs.deriveKeypair(familySeed) const keypair = deriveKeypair(familySeed)
const address = keypairs.deriveAddress(keypair.publicKey) const address = deriveAddress(keypair.publicKey)
expect(address).toEqual(account.getAddress()) expect(address).toEqual(account.getAddress())
expect(familySeed).toEqual(account.getFamilySeed()) expect(familySeed).toEqual(account.getFamilySeed())
}) })

View File

@@ -1,8 +1,16 @@
import * as utils from '../src/utils' import {
calculateChecksum,
checkChecksum,
entropyToSecret,
parseSecretString,
randomEntropy,
randomSecret,
secretToEntropy,
} from '../src/utils'
describe('Utils', () => { describe('Utils', () => {
it('randomEntropy: valid output', () => { it('randomEntropy: valid output', () => {
const data = utils.randomEntropy() const data = randomEntropy()
expect(typeof data).toEqual('object') expect(typeof data).toEqual('object')
expect(data instanceof Buffer).toBeTruthy() expect(data instanceof Buffer).toBeTruthy()
expect(data.length).toEqual(16) expect(data.length).toEqual(16)
@@ -11,32 +19,32 @@ describe('Utils', () => {
}) })
it('calculateChecksum: 1st position', () => { it('calculateChecksum: 1st position', () => {
expect(utils.calculateChecksum(0, 55988)).toEqual(8) expect(calculateChecksum(0, 55988)).toEqual(8)
}) })
it('calculateChecksum: 8th position', () => { it('calculateChecksum: 8th position', () => {
expect(utils.calculateChecksum(7, 49962)).toEqual(0) expect(calculateChecksum(7, 49962)).toEqual(0)
}) })
it('checkChecksum: 2nd position, split numbers', () => { it('checkChecksum: 2nd position, split numbers', () => {
expect(utils.checkChecksum(1, 55450, 3)).toBeTruthy() expect(checkChecksum(1, 55450, 3)).toBeTruthy()
}) })
it('checkChecksum: 7th position, split numbers', () => { it('checkChecksum: 7th position, split numbers', () => {
expect(utils.checkChecksum(6, 18373, 7)).toBeTruthy() expect(checkChecksum(6, 18373, 7)).toBeTruthy()
}) })
it('checkChecksum: 4th position, as string', () => { it('checkChecksum: 4th position, as string', () => {
expect(utils.checkChecksum(3, '391566')).toBeTruthy() expect(checkChecksum(3, '391566')).toBeTruthy()
}) })
it('randomSecret: valid checksums', () => { it('randomSecret: valid checksums', () => {
utils.randomSecret() randomSecret()
expect(0).toEqual(0) expect(0).toEqual(0)
}) })
it('randomSecret: valid output', () => { it('randomSecret: valid output', () => {
const data = utils.randomSecret() const data = randomSecret()
expect(Array.isArray(data)).toBeTruthy() expect(Array.isArray(data)).toBeTruthy()
expect(data.length).toEqual(8) expect(data.length).toEqual(8)
expect(typeof data[0]).toEqual('string') expect(typeof data[0]).toEqual('string')
@@ -56,7 +64,7 @@ describe('Utils', () => {
'076618', '076618',
'024286', '024286',
] ]
expect(utils.entropyToSecret(entropy)).toEqual(secret) expect(entropyToSecret(entropy)).toEqual(secret)
}) })
it('secretToEntropy', () => { it('secretToEntropy', () => {
@@ -71,7 +79,7 @@ describe('Utils', () => {
'024286', '024286',
] ]
const entropy = Buffer.from('76ebb2d06879b45b7568fb9c1ded097c', 'hex') const entropy = Buffer.from('76ebb2d06879b45b7568fb9c1ded097c', 'hex')
expect(utils.secretToEntropy(secret)).toEqual(entropy) expect(secretToEntropy(secret)).toEqual(entropy)
}) })
it('parseSecretString with spaces valid', () => { it('parseSecretString with spaces valid', () => {
@@ -86,17 +94,15 @@ describe('Utils', () => {
'024286', '024286',
] ]
expect( expect(
utils.parseSecretString( parseSecretString(
'304435 457766 267453 461717 300560 644127 076618 024286', '304435 457766 267453 461717 300560 644127 076618 024286',
), ),
).toEqual(secret) ).toEqual(secret)
expect( expect(
utils.parseSecretString( parseSecretString('304435457766267453461717300560644127076618024286'),
'304435457766267453461717300560644127076618024286',
),
).toEqual(secret) ).toEqual(secret)
expect( expect(
utils.parseSecretString(` parseSecretString(`
304435 457766 304435 457766
267453 461717 267453 461717
300560 644127 300560 644127

View File

@@ -14,7 +14,13 @@ import {
isValidXAddress, isValidXAddress,
xAddressToClassicAddress, xAddressToClassicAddress,
} from 'ripple-address-codec' } from 'ripple-address-codec'
import * as rbc from 'ripple-binary-codec' import {
encode as rbcEncode,
decode as rbcDecode,
encodeForMultisigning as rbcEncodeForMultisigning,
encodeForSigning as rbcEncodeForSigning,
encodeForSigningClaim as rbcEncodeForSigningClaim,
} from 'ripple-binary-codec'
import { verify as verifyKeypairSignature } from 'ripple-keypairs' import { verify as verifyKeypairSignature } from 'ripple-keypairs'
import { LedgerEntry } from '../models/ledger' import { LedgerEntry } from '../models/ledger'
@@ -83,7 +89,7 @@ function isValidSecret(secret: string): boolean {
* @returns A hex string representing the encoded object. * @returns A hex string representing the encoded object.
*/ */
function encode(object: Transaction | LedgerEntry): string { function encode(object: Transaction | LedgerEntry): string {
return rbc.encode(object) return rbcEncode(object)
} }
/** /**
@@ -93,7 +99,7 @@ function encode(object: Transaction | LedgerEntry): string {
* @returns A hex string representing the encoded object. * @returns A hex string representing the encoded object.
*/ */
function encodeForSigning(object: Transaction): string { function encodeForSigning(object: Transaction): string {
return rbc.encodeForSigning(object) return rbcEncodeForSigning(object)
} }
/** /**
@@ -103,7 +109,7 @@ function encodeForSigning(object: Transaction): string {
* @returns A hex string representing the encoded object. * @returns A hex string representing the encoded object.
*/ */
function encodeForSigningClaim(object: PaymentChannelClaim): string { function encodeForSigningClaim(object: PaymentChannelClaim): string {
return rbc.encodeForSigningClaim(object) return rbcEncodeForSigningClaim(object)
} }
/** /**
@@ -114,7 +120,7 @@ function encodeForSigningClaim(object: PaymentChannelClaim): string {
* @returns A hex string representing the encoded object. * @returns A hex string representing the encoded object.
*/ */
function encodeForMultiSigning(object: Transaction, signer: string): string { function encodeForMultiSigning(object: Transaction, signer: string): string {
return rbc.encodeForMultisigning(object, signer) return rbcEncodeForMultisigning(object, signer)
} }
/** /**
@@ -124,7 +130,7 @@ function encodeForMultiSigning(object: Transaction, signer: string): string {
* @returns The hex string decoded according to XRPL serialization format. * @returns The hex string decoded according to XRPL serialization format.
*/ */
function decode(hex: string): Record<string, unknown> { function decode(hex: string): Record<string, unknown> {
return rbc.decode(hex) return rbcDecode(hex)
} }
/** /**