github.com/cloudflare/circl@v1.5.0/dh/csidh/fp511_test.go (about) 1 package csidh 2 3 import ( 4 "crypto/rand" 5 "math/big" 6 "testing" 7 8 "github.com/cloudflare/circl/internal/test" 9 ) 10 11 func testFp512Mul3Nominal(t *testing.T, f func(*fp, *fp, uint64)) { 12 var mod, two64 big.Int 13 14 // modulus: 2^512 15 mod.SetUint64(1).Lsh(&mod, 512) 16 two64.SetUint64(1).Lsh(&two64, 64) 17 18 for i := 0; i < numIter; i++ { 19 multiplier64, _ := rand.Int(rand.Reader, &two64) 20 mul64 := multiplier64.Uint64() 21 22 fV := randomFp() 23 exp, _ := new(big.Int).SetString(fp2S(fV), 16) 24 exp.Mul(exp, multiplier64) 25 // Truncate to 512 bits 26 exp.Mod(exp, &mod) 27 28 f(&fV, &fV, mul64) 29 res, _ := new(big.Int).SetString(fp2S(fV), 16) 30 31 if exp.Cmp(res) != 0 { 32 test.ReportError(t, exp, res, fV) 33 } 34 } 35 } 36 37 // Check if mul512 produces result 38 // z = x*y mod 2^512. 39 func TestFp512Mul3_Nominal(t *testing.T) { 40 testFp512Mul3Nominal(t, mul512) 41 testFp512Mul3Nominal(t, mul512Generic) 42 } 43 44 func TestAddRdcRandom(t *testing.T) { 45 for i := 0; i < numIter; i++ { 46 a := randomFp() 47 bigA, _ := new(big.Int).SetString(fp2S(a), 16) 48 bigA.Mod(bigA, modulus) 49 copy(a[:], intGetU64(bigA)) 50 51 b := randomFp() 52 bigB, _ := new(big.Int).SetString(fp2S(b), 16) 53 bigB.Mod(bigB, modulus) 54 copy(b[:], intGetU64(bigB)) 55 56 addRdc(&a, &a, &b) 57 bigRet, _ := new(big.Int).SetString(fp2S(a), 16) 58 59 bigA.Add(bigA, bigB) 60 bigA.Mod(bigA, modulus) 61 62 if bigRet.Cmp(bigA) != 0 { 63 test.ReportError(t, bigRet, bigA, a, b) 64 } 65 } 66 } 67 68 func TestAddRdcNominal(t *testing.T) { 69 var res fp 70 71 tmp := oneFp512 72 addRdc(&res, &tmp, &p) 73 if !eqFp(&res, &tmp) { 74 t.Errorf("Wrong value\n%X", res) 75 } 76 77 tmp = zeroFp512 78 addRdc(&res, &p, &p) 79 if !eqFp(&res, &p) { 80 t.Errorf("Wrong value\n%X", res) 81 } 82 83 tmp = fp{1, 1, 1, 1, 1, 1, 1, 1} 84 addRdc(&res, &p, &tmp) 85 if !eqFp(&res, &tmp) { 86 t.Errorf("Wrong value\n%X", res) 87 } 88 89 tmp = fp{1, 1, 1, 1, 1, 1, 1, 1} 90 exp := fp{2, 2, 2, 2, 2, 2, 2, 2} 91 addRdc(&res, &tmp, &tmp) 92 if !eqFp(&res, &exp) { 93 t.Errorf("Wrong value\n%X", res) 94 } 95 } 96 97 func TestFp512Sub3_Nominal(t *testing.T) { 98 var ret fp 99 var mod big.Int 100 // modulus: 2^512 101 mod.SetUint64(1).Lsh(&mod, 512) 102 103 for i := 0; i < numIter; i++ { 104 a := randomFp() 105 bigA, _ := new(big.Int).SetString(fp2S(a), 16) 106 b := randomFp() 107 bigB, _ := new(big.Int).SetString(fp2S(b), 16) 108 109 sub512(&ret, &a, &b) 110 bigRet, _ := new(big.Int).SetString(fp2S(ret), 16) 111 bigA.Sub(bigA, bigB) 112 // Truncate to 512 bits 113 bigA.Mod(bigA, &mod) 114 115 if bigRet.Cmp(bigA) != 0 { 116 test.ReportError(t, bigRet, bigA, a, b) 117 } 118 } 119 } 120 121 func TestFp512Sub3_DoesntReturnCarry(t *testing.T) { 122 a := fp{} 123 b := fp{ 124 0xFFFFFFFFFFFFFFFF, 1, 125 0, 0, 126 0, 0, 127 0, 0, 128 } 129 c := fp{ 130 0xFFFFFFFFFFFFFFFF, 2, 131 0, 0, 132 0, 0, 133 0, 0, 134 } 135 136 if sub512(&a, &b, &c) != 1 { 137 t.Error("Carry not returned") 138 } 139 } 140 141 func TestFp512Sub3_ReturnsCarry(t *testing.T) { 142 a := fp{} 143 b := fp{ 144 0xFFFFFFFFFFFFFFFF, 2, 145 0, 0, 146 0, 0, 147 0, 0, 148 } 149 c := fp{ 150 0xFFFFFFFFFFFFFFFF, 1, 151 0, 0, 152 0, 0, 153 0, 0, 154 } 155 156 if sub512(&a, &b, &c) != 0 { 157 t.Error("Carry not returned") 158 } 159 } 160 161 func testCswap(t *testing.T, f func(*fp, *fp, uint8)) { 162 arg1 := randomFp() 163 arg2 := randomFp() 164 165 arg1cpy := arg1 166 f(&arg1, &arg2, 0) 167 if !eqFp(&arg1, &arg1cpy) { 168 t.Error("cswap swapped") 169 } 170 171 arg1cpy = arg1 172 f(&arg1, &arg2, 1) 173 if eqFp(&arg1, &arg1cpy) { 174 t.Error("cswap didn't swapped") 175 } 176 177 arg1cpy = arg1 178 f(&arg1, &arg2, 0xF2) 179 if eqFp(&arg1, &arg1cpy) { 180 t.Error("cswap didn't swapped") 181 } 182 } 183 184 func TestCswap(t *testing.T) { 185 testCswap(t, cswap512Generic) 186 testCswap(t, cswap512) 187 } 188 189 func TestSubRdc(t *testing.T) { 190 var res fp 191 192 // 1 - 1 mod P 193 tmp := oneFp512 194 subRdc(&res, &tmp, &tmp) 195 if !eqFp(&res, &zeroFp512) { 196 t.Errorf("Wrong value\n%X", res) 197 } 198 zero(&res) 199 200 // 0 - 1 mod P 201 exp := p 202 exp[0]-- 203 204 subRdc(&res, &zeroFp512, &oneFp512) 205 if !eqFp(&res, &exp) { 206 t.Errorf("Wrong value\n%X\n%X", res, exp) 207 } 208 zero(&res) 209 210 // P - (P-1) 211 pMinusOne := p 212 pMinusOne[0]-- 213 subRdc(&res, &p, &pMinusOne) 214 if !eqFp(&res, &oneFp512) { 215 t.Errorf("Wrong value\n[%X != %X]", res, oneFp512) 216 } 217 zero(&res) 218 219 subRdc(&res, &p, &oneFp512) 220 if !eqFp(&res, &pMinusOne) { 221 t.Errorf("Wrong value\n[%X != %X]", res, pMinusOne) 222 } 223 } 224 225 func testMulRdc(t *testing.T, f func(*fp, *fp, *fp)) { 226 var res fp 227 m1 := fp{ 228 0x85E2579C786882D0, 0x4E3433657E18DA95, 229 0x850AE5507965A0B3, 0xA15BC4E676475964, 230 } 231 m2 := fp{ 232 0x85E2579C786882CF, 0x4E3433657E18DA95, 233 0x850AE5507965A0B3, 0xA15BC4E676475964, 234 } 235 236 // Expected 237 m1m1 := fp{ 238 0xAEBF46E92C88A4B4, 0xCFE857977B946347, 239 0xD3B264FF08493901, 0x6EEB3D23746B6C7C, 240 0xC0CA874A349D64B4, 0x7AD4A38B406F8504, 241 0x38B6B6CEB82472FB, 0x1587015FD7DDFC7D, 242 } 243 m1m2 := fp{ 244 0x51534771258C4624, 0x2BFEDE86504E2160, 245 0xE8127D5E9329670B, 0x0C84DBD584491D75, 246 0x656C73C68B16E38C, 0x01C0DA470B30B8DE, 247 0x2532E3903EAA950B, 0x3F2C28EA97FE6FEC, 248 } 249 250 // 0*0 251 tmp := zeroFp512 252 f(&res, &tmp, &tmp) 253 if !eqFp(&res, &tmp) { 254 t.Errorf("Wrong value\n%X", res) 255 } 256 257 // 1*m1 == m1 258 zero(&res) 259 f(&res, &m1, &one) 260 if !eqFp(&res, &m1) { 261 t.Errorf("Wrong value\n%X", res) 262 } 263 264 // m1*m2 < p 265 zero(&res) 266 f(&res, &m1, &m2) 267 if !eqFp(&res, &m1m2) { 268 t.Errorf("Wrong value\n%X", res) 269 } 270 271 // m1*m1 > p 272 zero(&res) 273 f(&res, &m1, &m1) 274 if !eqFp(&res, &m1m1) { 275 t.Errorf("Wrong value\n%X", res) 276 } 277 } 278 279 func TestMulRdc(t *testing.T) { 280 testMulRdc(t, mulRdcGeneric) 281 testMulRdc(t, mulRdc) 282 } 283 284 func TestModExp(t *testing.T) { 285 var resExp, base, exp big.Int 286 var baseFp, expFp, resFp, resFpExp fp 287 288 for i := 0; i < numIter; i++ { 289 // Perform modexp with reference implementation 290 // in Montgomery domain 291 base.SetString(fp2S(randomFp()), 16) 292 exp.SetString(fp2S(randomFp()), 16) 293 resExp.Exp(&base, &exp, modulus) 294 toMont(&base, true) 295 toMont(&resExp, true) 296 297 // Convert to fp 298 copy(baseFp[:], intGetU64(&base)) 299 copy(expFp[:], intGetU64(&exp)) 300 copy(resFpExp[:], intGetU64(&resExp)) 301 302 // Perform modexp with our implementation 303 modExpRdc512(&resFp, &baseFp, &expFp) 304 305 if !eqFp(&resFp, &resFpExp) { 306 test.ReportError(t, resFp, intGetU64(&resExp), base, exp) 307 } 308 } 309 } 310 311 // Test uses Euler's Criterion. 312 func TestIsNonQuadRes(t *testing.T) { 313 var n, nMont big.Int 314 var pm1o2, rawP big.Int 315 var nMontFp fp 316 317 // (p-1)/2 318 pm1o2.SetString("0x32da4747ba07c4dffe455868af1f26255a16841d76e446212d7dfe63499164e6d3d56362b3f9aa83a8b398660f85a792e1390dfa2bd6541a8dc0dc8299e3643d", 0) 319 // modulus value (not in montgomery) 320 rawP.SetString("0x65b48e8f740f89bffc8ab0d15e3e4c4ab42d083aedc88c425afbfcc69322c9cda7aac6c567f35507516730cc1f0b4f25c2721bf457aca8351b81b90533c6c87b", 0) 321 322 // There is 641 quadratic residues in this range 323 for i := uint64(1); i < uint64(numIter); i++ { 324 n.SetUint64(i) 325 n.Exp(&n, &pm1o2, &rawP) 326 // exp == 1 iff n is quadratic non-residue 327 exp := n.Cmp(big.NewInt(1)) 328 if exp < 0 { 329 panic("Should never happen") 330 } 331 332 nMont.SetUint64(i) 333 toMont(&nMont, true) 334 copy(nMontFp[:], intGetU64(&nMont)) 335 ret := nMontFp.isNonQuadRes() 336 337 if ret != exp { 338 toMont(&nMont, false) 339 t.Errorf("Test failed for value %s", nMont.Text(10)) 340 } 341 } 342 } 343 344 func TestCheckSmaller(t *testing.T) { 345 // p-1 346 pMin1 := p 347 pMin1[0]-- 348 349 // p-1 < p => 1 350 if !isLess(&pMin1, &p) { 351 t.Error("pMin1>p") 352 } 353 354 // p < p-1 => 0 355 if isLess(&p, &pMin1) { 356 t.Error("p>pMin1") 357 } 358 359 // p == p => 0 360 if isLess(&p, &p) { 361 t.Error("p==p") 362 } 363 } 364 365 func BenchmarkFp(b *testing.B) { 366 var res, arg1 fp 367 var two64 big.Int 368 two64.SetUint64(1).Lsh(&two64, 64) 369 n, _ := rand.Int(rand.Reader, &two64) 370 u64 := n.Uint64() 371 arg2, arg3 := randomFp(), randomFp() 372 b.Run("sub512", func(b *testing.B) { 373 for n := 0; n < b.N; n++ { 374 sub512(&arg1, &arg2, &arg3) 375 } 376 }) 377 b.Run("mul", func(b *testing.B) { 378 for n := 0; n < b.N; n++ { 379 mul512(&arg2, &arg3, u64) 380 } 381 }) 382 b.Run("cswap", func(b *testing.B) { 383 for n := 0; n < b.N; n++ { 384 cswap512(&arg1, &arg2, uint8(n%2)) 385 } 386 }) 387 b.Run("add", func(b *testing.B) { 388 for n := 0; n < b.N; n++ { 389 addRdc(&res, &arg1, &arg2) 390 } 391 }) 392 b.Run("sub", func(b *testing.B) { 393 for n := 0; n < b.N; n++ { 394 subRdc(&res, &arg1, &arg2) 395 } 396 }) 397 b.Run("mul", func(b *testing.B) { 398 for n := 0; n < b.N; n++ { 399 mulRdc(&res, &arg1, &arg2) 400 } 401 }) 402 b.Run("exp", func(b *testing.B) { 403 for n := 0; n < b.N; n++ { 404 modExpRdc512(&res, &arg1, &arg2) 405 } 406 }) 407 }