xref: /aosp_15_r20/external/tink/go/subtle/x25519_test.go (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1*e7b1675dSTing-Kang Chang// Copyright 2021 Google LLC
2*e7b1675dSTing-Kang Chang//
3*e7b1675dSTing-Kang Chang// Licensed under the Apache License, Version 2.0 (the "License");
4*e7b1675dSTing-Kang Chang// you may not use this file except in compliance with the License.
5*e7b1675dSTing-Kang Chang// You may obtain a copy of the License at
6*e7b1675dSTing-Kang Chang//
7*e7b1675dSTing-Kang Chang//      http://www.apache.org/licenses/LICENSE-2.0
8*e7b1675dSTing-Kang Chang//
9*e7b1675dSTing-Kang Chang// Unless required by applicable law or agreed to in writing, software
10*e7b1675dSTing-Kang Chang// distributed under the License is distributed on an "AS IS" BASIS,
11*e7b1675dSTing-Kang Chang// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*e7b1675dSTing-Kang Chang// See the License for the specific language governing permissions and
13*e7b1675dSTing-Kang Chang// limitations under the License.
14*e7b1675dSTing-Kang Chang//
15*e7b1675dSTing-Kang Chang////////////////////////////////////////////////////////////////////////////////
16*e7b1675dSTing-Kang Chang
17*e7b1675dSTing-Kang Changpackage subtle_test
18*e7b1675dSTing-Kang Chang
19*e7b1675dSTing-Kang Changimport (
20*e7b1675dSTing-Kang Chang	"crypto/rand"
21*e7b1675dSTing-Kang Chang	"encoding/hex"
22*e7b1675dSTing-Kang Chang	"fmt"
23*e7b1675dSTing-Kang Chang	"testing"
24*e7b1675dSTing-Kang Chang
25*e7b1675dSTing-Kang Chang	"golang.org/x/crypto/curve25519"
26*e7b1675dSTing-Kang Chang	"github.com/google/tink/go/subtle"
27*e7b1675dSTing-Kang Chang	"github.com/google/tink/go/testutil"
28*e7b1675dSTing-Kang Chang)
29*e7b1675dSTing-Kang Chang
30*e7b1675dSTing-Kang Changfunc TestComputeSharedSecretX25519WithRFCTestVectors(t *testing.T) {
31*e7b1675dSTing-Kang Chang	// Test vectors are defined at
32*e7b1675dSTing-Kang Chang	// https://datatracker.ietf.org/doc/html/rfc7748#section-6.1.
33*e7b1675dSTing-Kang Chang	tests := []struct {
34*e7b1675dSTing-Kang Chang		priv string
35*e7b1675dSTing-Kang Chang		pub  string
36*e7b1675dSTing-Kang Chang	}{
37*e7b1675dSTing-Kang Chang		{"5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb", "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a"},
38*e7b1675dSTing-Kang Chang		{"77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a", "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f"},
39*e7b1675dSTing-Kang Chang	}
40*e7b1675dSTing-Kang Chang	shared := "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742"
41*e7b1675dSTing-Kang Chang
42*e7b1675dSTing-Kang Chang	for i, test := range tests {
43*e7b1675dSTing-Kang Chang		t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
44*e7b1675dSTing-Kang Chang			priv, err := hex.DecodeString(test.priv)
45*e7b1675dSTing-Kang Chang			if err != nil {
46*e7b1675dSTing-Kang Chang				t.Fatalf("DecodeString(priv): got err %q, want nil", err)
47*e7b1675dSTing-Kang Chang			}
48*e7b1675dSTing-Kang Chang			pub, err := hex.DecodeString(test.pub)
49*e7b1675dSTing-Kang Chang			if err != nil {
50*e7b1675dSTing-Kang Chang				t.Fatalf("DecodeString(pub): got err %q, want nil", err)
51*e7b1675dSTing-Kang Chang			}
52*e7b1675dSTing-Kang Chang
53*e7b1675dSTing-Kang Chang			gotShared, err := subtle.ComputeSharedSecretX25519(priv, pub)
54*e7b1675dSTing-Kang Chang			if err != nil {
55*e7b1675dSTing-Kang Chang				t.Fatalf("ComputeSharedSecretX25519(priv, pub): got err %q, want nil", err)
56*e7b1675dSTing-Kang Chang			}
57*e7b1675dSTing-Kang Chang			if got, want := hex.EncodeToString(gotShared), shared; got != want {
58*e7b1675dSTing-Kang Chang				t.Errorf("ComputeSharedSecretX25519(shared): got %v, want %v", got, want)
59*e7b1675dSTing-Kang Chang			}
60*e7b1675dSTing-Kang Chang		})
61*e7b1675dSTing-Kang Chang	}
62*e7b1675dSTing-Kang Chang}
63*e7b1675dSTing-Kang Chang
64*e7b1675dSTing-Kang Changtype x25519Suite struct {
65*e7b1675dSTing-Kang Chang	testutil.WycheproofSuite
66*e7b1675dSTing-Kang Chang	TestGroups []*x25519Group `json:"testGroups"`
67*e7b1675dSTing-Kang Chang}
68*e7b1675dSTing-Kang Chang
69*e7b1675dSTing-Kang Changtype x25519Group struct {
70*e7b1675dSTing-Kang Chang	testutil.WycheproofGroup
71*e7b1675dSTing-Kang Chang	Curve string        `json:"curve"`
72*e7b1675dSTing-Kang Chang	Tests []*x25519Case `json:"tests"`
73*e7b1675dSTing-Kang Chang}
74*e7b1675dSTing-Kang Chang
75*e7b1675dSTing-Kang Changtype x25519Case struct {
76*e7b1675dSTing-Kang Chang	testutil.WycheproofCase
77*e7b1675dSTing-Kang Chang	Public  string   `json:"public"`
78*e7b1675dSTing-Kang Chang	Private string   `json:"private"`
79*e7b1675dSTing-Kang Chang	Shared  string   `json:"shared"`
80*e7b1675dSTing-Kang Chang	Result  string   `json:"result"`
81*e7b1675dSTing-Kang Chang	Flags   []string `json:"flags"`
82*e7b1675dSTing-Kang Chang}
83*e7b1675dSTing-Kang Chang
84*e7b1675dSTing-Kang Changfunc TestComputeSharedSecretX25519WithWycheproofVectors(t *testing.T) {
85*e7b1675dSTing-Kang Chang	testutil.SkipTestIfTestSrcDirIsNotSet(t)
86*e7b1675dSTing-Kang Chang
87*e7b1675dSTing-Kang Chang	suite := new(x25519Suite)
88*e7b1675dSTing-Kang Chang	if err := testutil.PopulateSuite(suite, "x25519_test.json"); err != nil {
89*e7b1675dSTing-Kang Chang		t.Fatalf("testutil.PopulateSuite: %v", err)
90*e7b1675dSTing-Kang Chang	}
91*e7b1675dSTing-Kang Chang
92*e7b1675dSTing-Kang Chang	for _, group := range suite.TestGroups {
93*e7b1675dSTing-Kang Chang		if group.Curve != "curve25519" {
94*e7b1675dSTing-Kang Chang			continue
95*e7b1675dSTing-Kang Chang		}
96*e7b1675dSTing-Kang Chang
97*e7b1675dSTing-Kang Chang		for _, test := range group.Tests {
98*e7b1675dSTing-Kang Chang			t.Run(fmt.Sprintf("%d", test.CaseID), func(t *testing.T) {
99*e7b1675dSTing-Kang Chang				pub, err := hex.DecodeString(test.Public)
100*e7b1675dSTing-Kang Chang				if err != nil {
101*e7b1675dSTing-Kang Chang					t.Fatalf("DecodeString(pub): got err %q, want nil", err)
102*e7b1675dSTing-Kang Chang				}
103*e7b1675dSTing-Kang Chang				priv, err := hex.DecodeString(test.Private)
104*e7b1675dSTing-Kang Chang				if err != nil {
105*e7b1675dSTing-Kang Chang					t.Fatalf("DecodeString(priv): got err %q, want nil", err)
106*e7b1675dSTing-Kang Chang				}
107*e7b1675dSTing-Kang Chang
108*e7b1675dSTing-Kang Chang				gotShared, err := subtle.ComputeSharedSecretX25519(priv, pub)
109*e7b1675dSTing-Kang Chang				// ComputeSharedSecretX25519 fails on low order public values.
110*e7b1675dSTing-Kang Chang				wantErr := false
111*e7b1675dSTing-Kang Chang				for _, flag := range test.Flags {
112*e7b1675dSTing-Kang Chang					if flag == "LowOrderPublic" {
113*e7b1675dSTing-Kang Chang						wantErr = true
114*e7b1675dSTing-Kang Chang					}
115*e7b1675dSTing-Kang Chang				}
116*e7b1675dSTing-Kang Chang
117*e7b1675dSTing-Kang Chang				if wantErr {
118*e7b1675dSTing-Kang Chang					if err == nil {
119*e7b1675dSTing-Kang Chang						t.Error("ComputeSharedSecretX25519(priv, pub): got success, want err")
120*e7b1675dSTing-Kang Chang					}
121*e7b1675dSTing-Kang Chang				} else {
122*e7b1675dSTing-Kang Chang					if err != nil {
123*e7b1675dSTing-Kang Chang						t.Errorf("ComputeSharedSecretX25519(priv, pub): got err %q, want nil", err)
124*e7b1675dSTing-Kang Chang					}
125*e7b1675dSTing-Kang Chang					if got, want := hex.EncodeToString(gotShared), test.Shared; got != want {
126*e7b1675dSTing-Kang Chang						t.Errorf("ComputeSharedSecretX25519(shared): got %v, want %v", got, want)
127*e7b1675dSTing-Kang Chang					}
128*e7b1675dSTing-Kang Chang				}
129*e7b1675dSTing-Kang Chang			})
130*e7b1675dSTing-Kang Chang		}
131*e7b1675dSTing-Kang Chang	}
132*e7b1675dSTing-Kang Chang}
133*e7b1675dSTing-Kang Chang
134*e7b1675dSTing-Kang Changfunc TestComputeSharedSecretX25519Fails(t *testing.T) {
135*e7b1675dSTing-Kang Chang	pubs := []string{
136*e7b1675dSTing-Kang Chang		// Should fail on non-32-byte inputs.
137*e7b1675dSTing-Kang Chang		"77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c",
138*e7b1675dSTing-Kang Chang		"8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a2a",
139*e7b1675dSTing-Kang Chang		// Should fail on low order points, from Sodium
140*e7b1675dSTing-Kang Chang		// https://github.com/jedisct1/libsodium/blob/65621a1059a37d/src/libsodium/crypto_scalarmult/curve25519/ref10/x25519_ref10.c#L11-L70.
141*e7b1675dSTing-Kang Chang		"0000000000000000000000000000000000000000000000000000000000000000",
142*e7b1675dSTing-Kang Chang		"0100000000000000000000000000000000000000000000000000000000000000",
143*e7b1675dSTing-Kang Chang		"e0eb7a7c3b41b8ae1656e3faf19fc46ada098deb9c32b1fd866205165f49b800",
144*e7b1675dSTing-Kang Chang		"5f9c95bca3508c24b1d0b1559c83ef5b04445cc4581c8e86d8224eddd09f1157",
145*e7b1675dSTing-Kang Chang		"ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
146*e7b1675dSTing-Kang Chang		"edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
147*e7b1675dSTing-Kang Chang		"eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
148*e7b1675dSTing-Kang Chang	}
149*e7b1675dSTing-Kang Chang
150*e7b1675dSTing-Kang Chang	priv := make([]byte, curve25519.ScalarSize)
151*e7b1675dSTing-Kang Chang	if _, err := rand.Read(priv); err != nil {
152*e7b1675dSTing-Kang Chang		t.Fatal(err)
153*e7b1675dSTing-Kang Chang	}
154*e7b1675dSTing-Kang Chang
155*e7b1675dSTing-Kang Chang	for i, pubHex := range pubs {
156*e7b1675dSTing-Kang Chang		t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
157*e7b1675dSTing-Kang Chang			pub, err := hex.DecodeString(pubHex)
158*e7b1675dSTing-Kang Chang			if err != nil {
159*e7b1675dSTing-Kang Chang				t.Fatalf("DecodeString(pub): got err %q, want nil", err)
160*e7b1675dSTing-Kang Chang			}
161*e7b1675dSTing-Kang Chang			if _, err := subtle.ComputeSharedSecretX25519(priv, pub); err == nil {
162*e7b1675dSTing-Kang Chang				t.Error("ComputeSharedSecretX25519(priv, pub): got success, want err")
163*e7b1675dSTing-Kang Chang			}
164*e7b1675dSTing-Kang Chang		})
165*e7b1675dSTing-Kang Chang	}
166*e7b1675dSTing-Kang Chang}
167*e7b1675dSTing-Kang Chang
168*e7b1675dSTing-Kang Changfunc TestPublicFromPrivateX25519WithRFCTestVectors(t *testing.T) {
169*e7b1675dSTing-Kang Chang	// Test vectors are defined at
170*e7b1675dSTing-Kang Chang	// https://datatracker.ietf.org/doc/html/rfc7748#section-6.1.
171*e7b1675dSTing-Kang Chang	tests := []struct {
172*e7b1675dSTing-Kang Chang		priv string
173*e7b1675dSTing-Kang Chang		pub  string
174*e7b1675dSTing-Kang Chang	}{
175*e7b1675dSTing-Kang Chang		{"77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a", "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a"},
176*e7b1675dSTing-Kang Chang		{"5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb", "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f"},
177*e7b1675dSTing-Kang Chang	}
178*e7b1675dSTing-Kang Chang
179*e7b1675dSTing-Kang Chang	for i, test := range tests {
180*e7b1675dSTing-Kang Chang		t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
181*e7b1675dSTing-Kang Chang			priv, err := hex.DecodeString(test.priv)
182*e7b1675dSTing-Kang Chang			if err != nil {
183*e7b1675dSTing-Kang Chang				t.Fatalf("DecodeString(priv): got err %q, want nil", err)
184*e7b1675dSTing-Kang Chang			}
185*e7b1675dSTing-Kang Chang			gotPub, err := subtle.PublicFromPrivateX25519(priv)
186*e7b1675dSTing-Kang Chang			if err != nil {
187*e7b1675dSTing-Kang Chang				t.Fatalf("PublicFromPrivateX25519(priv): got err %q, want nil", err)
188*e7b1675dSTing-Kang Chang			}
189*e7b1675dSTing-Kang Chang			if got, want := hex.EncodeToString(gotPub), test.pub; got != want {
190*e7b1675dSTing-Kang Chang				t.Errorf("PublicFromPrivateX25519(priv): got %s, want %s", got, want)
191*e7b1675dSTing-Kang Chang			}
192*e7b1675dSTing-Kang Chang		})
193*e7b1675dSTing-Kang Chang	}
194*e7b1675dSTing-Kang Chang}
195*e7b1675dSTing-Kang Chang
196*e7b1675dSTing-Kang Changfunc TestPublicFromPrivateX25519Fails(t *testing.T) {
197*e7b1675dSTing-Kang Chang	// PublicFromPrivateX25519 fails on non-32-byte private keys.
198*e7b1675dSTing-Kang Chang	privs := []string{
199*e7b1675dSTing-Kang Chang		"77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c",
200*e7b1675dSTing-Kang Chang		"5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb95",
201*e7b1675dSTing-Kang Chang	}
202*e7b1675dSTing-Kang Chang
203*e7b1675dSTing-Kang Chang	for i, priv := range privs {
204*e7b1675dSTing-Kang Chang		t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
205*e7b1675dSTing-Kang Chang			priv, err := hex.DecodeString(priv)
206*e7b1675dSTing-Kang Chang			if err != nil {
207*e7b1675dSTing-Kang Chang				t.Fatalf("DecodeString(priv): got err %q, want nil", err)
208*e7b1675dSTing-Kang Chang			}
209*e7b1675dSTing-Kang Chang			if _, err := subtle.PublicFromPrivateX25519(priv); err == nil {
210*e7b1675dSTing-Kang Chang				t.Error("PublicFromPrivateX25519(priv): got success, want err")
211*e7b1675dSTing-Kang Chang			}
212*e7b1675dSTing-Kang Chang		})
213*e7b1675dSTing-Kang Chang	}
214*e7b1675dSTing-Kang Chang}
215