diff --git a/src/derivers/cip3.test.ts b/src/derivers/cip3.test.ts index 34747d3f..8445816d 100644 --- a/src/derivers/cip3.test.ts +++ b/src/derivers/cip3.test.ts @@ -5,10 +5,17 @@ import { BIP_32_HARDENED_OFFSET } from '../constants'; import { ed25519Bip32 } from '../curves'; import { SLIP10Node } from '../SLIP10Node'; import { + add, + bigIntToBytes, + bytesToBigInt, deriveChainCode, deriveChildKey, derivePrivateKey, derivePublicKey, + mod2Pow256, + padEnd32Bytes, + toReversed, + trunc28Mul8, } from './cip3'; const fixtureNodeToParentNode = ( @@ -160,4 +167,78 @@ describe('Cip3', () => { }); }); }); + + describe('toReversed', () => { + it('reverts bytes', () => { + const bytes = new Uint8Array([1, 2, 3, 4, 5]); + expect(toReversed(bytes)).toStrictEqual(new Uint8Array([5, 4, 3, 2, 1])); + }); + }); + + describe('bytesToBigInt', () => { + it('converts bytes to bigint', () => { + const bytes = new Uint8Array([1, 2, 3, 4, 5]); + expect(bytesToBigInt(bytes)).toStrictEqual(BigInt('0x0504030201')); + }); + }); + + describe('bigIntToBytes', () => { + it('converts bigint to bytes', () => { + const bigInt = BigInt('0x0504030201'); + expect(bigIntToBytes(bigInt)).toStrictEqual( + new Uint8Array([1, 2, 3, 4, 5]), + ); + }); + }); + + describe('padEnd32Bytes', () => { + it('pads end of byte array to 32 bytes', () => { + const bytes = new Uint8Array([1, 2, 3, 4, 5]); + const padding = new Array(27).fill(0); + const padded = new Uint8Array([1, 2, 3, 4, 5, ...padding]); + expect(padEnd32Bytes(bytes)).toStrictEqual(padded); + }); + }); + + describe('trunc28Mul8', () => { + it('truncates bytes to length 28 and multiply byt 8', () => { + const bytes = hexToBytes( + '0xade6ef960e9fc741bc1808bd91ed7c3944c760de5947662adc428029c722deab', + ); + const expectedResult = hexToBytes( + '0x68357fb774f83c0ee2c540e88d6ce7cb213a06f3ce3a3253e116024c01000000', + ); + const result = trunc28Mul8(bytes); + expect(result).toStrictEqual(expectedResult); + }); + }); + + describe('mod2Pow256', () => { + it('modulo 2^256', () => { + const bytes = hexToBytes( + '0xd664152bff95f76efdd0052643eb096eea6f18b6793365563bcaa12b3aa04fed', + ); + const expectedResult = hexToBytes( + '0xd664152bff95f76efdd0052643eb096eea6f18b6793365563bcaa12b3aa04fed', + ); + const result = mod2Pow256(bytes); + expect(result).toStrictEqual(expectedResult); + }); + }); + + describe('add', () => { + it('adds two arrays of bytes', () => { + const left = hexToBytes( + '0xa09de4b08a21d9223bd3b8196e3c92b809898755d6d0246d662063b203000000', + ); + const right = hexToBytes( + '0x5049005d5a97d5ea60753fb511460079a56b9981bc2e75f05e40dd46788c7748', + ); + const expectedResult = hexToBytes( + '0xf0e6e40de5b8ae0d9c48f8ce7f829231aff420d792ff995dc56040f97b8c7748', + ); + const result = add(left, right); + expect(result).toStrictEqual(expectedResult); + }); + }); }); diff --git a/src/derivers/cip3.ts b/src/derivers/cip3.ts index 8aa987d0..75219d04 100644 --- a/src/derivers/cip3.ts +++ b/src/derivers/cip3.ts @@ -33,7 +33,7 @@ import { generateEntropy, getValidatedPath, validateNode } from './shared'; * @param bytes - The input Uint8Array. * @returns A new Uint8Array with the bytes in reversed order. */ -const toReversed = (bytes: Uint8Array) => bytes.slice().reverse(); +export const toReversed = (bytes: Uint8Array) => bytes.slice().reverse(); /** * Converts an array of bytes to a BigInt. @@ -41,7 +41,7 @@ const toReversed = (bytes: Uint8Array) => bytes.slice().reverse(); * @param bytes - The array of bytes to convert. * @returns The BigInt representation of the bytes. */ -const bytesToBigInt = (bytes: Uint8Array) => { +export const bytesToBigInt = (bytes: Uint8Array) => { const reversed = toReversed(bytes); const bytesInHex = bytesToHex(reversed); return BigInt(bytesInHex); @@ -53,7 +53,7 @@ const bytesToBigInt = (bytes: Uint8Array) => { * @param bigInt - The BigInt to convert. * @returns The byte array representation of the BigInt. */ -const bigIntToBytes = (bigInt: bigint) => { +export const bigIntToBytes = (bigInt: bigint) => { const hexadecimal = bigInt.toString(16); return toReversed(hexToBytes(hexadecimal)); }; @@ -64,7 +64,7 @@ const bigIntToBytes = (bigInt: bigint) => { * @param bytes - The bytes array to pad. * @returns The padded bytes array. */ -const padEnd32Bytes = (bytes: Uint8Array) => { +export const padEnd32Bytes = (bytes: Uint8Array) => { return concatBytes([ bytes, new Uint8Array(Math.max(32 - bytes.length, 0)).fill(0), @@ -77,7 +77,7 @@ const padEnd32Bytes = (bytes: Uint8Array) => { * @param bytes - Little-Endian big number in bytes. * @returns PadEnd32Bytes(left[0, 28] * 8)). */ -const trunc28Mul8 = (bytes: Uint8Array): Uint8Array => { +export const trunc28Mul8 = (bytes: Uint8Array): Uint8Array => { const truncLeftMul8 = bytesToBigInt(bytes.slice(0, 28)) * BigInt(8); return padEnd32Bytes(bigIntToBytes(truncLeftMul8)); }; @@ -88,7 +88,7 @@ const trunc28Mul8 = (bytes: Uint8Array): Uint8Array => { * @param bytes - Little-Endian big number in bytes. * @returns PadEnd32Bytes(mod(bytes, 2^256))). */ -const mod2Pow256 = (bytes: Uint8Array): Uint8Array => { +export const mod2Pow256 = (bytes: Uint8Array): Uint8Array => { return padEnd32Bytes( bigIntToBytes(mod(bytesToBigInt(bytes), BigInt(2) ** BigInt(256))), ); @@ -101,7 +101,7 @@ const mod2Pow256 = (bytes: Uint8Array): Uint8Array => { * @param right - Right hand side Little-Endian big number. * @returns PadEnd32Bytes(left + right). */ -const add = (left: Uint8Array, right: Uint8Array): Uint8Array => { +export const add = (left: Uint8Array, right: Uint8Array): Uint8Array => { const added = bytesToBigInt(left) + bytesToBigInt(right); return padEnd32Bytes(bigIntToBytes(added)).slice(0, 32); }; @@ -114,7 +114,11 @@ const add = (left: Uint8Array, right: Uint8Array): Uint8Array => { * @param childIndex - Child index. * @returns PadEnd32Bytes(left + right). */ -const getKeyExtension = (tag: number, key: Uint8Array, childIndex: number) => { +export const getKeyExtension = ( + tag: number, + key: Uint8Array, + childIndex: number, +) => { return concatBytes([ new Uint8Array([tag]), key,