blob: 561dc6377d2dd5126a139916bb0f237013150aa8 [file] [log] [blame]
/**
* @license
* Copyright 2020 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import {assertExists} from '../testing/internal/test_utils';
import * as Bytes from './bytes';
import * as EllipticCurves from './elliptic_curves';
import * as Random from './random';
import {WYCHEPROOF_ECDH_TEST_VECTORS} from './wycheproof_ecdh_test_vectors';
describe('elliptic curves test', function() {
beforeEach(function() {
// Use a generous promise timeout for running continuously.
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000 * 1000; // 1000s
});
afterEach(function() {
// Reset the promise timeout to default value.
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000; // 1s
});
it('compute ecdh shared secret', async function() {
const aliceKeyPair = await EllipticCurves.generateKeyPair('ECDH', 'P-256');
const bobKeyPair = await EllipticCurves.generateKeyPair('ECDH', 'P-256');
const sharedSecret1 = await EllipticCurves.computeEcdhSharedSecret(
aliceKeyPair.privateKey!, bobKeyPair.publicKey!);
const sharedSecret2 = await EllipticCurves.computeEcdhSharedSecret(
bobKeyPair.privateKey!, aliceKeyPair.publicKey!);
expect(Bytes.toHex(sharedSecret2)).toBe(Bytes.toHex(sharedSecret1));
});
it('wycheproof, wycheproof webcrypto', async function() {
for (const testGroup of WYCHEPROOF_ECDH_TEST_VECTORS['testGroups']) {
let errors = '';
for (const test of testGroup['tests']) {
errors += await runWycheproofTest(test);
}
if (errors !== '') {
fail(errors);
}
}
});
// Test that both ECDH public and private key are defined in the result.
it('generate key pair e c d h', async function() {
const curveTypes = [
EllipticCurves.CurveType.P256, EllipticCurves.CurveType.P384,
EllipticCurves.CurveType.P521
];
for (const curve of curveTypes) {
const curveTypeString = EllipticCurves.curveToString(curve);
const keyPair =
await EllipticCurves.generateKeyPair('ECDH', curveTypeString);
expect(keyPair.privateKey! != null).toBe(true);
expect(keyPair.publicKey! != null).toBe(true);
}
});
// Test that both ECDSA public and private key are defined in the result.
it('generate key pair e c d s a', async function() {
const curveTypes = [
EllipticCurves.CurveType.P256, EllipticCurves.CurveType.P384,
EllipticCurves.CurveType.P521
];
for (const curve of curveTypes) {
const curveTypeString = EllipticCurves.curveToString(curve);
const keyPair =
await EllipticCurves.generateKeyPair('ECDSA', curveTypeString);
expect(keyPair.privateKey! != null).toBe(true);
expect(keyPair.publicKey! != null).toBe(true);
}
});
// Test that when ECDH crypto key is exported and imported it gives the same
// key as the original one.
it('import export crypto key e c d h', async function() {
const curveTypes = [
EllipticCurves.CurveType.P256, EllipticCurves.CurveType.P384,
EllipticCurves.CurveType.P521
];
for (const curve of curveTypes) {
const curveTypeString = EllipticCurves.curveToString(curve);
const keyPair =
await EllipticCurves.generateKeyPair('ECDH', curveTypeString);
const publicKey = keyPair.publicKey!;
const publicCryptoKey = await EllipticCurves.exportCryptoKey(publicKey);
const importedPublicKey =
await EllipticCurves.importPublicKey('ECDH', publicCryptoKey);
expect(importedPublicKey).toEqual(publicKey);
const privateKey = keyPair.privateKey!;
const privateCryptoKey = await EllipticCurves.exportCryptoKey(privateKey);
const importedPrivateKey =
await EllipticCurves.importPrivateKey('ECDH', privateCryptoKey);
expect(importedPrivateKey).toEqual(privateKey);
}
});
// Test that when ECDSA crypto key is exported and imported it gives the same
// key as the original one.
it('import export crypto key e c d s a', async function() {
const curveTypes = [
EllipticCurves.CurveType.P256, EllipticCurves.CurveType.P384,
EllipticCurves.CurveType.P521
];
for (const curve of curveTypes) {
const curveTypeString = EllipticCurves.curveToString(curve);
const keyPair =
await EllipticCurves.generateKeyPair('ECDSA', curveTypeString);
const publicKey = keyPair.publicKey!;
const publicCryptoKey = await EllipticCurves.exportCryptoKey(publicKey);
const importedPublicKey =
await EllipticCurves.importPublicKey('ECDSA', publicCryptoKey);
expect(importedPublicKey).toEqual(publicKey);
const privateKey = keyPair.privateKey!;
const privateCryptoKey = await EllipticCurves.exportCryptoKey(privateKey);
const importedPrivateKey =
await EllipticCurves.importPrivateKey('ECDSA', privateCryptoKey);
expect(importedPrivateKey).toEqual(privateKey);
}
});
// Test that when JSON ECDH web key is imported and exported it gives the same
// key as the original one.
it('import export json key e c d h', async function() {
for (const testKey of TEST_KEYS) {
const jwk: JsonWebKey = ({
'kty': 'EC',
'crv': testKey.curve,
'x': Bytes.toBase64(Bytes.fromHex(testKey.x), true),
'y': Bytes.toBase64(Bytes.fromHex(testKey.y), true),
'ext': true,
});
let importedKey;
if (!testKey.d) {
jwk['key_ops'] = [];
importedKey = await EllipticCurves.importPublicKey('ECDH', jwk);
} else {
jwk['key_ops'] = ['deriveKey', 'deriveBits'];
jwk['d'] = Bytes.toBase64(Bytes.fromHex(testKey.d), true);
importedKey = await EllipticCurves.importPrivateKey('ECDH', jwk);
}
const exportedKey = await EllipticCurves.exportCryptoKey(importedKey);
expect(exportedKey).toEqual(jwk);
}
});
// Test that when JSON ECDSA web key is imported and exported it gives the
// same key as the original one.
it('import export json key e c d s a', async function() {
for (const testKey of TEST_KEYS) {
const jwk: JsonWebKey = ({
'kty': 'EC',
'crv': testKey.curve,
'x': Bytes.toBase64(Bytes.fromHex(testKey.x), true),
'y': Bytes.toBase64(Bytes.fromHex(testKey.y), true),
'ext': true,
});
let importedKey;
if (!testKey.d) {
jwk['key_ops'] = ['verify'];
importedKey = await EllipticCurves.importPublicKey('ECDSA', jwk);
} else {
jwk['key_ops'] = ['sign'];
jwk['d'] = Bytes.toBase64(Bytes.fromHex(testKey.d), true);
importedKey = await EllipticCurves.importPrivateKey('ECDSA', jwk);
}
const exportedKey = await EllipticCurves.exportCryptoKey(importedKey);
expect(exportedKey).toEqual(jwk);
}
});
it('curve to string', function() {
expect(EllipticCurves.curveToString(EllipticCurves.CurveType.P256))
.toBe('P-256');
expect(EllipticCurves.curveToString(EllipticCurves.CurveType.P384))
.toBe('P-384');
expect(EllipticCurves.curveToString(EllipticCurves.CurveType.P521))
.toBe('P-521');
});
it('curve from string', function() {
expect(EllipticCurves.curveFromString('P-256'))
.toBe(EllipticCurves.CurveType.P256);
expect(EllipticCurves.curveFromString('P-384'))
.toBe(EllipticCurves.CurveType.P384);
expect(EllipticCurves.curveFromString('P-521'))
.toBe(EllipticCurves.CurveType.P521);
});
it('field size in bytes', function() {
expect(EllipticCurves.fieldSizeInBytes(EllipticCurves.CurveType.P256))
.toBe(256 / 8);
expect(EllipticCurves.fieldSizeInBytes(EllipticCurves.CurveType.P384))
.toBe(384 / 8);
expect(EllipticCurves.fieldSizeInBytes(EllipticCurves.CurveType.P521))
.toBe((521 + 7) / 8);
});
it('encoding size in bytes, uncompressed point format type', function() {
expect(EllipticCurves.encodingSizeInBytes(
EllipticCurves.CurveType.P256,
EllipticCurves.PointFormatType.UNCOMPRESSED))
.toBe(2 * (256 / 8) + 1);
expect(EllipticCurves.encodingSizeInBytes(
EllipticCurves.CurveType.P384,
EllipticCurves.PointFormatType.UNCOMPRESSED))
.toBe(2 * (384 / 8) + 1);
expect(EllipticCurves.encodingSizeInBytes(
EllipticCurves.CurveType.P521,
EllipticCurves.PointFormatType.UNCOMPRESSED))
.toBe(2 * ((521 + 7) / 8) + 1);
});
it('encoding size in bytes, compressed point format type', function() {
expect(EllipticCurves.encodingSizeInBytes(
EllipticCurves.CurveType.P256,
EllipticCurves.PointFormatType.COMPRESSED))
.toBe((256 / 8) + 1);
expect(EllipticCurves.encodingSizeInBytes(
EllipticCurves.CurveType.P384,
EllipticCurves.PointFormatType.COMPRESSED))
.toBe((384 / 8) + 1);
expect(EllipticCurves.encodingSizeInBytes(
EllipticCurves.CurveType.P521,
EllipticCurves.PointFormatType.COMPRESSED))
.toBe(((521 + 7) / 8) + 1);
});
it('encoding size in bytes, crunchy uncompressed point format type',
function() {
expect(
EllipticCurves.encodingSizeInBytes(
EllipticCurves.CurveType.P256,
EllipticCurves.PointFormatType.DO_NOT_USE_CRUNCHY_UNCOMPRESSED))
.toBe(2 * (256 / 8));
expect(
EllipticCurves.encodingSizeInBytes(
EllipticCurves.CurveType.P384,
EllipticCurves.PointFormatType.DO_NOT_USE_CRUNCHY_UNCOMPRESSED))
.toBe(2 * (384 / 8));
expect(
EllipticCurves.encodingSizeInBytes(
EllipticCurves.CurveType.P521,
EllipticCurves.PointFormatType.DO_NOT_USE_CRUNCHY_UNCOMPRESSED))
.toBe(2 * ((521 + 7) / 8));
});
it('point decode, wrong point size', function() {
const point = new Uint8Array(10);
const format = EllipticCurves.PointFormatType.UNCOMPRESSED;
for (const curve
of [EllipticCurves.CurveType.P256, EllipticCurves.CurveType.P384,
EllipticCurves.CurveType.P521]) {
const curveTypeString = EllipticCurves.curveToString(curve);
// It should throw an exception as the point array is too short.
try {
EllipticCurves.pointDecode(curveTypeString, format, point);
fail('Should throw an exception.');
// Preserving old behavior when moving to
// https://www.typescriptlang.org/tsconfig#useUnknownInCatchVariables
// tslint:disable-next-line:no-any
} catch (e: any) {
expect(e.toString()).toBe('InvalidArgumentsException: invalid point');
}
}
});
it('point decode, unknown curve', function() {
const point = new Uint8Array(10);
const format = EllipticCurves.PointFormatType.UNCOMPRESSED;
const curve = 'some-unknown-curve';
try {
EllipticCurves.pointDecode(curve, format, point);
fail('Should throw an exception.');
// Preserving old behavior when moving to
// https://www.typescriptlang.org/tsconfig#useUnknownInCatchVariables
// tslint:disable-next-line:no-any
} catch (e: any) {
expect(e.toString().includes('unknown curve')).toBe(true);
}
});
it('point encode, compressed', () => {
for (const test of TEST_VECTORS) {
const format = EllipticCurves.formatFromString(test.format);
if (format !== EllipticCurves.PointFormatType.COMPRESSED) {
// TODO(b/214598739): Investigate compatibility of other formats with
// Java test vectors.
continue;
}
const point: JsonWebKey = {
kty: 'EC',
crv: test.curve,
x: Bytes.toBase64(
EllipticCurves.integerToByteArray(BigInt('0x' + test.x)),
/* websafe = */ true),
y: Bytes.toBase64(
EllipticCurves.integerToByteArray(BigInt('0x' + test.y)),
/* websafe = */ true),
ext: true,
};
const encodedPoint =
EllipticCurves.pointEncode(assertExists(point.crv), format, point);
expect(Bytes.toHex(encodedPoint)).toEqual(test.encoded);
}
});
it('point decode, compressed', () => {
for (const test of TEST_VECTORS) {
const format = EllipticCurves.formatFromString(test.format);
if (format !== EllipticCurves.PointFormatType.COMPRESSED) {
// TODO(b/214598739): Investigate compatibility of other formats with
// Java test vectors.
continue;
}
const decodedPoint = EllipticCurves.pointDecode(
test.curve, format, Bytes.fromHex(test.encoded));
// NOTE: Any leading zero inserted by Bytes.toHex() must be removed.
const decodedX =
Bytes.toHex(Bytes.fromBase64(assertExists(decodedPoint.x), true))
.replace(/^0?/, '');
const decodedY =
Bytes.toHex(Bytes.fromBase64(assertExists(decodedPoint.y), true))
.replace(/^0?/, '');
expect(decodedX).toEqual(test.x);
expect(decodedY).toEqual(test.y);
}
});
it('point encode decode', () => {
for (const test of TEST_VECTORS) {
const format = EllipticCurves.formatFromString(test.format);
if (format !== EllipticCurves.PointFormatType.COMPRESSED) {
// TODO(b/214598739): Investigate compatibility of other formats with
// Java test vectors.
continue;
}
const point: JsonWebKey = {
kty: 'EC',
crv: test.curve,
x: Bytes.toBase64(
EllipticCurves.integerToByteArray(BigInt('0x' + test.x)),
/* websafe = */ true),
y: Bytes.toBase64(
EllipticCurves.integerToByteArray(BigInt('0x' + test.y)),
/* websafe = */ true),
ext: true,
};
const encodedPoint =
EllipticCurves.pointEncode(assertExists(point.crv), format, point);
const decodedPoint = EllipticCurves.pointDecode(
assertExists(point.crv), format, encodedPoint);
expect(decodedPoint).toEqual(point);
}
});
it('point encode decode, random points', () => {
for (const format of
[EllipticCurves.PointFormatType.UNCOMPRESSED,
EllipticCurves.PointFormatType.DO_NOT_USE_CRUNCHY_UNCOMPRESSED]) {
for (const curveType
of [EllipticCurves.CurveType.P256, EllipticCurves.CurveType.P384,
EllipticCurves.CurveType.P521]) {
const curveTypeString = EllipticCurves.curveToString(curveType);
const x = Random.randBytes(EllipticCurves.fieldSizeInBytes(curveType));
const y = Random.randBytes(EllipticCurves.fieldSizeInBytes(curveType));
const point: JsonWebKey = {
kty: 'EC',
crv: curveTypeString,
x: Bytes.toBase64(x, /* websafe = */ true),
y: Bytes.toBase64(y, /* websafe = */ true),
ext: true,
};
const encodedPoint =
EllipticCurves.pointEncode(assertExists(point.crv), format, point);
const decodedPoint =
EllipticCurves.pointDecode(curveTypeString, format, encodedPoint);
expect(decodedPoint).toEqual(point);
}
}
});
it('ecdsa der2 ieee', function() {
for (const test of ECDSA_IEEE_DER_TEST_VECTORS) {
expect(EllipticCurves.ecdsaDer2Ieee(test.der, test.ieee.length))
.toEqual(test.ieee);
}
});
it('ecdsa der2 ieee with invalid signatures', function() {
for (const test of INVALID_DER_ECDSA_SIGNATURES) {
try {
EllipticCurves.ecdsaDer2Ieee(
Bytes.fromHex(test), 1 /* ieeeLength, ignored */);
// Preserving old behavior when moving to
// https://www.typescriptlang.org/tsconfig#useUnknownInCatchVariables
// tslint:disable-next-line:no-any
} catch (e: any) {
expect(e.toString())
.toBe('InvalidArgumentsException: invalid DER signature');
}
}
});
it('ecdsa ieee2 der', function() {
for (const test of ECDSA_IEEE_DER_TEST_VECTORS) {
expect(EllipticCurves.ecdsaIeee2Der(test.ieee)).toEqual(test.der);
}
});
it('is valid der ecdsa signature', function() {
for (const test of INVALID_DER_ECDSA_SIGNATURES) {
expect(EllipticCurves.isValidDerEcdsaSignature(Bytes.fromHex(test)))
.toBe(false);
}
});
});
/**
* Runs the test with test vector given as an input and returns either empty
* string or a text describing the failure.
*/
async function runWycheproofTest(test: {
'tcId': number,
'public': JsonWebKey,
'private': JsonWebKey,
'shared': string,
'result': string,
}): Promise<string> {
try {
const privateKey =
await EllipticCurves.importPrivateKey('ECDH', test['private']);
try {
const publicKey =
await EllipticCurves.importPublicKey('ECDH', test['public']);
const sharedSecret =
await EllipticCurves.computeEcdhSharedSecret(privateKey, publicKey);
if (test['result'] === 'invalid') {
return 'Fail on test ' + test['tcId'] + ': No exception thrown.\n';
}
const sharedSecretHex = Bytes.toHex(sharedSecret);
if (sharedSecretHex !== test['shared']) {
return 'Fail on test ' + test['tcId'] + ': unexpected result was "' +
sharedSecretHex + '".\n';
}
// Preserving old behavior when moving to
// https://www.typescriptlang.org/tsconfig#useUnknownInCatchVariables
// tslint:disable-next-line:no-any
} catch (e: any) {
if (test['result'] === 'valid') {
return 'Fail on test ' + test['tcId'] + ': unexpected exception "' +
e.toString() + '".\n';
}
}
// Preserving old behavior when moving to
// https://www.typescriptlang.org/tsconfig#useUnknownInCatchVariables
// tslint:disable-next-line:no-any
} catch (e: any) {
if (test['result'] === 'valid') {
if (test['private']['crv'] == "P-256K") {
// P-256K doesn't have to be supported. Hence failing to import the
// key is OK.
return '';
}
return 'Fail on test ' + test['tcId'] +
': unexpected exception trying to import private key "' +
e.toString() + '".\n';
}
}
// If the test passes return an empty string.
return '';
}
class TestKey {
constructor(
readonly curve: string, readonly x: string, readonly y: string,
readonly d?: string) {}
}
// This set of keys was generated by Java version of Tink.
// It contains one private and one public key for each curve type supported by
// Tink.
const TEST_KEYS: TestKey[] = [
new TestKey(
/* curve = */ 'P-256',
/* x = */
'2eab800e5d8e9b15d0f87c55324b477ffc9382d7137599e0203113a4e41b50d0',
/* y = */
'50bb2c11cfb72f3c380c2f93ea088d6938b91bcf581cd94a73ed0a3f623a6b8b'),
new TestKey(
/* curve = */ 'P-256',
/* x = */
'844c085cc4450297b681126356e10da074dea817f69bc2b1f3d6b1fc82593c7d',
/* y = */
'3cdb41fc89867d2066cc9c4f9ad7e890152bad24de20621abfe608234cbe40f1',
/* opt_d = */
'f96796cc28b36038817cc5d7db01c52ee0411dd848dc0833e9e26e989e4a64db'),
new TestKey(
/* curve = */ 'P-384',
/* x = */
'f3290cc80faa65e8821b0bf835f51e3431a4d78dcebd81b74c53b9b704bd995df93b648d51057a9a96a654fb8332391e',
/* y = */
'7e52bb9f654781a6894ef5ae77869207fa32ddbcec4a02d27ba1ead5472b3b9f39b09e9bca7d936809c143e99c655401'),
new TestKey(
/* curve = */ 'P-384',
/* x = */
'be9df79abedb82fc0e527630955f63f2f74b4984f0a4ac063a089565393ed20ac7a784f4efa434f5b1fa1837c76c8472',
/* y = */
'cf34ad0d4f3f2cbd546780509ec7073bb26fa0547d09ed10b83bf9b90903037ac956dbd661d02ce3e397e0547356b331',
/* opt_d = */
'34d86595280a8bdca23ccd60eeac9581016e895c2bc867c26dc2f99f6d0f627ce586ad36d1d2981968d8852dc9276d12'),
new TestKey(
/* curve = */ 'P-521',
/* x = */
'012f2211ec7e634919857be3066becf20c438b84ff24501712c91c98f527b44c7b001f8611935cb1179541c2b3cc3a1fc9259d50cd4842a847ea0cafe22cd75fe788',
/* y = */
'016b5d3f5480122643a26ef9e7c7e36875f53c28167d6afc35777d32ea76127d34287325bf14779f2e4cf3864fcc951ba601cec92b03291e34db2e815d4bd6fc2045'),
new TestKey(
/* curve = */ 'P-521',
/* x = */
'01ee3aabecef323cb4581e044be21914b567c426eae18d71720a71a0b236f5324ef9666fe855f5d7986d3e33a9250396f63c780572b3ad9417d69c2a87773ce39194',
/* y = */
'0036bea90db019304719d269e5335f9790e730e241a1b02cfdab8bdcfd0bcff8bdcb3ddeb9c3a94ecff1ab6abb80b0c1655f871c6089d3a4bf8625cf6bd182897f1b',
/* opt_d = */
'00b9f9f5d91cbfa9b7f92b041b137ac9822ca4a38f71ce227f624cac6178ca8351fab24bc2cc3f85d7ab72f54a0f9d1bb11a888a79a9c7b1ca267ddc82043585e437')
];
class EcdsaIeeeDerTestVector {
ieee: Uint8Array;
der: Uint8Array;
constructor(ieee: string, der: string) {
this.ieee = Bytes.fromHex(ieee);
this.der = Bytes.fromHex(der);
}
}
const ECDSA_IEEE_DER_TEST_VECTORS: EcdsaIeeeDerTestVector[] = [
new EcdsaIeeeDerTestVector( // normal case, short-form length
'0102030405060708090a0b0c0d0e0f100102030405060708090a0b0c0d0e0f10',
'302402100102030405060708090a0b0c0d0e0f1002100102030405060708090a0b0c0d0e0f10'),
new EcdsaIeeeDerTestVector( // normal case, long-form length
'010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000203010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000203',
'30818802420100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000002030242010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000203'),
new EcdsaIeeeDerTestVector( // zero prefix.
'0002030405060708090a0b0c0d0e0f100002030405060708090a0b0c0d0e0f10',
'3022020f02030405060708090a0b0c0d0e0f10020f02030405060708090a0b0c0d0e0f10'),
new EcdsaIeeeDerTestVector( // highest bit is set.
'00ff030405060708090a0b0c0d0e0f1000ff030405060708090a0b0c0d0e0f10',
'3024021000ff030405060708090a0b0c0d0e0f10021000ff030405060708090a0b0c0d0e0f10'),
new EcdsaIeeeDerTestVector( // highest bit is set, full length.
'ff02030405060708090a0b0c0d0e0f10ff02030405060708090a0b0c0d0e0f10',
'3026021100ff02030405060708090a0b0c0d0e0f10021100ff02030405060708090a0b0c0d0e0f10'),
new EcdsaIeeeDerTestVector( // all zeros.
'0000000000000000000000000000000000000000000000000000000000000000',
'3006020100020100'),
];
const INVALID_DER_ECDSA_SIGNATURES: string[] = [
'2006020101020101', // 1st byte is not 0x30 (SEQUENCE tag)
'3006050101020101', // 3rd byte is not 0x02 (INTEGER tag)
'3006020101050101', // 6th byte is not 0x02 (INTEGER tag)
'308206020101020101', // long form length is not 0x81
'30ff020101020101', // invalid total length
'3006020201020101', // invalid rLength
'3006020101020201', // invalid sLength
'30060201ff020101', // no extra zero when highest bit of r is set
'30060201010201ff', // no extra zero when highest bit of s is set
];
// Following test vectors copied from 'testVectors2' variable in
// /src/test/java/com/google/crypto/tink/subtle/EllipticCurvesTest.java.
class TestVector {
constructor(
readonly curve: string, readonly format: string, readonly x: string,
readonly y: string, readonly encoded: string) {}
}
const TEST_VECTORS:
TestVector[] =
[
new TestVector(
/* curve = */ 'P-256',
/* format = */ 'UNCOMPRESSED',
/* x = */
'b0cfc7bc02fc980d858077552947ffb449b10df8949dee4e56fe21e016dcb25a',
/* y = */
'1886ccdca5487a6772f9401888203f90587cc00a730e2b83d5c6f89b3b568df7',
/* encoded = */
'04b0cfc7bc02fc980d858077552947ffb449b10df8949dee4e56fe21e016dcb25a1886ccdca5487a6772f9401888203f90587cc00a730e2b83d5c6f89b3b568df7',
),
new TestVector(
/* curve = */ 'P-256',
/* format = */ 'DO_NOT_USE_CRUNCHY_UNCOMPRESSED',
/* x = */
'b0cfc7bc02fc980d858077552947ffb449b10df8949dee4e56fe21e016dcb25a',
/* y = */
'1886ccdca5487a6772f9401888203f90587cc00a730e2b83d5c6f89b3b568df7',
/* encoded = */
'b0cfc7bc02fc980d858077552947ffb449b10df8949dee4e56fe21e016dcb25a1886ccdca5487a6772f9401888203f90587cc00a730e2b83d5c6f89b3b568df7',
),
new TestVector(
/* curve = */ 'P-256',
/* format = */ 'COMPRESSED',
/* x = */
'b0cfc7bc02fc980d858077552947ffb449b10df8949dee4e56fe21e016dcb25a',
/* y = */
'1886ccdca5487a6772f9401888203f90587cc00a730e2b83d5c6f89b3b568df7',
/* encoded = */
'03b0cfc7bc02fc980d858077552947ffb449b10df8949dee4e56fe21e016dcb25a',
),
new TestVector(
/* curve = */ 'P-256',
/* format = */ 'UNCOMPRESSED',
/* x = */ '0',
/* y = */
'66485c780e2f83d72433bd5d84a06bb6541c2af31dae871728bf856a174f93f4',
/* encoded = */
'04000000000000000000000000000000000000000000000000000000000000000066485c780e2f83d72433bd5d84a06bb6541c2af31dae871728bf856a174f93f4',
),
new TestVector(
/* curve = */ 'P-256',
/* format = */ 'DO_NOT_USE_CRUNCHY_UNCOMPRESSED',
/* x = */ '0',
/* y = */
'66485c780e2f83d72433bd5d84a06bb6541c2af31dae871728bf856a174f93f4',
/* encoded = */
'000000000000000000000000000000000000000000000000000000000000000066485c780e2f83d72433bd5d84a06bb6541c2af31dae871728bf856a174f93f4',
),
new TestVector(
/* curve = */ 'P-256',
/* format = */ 'COMPRESSED',
/* x = */ '0',
/* y = */
'66485c780e2f83d72433bd5d84a06bb6541c2af31dae871728bf856a174f93f4',
/* encoded = */
'020000000000000000000000000000000000000000000000000000000000000000',
),
new TestVector(
/* curve = */ 'P-256',
/* format = */ 'UNCOMPRESSED',
/* x = */
'ffffffff00000001000000000000000000000000fffffffffffffffffffffffc',
/* y = */
'19719bebf6aea13f25c96dfd7c71f5225d4c8fc09eb5a0ab9f39e9178e55c121',
/* encoded = */
'04ffffffff00000001000000000000000000000000fffffffffffffffffffffffc19719bebf6aea13f25c96dfd7c71f5225d4c8fc09eb5a0ab9f39e9178e55c121',
),
new TestVector(
/* curve = */ 'P-256',
/* format = */ 'DO_NOT_USE_CRUNCHY_UNCOMPRESSED',
/* x = */
'ffffffff00000001000000000000000000000000fffffffffffffffffffffffc',
/* y = */
'19719bebf6aea13f25c96dfd7c71f5225d4c8fc09eb5a0ab9f39e9178e55c121',
/* encoded = */
'ffffffff00000001000000000000000000000000fffffffffffffffffffffffc19719bebf6aea13f25c96dfd7c71f5225d4c8fc09eb5a0ab9f39e9178e55c121',
),
new TestVector(
/* curve = */ 'P-256',
/* format = */ 'COMPRESSED',
/* x = */
'ffffffff00000001000000000000000000000000fffffffffffffffffffffffc',
/* y = */
'19719bebf6aea13f25c96dfd7c71f5225d4c8fc09eb5a0ab9f39e9178e55c121',
/* encoded = */
'03ffffffff00000001000000000000000000000000fffffffffffffffffffffffc',
),
new TestVector(
/* curve = */ 'P-384',
/* format = */ 'UNCOMPRESSED',
/* x = */
'aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7',
/* y = */
'3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f',
/* encoded = */
'04aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab73617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f',
),
new TestVector(
/* curve = */ 'P-384',
/* format = */ 'COMPRESSED',
/* x = */
'aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7',
/* y = */
'3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f',
/* encoded = */
'03aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7',
),
new TestVector(
/* curve = */ 'P-384',
/* format = */ 'UNCOMPRESSED',
/* x = */ '0',
/* y = */
'3cf99ef04f51a5ea630ba3f9f960dd593a14c9be39fd2bd215d3b4b08aaaf86bbf927f2c46e52ab06fb742b8850e521e',
/* encoded = */
'040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003cf99ef04f51a5ea630ba3f9f960dd593a14c9be39fd2bd215d3b4b08aaaf86bbf927f2c46e52ab06fb742b8850e521e',
),
new TestVector(
/* curve = */ 'P-384',
/* format = */ 'COMPRESSED',
/* x = */ '0',
/* y = */
'3cf99ef04f51a5ea630ba3f9f960dd593a14c9be39fd2bd215d3b4b08aaaf86bbf927f2c46e52ab06fb742b8850e521e',
/* encoded = */
'02000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
),
new TestVector(
/* curve = */ 'P-384',
/* format = */ 'UNCOMPRESSED',
/* x = */ '2',
/* y = */
'732152442fb6ee5c3e6ce1d920c059bc623563814d79042b903ce60f1d4487fccd450a86da03f3e6ed525d02017bfdb3',
/* encoded = */
'04000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002732152442fb6ee5c3e6ce1d920c059bc623563814d79042b903ce60f1d4487fccd450a86da03f3e6ed525d02017bfdb3',
),
new TestVector(
/* curve = */ 'P-384',
/* format = */ 'COMPRESSED',
/* x = */ '2',
/* y = */
'732152442fb6ee5c3e6ce1d920c059bc623563814d79042b903ce60f1d4487fccd450a86da03f3e6ed525d02017bfdb3',
/* encoded = */
'03000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002',
),
new TestVector(
/* curve = */ 'P-384',
/* format = */ 'UNCOMPRESSED',
/* x = */
'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc',
/* y = */
'2de9de09a95b74e6b2c430363e1afb8dff7164987a8cfe0a0d5139250ac02f797f81092a9bdc0e09b574a8f43bf80c17',
/* encoded = */
'04fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc2de9de09a95b74e6b2c430363e1afb8dff7164987a8cfe0a0d5139250ac02f797f81092a9bdc0e09b574a8f43bf80c17',
),
new TestVector(
/* curve = */ 'P-384',
/* format = */ 'COMPRESSED',
/* x = */
'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc',
/* y = */
'2de9de09a95b74e6b2c430363e1afb8dff7164987a8cfe0a0d5139250ac02f797f81092a9bdc0e09b574a8f43bf80c17',
/* encoded = */
'03fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc',
),
new TestVector(
/* curve = */ 'P-521',
/* format = */ 'UNCOMPRESSED',
/* x = */
'c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66',
/* y = */
'11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650',
/* encoded = */
'0400c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650',
),
new TestVector(
/* curve = */ 'P-521',
/* format = */ 'COMPRESSED',
/* x = */
'c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66',
/* y = */
'11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650',
/* encoded = */
'0200c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66',
),
new TestVector(
/* curve = */ 'P-521',
/* format = */ 'UNCOMPRESSED',
/* x = */ '0',
/* y = */
'd20ec9fea6b577c10d26ca1bb446f40b299e648b1ad508aad068896fee3f8e614bc63054d5772bf01a65d412e0bcaa8e965d2f5d332d7f39f846d440ae001f4f87',
/* encoded = */
'0400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d20ec9fea6b577c10d26ca1bb446f40b299e648b1ad508aad068896fee3f8e614bc63054d5772bf01a65d412e0bcaa8e965d2f5d332d7f39f846d440ae001f4f87',
),
new TestVector(
/* curve = */ 'P-521',
/* format = */ 'COMPRESSED',
/* x = */ '0',
/* y = */
'd20ec9fea6b577c10d26ca1bb446f40b299e648b1ad508aad068896fee3f8e614bc63054d5772bf01a65d412e0bcaa8e965d2f5d332d7f39f846d440ae001f4f87',
/* encoded = */
'03000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
),
new TestVector(
/* curve = */ 'P-521',
/* format = */ 'UNCOMPRESSED',
/* x = */ '1',
/* y = */
'10e59be93c4f269c0269c79e2afd65d6aeaa9b701eacc194fb3ee03df47849bf550ec636ebee0ddd4a16f1cd9406605af38f584567770e3f272d688c832e843564',
/* encoded = */
'040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010010e59be93c4f269c0269c79e2afd65d6aeaa9b701eacc194fb3ee03df47849bf550ec636ebee0ddd4a16f1cd9406605af38f584567770e3f272d688c832e843564',
),
new TestVector(
/* curve = */ 'P-521',
/* format = */ 'COMPRESSED',
/* x = */ '1',
/* y = */
'10e59be93c4f269c0269c79e2afd65d6aeaa9b701eacc194fb3ee03df47849bf550ec636ebee0ddd4a16f1cd9406605af38f584567770e3f272d688c832e843564',
/* encoded = */
'02000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001',
),
new TestVector(
/* curve = */ 'P-521',
/* format = */ 'UNCOMPRESSED',
/* x = */ '2',
/* y = */
'd9254fdf800496acb33790b103c5ee9fac12832fe546c632225b0f7fce3da4574b1a879b623d722fa8fc34d5fc2a8731aad691a9a8bb8b554c95a051d6aa505acf',
/* encoded = */
'0400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200d9254fdf800496acb33790b103c5ee9fac12832fe546c632225b0f7fce3da4574b1a879b623d722fa8fc34d5fc2a8731aad691a9a8bb8b554c95a051d6aa505acf',
),
new TestVector(
/* curve = */ 'P-521',
/* format = */ 'COMPRESSED',
/* x = */ '2',
/* y = */
'd9254fdf800496acb33790b103c5ee9fac12832fe546c632225b0f7fce3da4574b1a879b623d722fa8fc34d5fc2a8731aad691a9a8bb8b554c95a051d6aa505acf',
/* encoded = */
'03000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002',
),
new TestVector(
/* curve = */ 'P-521',
/* format = */ 'UNCOMPRESSED',
/* x = */
'1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd',
/* y = */
'10e59be93c4f269c0269c79e2afd65d6aeaa9b701eacc194fb3ee03df47849bf550ec636ebee0ddd4a16f1cd9406605af38f584567770e3f272d688c832e843564',
/* encoded = */
'0401fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd0010e59be93c4f269c0269c79e2afd65d6aeaa9b701eacc194fb3ee03df47849bf550ec636ebee0ddd4a16f1cd9406605af38f584567770e3f272d688c832e843564',
),
new TestVector(
/* curve = */ 'P-521',
/* format = */ 'COMPRESSED',
/* x = */
'1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd',
/* y = */
'10e59be93c4f269c0269c79e2afd65d6aeaa9b701eacc194fb3ee03df47849bf550ec636ebee0ddd4a16f1cd9406605af38f584567770e3f272d688c832e843564',
/* encoded = */
'0201fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd',
)
];