return 0\r
}\r
\r
+// Validate signature scalar S is canonical (S < L)\r
+function canonical (S: StaticArray<u8>): boolean {\r
+ // If S >= 2^253 then S >= L for sure.\r
+ if ((S[32] & 0xE0) != 0) return false\r
+\r
+ // Check S-L for underflow (c=1) which means S < L\r
+ let c = 0\r
+ for (let i = 0; i < 32; i++) {\r
+ const diff = S[i] - L[i] - c\r
+ c = (diff >> 31) & 1\r
+ }\r
+ return c == 1\r
+}\r
+\r
const blake2b = new Blake2b()\r
function crypto_hash (o: StaticArray<u8>, i: StaticArray<u8>): void {\r
blake2b.init().update(i).digest(o)\r
q[3].fill(0)\r
\r
// fail\r
- if (unpackneg(q, k)) {\r
- return false\r
- }\r
+ if (unpackneg(q, k)) return false\r
\r
// signature is nonce point R and scalar S (R || S)\r
// data to hash is nonce point R, public key A, and message M (R || A || M)\r
sm[i + 32] = k[i]\r
sm[i + 64] = h[i]\r
}\r
+\r
+ // fail as non-canonical\r
+ const c = canonical(S)\r
+ trace(`c: ${c}`)\r
+ if (!canonical(S)) return false\r
+\r
crypto_hash(d, sm)\r
reduce(d)\r
scalarmult(p, q, d)\r
blockHash: 'BB569136FA05F8CBF65CEF2EDE368475B289C4477342976556BA4C0DDF216E45',
privateKey: '781186FB9EF17DB6E3D1056550D9FAE5D5BBADA6A6BC370E4CBB938B1DC71DA3',
publicKey: '3068BB1CA04525BB0E416C485FE6A67FD52540227D267CC8B6E8DA958A7FA039',
- signature: '74BCC59DBA39A1E34A5F75F96D6DE9154E3477AAD7DE30EA563DFCFE501A804228008F98DDF4A15FD35705102785C50EF76732C3A74B0FEC5B0DD67B574A5900'
+ signature: '74BCC59DBA39A1E34A5F75F96D6DE9154E3477AAD7DE30EA563DFCFE501A804228008F98DDF4A15FD35705102785C50EF76732C3A74B0FEC5B0DD67B574A5900',
+ badSignature: '74BCC59DBA39A1E34A5F75F96D6DE9154E3477AAD7DE30EA563DFCFE501A804215d484f5f757b4b7a9f4fcb2057fa423f76732c3a74b0fec5b0dd67b574a5910'
}
const zeroes = '0000000000000000000000000000000000000000000000000000000000000000'
const expect = []
expect.push(result)
// XFAIL
+ result = await NanoNaCl.verify(TEST_VECTORS.blockHash, TEST_VECTORS.badSignature, TEST_VECTORS.publicKey)
+ console.log(result)
+ result = result === false
+ console.log(`verify() output for non-canonical signature is ${result === true ? 'correct' : 'incorrect'}`)
+ expect.push(result)
+
result = await NanoNaCl.verify(zeroes, TEST_VECTORS.signature, TEST_VECTORS.publicKey)
console.log(result)
result = result === false