github.com/cloudflare/circl@v1.5.0/dh/sidh/internal/templates/curve_test.gotemp (about) 1 // Code generated by go generate; DO NOT EDIT. 2 // This file was generated by robots. 3 4 package {{.PACKAGE}} 5 6 import ( 7 "bytes" 8 "testing" 9 "math" 10 "math/rand" 11 crand "crypto/rand" 12 "io" 13 . "github.com/cloudflare/circl/dh/sidh/internal/common" 14 "time" 15 ) 16 17 func vartimeEqProjFp2(lhs, rhs *ProjectivePoint) bool { 18 var t0, t1 Fp2 19 mul(&t0, &lhs.X, &rhs.Z) 20 mul(&t1, &lhs.Z, &rhs.X) 21 return vartimeEqFp2(&t0, &t1) 22 } 23 24 func toAffine(point *ProjectivePoint) *Fp2 { 25 var affineX Fp2 26 inv(&affineX, &point.Z) 27 mul(&affineX, &affineX, &point.X) 28 return &affineX 29 } 30 31 func Test_jInvariant(t *testing.T) { 32 curve := ProjectiveCurveParameters{A: curveA, C: curveC} 33 jbufRes := make([]byte, params.SharedSecretSize) 34 jbufExp := make([]byte, params.SharedSecretSize) 35 var jInv Fp2 36 37 Jinvariant(&curve, &jInv) 38 FromMontgomery(&jInv, &jInv) 39 Fp2ToBytes(jbufRes, &jInv, params.Bytelen) 40 41 jInv = expectedJ 42 FromMontgomery(&jInv, &jInv) 43 Fp2ToBytes(jbufExp, &jInv, params.Bytelen) 44 45 if !bytes.Equal(jbufRes[:], jbufExp[:]) { 46 t.Error("Computed incorrect j-invariant: found\n", jbufRes, "\nexpected\n", jbufExp) 47 } 48 } 49 50 func TestProjectivePointVartimeEq(t *testing.T) { 51 var xP ProjectivePoint 52 53 xP = ProjectivePoint{X: affineXP, Z: params.OneFp2} 54 xQ := xP 55 56 // Scale xQ, which results in the same projective point 57 mul(&xQ.X, &xQ.X, &curveA) 58 mul(&xQ.Z, &xQ.Z, &curveA) 59 if !vartimeEqProjFp2(&xP, &xQ) { 60 t.Error("Expected the scaled point to be equal to the original") 61 } 62 } 63 64 func TestPointMulVersusSage(t *testing.T) { 65 curve := ProjectiveCurveParameters{A: curveA, C: curveC} 66 cparams := CalcCurveParamsEquiv4(&curve) 67 var xP ProjectivePoint 68 69 // x 2 70 xP = ProjectivePoint{X: affineXP, Z: params.OneFp2} 71 Pow2k(&xP, &cparams, 1) 72 afxQ := toAffine(&xP) 73 if !vartimeEqFp2(afxQ, &affineXP2) { 74 t.Error("\nExpected\n", affineXP2, "\nfound\n", afxQ) 75 } 76 77 // x 4 78 xP = ProjectivePoint{X: affineXP, Z: params.OneFp2} 79 Pow2k(&xP, &cparams, 2) 80 afxQ = toAffine(&xP) 81 if !vartimeEqFp2(afxQ, &affineXP4) { 82 t.Error("\nExpected\n", affineXP4, "\nfound\n", afxQ) 83 } 84 } 85 86 func TestPointMul9VersusSage(t *testing.T) { 87 curve := ProjectiveCurveParameters{A: curveA, C: curveC} 88 cparams := CalcCurveParamsEquiv3(&curve) 89 var xP ProjectivePoint 90 91 xP = ProjectivePoint{X: affineXP, Z: params.OneFp2} 92 Pow3k(&xP, &cparams, 2) 93 afxQ := toAffine(&xP) 94 if !vartimeEqFp2(afxQ, &affineXP9) { 95 t.Error("\nExpected\n", affineXP9, "\nfound\n", afxQ) 96 } 97 } 98 99 func BenchmarkThreePointLadder(b *testing.B) { 100 curve := ProjectiveCurveParameters{A: curveA, C: curveC} 101 for n := 0; n < b.N; n++ { 102 ScalarMul3Pt(&curve, &threePointLadderInputs[0], &threePointLadderInputs[1], &threePointLadderInputs[2], uint(len(scalar3Pt)*8), scalar3Pt[:]) 103 } 104 } 105 106 /* ------------------------------------------------------------------------- 107 Generate invalid public key points / ciphertext for test TestKEMInvalidPK 108 -------------------------------------------------------------------------*/ 109 110 // Left-to-right Montgomery ladder, Algorithm 4 in Costello-Smith 111 // Input: ProjectivePoint P (xP, zP) 112 // Output: x([scalar]P), z([scalar]P) 113 func montgomeryLadder(cparams *ProjectiveCurveParameters, P *ProjectivePoint, scalar []uint8, random uint) ProjectivePoint { 114 var R0, R2, R1 ProjectivePoint 115 coefEq := CalcCurveParamsEquiv4(cparams) // for xDbl 116 aPlus2Over4 := CalcAplus2Over4(cparams) // for xDblAdd 117 R0 = *P // RO <- P 118 R1 = *P 119 Pow2k(&R1, &coefEq, 1) // R1 <- [2]P 120 R2 = *P // R2 = R1-R0 = P 121 122 prevBit := uint8(0) 123 for i := int(random); i >= 0; i-- { 124 bit := (scalar[i>>3] >> (i & 7) & 1) 125 swap := prevBit ^ bit 126 prevBit = bit 127 cswap(&R0.X, &R0.Z, &R1.X, &R1.Z, swap) 128 R0, R1 = xDbladd(&R0, &R1, &R2, &aPlus2Over4) 129 } 130 cswap(&R0.X, &R0.Z, &R1.X, &R1.Z, prevBit) 131 return R0 132 } 133 134 // P = P + T 135 // From paper https://eprint.iacr.org/2017/212.pdf 136 // The map tau_T: P->P+T is (X : Z) -> (Z : X) on Montgomery curves 137 func tauT(P *ProjectivePoint) { 138 P.X, P.Z = P.Z, P.X // magic! 139 } 140 141 // Construct Invalid public key tuple (P,Q) such that P and Q are linearly dependent 142 // Simulate section 3.1.1 of paper https://eprint.iacr.org/2022/054.pdf 143 // We only construct point P and Q because in the attacks the third point is P-Q by construction 144 // and the countermeasure does not test it 145 // Without loss of generality, we assume the curve is the starting curve 146 func testInvalidPKNoneLinear(t *testing.T) { 147 148 // Generate random scalar as secret 149 secret := make([]byte, params.B.SecretByteLen) 150 _, err := io.ReadFull(crand.Reader, secret) 151 if err != nil{ 152 t.Error("Fail read random bytes") 153 } 154 155 var P, Q ProjectivePoint 156 157 rand.Seed(time.Now().UnixNano()) 158 random_index := rand.Intn(int(params.B.SecretByteLen-1)*8) 159 160 // Set P as a point of order 3^e3 161 P = ProjectivePoint{X: params.B.AffineP, Z: params.OneFp2} 162 163 // Set Q = [k]P, where k = secret[:random_index] 164 Q = montgomeryLadder(¶ms.InitCurve, &P, secret, uint(random_index)) 165 166 // Make sure Q is of full order 3^e_3, 167 var test_Q ProjectivePoint 168 test_Q = Q 169 170 var e3 uint32 171 e3_float := float64(int(params.B.SecretBitLen)+1)/math.Log2(3) 172 e3 = uint32(e3_float) 173 cparam_q := CalcCurveParamsEquiv3(¶ms.InitCurve) 174 Pow3k(&test_Q, &cparam_q, e3-1) 175 176 var test_QZ Fp2 177 FromMontgomery(&test_QZ, &test_Q.Z) 178 179 // Q are not of full order 3^e_3 180 for((isZero(&test_QZ)==1)){ 181 rand.Seed(time.Now().UnixNano()) 182 random_index = rand.Intn(int(params.B.SecretByteLen-1)*8) 183 Q = montgomeryLadder(¶ms.InitCurve, &P, secret, uint(random_index)) 184 test_Q = Q 185 Pow3k(&test_Q, &cparam_q, e3-1) 186 FromMontgomery(&test_QZ, &test_Q.Z) 187 } 188 189 // invQz = 1/Q.Z 190 var invQz Fp2 191 invQz = Q.Z 192 inv(&invQz, &invQz) 193 194 mul(&P.X, &P.X, &P.Z) 195 mul(&Q.X, &Q.X, &invQz) 196 197 var xP, xQ, xQmP ProjectivePoint 198 xP = ProjectivePoint{X: P.X, Z: params.OneFp2} 199 xQ = ProjectivePoint{X: Q.X, Z: params.OneFp2} 200 xQmP = ProjectivePoint{X: params.OneFp2, Z: params.OneFp2} 201 202 error_verify := PublicKeyValidation(¶ms.InitCurve, &xP, &xQ, &xQmP, params.B.SecretBitLen) 203 if error_verify==nil{ 204 t.Errorf("\nExpect linearly dependent ciphertext to fail, index: %v scalar: %v ", random_index, secret) 205 } 206 } 207 208 // Construct Invalid public key tuple (P,Q) such that Q = [k]P + T, where k is random and T is the point of order 2. 209 // Simulate HB and section 3.1.2 of paper https://eprint.iacr.org/2022/054.pdf 210 // We only construct point P and Q because in the attacks the third point is P-Q by construction 211 // and the countermeasure does not test it 212 // Without loss of generality, we assume the curve is the starting curve 213 func testInvalidPKT(t *testing.T) { 214 215 // Generate random scalar as secret 216 secret := make([]byte, params.B.SecretByteLen) 217 _, err := io.ReadFull(crand.Reader, secret) 218 if err != nil{ 219 t.Error("Fail read random bytes") 220 } 221 222 223 var P, Q ProjectivePoint 224 225 rand.Seed(time.Now().UnixNano()) 226 random_index := rand.Intn(int(params.B.SecretByteLen-1)*8) 227 228 // Set P as a point of order 3^e3 229 P = ProjectivePoint{X: params.B.AffineP, Z: params.OneFp2} 230 231 // Set Q = [k]P, where k = secret[:random_index] 232 Q = montgomeryLadder(¶ms.InitCurve, &P, secret, uint(random_index)) 233 // Q = [k]P + T 234 tauT(&Q) 235 236 var invQz Fp2 237 invQz = Q.Z 238 inv(&invQz, &invQz) 239 240 mul(&P.X, &P.X, &P.Z) 241 mul(&Q.X, &Q.X, &invQz) 242 243 var xP, xQ, xQmP ProjectivePoint 244 xP = ProjectivePoint{X: P.X, Z: params.OneFp2} 245 xQ = ProjectivePoint{X: Q.X, Z: params.OneFp2} 246 xQmP = ProjectivePoint{X: params.OneFp2, Z: params.OneFp2} 247 248 error_verify := PublicKeyValidation(¶ms.InitCurve, &xP, &xQ, &xQmP, params.B.SecretBitLen) 249 if error_verify==nil{ 250 t.Errorf("\nExpect ciphertext involve point T to fail, index: %v scalar: %v ", random_index, secret) 251 } 252 } 253 254 255 // Construct Invalid public key tuple (P,Q) such that P and Q are in E[2^e2] 256 // Simulate section 3.2 of paper https://eprint.iacr.org/2022/054.pdf 257 // We only construct point P and Q because in the attacks the third point is P-Q by construction 258 // and the countermeasure does not test it 259 // Without loss of generality, we assume the curve is the starting curve 260 func testInvalidPKOrder2(t *testing.T) { 261 262 // Generate random scalar as secret 263 secret := make([]byte, params.B.SecretByteLen) 264 _, err := io.ReadFull(crand.Reader, secret) 265 if err != nil{ 266 t.Error("Fail read random bytes") 267 } 268 269 270 var P, Q ProjectivePoint 271 272 P = ProjectivePoint{X: params.A.AffineP, Z: params.OneFp2} 273 Q = ProjectivePoint{X: params.A.AffineQ, Z: params.OneFp2} 274 275 rand.Seed(time.Now().UnixNano()) 276 random_index_p := rand.Intn(int(params.A.SecretByteLen-1)*8) 277 random_index_q := rand.Intn(int(params.A.SecretByteLen-1)*8) 278 279 P = montgomeryLadder(¶ms.InitCurve, &P, secret, uint(random_index_p)) 280 Q = montgomeryLadder(¶ms.InitCurve, &Q, secret, uint(random_index_q)) 281 282 var invQz, invPz Fp2 283 invQz = Q.Z 284 invPz = P.Z 285 inv(&invQz, &invQz) 286 inv(&invPz, &invPz) 287 288 mul(&P.X, &P.X, &invPz) 289 mul(&Q.X, &Q.X, &invQz) 290 291 var xP, xQ, xQmP ProjectivePoint 292 xP = ProjectivePoint{X: P.X, Z: params.OneFp2} 293 xQ = ProjectivePoint{X: Q.X, Z: params.OneFp2} 294 xQmP = ProjectivePoint{X: params.OneFp2, Z: params.OneFp2} 295 296 error_verify := PublicKeyValidation(¶ms.InitCurve, &xP, &xQ, &xQmP, params.B.SecretBitLen) 297 if error_verify==nil{ 298 t.Errorf("\nExpect ciphertext in torsion E[2^e2] to fail, index_p: %v index_q: %v scalar: %v ", random_index_p, random_index_q, secret) 299 } 300 301 } 302 303 304 // Construct Invalid public key tuple (P,Q) such that P and Q are in E[3^e3] but not of full order 3^e3 305 // Simulate section 3.1.1 of paper https://eprint.iacr.org/2022/054.pdf 306 // We only construct point P and Q because in the attacks the third point is P-Q by construction 307 // and the countermeasure does not test it 308 // Without loss of generality, we assume the curve is the starting curve 309 func testInvalidPKFullOrder(t *testing.T) { 310 311 var P, Q ProjectivePoint 312 313 P = ProjectivePoint{X: params.B.AffineP, Z: params.OneFp2} 314 Q = ProjectivePoint{X: params.B.AffineQ, Z: params.OneFp2} 315 316 var e3 uint32 317 e3_float := float64(int(params.B.SecretBitLen)+1)/math.Log2(3) 318 e3 = uint32(e3_float) 319 320 rand.Seed(time.Now().UnixNano()) 321 random_index_p := rand.Intn(int(e3)) 322 random_index_q := rand.Intn(int(e3)) 323 324 cparam_q := CalcCurveParamsEquiv3(¶ms.InitCurve) 325 Pow3k(&P, &cparam_q, uint32(random_index_p)) 326 Pow3k(&Q, &cparam_q, uint32(random_index_q)) 327 328 329 var invQz, invPz Fp2 330 invQz = Q.Z 331 invPz = P.Z 332 inv(&invQz, &invQz) 333 inv(&invPz, &invPz) 334 335 mul(&P.X, &P.X, &invPz) 336 mul(&Q.X, &Q.X, &invQz) 337 338 var xP, xQ, xQmP ProjectivePoint 339 xP = ProjectivePoint{X: P.X, Z: params.OneFp2} 340 xQ = ProjectivePoint{X: Q.X, Z: params.OneFp2} 341 xQmP = ProjectivePoint{X: params.OneFp2, Z: params.OneFp2} 342 343 error_verify := PublicKeyValidation(¶ms.InitCurve, &xP, &xQ, &xQmP, params.B.SecretBitLen) 344 if error_verify==nil{ 345 t.Errorf("\nExpect ciphertext not of full order to fail, index_p: %v index_q: %v ", random_index_p, random_index_q) 346 } 347 348 } 349 350 // A trivial test case not covered by paper https://eprint.iacr.org/2022/054.pdf and HB 351 // Countermeasure in https://eprint.iacr.org/2022/054.pdf only cares about P and Q 352 // But if PmQ is point T or O, that can also lead to recovery of the first bit 353 func testInvalidPmQ(t *testing.T) { 354 355 var zero Fp2 356 var xP, xQ, xQmP ProjectivePoint 357 xP = ProjectivePoint{X: params.A.AffineP, Z: params.OneFp2} 358 xQ = ProjectivePoint{X: params.A.AffineQ, Z: params.OneFp2} 359 xQmP = ProjectivePoint{X: zero, Z: params.OneFp2} 360 361 error_verify := PublicKeyValidation(¶ms.InitCurve, &xP, &xQ, &xQmP, params.B.SecretBitLen) 362 if error_verify==nil{ 363 t.Errorf("\nExpect PmQ as T to fail\n") 364 } 365 366 } 367 368 // Test valid ciphertext 369 // Where P, Q are linearly independent points of correct order 3^e3 in E[3^e3] 370 func testValidPQ(t *testing.T) { 371 372 var xP, xQ, xQmP ProjectivePoint 373 xP = ProjectivePoint{X: params.B.AffineP, Z: params.OneFp2} 374 xQ = ProjectivePoint{X: params.B.AffineQ, Z: params.OneFp2} 375 xQmP = ProjectivePoint{X: params.OneFp2, Z: params.OneFp2} 376 377 error_verify := PublicKeyValidation(¶ms.InitCurve, &xP, &xQ, &xQmP, params.B.SecretBitLen) 378 if error_verify!=nil{ 379 t.Errorf("\nExpect correct ciphertext to not fail\n") 380 } 381 382 } 383 384 385 /* ------------------------------------------------------------------------- 386 Public key / Ciphertext validation against attacks proposed in paper https://eprint.iacr.org/2022/054.pdf and HB 387 -------------------------------------------------------------------------*/ 388 389 func TestInvalidPK(t *testing.T) { 390 391 t.Run("InvalidPmQ", testInvalidPmQ) 392 t.Run("InvalidPKNoneLinear", testInvalidPKNoneLinear) 393 t.Run("InvalidPKT", testInvalidPKT) 394 t.Run("InvalidPKOrder2", testInvalidPKOrder2) 395 t.Run("InvalidPKFullOrder", testInvalidPKFullOrder) 396 t.Run("ValidPQ", testValidPQ) 397 398 }