From: Chris Duncan Date: Fri, 4 Sep 2026 18:18:11 +0000 (-0700) Subject: Add comprehensive equalbytes unit tests to check byte pairs that would cancel each... X-Git-Url: https://git.codecow.com/?a=commitdiff_plain;h=84624f9a838ac162b530a911b876fa6bf27419ae;p=nano25519.git Add comprehensive equalbytes unit tests to check byte pairs that would cancel each other out if the |= accumulator was accidentally replaced with a different, and wrong, operator. --- diff --git a/src/assembly/tests.ts b/src/assembly/tests.ts index cefee97..635a324 100644 --- a/src/assembly/tests.ts +++ b/src/assembly/tests.ts @@ -6,22 +6,38 @@ import { equalbytes } from './utils' /** * Tests run on initialization to ensure build is correct. */ +function err (fname: string, vector: string, expected: string, actual: string): void { + throw new Error(`${fname} build error from "${vector}": expected ${expected}; actual ${actual}`) +} + +function xpass_equalbytes (vector: string, expected: StaticArray, actual: StaticArray): void { + if (!equalbytes(expected, actual, 32)) { + err('equalbytes', vector, `pass [${expected}]`, `fail [${actual}]`) + } +} + +function xfail_equalbytes (vector: string, expected: StaticArray, actual: StaticArray): void { + if (equalbytes(expected, actual, 32)) { + err('equalbytes', vector, `fail [${expected}]`, `pass [${actual}]`) + } +} /** - * equalbytes - checks masked bytes against the following test keys: - * - random bytes - * - all zeros - * - all ones + * equalbytes must report "unequal" for every difference regardless of shape + * - `zeros`: lower boundary with every bit cleared + * - `ones`: upper boundary with every bit set + * - `spread`: all bytes distinct from each other and setting each bit to 0 or 1 */ const zeros = new StaticArray(32).fill(0) const ones = new StaticArray(32).fill(255) -const random = new StaticArray(32) +const spread = new StaticArray(32) +// 37 is large enough prime to cover all bit positions as either 0 or 1 for (let i = 0; i < 32; i++) { - random[i] = u8(Math.random() * 256) + spread[i] = u8(i * 37) } -const vectors = ['zeros', 'ones', 'random',] -const expecteds = [zeros, ones, random,] +const vectors = ['zeros', 'ones', 'spread',] +const expecteds = [zeros, ones, spread,] const actual = new StaticArray(32) @@ -29,15 +45,27 @@ for (let v = 0; v < vectors.length; v++) { const vector = vectors[v] const expected = expecteds[v] memory.copy(changetype(actual), changetype(expected), 32) - if (!equalbytes(actual, expected, 32)) { - throw new Error(`equalbytes build error: ${vector} failed instead of passing (expected [${expected}], actual [${actual}])`) - } + xpass_equalbytes('equal bytes', expected, actual) + for (let i = 0; i < 32; i++) { for (let j = 1; j < 256; j++) { - actual[i] ^= u8(j) - if (equalbytes(actual, expected, 32)) { - throw new Error(`equalbytes build error: ${vector} passed instead of failing (expected [${expected}], actual [${actual}])`) + const p = u8(j) + const q = u8(256 - j) + + // check that any individual bit difference fails + actual[i] ^= p + xfail_equalbytes(vector, expected, actual) + + // check that |= was not replaced by ^= or += due to a typo + // only necessary to check once per vector, for all bit positions + if (i === 0) { + actual[i + 1] ^= p + xfail_equalbytes(vector, expected, actual) + actual[i + 1] ^= p ^ q + xfail_equalbytes(vector, expected, actual) + actual[i + 1] = expected[i + 1] } + actual[i] = expected[i] } }