Skip to content

subset of small-order Ed25519 vectors is failing in WPTs #54572

Description

@avivkeller

I've been working on upgrading the Web Platform Tests in PR #54468, but I'm running into an issue with the WebCryptoAPI tests failing. After investigating, I found that I could reproduce the problem in Node.js. The error seems to be related to the crypto.subtle API, which isn't producing the expected results when verifying data in Ed25519.

FWIW Node.js isn't the only runtime per https://wpt.fyi/results/WebCryptoAPI/sign_verify/eddsa.https.any.html?label=experimental&label=master&aligned

The original error from running the Web Platform Tests is:

[UNEXPECTED_FAILURE][FAIL] Ed25519 Verification checks with small-order key of order - Test 0
assert_equals: Signature verification result. expected false but got true
at Test.<anonymous> (/test/fixtures/wpt/WebCryptoAPI/sign_verify/eddsa.js:235:15)
Command: /out/Release/node /test/wpt/test-webcrypto.js 'sign_verify/eddsa.https.any.js'
[UNEXPECTED_FAILURE][FAIL] Ed25519 Verification checks with small-order key of order - Test 1
assert_equals: Signature verification result. expected false but got true
at Test.<anonymous> (/test/fixtures/wpt/WebCryptoAPI/sign_verify/eddsa.js:235:15)
Command: /out/Release/node /test/wpt/test-webcrypto.js 'sign_verify/eddsa.https.any.js'
[UNEXPECTED_FAILURE][FAIL] Ed25519 Verification checks with small-order key of order - Test 2
assert_equals: Signature verification result. expected false but got true
at Test.<anonymous> (/test/fixtures/wpt/WebCryptoAPI/sign_verify/eddsa.js:235:15)
Command: /out/Release/node /test/wpt/test-webcrypto.js 'sign_verify/eddsa.https.any.js'

My minimal reproduction is:

varpubKeys=[[0xc7,0x17,0x6a,0x70,0x3d,0x4d,0xd8,0x4f,0xba,0x3c,0x0b,0x76,0x0d,0x10,0x67,0x0f,0x2a,0x20,0x53,0xfa,0x2c,0x39,0xcc,0xc6,0x4e,0xc7,0xfd,0x77,0x92,0xac,0x03,0xfa],// kSmallOrderPoints #5[0xf7,0xba,0xde,0xc5,0xb8,0xab,0xea,0xf6,0x99,0x58,0x39,0x92,0x21,0x9b,0x7b,0x22,0x3f,0x1d,0xf3,0xfb,0xbe,0xa9,0x19,0x84,0x4e,0x3f,0x7c,0x55,0x4a,0x43,0xdd,0x43],// highest 32 bytes of case "1" signature[0xec,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff],// kSmallOrderPoints #9[0xEC,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F],// kSmallOrderPoints #1]consttests=[{id: "0",// S = 0 | A's order = small | R's order = small | (1) = pass | (2) = passmessage: Uint8Array.from([0x8c,0x93,0x25,0x5d,0x71,0xdc,0xab,0x10,0xe8,0xf3,0x79,0xc2,0x62,0x00,0xf3,0xc7,0xbd,0x5f,0x09,0xd9,0xbc,0x30,0x68,0xd3,0xef,0x4e,0xde,0xb4,0x85,0x30,0x22,0xb6]),keyData: Uint8Array.from(pubKeys[0]),signature: Uint8Array.from([0xc7,0x17,0x6a,0x70,0x3d,0x4d,0xd8,0x4f,0xba,0x3c,0x0b,0x76,0x0d,0x10,0x67,0x0f,0x2a,0x20,0x53,0xfa,0x2c,0x39,0xcc,0xc6,0x4e,0xc7,0xfd,0x77,0x92,0xac,0x03,0x7a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]),verified: false,// small-order signature's R fail in the verification.},{id: "1",// 0 < S < L | A's order = small | R's order = mixed | (1) = pass | (2) = passmessage: Uint8Array.from([0x9b,0xd9,0xf4,0x4f,0x4d,0xcc,0x75,0xbd,0x53,0x1b,0x56,0xb2,0xcd,0x28,0x0b,0x0b,0xb3,0x8f,0xc1,0xcd,0x6d,0x12,0x30,0xe1,0x48,0x61,0xd8,0x61,0xde,0x09,0x2e,0x79]),keyData: Uint8Array.from(pubKeys[0]),signature: Uint8Array.from([0xf7,0xba,0xde,0xc5,0xb8,0xab,0xea,0xf6,0x99,0x58,0x39,0x92,0x21,0x9b,0x7b,0x22,0x3f,0x1d,0xf3,0xfb,0xbe,0xa9,0x19,0x84,0x4e,0x3f,0x7c,0x55,0x4a,0x43,0xdd,0x43,0xa5,0xbb,0x70,0x47,0x86,0xbe,0x79,0xfc,0x47,0x6f,0x91,0xd3,0xf3,0xf8,0x9b,0x03,0x98,0x4d,0x80,0x68,0xdc,0xf1,0xbb,0x7d,0xfc,0x66,0x37,0xb4,0x54,0x50,0xac,0x04]),verified: false,// small-order key's data fail in the verification.},{id: "2",// 0 < S < L | A's order = mixed | R's order = small | (1) = pass | (2) = passmessage: Uint8Array.from([0xae,0xbf,0x3f,0x26,0x01,0xa0,0xc8,0xc5,0xd3,0x9c,0xc7,0xd8,0x91,0x16,0x42,0xf7,0x40,0xb7,0x81,0x68,0x21,0x8d,0xa8,0x47,0x17,0x72,0xb3,0x5f,0x9d,0x35,0xb9,0xab]),keyData: Uint8Array.from(pubKeys[1]),signature: Uint8Array.from([0xc7,0x17,0x6a,0x70,0x3d,0x4d,0xd8,0x4f,0xba,0x3c,0x0b,0x76,0x0d,0x10,0x67,0x0f,0x2a,0x20,0x53,0xfa,0x2c,0x39,0xcc,0xc6,0x4e,0xc7,0xfd,0x77,0x92,0xac,0x03,0xfa,0x8c,0x4b,0xd4,0x5a,0xec,0xac,0xa5,0xb2,0x4f,0xb9,0x7b,0xc1,0x0a,0xc2,0x7a,0xc8,0x75,0x1a,0x7d,0xfe,0x1b,0xaf,0xf8,0xb9,0x53,0xec,0x9f,0x58,0x33,0xca,0x26,0x0e]),verified: false,// small-order signature's R fail in the verification.},{id: "11",// 0 < S < L | A's order = small (non-canonical) | R's order = mixed | (1) = ? | (2) = ? Implementations that reduce A before hashing will accept #10 and accept #11, and viceversamessage: Uint8Array.from([0x39,0xa5,0x91,0xf5,0x32,0x1b,0xbe,0x07,0xfd,0x5a,0x23,0xdc,0x2f,0x39,0xd0,0x25,0xd7,0x45,0x26,0x61,0x57,0x46,0x72,0x7c,0xee,0xfd,0x6e,0x82,0xae,0x65,0xc0,0x6f]),keyData: Uint8Array.from(pubKeys[2]),signature: Uint8Array.from([0xa9,0xd5,0x52,0x60,0xf7,0x65,0x26,0x1e,0xb9,0xb8,0x4e,0x10,0x6f,0x66,0x5e,0x00,0xb8,0x67,0x28,0x7a,0x76,0x19,0x90,0xd7,0x13,0x59,0x63,0xee,0x0a,0x7d,0x59,0xdc,0xa5,0xbb,0x70,0x47,0x86,0xbe,0x79,0xfc,0x47,0x6f,0x91,0xd3,0xf3,0xf8,0x9b,0x03,0x98,0x4d,0x80,0x68,0xdc,0xf1,0xbb,0x7d,0xfc,0x66,0x37,0xb4,0x54,0x50,0xac,0x04]),verified: false,// non-canonical point should fail in the verificaton (RFC8032)},// https://eprint.iacr.org/2020/1244.pdf#section.A.2// cases breaking non-repudiation{id: "12",// 0 < S < L | A's order = small | R's order = mixed | (1) = ? | (2) = ?message: Uint8Array.from([0x53,0x65,0x6e,0x64,0x20,0x31,0x30,0x30,0x20,0x55,0x53,0x44,0x20,0x74,0x6f,0x20,0x41,0x6c,0x69,0x63,0x65]),keyData: Uint8Array.from(pubKeys[3]),signature: Uint8Array.from([0xa9,0xd5,0x52,0x60,0xf7,0x65,0x26,0x1e,0xb9,0xb8,0x4e,0x10,0x6f,0x66,0x5e,0x00,0xb8,0x67,0x28,0x7a,0x76,0x19,0x90,0xd7,0x13,0x59,0x63,0xee,0x0a,0x7d,0x59,0xdc,0xa5,0xbb,0x70,0x47,0x86,0xbe,0x79,0xfc,0x47,0x6f,0x91,0xd3,0xf3,0xf8,0x9b,0x03,0x98,0x4d,0x80,0x68,0xdc,0xf1,0xbb,0x7d,0xfc,0x66,0x37,0xb4,0x54,0x50,0xac,0x04]),verified: false,},{id: "13",// 0 < S < L | A's order = small | R's order = mixed | (1) = ? | (2) = ?message: Uint8Array.from([0x53,0x65,0x6e,0x64,0x20,0x31,0x30,0x30,0x30,0x30,0x30,0x20,0x55,0x53,0x44,0x20,0x74,0x6f,0x20,0x41,0x6c,0x69,0x63,0x65]),keyData: Uint8Array.from(pubKeys[3]),signature: Uint8Array.from([0xa9,0xd5,0x52,0x60,0xf7,0x65,0x26,0x1e,0xb9,0xb8,0x4e,0x10,0x6f,0x66,0x5e,0x00,0xb8,0x67,0x28,0x7a,0x76,0x19,0x90,0xd7,0x13,0x59,0x63,0xee,0x0a,0x7d,0x59,0xdc,0xa5,0xbb,0x70,0x47,0x86,0xbe,0x79,0xfc,0x47,0x6f,0x91,0xd3,0xf3,0xf8,0x9b,0x03,0x98,0x4d,0x80,0x68,0xdc,0xf1,0xbb,0x7d,0xfc,0x66,0x37,0xb4,0x54,0x50,0xac,0x04]),verified: false,}]constalgorithm={name: "Ed25519"};for(leti=0;i<tests.length;i++){consttest=tests[i];constpublicKey=awaitcrypto.subtle.importKey("raw",test.keyData,algorithm,false,["verify"]);constisVerified=awaitcrypto.subtle.verify(algorithm,publicKey,test.signature,test.message);console.log(test.id,isVerified===test.verified);}

Modified from https://github.com/web-platform-tests/wpt/blob/master/WebCryptoAPI/sign_verify/eddsa.js. I've excluded the passing tests.

Results:

(node:73243) ExperimentalWarning: The Ed25519 Web Crypto API algorithm is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
0 false
1 false
2 false
11 false
12 false
13 false
Expand for a version with all tests, including passing ones
varpubKeys=[[0xc7,0x17,0x6a,0x70,0x3d,0x4d,0xd8,0x4f,0xba,0x3c,0x0b,0x76,0x0d,0x10,0x67,0x0f,0x2a,0x20,0x53,0xfa,0x2c,0x39,0xcc,0xc6,0x4e,0xc7,0xfd,0x77,0x92,0xac,0x03,0xfa],// kSmallOrderPoints #5[0xf7,0xba,0xde,0xc5,0xb8,0xab,0xea,0xf6,0x99,0x58,0x39,0x92,0x21,0x9b,0x7b,0x22,0x3f,0x1d,0xf3,0xfb,0xbe,0xa9,0x19,0x84,0x4e,0x3f,0x7c,0x55,0x4a,0x43,0xdd,0x43],// highest 32 bytes of case "1" signature[0xcd,0xb2,0x67,0xce,0x40,0xc5,0xcd,0x45,0x30,0x6f,0xa5,0xd2,0xf2,0x97,0x31,0x45,0x93,0x87,0xdb,0xf9,0xeb,0x93,0x3b,0x7b,0xd5,0xae,0xd9,0xa7,0x65,0xb8,0x8d,0x4d],[0x44,0x2a,0xad,0x9f,0x08,0x9a,0xd9,0xe1,0x46,0x47,0xb1,0xef,0x90,0x99,0xa1,0xff,0x47,0x98,0xd7,0x85,0x89,0xe6,0x6f,0x28,0xec,0xa6,0x9c,0x11,0xf5,0x82,0xa6,0x23],[0xec,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff],// kSmallOrderPoints #9[0xEC,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F],// kSmallOrderPoints #1]consttests=[{id: "0",// S = 0 | A's order = small | R's order = small | (1) = pass | (2) = passmessage: Uint8Array.from([0x8c,0x93,0x25,0x5d,0x71,0xdc,0xab,0x10,0xe8,0xf3,0x79,0xc2,0x62,0x00,0xf3,0xc7,0xbd,0x5f,0x09,0xd9,0xbc,0x30,0x68,0xd3,0xef,0x4e,0xde,0xb4,0x85,0x30,0x22,0xb6]),keyData: Uint8Array.from(pubKeys[0]),signature: Uint8Array.from([0xc7,0x17,0x6a,0x70,0x3d,0x4d,0xd8,0x4f,0xba,0x3c,0x0b,0x76,0x0d,0x10,0x67,0x0f,0x2a,0x20,0x53,0xfa,0x2c,0x39,0xcc,0xc6,0x4e,0xc7,0xfd,0x77,0x92,0xac,0x03,0x7a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]),verified: false,// small-order signature's R fail in the verification.},{id: "1",// 0 < S < L | A's order = small | R's order = mixed | (1) = pass | (2) = passmessage: Uint8Array.from([0x9b,0xd9,0xf4,0x4f,0x4d,0xcc,0x75,0xbd,0x53,0x1b,0x56,0xb2,0xcd,0x28,0x0b,0x0b,0xb3,0x8f,0xc1,0xcd,0x6d,0x12,0x30,0xe1,0x48,0x61,0xd8,0x61,0xde,0x09,0x2e,0x79]),keyData: Uint8Array.from(pubKeys[0]),signature: Uint8Array.from([0xf7,0xba,0xde,0xc5,0xb8,0xab,0xea,0xf6,0x99,0x58,0x39,0x92,0x21,0x9b,0x7b,0x22,0x3f,0x1d,0xf3,0xfb,0xbe,0xa9,0x19,0x84,0x4e,0x3f,0x7c,0x55,0x4a,0x43,0xdd,0x43,0xa5,0xbb,0x70,0x47,0x86,0xbe,0x79,0xfc,0x47,0x6f,0x91,0xd3,0xf3,0xf8,0x9b,0x03,0x98,0x4d,0x80,0x68,0xdc,0xf1,0xbb,0x7d,0xfc,0x66,0x37,0xb4,0x54,0x50,0xac,0x04]),verified: false,// small-order key's data fail in the verification.},{id: "2",// 0 < S < L | A's order = mixed | R's order = small | (1) = pass | (2) = passmessage: Uint8Array.from([0xae,0xbf,0x3f,0x26,0x01,0xa0,0xc8,0xc5,0xd3,0x9c,0xc7,0xd8,0x91,0x16,0x42,0xf7,0x40,0xb7,0x81,0x68,0x21,0x8d,0xa8,0x47,0x17,0x72,0xb3,0x5f,0x9d,0x35,0xb9,0xab]),keyData: Uint8Array.from(pubKeys[1]),signature: Uint8Array.from([0xc7,0x17,0x6a,0x70,0x3d,0x4d,0xd8,0x4f,0xba,0x3c,0x0b,0x76,0x0d,0x10,0x67,0x0f,0x2a,0x20,0x53,0xfa,0x2c,0x39,0xcc,0xc6,0x4e,0xc7,0xfd,0x77,0x92,0xac,0x03,0xfa,0x8c,0x4b,0xd4,0x5a,0xec,0xac,0xa5,0xb2,0x4f,0xb9,0x7b,0xc1,0x0a,0xc2,0x7a,0xc8,0x75,0x1a,0x7d,0xfe,0x1b,0xaf,0xf8,0xb9,0x53,0xec,0x9f,0x58,0x33,0xca,0x26,0x0e]),verified: false,// small-order signature's R fail in the verification.},{id: "3",// 0 < S < L | A's order = mixed | R's order = mixed | (1) = pass | (2) = passmessage: Uint8Array.from([0x9b,0xd9,0xf4,0x4f,0x4d,0xcc,0x75,0xbd,0x53,0x1b,0x56,0xb2,0xcd,0x28,0x0b,0x0b,0xb3,0x8f,0xc1,0xcd,0x6d,0x12,0x30,0xe1,0x48,0x61,0xd8,0x61,0xde,0x09,0x2e,0x79]),keyData: Uint8Array.from(pubKeys[2]),signature: Uint8Array.from([0x90,0x46,0xa6,0x47,0x50,0x44,0x49,0x38,0xde,0x19,0xf2,0x27,0xbb,0x80,0x48,0x5e,0x92,0xb8,0x3f,0xdb,0x4b,0x65,0x06,0xc1,0x60,0x48,0x4c,0x01,0x6c,0xc1,0x85,0x2f,0x87,0x90,0x9e,0x14,0x42,0x8a,0x7a,0x1d,0x62,0xe9,0xf2,0x2f,0x3d,0x3a,0xd7,0x80,0x2d,0xb0,0x2e,0xb2,0xe6,0x88,0xb6,0xc5,0x2f,0xcd,0x66,0x48,0xa9,0x8b,0xd0,0x09]),verified: true,// mixed-order points are not checked.},{id: "4",// 0 < S < L | A's order = mixed | R's order = mixed | (1) = pass | (2) = failmessage: Uint8Array.from([0xe4,0x7d,0x62,0xc6,0x3f,0x83,0x0d,0xc7,0xa6,0x85,0x1a,0x0b,0x1f,0x33,0xae,0x4b,0xb2,0xf5,0x07,0xfb,0x6c,0xff,0xec,0x40,0x11,0xea,0xcc,0xd5,0x5b,0x53,0xf5,0x6c]),keyData: Uint8Array.from(pubKeys[2]),signature: Uint8Array.from([0x16,0x0a,0x1c,0xb0,0xdc,0x9c,0x02,0x58,0xcd,0x0a,0x7d,0x23,0xe9,0x4d,0x8f,0xa8,0x78,0xbc,0xb1,0x92,0x5f,0x2c,0x64,0x24,0x6b,0x2d,0xee,0x17,0x96,0xbe,0xd5,0x12,0x5e,0xc6,0xbc,0x98,0x2a,0x26,0x9b,0x72,0x3e,0x06,0x68,0xe5,0x40,0x91,0x1a,0x9a,0x6a,0x58,0x92,0x1d,0x69,0x25,0xe4,0x34,0xab,0x10,0xaa,0x79,0x40,0x55,0x1a,0x09]),verified: false,// expect a cofactorless verification algorithm.},{id: "5",// 0 < S < L | A's order = mixed | R's order = L | (1) = pass | (2) = failmessage: Uint8Array.from([0xe4,0x7d,0x62,0xc6,0x3f,0x83,0x0d,0xc7,0xa6,0x85,0x1a,0x0b,0x1f,0x33,0xae,0x4b,0xb2,0xf5,0x07,0xfb,0x6c,0xff,0xec,0x40,0x11,0xea,0xcc,0xd5,0x5b,0x53,0xf5,0x6c]),keyData: Uint8Array.from(pubKeys[2]),signature: Uint8Array.from([0x21,0x12,0x2a,0x84,0xe0,0xb5,0xfc,0xa4,0x05,0x2f,0x5b,0x12,0x35,0xc8,0x0a,0x53,0x78,0x78,0xb3,0x8f,0x31,0x42,0x35,0x6b,0x2c,0x23,0x84,0xeb,0xad,0x46,0x68,0xb7,0xe4,0x0b,0xc8,0x36,0xda,0xc0,0xf7,0x10,0x76,0xf9,0xab,0xe3,0xa5,0x3f,0x9c,0x03,0xc1,0xce,0xee,0xdd,0xb6,0x58,0xd0,0x03,0x04,0x94,0xac,0xe5,0x86,0x68,0x74,0x05]),verified: false,// expect a cofactorless verification algorithm.},{id: "6",// S > L | A's order = L | R's order = L | (1) = pass | (2) = passmessage: Uint8Array.from([0x85,0xe2,0x41,0xa0,0x7d,0x14,0x8b,0x41,0xe4,0x7d,0x62,0xc6,0x3f,0x83,0x0d,0xc7,0xa6,0x85,0x1a,0x0b,0x1f,0x33,0xae,0x4b,0xb2,0xf5,0x07,0xfb,0x6c,0xff,0xec,0x40]),keyData: Uint8Array.from(pubKeys[3]),signature: Uint8Array.from([0xe9,0x6f,0x66,0xbe,0x97,0x6d,0x82,0xe6,0x01,0x50,0xba,0xec,0xff,0x99,0x06,0x68,0x4a,0xeb,0xb1,0xef,0x18,0x1f,0x67,0xa7,0x18,0x9a,0xc7,0x8e,0xa2,0x3b,0x6c,0x0e,0x54,0x7f,0x76,0x90,0xa0,0xe2,0xdd,0xcd,0x04,0xd8,0x7d,0xbc,0x34,0x90,0xdc,0x19,0xb3,0xb3,0x05,0x2f,0x7f,0xf0,0x53,0x8c,0xb6,0x8a,0xfb,0x36,0x9b,0xa3,0xa5,0x14]),verified: false,// S out of bounds},{id: "7",// S >> L | A's order = L | R's order = L | (1) = pass | (2) = passmessage: Uint8Array.from([0x85,0xe2,0x41,0xa0,0x7d,0x14,0x8b,0x41,0xe4,0x7d,0x62,0xc6,0x3f,0x83,0x0d,0xc7,0xa6,0x85,0x1a,0x0b,0x1f,0x33,0xae,0x4b,0xb2,0xf5,0x07,0xfb,0x6c,0xff,0xec,0x40]),keyData: Uint8Array.from(pubKeys[3]),signature: Uint8Array.from([0x8c,0xe5,0xb9,0x6c,0x8f,0x26,0xd0,0xab,0x6c,0x47,0x95,0x8c,0x9e,0x68,0xb9,0x37,0x10,0x4c,0xd3,0x6e,0x13,0xc3,0x35,0x66,0xac,0xd2,0xfe,0x8d,0x38,0xaa,0x19,0x42,0x7e,0x71,0xf9,0x8a,0x47,0x34,0xe7,0x4f,0x2f,0x13,0xf0,0x6f,0x97,0xc2,0x0d,0x58,0xcc,0x3f,0x54,0xb8,0xbd,0x0d,0x27,0x2f,0x42,0xb6,0x95,0xdd,0x7e,0x89,0xa8,0xc2,0x02]),verified: false,// S out of bounds},{id: "8",// 0 < S < L | A's order = mixed | R's order = small (non-canonical) | (1) = ? | (2) = ? Implementations that reduce A before hashing will accept #8 and accept #9, and viceversamessage: Uint8Array.from([0x9b,0xed,0xc2,0x67,0x42,0x37,0x25,0xd4,0x73,0x88,0x86,0x31,0xeb,0xf4,0x59,0x88,0xba,0xd3,0xdb,0x83,0x85,0x1e,0xe8,0x5c,0x85,0xe2,0x41,0xa0,0x7d,0x14,0x8b,0x41]),keyData: Uint8Array.from(pubKeys[1]),signature: Uint8Array.from([0xec,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0xbe,0x96,0x78,0xac,0x10,0x2e,0xdc,0xd9,0x2b,0x02,0x10,0xbb,0x34,0xd7,0x42,0x8d,0x12,0xff,0xc5,0xdf,0x5f,0x37,0xe3,0x59,0x94,0x12,0x66,0xa4,0xe3,0x5f,0x0f]),verified: false,// non-canonical point should fail in the verificaton (RFC8032)},{id: "9",// 0 < S < L | A's order = mixed | R's order = small (non-canonical) | (1) = ? | (2) = ?message: Uint8Array.from([0x9b,0xed,0xc2,0x67,0x42,0x37,0x25,0xd4,0x73,0x88,0x86,0x31,0xeb,0xf4,0x59,0x88,0xba,0xd3,0xdb,0x83,0x85,0x1e,0xe8,0x5c,0x85,0xe2,0x41,0xa0,0x7d,0x14,0x8b,0x41]),keyData: Uint8Array.from(pubKeys[1]),signature: Uint8Array.from([0xec,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xca,0x8c,0x5b,0x64,0xcd,0x20,0x89,0x82,0xaa,0x38,0xd4,0x93,0x66,0x21,0xa4,0x77,0x5a,0xa2,0x33,0xaa,0x05,0x05,0x71,0x1d,0x8f,0xdc,0xfd,0xaa,0x94,0x3d,0x49,0x08]),verified: false,// non-canonical point should fail in the verificaton (RFC8032)},{id: "10",// 0 < S < L | A's order = small (non-canonical) | R's order = mixed | (1) = ? | (2) = ? Implementations that reduce A before hashing will accept #10 and accept #11, and viceversamessage: Uint8Array.from([0xe9,0x6b,0x70,0x21,0xeb,0x39,0xc1,0xa1,0x63,0xb6,0xda,0x4e,0x30,0x93,0xdc,0xd3,0xf2,0x13,0x87,0xda,0x4c,0xc4,0x57,0x2b,0xe5,0x88,0xfa,0xfa,0xe2,0x3c,0x15,0x5b]),keyData: Uint8Array.from(pubKeys[4]),signature: Uint8Array.from([0xa9,0xd5,0x52,0x60,0xf7,0x65,0x26,0x1e,0xb9,0xb8,0x4e,0x10,0x6f,0x66,0x5e,0x00,0xb8,0x67,0x28,0x7a,0x76,0x19,0x90,0xd7,0x13,0x59,0x63,0xee,0x0a,0x7d,0x59,0xdc,0xa5,0xbb,0x70,0x47,0x86,0xbe,0x79,0xfc,0x47,0x6f,0x91,0xd3,0xf3,0xf8,0x9b,0x03,0x98,0x4d,0x80,0x68,0xdc,0xf1,0xbb,0x7d,0xfc,0x66,0x37,0xb4,0x54,0x50,0xac,0x04]),verified: false,// non-canonical point should fail in the verificaton (RFC8032)},{id: "11",// 0 < S < L | A's order = small (non-canonical) | R's order = mixed | (1) = ? | (2) = ? Implementations that reduce A before hashing will accept #10 and accept #11, and viceversamessage: Uint8Array.from([0x39,0xa5,0x91,0xf5,0x32,0x1b,0xbe,0x07,0xfd,0x5a,0x23,0xdc,0x2f,0x39,0xd0,0x25,0xd7,0x45,0x26,0x61,0x57,0x46,0x72,0x7c,0xee,0xfd,0x6e,0x82,0xae,0x65,0xc0,0x6f]),keyData: Uint8Array.from(pubKeys[4]),signature: Uint8Array.from([0xa9,0xd5,0x52,0x60,0xf7,0x65,0x26,0x1e,0xb9,0xb8,0x4e,0x10,0x6f,0x66,0x5e,0x00,0xb8,0x67,0x28,0x7a,0x76,0x19,0x90,0xd7,0x13,0x59,0x63,0xee,0x0a,0x7d,0x59,0xdc,0xa5,0xbb,0x70,0x47,0x86,0xbe,0x79,0xfc,0x47,0x6f,0x91,0xd3,0xf3,0xf8,0x9b,0x03,0x98,0x4d,0x80,0x68,0xdc,0xf1,0xbb,0x7d,0xfc,0x66,0x37,0xb4,0x54,0x50,0xac,0x04]),verified: false,// non-canonical point should fail in the verificaton (RFC8032)},// https://eprint.iacr.org/2020/1244.pdf#section.A.2// cases breaking non-repudiation{id: "12",// 0 < S < L | A's order = small | R's order = mixed | (1) = ? | (2) = ?message: Uint8Array.from([0x53,0x65,0x6e,0x64,0x20,0x31,0x30,0x30,0x20,0x55,0x53,0x44,0x20,0x74,0x6f,0x20,0x41,0x6c,0x69,0x63,0x65]),keyData: Uint8Array.from(pubKeys[5]),signature: Uint8Array.from([0xa9,0xd5,0x52,0x60,0xf7,0x65,0x26,0x1e,0xb9,0xb8,0x4e,0x10,0x6f,0x66,0x5e,0x00,0xb8,0x67,0x28,0x7a,0x76,0x19,0x90,0xd7,0x13,0x59,0x63,0xee,0x0a,0x7d,0x59,0xdc,0xa5,0xbb,0x70,0x47,0x86,0xbe,0x79,0xfc,0x47,0x6f,0x91,0xd3,0xf3,0xf8,0x9b,0x03,0x98,0x4d,0x80,0x68,0xdc,0xf1,0xbb,0x7d,0xfc,0x66,0x37,0xb4,0x54,0x50,0xac,0x04]),verified: false,},{id: "13",// 0 < S < L | A's order = small | R's order = mixed | (1) = ? | (2) = ?message: Uint8Array.from([0x53,0x65,0x6e,0x64,0x20,0x31,0x30,0x30,0x30,0x30,0x30,0x20,0x55,0x53,0x44,0x20,0x74,0x6f,0x20,0x41,0x6c,0x69,0x63,0x65]),keyData: Uint8Array.from(pubKeys[5]),signature: Uint8Array.from([0xa9,0xd5,0x52,0x60,0xf7,0x65,0x26,0x1e,0xb9,0xb8,0x4e,0x10,0x6f,0x66,0x5e,0x00,0xb8,0x67,0x28,0x7a,0x76,0x19,0x90,0xd7,0x13,0x59,0x63,0xee,0x0a,0x7d,0x59,0xdc,0xa5,0xbb,0x70,0x47,0x86,0xbe,0x79,0xfc,0x47,0x6f,0x91,0xd3,0xf3,0xf8,0x9b,0x03,0x98,0x4d,0x80,0x68,0xdc,0xf1,0xbb,0x7d,0xfc,0x66,0x37,0xb4,0x54,0x50,0xac,0x04]),verified: false,}]constalgorithm={name: "Ed25519"};for(leti=0;i<tests.length;i++){consttest=tests[i];constpublicKey=awaitcrypto.subtle.importKey("raw",test.keyData,algorithm,false,["verify"]);constisVerified=awaitcrypto.subtle.verify(algorithm,publicKey,test.signature,test.message);console.log(test.id,isVerified===test.verified);}
(node:77667) ExperimentalWarning: The Ed25519 Web Crypto API algorithm is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
0 false
1 false
2 false
3 true
4 true
5 true
6 true
7 true
8 true
9 true
10 true
11 false
12 false
13 false

CC @nodejs/crypto

Metadata

Metadata

Assignees

No one assigned

    Labels

    cryptoIssues and PRs related to the crypto subsystem.web-standardsIssues and PRs related to Web APIswebcrypto

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions