diff --git a/package.json b/package.json index cdd1cea..454c7a1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@beamnetwork/nonce-2d", - "version": "1.0.1", + "version": "1.1.0", "description": "", "main": "./dist/index.js", "module": "./dist/index.mjs", diff --git a/src/index.ts b/src/index.ts index 8b068c8..c5df34a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,6 @@ +// Size of a hex character in bits +export const NONCE_2D_BIT_TO_HEX = 4 + // Bit length of the nonce export const NONCE_2D_BIT_LENGTH = 256 @@ -16,6 +19,15 @@ export const NONCE_2D_KEY_META_DATA_BIT_LENGTH = 32 // 4*8 // Radix for hex const HEX_RADIS = 16 +/** + * Reverses the string, returns a reference + * + * @param str string to reverse + * @returns + */ +function reverseString(str: string): string { + return str.split('').reverse().join('') +} /** * The structure of the Nonce2D, [key, seq] == [192|64] == 256 bits. The key is split up into a 32 bit meta data and a 160 bit address. * This class assumes that the nonce key is intended to pass on information in the meta data for use with the encoded address. @@ -36,12 +48,11 @@ export class Nonce2D { private constructor(hexNonce2D: string) { hexNonce2D = include0x(hexNonce2D) - const { key, meta, address } = this.getKeyHex(BigInt(hexNonce2D)) - this._key = key - this._meta = meta - this._address = address - - this._seq = this.getSequenceHex(BigInt(hexNonce2D)) + const decoded = this.decodeHex(hexNonce2D) + this._key = decoded.key + this._seq = decoded.seq + this._address = decoded.address + this._meta = decoded.meta } /** @@ -63,7 +74,6 @@ export class Nonce2D { //add the NONCE_2D_SEQ_BIT_LENGTH sequence number bits sum += BigInt(this._seq) - return this.toHex(sum) } @@ -121,6 +131,15 @@ export class Nonce2D { return (BigInt(1) << BigInt(maskLength)) - BigInt(1) } + /** + * Converts a bit length to a character length + * @param bitLength the length in bits + * @returns the length in characters + */ + static toCharNum(bitLength: number): number { + return bitLength / NONCE_2D_BIT_TO_HEX + } + // Returns the (up to)192 bit key as a hex string get key(): string { return this._key @@ -141,6 +160,41 @@ export class Nonce2D { return this._seq } + /** + * Decodes the 256 bit Nonce2D into its 192 bit key and 64 bit sequence + * @returns the 2d nonce decoded into its key and sequence + */ + decodeHex(hexNonce2D: string): { + key: string + seq: string + address: string + meta: string + } { + //check that its a valid hex string + BigInt(hexNonce2D) + const rev = reverseString(stripOx(hexNonce2D)) + const seq = reverseString( + rev.slice(0, Nonce2D.toCharNum(NONCE_2D_SEQ_BIT_LENGTH)), + ) + const key = rev.slice( + Nonce2D.toCharNum(NONCE_2D_SEQ_BIT_LENGTH), + rev.length, + ) + const address = reverseString( + key.slice(0, Nonce2D.toCharNum(NONCE_2D_KEY_ADDRESS_BIT_LENGTH)), + ) + const meta = reverseString( + key.slice(Nonce2D.toCharNum(NONCE_2D_KEY_ADDRESS_BIT_LENGTH), key.length), + ) + + return { + key: '0x' + reverseString(key), + seq: '0x' + seq, + address: '0x' + address, + meta: '0x' + meta, + } + } + /** * Gets the 192 bit key from a 256 bit Nonce2D * @returns The 192 bit key as a hex string diff --git a/test/index.spec.ts b/test/index.spec.ts index aa2406e..c9a352e 100644 --- a/test/index.spec.ts +++ b/test/index.spec.ts @@ -15,7 +15,7 @@ const testsHexNonce = // 192 bit key = 4 bytes for meta = 5(00000005), 20 bytes for address(e7f1725E7734CE288F8367e1Bb143E90bb3F0512) const testsKey = '0x5e7f1725e7734ce288f8367e1bb143e90bb3f0512' // 64 bit sequence = 8 bytes -const testsSeq = '0x1' +const testsSeq = '0x0000000000000001' // 160 bit address const testsAddress = '0xe7f1725e7734ce288f8367e1bb143e90bb3f0512' @@ -46,7 +46,7 @@ describe('Nonce2D tests', () => { }) it('should create a Nonce2D object from a valid key with optional seq', () => { - const seq: string = '0xd' + const seq: string = '0x000000000000000d' const n = Nonce2D.fromHex(testsKey, seq) expect(n.meta).toBe(testMeta) expect(n.address).toBe(testsAddress) @@ -87,6 +87,17 @@ describe('Nonce2D tests', () => { expect(n.toHexNonce()).toBe(testsHexNonce) }) + it('should not cut off leading 0 in address', () => { + // const nonceHash = '50C77C13C2A7736140B2B9FA9F4E16B4BECCD665A0000000000000007' + const destinationAddress = + '0x0C77C13c2a7736140b2b9Fa9F4e16B4bECCd665A'.toLocaleLowerCase() + const stable = '5' + const key = Nonce2D.getHexKeyForDestination(destinationAddress, stable) + const nonceHash = ((BigInt(key) << BigInt(64)) + BigInt(7)).toString(16) + const n = Nonce2D.fromHexNonce(nonceHash) + expect(n.address).toBe(destinationAddress) + }) + it('should support lack of 0x infrom of string', () => { const missing = testsHexNonce.substring(2) const n = Nonce2D.fromHexNonce(missing)