From c7aa1ff35e1c04b49f54a58edc97d10c4147b764 Mon Sep 17 00:00:00 2001 From: Gabriel Rocheleau Date: Fri, 16 Aug 2024 17:11:41 -0400 Subject: [PATCH] util: add matching bytes length util from verkle --- packages/util/src/bytes.ts | 23 ++++++++++++++++ packages/util/test/bytes.spec.ts | 45 ++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/packages/util/src/bytes.ts b/packages/util/src/bytes.ts index 7226c5b4b5..543540323a 100644 --- a/packages/util/src/bytes.ts +++ b/packages/util/src/bytes.ts @@ -551,3 +551,26 @@ export { bytesToUtf8, equalsBytes, utf8ToBytes } from 'ethereum-cryptography/uti export function hexToBigInt(input: PrefixedHexString): bigint { return bytesToBigInt(hexToBytes(isHexString(input) ? input : `0x${input}`)) } + +/** + * Compares two byte arrays and returns the count of consecutively matching items from the start. + * + * @function + * @param {Uint8Array} bytes1 - The first Uint8Array to compare. + * @param {Uint8Array} bytes2 - The second Uint8Array to compare. + * @returns {number} The count of consecutively matching items from the start. + */ +export function matchingBytesLength(bytes1: Uint8Array, bytes2: Uint8Array): number { + let count = 0 + const minLength = Math.min(bytes1.length, bytes2.length) + + for (let i = 0; i < minLength; i++) { + if (bytes1[i] === bytes2[i]) { + count++ + } else { + // Break early if a mismatch is found + break + } + } + return count +} diff --git a/packages/util/test/bytes.spec.ts b/packages/util/test/bytes.spec.ts index cf031f98af..8f41e56dea 100644 --- a/packages/util/test/bytes.spec.ts +++ b/packages/util/test/bytes.spec.ts @@ -17,6 +17,7 @@ import { intToHex, intToUnpaddedBytes, isZeroAddress, + matchingBytesLength, setLengthLeft, setLengthRight, short, @@ -482,3 +483,47 @@ describe('unprefixedHexToBytes', () => { assert.deepEqual(converted, new Uint8Array([17])) }) }) + +describe('matchingBytesLength', () => { + it('should return 0 when both arrays are empty', () => { + const bytes1 = new Uint8Array([]) + const bytes2 = new Uint8Array([]) + assert.equal(matchingBytesLength(bytes1, bytes2), 0) + }) + + it('should return 0 when one of the arrays is empty', () => { + const bytes1 = new Uint8Array([1, 2, 3]) + const bytes2 = new Uint8Array([]) + assert.equal(matchingBytesLength(bytes1, bytes2), 0) + }) + + it('should return 0 when arrays have no matching elements', () => { + const bytes1 = new Uint8Array([1, 2, 3]) + const bytes2 = new Uint8Array([4, 5, 6]) + assert.equal(matchingBytesLength(bytes1, bytes2), 0) + }) + + it('should handle arrays with same elements but different lengths', () => { + const bytes1 = new Uint8Array([1, 2, 3]) + const bytes2 = new Uint8Array([1, 2, 3, 4]) + assert.equal(matchingBytesLength(bytes1, bytes2), 3) + }) + + it('should handle arrays with matching elements at end', () => { + const bytes1 = new Uint8Array([1, 2, 3]) + const bytes2 = new Uint8Array([0, 1, 2, 3]) + assert.equal(matchingBytesLength(bytes1, bytes2), 0) + }) + + it('should handle arrays with matching elements at start', () => { + const bytes1 = new Uint8Array([1, 2, 3]) + const bytes2 = new Uint8Array([1, 2, 3, 4, 5]) + assert.equal(matchingBytesLength(bytes1, bytes2), 3) + }) + + it('should handle arrays with large number of elements', () => { + const bytes1 = new Uint8Array(Array.from({ length: 1000000 }, (_, i) => i)) + const bytes2 = new Uint8Array(Array.from({ length: 1000000 }, (_, i) => i)) + assert.equal(matchingBytesLength(bytes1, bytes2), 1000000) + }) +})