xref: /aosp_15_r20/external/tink/go/hybrid/subtle/elliptic_curves_test.go (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1// Copyright 2020 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15////////////////////////////////////////////////////////////////////////////////
16
17package subtle_test
18
19import (
20	"bytes"
21	"crypto/ecdsa"
22	"crypto/elliptic"
23	"crypto/x509"
24	"encoding/hex"
25	"errors"
26	"fmt"
27	"math/big"
28	"strings"
29	"testing"
30
31	"github.com/google/tink/go/hybrid/subtle"
32	"github.com/google/tink/go/testutil"
33)
34
35// The tests are from
36// http://google.github.io/end-to-end/api/source/src/javascript/crypto/e2e/ecc/ecdh_testdata.js.src.html.
37type testEC1 struct {
38	elliptic.Curve
39	pubX, pubY string
40}
41
42type testEC2 struct {
43	elliptic.Curve
44	pointFormat string
45	encoded     string
46	X, Y        string
47}
48
49var (
50	tEC1 = []testEC1{
51		{
52			elliptic.P256(),
53			"700c48f77f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287",
54			"db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac",
55		},
56		{
57			elliptic.P256(),
58			"809f04289c64348c01515eb03d5ce7ac1a8cb9498f5caa50197e58d43a86a7ae",
59			"b29d84e811197f25eba8f5194092cb6ff440e26d4421011372461f579271cda3",
60		},
61		{
62			elliptic.P256(),
63			"df3989b9fa55495719b3cf46dccd28b5153f7808191dd518eff0c3cff2b705ed",
64			"422294ff46003429d739a33206c8752552c8ba54a270defc06e221e0feaf6ac4",
65		},
66		{
67			elliptic.P256(),
68			"356c5a444c049a52fee0adeb7e5d82ae5aa83030bfff31bbf8ce2096cf161c4b",
69			"57d128de8b2a57a094d1a001e572173f96e8866ae352bf29cddaf92fc85b2f92",
70		},
71		{
72			elliptic.P384(),
73			"a7c76b970c3b5fe8b05d2838ae04ab47697b9eaf52e764592efda27fe7513272" +
74				"734466b400091adbf2d68c58e0c50066",
75			"ac68f19f2e1cb879aed43a9969b91a0839c4c38a49749b661efedf243451915e" +
76				"d0905a32b060992b468c64766fc8437a",
77		},
78		{
79			elliptic.P384(),
80			"30f43fcf2b6b00de53f624f1543090681839717d53c7c955d1d69efaf0349b736" +
81				"3acb447240101cbb3af6641ce4b88e0",
82			"25e46c0c54f0162a77efcc27b6ea792002ae2ba82714299c860857a68153ab62e" +
83				"525ec0530d81b5aa15897981e858757",
84		},
85		{
86			elliptic.P521(),
87			"000000685a48e86c79f0f0875f7bc18d25eb5fc8c0b07e5da4f4370f3a9490340" +
88				"854334b1e1b87fa395464c60626124a4e70d0f785601d37c09870ebf176666877a2" +
89				"046d",
90			"000001ba52c56fc8776d9e8f5db4f0cc27636d0b741bbe05400697942e80b7398" +
91				"84a83bde99e0f6716939e632bc8986fa18dccd443a348b6c3e522497955a4f3c302" +
92				"f676",
93		},
94		{
95			elliptic.P521(),
96			"000001df277c152108349bc34d539ee0cf06b24f5d3500677b4445453ccc21409" +
97				"453aafb8a72a0be9ebe54d12270aa51b3ab7f316aa5e74a951c5e53f74cd95fc29a" +
98				"ee7a",
99			"0000013d52f33a9f3c14384d1587fa8abe7aed74bc33749ad9c570b471776422c" +
100				"7d4505d9b0a96b3bfac041e4c6a6990ae7f700e5b4a6640229112deafa0cd8bb0d0" +
101				"89b0",
102		},
103		{
104			elliptic.P521(),
105			"00000092db3142564d27a5f0006f819908fba1b85038a5bc2509906a497daac67" +
106				"fd7aee0fc2daba4e4334eeaef0e0019204b471cd88024f82115d8149cc0cf4f7ce1" +
107				"a4d5",
108			"0000016bad0623f517b158d9881841d2571efbad63f85cbe2e581960c5d670601" +
109				"a6760272675a548996217e4ab2b8ebce31d71fca63fcc3c08e91c1d8edd91cf6fe8" +
110				"45f8",
111		},
112		{
113			elliptic.P521(),
114			"0000004f38816681771289ce0cb83a5e29a1ab06fc91f786994b23708ff08a08a" +
115				"0f675b809ae99e9f9967eb1a49f196057d69e50d6dedb4dd2d9a81c02bdcc8f7f51" +
116				"8460",
117			"0000009efb244c8b91087de1eed766500f0e81530752d469256ef79f6b965d8a2" +
118				"232a0c2dbc4e8e1d09214bab38485be6e357c4200d073b52f04e4a16fc6f5247187" +
119				"aecb",
120		},
121		{
122			elliptic.P521(),
123			"000001a32099b02c0bd85371f60b0dd20890e6c7af048c8179890fda308b359db" +
124				"bc2b7a832bb8c6526c4af99a7ea3f0b3cb96ae1eb7684132795c478ad6f962e4a6f" +
125				"446d",
126			"0000017627357b39e9d7632a1370b3e93c1afb5c851b910eb4ead0c9d387df67c" +
127				"de85003e0e427552f1cd09059aad0262e235cce5fba8cedc4fdc1463da76dcd4b6d" +
128				"1a46",
129		},
130	}
131	tEC2 = []testEC2{
132		// NIST_P256
133		{
134			elliptic.P256(),
135			"UNCOMPRESSED",
136			"04" +
137				"b0cfc7bc02fc980d858077552947ffb449b10df8949dee4e56fe21e016dcb25a" +
138				"1886ccdca5487a6772f9401888203f90587cc00a730e2b83d5c6f89b3b568df7",
139			"79974177209371530366349631093481213364328002500948308276357601809416549347930",
140			"11093679777528052772423074391650378811758820120351664471899251711300542565879",
141		},
142		{
143			elliptic.P256(),
144			"DO_NOT_USE_CRUNCHY_UNCOMPRESSED",
145			"b0cfc7bc02fc980d858077552947ffb449b10df8949dee4e56fe21e016dcb25a" +
146				"1886ccdca5487a6772f9401888203f90587cc00a730e2b83d5c6f89b3b568df7",
147			"79974177209371530366349631093481213364328002500948308276357601809416549347930",
148			"11093679777528052772423074391650378811758820120351664471899251711300542565879",
149		},
150		{
151			elliptic.P256(),
152			"COMPRESSED",
153			"03b0cfc7bc02fc980d858077552947ffb449b10df8949dee4e56fe21e016dcb25a",
154			"79974177209371530366349631093481213364328002500948308276357601809416549347930",
155			"11093679777528052772423074391650378811758820120351664471899251711300542565879",
156		},
157		// Exceptional point: x==0
158		{
159			elliptic.P256(),
160			"UNCOMPRESSED",
161			"04" +
162				"0000000000000000000000000000000000000000000000000000000000000000" +
163				"66485c780e2f83d72433bd5d84a06bb6541c2af31dae871728bf856a174f93f4",
164			"0",
165			"46263761741508638697010950048709651021688891777877937875096931459006746039284",
166		},
167		{
168			elliptic.P256(),
169			"DO_NOT_USE_CRUNCHY_UNCOMPRESSED",
170			"0000000000000000000000000000000000000000000000000000000000000000" +
171				"66485c780e2f83d72433bd5d84a06bb6541c2af31dae871728bf856a174f93f4",
172			"0",
173			"46263761741508638697010950048709651021688891777877937875096931459006746039284",
174		},
175		{
176			elliptic.P256(),
177			"COMPRESSED",
178			"020000000000000000000000000000000000000000000000000000000000000000",
179			"0",
180			"46263761741508638697010950048709651021688891777877937875096931459006746039284",
181		},
182		// Exceptional point: x==-3
183		{
184			elliptic.P256(),
185			"UNCOMPRESSED",
186			"04" +
187				"ffffffff00000001000000000000000000000000fffffffffffffffffffffffc" +
188				"19719bebf6aea13f25c96dfd7c71f5225d4c8fc09eb5a0ab9f39e9178e55c121",
189			"115792089210356248762697446949407573530086143415290314195533631308867097853948",
190			"11508551065151498768481026661199445482476508121209842448718573150489103679777",
191		},
192		{
193			elliptic.P256(),
194			"DO_NOT_USE_CRUNCHY_UNCOMPRESSED",
195			"ffffffff00000001000000000000000000000000fffffffffffffffffffffffc" +
196				"19719bebf6aea13f25c96dfd7c71f5225d4c8fc09eb5a0ab9f39e9178e55c121",
197			"115792089210356248762697446949407573530086143415290314195533631308867097853948",
198			"11508551065151498768481026661199445482476508121209842448718573150489103679777",
199		},
200		{
201			elliptic.P256(),
202			"COMPRESSED",
203			"03ffffffff00000001000000000000000000000000fffffffffffffffffffffffc",
204			"115792089210356248762697446949407573530086143415290314195533631308867097853948",
205			"11508551065151498768481026661199445482476508121209842448718573150489103679777",
206		},
207		// NIST_P384
208		{
209			elliptic.P384(),
210			"UNCOMPRESSED",
211			"04aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a" +
212				"385502f25dbf55296c3a545e3872760ab73617de4a96262c6f5d9e98bf9292dc" +
213				"29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e" +
214				"5f",
215			"2624703509579968926862315674456698189185292349110921338781561590" +
216				"0925518854738050089022388053975719786650872476732087",
217			"8325710961489029985546751289520108179287853048861315594709205902" +
218				"480503199884419224438643760392947333078086511627871",
219		},
220		{
221			elliptic.P384(),
222			"COMPRESSED",
223			"03aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a" +
224				"385502f25dbf55296c3a545e3872760ab7",
225			"2624703509579968926862315674456698189185292349110921338781561590" +
226				"0925518854738050089022388053975719786650872476732087",
227			"8325710961489029985546751289520108179287853048861315594709205902" +
228				"480503199884419224438643760392947333078086511627871",
229		},
230		// x = 0
231		{
232			elliptic.P384(),
233			"UNCOMPRESSED",
234			"0400000000000000000000000000000000000000000000000000000000000000" +
235				"00000000000000000000000000000000003cf99ef04f51a5ea630ba3f9f960dd" +
236				"593a14c9be39fd2bd215d3b4b08aaaf86bbf927f2c46e52ab06fb742b8850e52" +
237				"1e",
238			"0",
239			"9384923975005507693384933751151973636103286582194273515051780595" +
240				"652610803541482195894618304099771370981414591681054",
241		},
242		{
243			elliptic.P384(),
244			"COMPRESSED",
245			"0200000000000000000000000000000000000000000000000000000000000000" +
246				"0000000000000000000000000000000000",
247			"0",
248			"9384923975005507693384933751151973636103286582194273515051780595" +
249				"652610803541482195894618304099771370981414591681054",
250		},
251		// x = 2
252		{
253			elliptic.P384(),
254			"UNCOMPRESSED",
255			"0400000000000000000000000000000000000000000000000000000000000000" +
256				"0000000000000000000000000000000002732152442fb6ee5c3e6ce1d920c059" +
257				"bc623563814d79042b903ce60f1d4487fccd450a86da03f3e6ed525d02017bfd" +
258				"b3",
259			"2",
260			"1772015366480916228638409476801818679957736647795608728422858375" +
261				"4887974043472116432532980617621641492831213601947059",
262		},
263		{
264			elliptic.P384(),
265			"COMPRESSED",
266			"0300000000000000000000000000000000000000000000000000000000000000" +
267				"0000000000000000000000000000000002",
268			"2",
269			"1772015366480916228638409476801818679957736647795608728422858375" +
270				"4887974043472116432532980617621641492831213601947059",
271		},
272		// x = -3
273		{
274			elliptic.P384(),
275			"UNCOMPRESSED",
276			"04ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" +
277				"feffffffff0000000000000000fffffffc2de9de09a95b74e6b2c430363e1afb" +
278				"8dff7164987a8cfe0a0d5139250ac02f797f81092a9bdc0e09b574a8f43bf80c" +
279				"17",
280			"3940200619639447921227904010014361380507973927046544666794829340" +
281				"4245721771496870329047266088258938001861606973112316",
282			"7066741234775658874139271223692271325950306561732202191471600407" +
283				"582071247913794644254895122656050391930754095909911",
284		},
285		{
286			elliptic.P384(),
287			"COMPRESSED",
288			"03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" +
289				"feffffffff0000000000000000fffffffc",
290			"3940200619639447921227904010014361380507973927046544666794829340" +
291				"4245721771496870329047266088258938001861606973112316",
292			"7066741234775658874139271223692271325950306561732202191471600407" +
293				"582071247913794644254895122656050391930754095909911",
294		},
295		// NIST_P521
296		{
297			elliptic.P521(),
298			"UNCOMPRESSED",
299			"0400c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b" +
300				"4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2" +
301				"e5bd66011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd" +
302				"17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94" +
303				"769fd16650",
304			"2661740802050217063228768716723360960729859168756973147706671368" +
305				"4188029449964278084915450806277719023520942412250655586621571135" +
306				"45570916814161637315895999846",
307			"3757180025770020463545507224491183603594455134769762486694567779" +
308				"6155444774405563166912344050129455395621444445372894285225856667" +
309				"29196580810124344277578376784",
310		},
311		{
312			elliptic.P521(),
313			"COMPRESSED",
314			"0200c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b" +
315				"4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2" +
316				"e5bd66",
317			"2661740802050217063228768716723360960729859168756973147706671368" +
318				"4188029449964278084915450806277719023520942412250655586621571135" +
319				"45570916814161637315895999846",
320			"3757180025770020463545507224491183603594455134769762486694567779" +
321				"6155444774405563166912344050129455395621444445372894285225856667" +
322				"29196580810124344277578376784",
323		},
324		// x = 0
325		{
326			elliptic.P521(),
327			"UNCOMPRESSED",
328			"0400000000000000000000000000000000000000000000000000000000000000" +
329				"0000000000000000000000000000000000000000000000000000000000000000" +
330				"00000000d20ec9fea6b577c10d26ca1bb446f40b299e648b1ad508aad068896f" +
331				"ee3f8e614bc63054d5772bf01a65d412e0bcaa8e965d2f5d332d7f39f846d440" +
332				"ae001f4f87",
333			"0",
334			"2816414230262626695230339754503506208598534788872316917808418392" +
335				"0894686826982898181454171638541149642517061885689521392260532032" +
336				"30035588176689756661142736775",
337		},
338		{
339			elliptic.P521(),
340			"COMPRESSED",
341			"0300000000000000000000000000000000000000000000000000000000000000" +
342				"0000000000000000000000000000000000000000000000000000000000000000" +
343				"000000",
344			"0",
345			"2816414230262626695230339754503506208598534788872316917808418392" +
346				"0894686826982898181454171638541149642517061885689521392260532032" +
347				"30035588176689756661142736775",
348		},
349		// x = 1
350		{
351			elliptic.P521(),
352			"UNCOMPRESSED",
353			"0400000000000000000000000000000000000000000000000000000000000000" +
354				"0000000000000000000000000000000000000000000000000000000000000000" +
355				"0000010010e59be93c4f269c0269c79e2afd65d6aeaa9b701eacc194fb3ee03d" +
356				"f47849bf550ec636ebee0ddd4a16f1cd9406605af38f584567770e3f272d688c" +
357				"832e843564",
358			"1",
359			"2265505274322546447629271557184988697103589068170534253193208655" +
360				"0778100463909972583865730916407864371153050622267306901033104806" +
361				"9570407113457901669103973732",
362		},
363		{
364			elliptic.P521(),
365			"COMPRESSED",
366			"0200000000000000000000000000000000000000000000000000000000000000" +
367				"0000000000000000000000000000000000000000000000000000000000000000" +
368				"000001",
369			"1",
370			"2265505274322546447629271557184988697103589068170534253193208655" +
371				"0778100463909972583865730916407864371153050622267306901033104806" +
372				"9570407113457901669103973732",
373		},
374		// x = 2
375		{
376			elliptic.P521(),
377			"UNCOMPRESSED",
378			"0400000000000000000000000000000000000000000000000000000000000000" +
379				"0000000000000000000000000000000000000000000000000000000000000000" +
380				"00000200d9254fdf800496acb33790b103c5ee9fac12832fe546c632225b0f7f" +
381				"ce3da4574b1a879b623d722fa8fc34d5fc2a8731aad691a9a8bb8b554c95a051" +
382				"d6aa505acf",
383			"2",
384			"2911448509017565583245824537994174021964465504209366849707937264" +
385				"0417919148200722009442607963590225526059407040161685364728526719" +
386				"10134103604091376779754756815",
387		},
388		{
389			elliptic.P521(),
390			"COMPRESSED",
391			"0300000000000000000000000000000000000000000000000000000000000000" +
392				"0000000000000000000000000000000000000000000000000000000000000000" +
393				"000002",
394			"2",
395			"2911448509017565583245824537994174021964465504209366849707937264" +
396				"0417919148200722009442607963590225526059407040161685364728526719" +
397				"10134103604091376779754756815",
398		},
399		// x = -2
400		{
401			elliptic.P521(),
402			"UNCOMPRESSED",
403			"0401ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" +
404				"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" +
405				"fffffd0010e59be93c4f269c0269c79e2afd65d6aeaa9b701eacc194fb3ee03d" +
406				"f47849bf550ec636ebee0ddd4a16f1cd9406605af38f584567770e3f272d688c" +
407				"832e843564",
408			"6864797660130609714981900799081393217269435300143305409394463459" +
409				"1855431833976560521225596406614545549772963113914808580371219879" +
410				"99716643812574028291115057149",
411			"2265505274322546447629271557184988697103589068170534253193208655" +
412				"0778100463909972583865730916407864371153050622267306901033104806" +
413				"9570407113457901669103973732",
414		},
415		{
416			elliptic.P521(),
417			"COMPRESSED",
418			"0201ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" +
419				"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" +
420				"fffffd",
421			"6864797660130609714981900799081393217269435300143305409394463459" +
422				"1855431833976560521225596406614545549772963113914808580371219879" +
423				"99716643812574028291115057149",
424			"2265505274322546447629271557184988697103589068170534253193208655" +
425				"0778100463909972583865730916407864371153050622267306901033104806" +
426				"9570407113457901669103973732",
427		},
428	}
429)
430
431func TestPointOnCurve(t *testing.T) {
432	for i := 0; i < len(tEC1); i++ {
433		x, y, ye := new(big.Int), new(big.Int), new(big.Int)
434		x.SetString(tEC1[i].pubX, 16)
435		y.SetString(tEC1[i].pubY, 16)
436		ye.Sub(y, big.NewInt(1))
437		if !tEC1[i].Curve.IsOnCurve(x, y) {
438			t.Fatalf("valid points not on curve for test case :%d", i)
439		}
440		if tEC1[i].Curve.IsOnCurve(x, ye) {
441			t.Fatalf("invalid points is on curve for test case :%d", i)
442		}
443	}
444
445}
446
447func TestPointEncode(t *testing.T) {
448	for i := 0; i < len(tEC2); i++ {
449		x, y := new(big.Int), new(big.Int)
450		x.SetString(tEC2[i].X, 10)
451		y.SetString(tEC2[i].Y, 10)
452		p := subtle.ECPoint{
453			X: x,
454			Y: y,
455		}
456		encodedpoint, err := subtle.PointEncode(tEC2[i].Curve, tEC2[i].pointFormat, p)
457		if err != nil {
458			t.Errorf("error in point encoding in test case %d : %v", i, err)
459		}
460		want, err := hex.DecodeString(tEC2[i].encoded)
461		if err != nil {
462			t.Errorf("error reading encoded point in test case %d", i)
463		}
464		if !bytes.Equal(encodedpoint, want) {
465			t.Errorf("mismatch point encoding in test case %d", i)
466		}
467	}
468}
469
470func TestPointDecode(t *testing.T) {
471	for i := 0; i < len(tEC2); i++ {
472		x, y := new(big.Int), new(big.Int)
473		x.SetString(tEC2[i].X, 10)
474		y.SetString(tEC2[i].Y, 10)
475		e, err := hex.DecodeString(tEC2[i].encoded)
476		if err != nil {
477			t.Errorf("error reading encoded point in test case %d", i)
478		}
479		pt, err := subtle.PointDecode(tEC2[i].Curve, tEC2[i].pointFormat, e)
480		if err != nil {
481			t.Errorf("error in point decoding in test case %d: %v", i, err)
482		}
483		spt := subtle.ECPoint{
484			X: x,
485			Y: y,
486		}
487
488		if pt.X.Cmp(spt.X) != 0 || pt.Y.Cmp(spt.Y) != 0 {
489			t.Errorf("mismatch point decoding in test case %d", i)
490		}
491	}
492}
493
494func checkFlag(t *testing.T, flags []string, check []string) bool {
495	t.Helper()
496	for _, f := range flags {
497		for _, c := range check {
498			if strings.Compare(f, c) == 0 {
499				return true
500			}
501		}
502	}
503	return false
504}
505
506// convertX509PublicKey converts an encoded public key to an ECPublicKey.
507func convertX509PublicKey(t *testing.T, b []byte) (*subtle.ECPublicKey, error) {
508	t.Helper()
509	pkey, err := x509.ParsePKIXPublicKey(b)
510	if err != nil {
511		return nil, err
512	}
513	ecdsaP, ok := pkey.(*ecdsa.PublicKey)
514	if !ok {
515		return nil, errors.New("invalid elliptic curve key")
516	}
517	return &subtle.ECPublicKey{
518		Curve: ecdsaP.Curve,
519		Point: subtle.ECPoint{
520			X: ecdsaP.X,
521			Y: ecdsaP.Y,
522		},
523	}, nil
524}
525
526// convertPointPublicKey converts an EC point public key to an ECPublicKey.
527func convertPointPublicKey(t *testing.T, pk []byte, curve elliptic.Curve, flags []string) (*subtle.ECPublicKey, error) {
528	ptFormat := "UNCOMPRESSED"
529	if checkFlag(t, flags, []string{"CompressedPoint"}) {
530		ptFormat = "COMPRESSED"
531	}
532	pt, err := subtle.PointDecode(curve, ptFormat, pk)
533	if err != nil {
534		return nil, err
535	}
536	return &subtle.ECPublicKey{
537		Curve: curve,
538		Point: *pt,
539	}, nil
540}
541
542func TestECWycheproofCases(t *testing.T) {
543	testutil.SkipTestIfTestSrcDirIsNotSet(t)
544
545	vectors := []string{
546		"ecdh_test.json",
547		"ecdh_secp224r1_ecpoint_test.json",
548		"ecdh_secp256r1_ecpoint_test.json",
549		"ecdh_secp384r1_ecpoint_test.json",
550		"ecdh_secp521r1_ecpoint_test.json",
551	}
552	for _, v := range vectors {
553		suite := new(ecdhSuite)
554		if err := testutil.PopulateSuite(suite, v); err != nil {
555			t.Fatalf("failed populating suite: %s", err)
556		}
557		for _, group := range suite.TestGroups {
558			curve, err := subtle.GetCurve(group.Curve)
559			if err != nil {
560				t.Logf("unsupported curve: %s", group.Curve)
561				continue
562			}
563			for _, test := range group.Tests {
564				caseName := fmt.Sprintf("%s-%s:Case-%d", suite.Algorithm, group.Type, test.CaseID)
565				t.Run(caseName, func(t *testing.T) {
566					pvtKey := subtle.GetECPrivateKey(curve, test.Private)
567
568					var pubKey *subtle.ECPublicKey
569					var errPub error
570					switch suite.Schema {
571					case "ecdh_test_schema.json":
572						pubKey, errPub = convertX509PublicKey(t, test.Public)
573					case "ecdh_ecpoint_test_schema.json":
574						pubKey, errPub = convertPointPublicKey(t, test.Public, curve, test.Flags)
575					default:
576						t.Logf("Unsupported schema: %q", suite.Schema)
577						return
578					}
579
580					switch test.Result {
581					case "valid":
582						if errPub != nil {
583							t.Fatalf("failed decoding public key: %s", errPub)
584						}
585
586						shared, err := subtle.ComputeSharedSecret(&pubKey.Point, pvtKey)
587						if err != nil {
588							t.Errorf("subtle.ComputeSharedSecret() failed: %s", err)
589						}
590						if !bytes.Equal(shared, test.Shared) {
591							t.Error("valid test case, incorrect shared secret")
592						}
593
594					case "invalid":
595						if errPub != nil {
596							// Public key not decoded. OK for invalid test case.
597							return
598						}
599
600						shared, err := subtle.ComputeSharedSecret(&pubKey.Point, pvtKey)
601						if err != nil {
602							// Shared secret was not computed. OK for invalid test case.
603							return
604						}
605						validReason := checkFlag(t, test.Flags, []string{"WrongOrder", "WeakPublicKey", "UnnamedCurve"})
606						if validReason && bytes.Equal(shared, test.Shared) {
607							t.Log("accepted invalid parameters but shared secret is correct")
608							return
609						}
610						t.Error("accepted invalid parameters")
611
612					case "acceptable":
613						if errPub != nil {
614							// Public key not decoded. OK for acceptable test case.
615							return
616						}
617
618						shared, err := subtle.ComputeSharedSecret(&pubKey.Point, pvtKey)
619						if err != nil {
620							// Shared secret was not computed. OK for acceptable test case.
621							return
622						}
623						if !bytes.Equal(shared, test.Shared) {
624							t.Error("acceptable test case, incorrect shared secret")
625						}
626
627					default:
628						t.Errorf("unsupported test result: %q", test.Result)
629					}
630				})
631			}
632		}
633	}
634}
635