@@ -380,6 +380,82 @@ proc main() =
380
380
doAssert pow(zero, 0 ) == one
381
381
doAssert pow(zero, 1 ) == zero
382
382
383
+ block : # invmod
384
+ # with prime modulus
385
+ let a = " 30292868" .initBigInt
386
+ let b = " 48810860" .initBigInt
387
+ let p = " 60449131" .initBigInt # p is prime
388
+ doAssert invmod(a, p) == " 51713091" .initBigInt
389
+ doAssert invmod(- b, p) == " 31975542" .initBigInt
390
+ # with composite modulus
391
+ let c = " 2472018" .initBigInt
392
+ let n = " 3917515" .initBigInt # 5 * 7 * 19 * 43 * 137
393
+ let d = " 1831482" .initBigInt
394
+ let e = " 2502552" .initBigInt
395
+ let f = " 2086033" .initBigInt
396
+ let h = " 1414963" .initBigInt
397
+ doAssert invmod(c, n) == " 2622632" .initBigInt
398
+ doAssert invmod(one, n) == one
399
+ doAssert invmod(n- one, n) == n- one
400
+
401
+ doAssert invmod( d, n) == h
402
+ doAssert invmod(- d, n) == e
403
+ doAssert invmod( f, n) == e
404
+ doAssert invmod(- f, n) == h
405
+ doAssert invmod( e, n) == f
406
+ doAssert invmod(- e, n) == d
407
+ doAssert invmod( h, n) == d
408
+ doAssert invmod(- h, n) == f
409
+
410
+ doAssertRaises(DivByZeroDefect): discard invmod(zero, n)
411
+ doAssertRaises(DivByZeroDefect): discard invmod(one, zero)
412
+ doAssertRaises(ValueError): discard invmod(one, - 7 .initBigInt)
413
+ doAssertRaises(ValueError): discard invmod(3 .initBigInt, 18 .initBigInt) # 3 is not invertible since gcd(3, 18) = 3 != 1
414
+
415
+ block : # powmod
416
+ let a = " 30292868" .initBigInt
417
+ let p = " 60449131" .initBigInt # p is prime
418
+ let two = 2 .initBigInt
419
+ doAssert powmod(a, two, p) == " 25760702" .initBigInt
420
+ # Fermat's little theorem: a^p ≡ a mod p
421
+ doAssert powmod(a, p, p) == a
422
+ # Euler's identity a^(p-1) \equiv 1 \bmod p
423
+ doAssert powmod(a, p - one, p) == one
424
+ # We can invert a using Euler's identity / Fermat's little theorem
425
+ doAssert powmod(a, p - two, p) == " 51713091" .initBigInt
426
+ # We can reduce the exponent modulo phi(p) = p - 1, since p is prime
427
+ doAssert powmod(a, 2 .initBigInt* p, p) == (a * a mod p)
428
+
429
+ let p2 = 761 .initBigInt
430
+ var a2 = 1 .initBigInt
431
+ # Fermat's little theorem: a^p ≡ a mod p
432
+ while a2 < p2:
433
+ doAssert powmod(a2, p2, p2) == a2
434
+ a2.inc
435
+
436
+ block : # Composite modulus
437
+ let a = " 2472018" .initBigInt
438
+ let n = " 3917515" .initBigInt # 5 * 7 * 19 * 43 * 137
439
+ let euler_phi = " 2467584" .initBigInt
440
+ doAssert powmod(a, 52 .initBigInt, n) == " 2305846" .initBigInt
441
+ doAssert powmod(a, euler_phi, n) == one
442
+ # Edge cases
443
+ doAssert powmod(a, one, n) == a
444
+ doAssert powmod(a, zero, n) == one
445
+ doAssert powmod(zero, zero, n) == one
446
+ doAssert powmod(zero, one, n) == zero
447
+
448
+ block : # powmod with negative base
449
+ let a = " 1986599" .initBigInt
450
+ let p = " 10230581" .initBigInt
451
+ doAssert powmod(- a, 2 .initBigInt, p) == " 6199079" .initBigInt
452
+
453
+ block : # powmod with negative exponent
454
+ let a = " 1912" .initBigInt
455
+ let p = " 5297" .initBigInt
456
+ doAssert powmod(a, - 1 .initBigInt, p) == " 1460" .initBigInt
457
+ doAssert powmod(a, one- p, p) == one
458
+
383
459
block : # div/mod
384
460
doAssertRaises(DivByZeroDefect): discard one div zero
385
461
doAssertRaises(DivByZeroDefect): discard one mod zero
@@ -455,6 +531,5 @@ proc main() =
455
531
doAssert pred(a, 3 ) == initBigInt(4 )
456
532
doAssert succ(a, 3 ) == initBigInt(10 )
457
533
458
-
459
534
static : main()
460
535
main()
0 commit comments