github.com/cloudflare/circl@v1.5.0/dh/csidh/csidh_test.go (about) 1 package csidh 2 3 import ( 4 "bytes" 5 "crypto/rand" 6 "encoding/binary" 7 "encoding/hex" 8 "encoding/json" 9 "os" 10 "testing" 11 12 . "github.com/cloudflare/circl/internal/test" 13 ) 14 15 // Possible values for "Status" 16 const ( 17 Valid = iota // Indicates that shared secret must be agreed correctly 18 ValidPublicKey2 // Public key 2 must succeed validation 19 InvalidSharedSecret // Calculated shared secret must be different than test vector 20 InvalidPublicKey1 // Public key 1 generated from private key must be different than test vector 21 InvalidPublicKey2 // Public key 2 must fail validation 22 ) 23 24 var StatusValues = map[int]string{ 25 Valid: "valid", 26 ValidPublicKey2: "valid_public_key2", 27 InvalidSharedSecret: "invalid_shared_secret", 28 InvalidPublicKey1: "invalid_public_key1", 29 InvalidPublicKey2: "invalid_public_key2", 30 } 31 32 var rng = rand.Reader 33 34 type TestVector struct { 35 ID int `json:"Id"` 36 Pk1 string `json:"Pk1"` 37 Pr1 string `json:"Pr1"` 38 Pk2 string `json:"Pk2"` 39 Ss string `json:"Ss"` 40 Status string `json:"status"` 41 } 42 43 type TestVectors struct { 44 Vectors []TestVector `json:"Vectors"` 45 } 46 47 func TestCompare64(t *testing.T) { 48 const s uint64 = 0xFFFFFFFFFFFFFFFF 49 val1 := fp{0, 2, 3, 4, 5, 6, 7, 8} 50 val2 := fp{s, s, s, s, s, s, s, s} 51 var zero fp 52 53 if !zero.isZero() { 54 t.Errorf("isZero returned true, where it should be false") 55 } 56 if val1.isZero() { 57 t.Errorf("isZero returned false, where it should be true") 58 } 59 if val2.isZero() { 60 t.Errorf("isZero returned false, where it should be true") 61 } 62 } 63 64 func TestEphemeralKeyExchange(t *testing.T) { 65 var ss1, ss2 [64]byte 66 var prv1, prv2 PrivateKey 67 var pub1, pub2 PublicKey 68 69 prvBytes1 := []byte{0xaa, 0x54, 0xe4, 0xd4, 0xd0, 0xbd, 0xee, 0xcb, 0xf4, 0xd0, 0xc2, 0xbc, 0x52, 0x44, 0x11, 0xee, 0xe1, 0x14, 0xd2, 0x24, 0xe5, 0x0, 0xcc, 0xf5, 0xc0, 0xe1, 0x1e, 0xb3, 0x43, 0x52, 0x45, 0xbe, 0xfb, 0x54, 0xc0, 0x55, 0xb2} 70 prv1.Import(prvBytes1) 71 GeneratePublicKey(&pub1, &prv1, rng) 72 73 CheckNoErr(t, GeneratePrivateKey(&prv2, rng), "PrivateKey generation failed") 74 GeneratePublicKey(&pub2, &prv2, rng) 75 76 CheckOk( 77 DeriveSecret(&ss1, &pub1, &prv2, rng), 78 "Derivation failed", t) 79 CheckOk( 80 DeriveSecret(&ss2, &pub2, &prv1, rng), 81 "Derivation failed", t) 82 83 if !bytes.Equal(ss1[:], ss2[:]) { 84 t.Error("ss1 != ss2") 85 } 86 } 87 88 func TestPrivateKeyExportImport(t *testing.T) { 89 var buf [37]byte 90 for i := 0; i < numIter; i++ { 91 var prv1, prv2 PrivateKey 92 CheckNoErr(t, GeneratePrivateKey(&prv1, rng), "PrivateKey generation failed") 93 prv1.Export(buf[:]) 94 prv2.Import(buf[:]) 95 96 for i := 0; i < len(prv1.e); i++ { 97 if prv1.e[i] != prv2.e[i] { 98 t.Error("Error occurred when public key export/import") 99 } 100 } 101 } 102 } 103 104 func TestValidateNegative(t *testing.T) { 105 pk := PublicKey{a: p} 106 pk.a[0]++ 107 if Validate(&pk, rng) { 108 t.Error("Public key > p has been validated") 109 } 110 111 pk = PublicKey{a: p} 112 if Validate(&pk, rng) { 113 t.Error("Public key == p has been validated") 114 } 115 116 pk = PublicKey{a: two} 117 if Validate(&pk, rng) { 118 t.Error("Public key == 2 has been validated") 119 } 120 121 pk = PublicKey{a: twoNeg} 122 if Validate(&pk, rng) { 123 t.Error("Public key == -2 has been validated") 124 } 125 } 126 127 func TestPublicKeyExportImport(t *testing.T) { 128 var buf [64]byte 129 eq64 := func(x, y []uint64) bool { 130 for i := range x { 131 if x[i] != y[i] { 132 return false 133 } 134 } 135 return true 136 } 137 138 for i := 0; i < numIter; i++ { 139 var prv PrivateKey 140 var pub1, pub2 PublicKey 141 CheckNoErr(t, GeneratePrivateKey(&prv, rng), "PrivateKey generation failed") 142 GeneratePublicKey(&pub1, &prv, rng) 143 144 pub1.Export(buf[:]) 145 pub2.Import(buf[:]) 146 147 if !eq64(pub1.a[:], pub2.a[:]) { 148 t.Error("Error occurred when public key export/import") 149 } 150 } 151 } 152 153 // Test vectors generated by reference implementation. 154 func TestKAT(t *testing.T) { 155 var tests TestVectors 156 // Helper checks if e==true and reports an error if not. 157 checkExpr := func(e bool, vec *TestVector, t *testing.T, msg string) { 158 t.Helper() 159 if !e { 160 t.Errorf("[Test ID=%d] "+msg, vec.ID) 161 } 162 } 163 // checkSharedSecret implements nominal case - imports asymmetric keys for 164 // both parties, derives secret key and compares it to value in test vector. 165 // Comparison must succeed in case status is "Valid" in any other case 166 // it must fail. 167 checkSharedSecret := func(vec *TestVector, t *testing.T, status int) { 168 var prv1 PrivateKey 169 var pub1, pub2 PublicKey 170 var ss [SharedSecretSize]byte 171 172 prBuf, err := hex.DecodeString(vec.Pr1) 173 if err != nil { 174 t.Fatal(err) 175 } 176 checkExpr(prv1.Import(prBuf[:]), vec, t, "PrivateKey wrong") 177 pkBuf, err := hex.DecodeString(vec.Pk1) 178 if err != nil { 179 t.Fatal(err) 180 } 181 checkExpr(pub1.Import(pkBuf[:]), vec, t, "PublicKey 1 wrong") 182 pkBuf, err = hex.DecodeString(vec.Pk2) 183 if err != nil { 184 t.Fatal(err) 185 } 186 checkExpr(pub2.Import(pkBuf[:]), vec, t, "PublicKey 2 wrong") 187 checkExpr(DeriveSecret(&ss, &pub2, &prv1, rng), vec, t, "Error when deriving key") 188 ssExp, err := hex.DecodeString(vec.Ss) 189 if err != nil { 190 t.Fatal(err) 191 } 192 checkExpr(bytes.Equal(ss[:], ssExp) == (status == Valid), vec, t, "Unexpected value of shared secret") 193 } 194 // checkPublicKey1 imports public and private key for one party A 195 // and tries to generate public key for a private key. After that 196 // it compares generated key to a key from test vector. Comparison 197 // must fail. 198 checkPublicKey1 := func(vec *TestVector, t *testing.T) { 199 var prv PrivateKey 200 var pub PublicKey 201 var pubBytesGot [PublicKeySize]byte 202 203 prBuf, err := hex.DecodeString(vec.Pr1) 204 if err != nil { 205 t.Fatal(err) 206 } 207 208 pubBytesExp, err := hex.DecodeString(vec.Pk1) 209 if err != nil { 210 t.Fatal(err) 211 } 212 213 checkExpr( 214 prv.Import(prBuf[:]), 215 vec, t, "PrivateKey wrong") 216 217 // Generate public key 218 CheckNoErr(t, GeneratePrivateKey(&prv, rng), "PrivateKey generation failed") 219 pub.Export(pubBytesGot[:]) 220 221 // pubBytesGot must be different than pubBytesExp 222 checkExpr( 223 !bytes.Equal(pubBytesGot[:], pubBytesExp), 224 vec, t, "Public key generated is the same as public key from the test vector") 225 } 226 // checkPublicKey2 the goal is to test key validation. Test tries to 227 // import public key for B and ensure that import succeeds in case 228 // status is "Valid" and fails otherwise. 229 checkPublicKey2 := func(vec *TestVector, t *testing.T, status int) { 230 var pub PublicKey 231 pubBytesExp, err := hex.DecodeString(vec.Pk2) 232 if err != nil { 233 t.Fatal(err) 234 } 235 // Import validates an input, so it must fail 236 pub.Import(pubBytesExp[:]) 237 checkExpr( 238 Validate(&pub, rng) == (status == Valid || status == ValidPublicKey2), 239 vec, t, "PublicKey has been validated correctly") 240 } 241 // Load test data 242 file, err := os.Open(katFile) 243 if err != nil { 244 t.Fatal(err.Error()) 245 } 246 err = json.NewDecoder(file).Decode(&tests) 247 if err != nil { 248 t.Fatal(err.Error()) 249 } 250 // Loop over numIter test cases 251 // The algorithm is relatively slow, so it tests a smaller number. 252 N := len(tests.Vectors) 253 var buf [2]byte 254 for i := 0; i < numIter; i++ { 255 _, _ = rand.Read(buf[:]) 256 idx := binary.LittleEndian.Uint16(buf[:]) % uint16(N) 257 test := tests.Vectors[idx] 258 switch test.Status { 259 case StatusValues[Valid]: 260 checkSharedSecret(&test, t, Valid) 261 checkPublicKey2(&test, t, Valid) 262 case StatusValues[InvalidSharedSecret]: 263 checkSharedSecret(&test, t, InvalidSharedSecret) 264 case StatusValues[InvalidPublicKey1]: 265 checkPublicKey1(&test, t) 266 case StatusValues[InvalidPublicKey2]: 267 checkPublicKey2(&test, t, InvalidPublicKey2) 268 case StatusValues[InvalidPublicKey2]: 269 checkPublicKey2(&test, t, InvalidPublicKey2) 270 case StatusValues[ValidPublicKey2]: 271 checkPublicKey2(&test, t, ValidPublicKey2) 272 } 273 } 274 } 275 276 var ( 277 prv1, prv2 PrivateKey 278 pub1, pub2 PublicKey 279 ) 280 281 // Private key generation. 282 func BenchmarkGeneratePrivate(b *testing.B) { 283 for n := 0; n < b.N; n++ { 284 _ = GeneratePrivateKey(&prv1, rng) 285 } 286 } 287 288 // Public key generation from private (group action on empty key). 289 func BenchmarkGenerateKeyPair(b *testing.B) { 290 for n := 0; n < b.N; n++ { 291 var pub PublicKey 292 _ = GeneratePrivateKey(&prv1, rng) 293 GeneratePublicKey(&pub, &prv1, rng) 294 } 295 } 296 297 // Benchmark validation on same key multiple times. 298 func BenchmarkValidate(b *testing.B) { 299 prvBytes := []byte{0xaa, 0x54, 0xe4, 0xd4, 0xd0, 0xbd, 0xee, 0xcb, 0xf4, 0xd0, 0xc2, 0xbc, 0x52, 0x44, 0x11, 0xee, 0xe1, 0x14, 0xd2, 0x24, 0xe5, 0x0, 0xcc, 0xf5, 0xc0, 0xe1, 0x1e, 0xb3, 0x43, 0x52, 0x45, 0xbe, 0xfb, 0x54, 0xc0, 0x55, 0xb2} 300 prv1.Import(prvBytes) 301 302 var pub PublicKey 303 GeneratePublicKey(&pub, &prv1, rng) 304 305 for n := 0; n < b.N; n++ { 306 Validate(&pub, rng) 307 } 308 } 309 310 // Benchmark validation on random (most probably wrong) key. 311 func BenchmarkValidateRandom(b *testing.B) { 312 var tmp [64]byte 313 var pub PublicKey 314 315 // Initialize seed 316 for n := 0; n < b.N; n++ { 317 if _, err := rng.Read(tmp[:]); err != nil { 318 b.FailNow() 319 } 320 pub.Import(tmp[:]) 321 } 322 } 323 324 // Benchmark validation on different keys. 325 func BenchmarkValidateGenerated(b *testing.B) { 326 for n := 0; n < b.N; n++ { 327 _ = GeneratePrivateKey(&prv1, rng) 328 GeneratePublicKey(&pub1, &prv1, rng) 329 Validate(&pub1, rng) 330 } 331 } 332 333 // Generate some keys and benchmark derive. 334 func BenchmarkDerive(b *testing.B) { 335 var ss [64]byte 336 337 _ = GeneratePrivateKey(&prv1, rng) 338 GeneratePublicKey(&pub1, &prv1, rng) 339 340 _ = GeneratePrivateKey(&prv2, rng) 341 GeneratePublicKey(&pub2, &prv2, rng) 342 343 b.ResetTimer() 344 for n := 0; n < b.N; n++ { 345 DeriveSecret(&ss, &pub2, &prv1, rng) 346 } 347 } 348 349 // Benchmarks both - key generation and derivation. 350 func BenchmarkDeriveGenerated(b *testing.B) { 351 var ss [64]byte 352 353 for n := 0; n < b.N; n++ { 354 _ = GeneratePrivateKey(&prv1, rng) 355 GeneratePublicKey(&pub1, &prv1, rng) 356 357 _ = GeneratePrivateKey(&prv2, rng) 358 GeneratePublicKey(&pub2, &prv2, rng) 359 360 DeriveSecret(&ss, &pub2, &prv1, rng) 361 } 362 }