//! SPDX-License-Identifier: GPL-3.0-or-later
import { KEY_BYTELENGTH } from './constants'
+import { ge_is_canonical } from './ed25519/ge'
import { equalbytes } from './ed25519/utils'
import { raise, } from './env'
import { ERROR_SELFTEST_XFAIL_ONE, ERROR_SELFTEST_XFAIL_PAIR, ERROR_SELFTEST_XPASS, } from './errors'
spread[i] = u8(i * 37 + 11)
}
+const actual = new StaticArray<u8>(KEY_BYTELENGTH)
+
// Vector index is the error detail: 0 zeros, 1 ones, 2 spread
const expecteds = [zeros, ones, spread,]
-const actual = new StaticArray<u8>(KEY_BYTELENGTH)
-
for (let v = 0; v < expecteds.length; v++) {
const expected = expecteds[v]
memory.copy(changetype<usize>(actual), changetype<usize>(expected), KEY_BYTELENGTH)
}
}
}
+
+function xpass_ge_is_canonical (vector: i32, data: StaticArray<u8>): void {
+ if (!ge_is_canonical(data)) {
+ raise(ERROR_SELFTEST_XPASS, vector, 0)
+ }
+}
+
+function xfail_ge_is_canonical_one (vector: i32, position: i32, mask: i32, data: StaticArray<u8>): void {
+ if (ge_is_canonical(data)) {
+ raise(ERROR_SELFTEST_XFAIL_ONE, vector, (position << 8) | mask)
+ }
+}
+
+function xfail_ge_is_canonical_pair (vector: i32, i: i32, j: i32, data: StaticArray<u8>): void {
+ if (ge_is_canonical(data)) {
+ raise(ERROR_SELFTEST_XFAIL_PAIR, vector, (i << 8) | j)
+ }
+}
+
+/**
+ * ge_is_canonical must report "non-canonical" 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
+ */
+
+// Vector index is the error detail: 0 zeros, 1 ones, 2 spread
+const expected_ge_is_canonical = [zeros, ones, spread,]
+
+for (let v = 0; v < expected_ge_is_canonical.length; v++) {
+ const expected = expected_ge_is_canonical[v]
+ memory.copy(changetype<usize>(actual), changetype<usize>(expected), KEY_BYTELENGTH)
+ xpass_ge_is_canonical(v, actual)
+
+ for (let i = 0; i < KEY_BYTELENGTH; i++) {
+
+ // verify any individual bit difference fails
+ for (let j = 1; j < 256; j++) {
+ actual[i] ^= u8(j)
+ xfail_ge_is_canonical_one(v, i, j, actual)
+ actual[i] = expected[i]
+ }
+
+ // verify |= was not replaced by ^= or += due to a typo
+ // invisible to single byte checks, caught only by comparing byte pairs
+ for (let j = i + 1; j < KEY_BYTELENGTH; j++) {
+ actual[i] ^= 128
+ actual[j] ^= 128
+ xfail_ge_is_canonical_pair(v, i, j, actual)
+ actual[i] = expected[i]
+ actual[j] = expected[j]
+ }
+ }
+}