]> Cypherpunks repositories - gostls13.git/commitdiff
math/big: handle negative moduli in ModInverse
authorBrian Kessler <brian.m.kessler@gmail.com>
Thu, 19 Apr 2018 15:08:24 +0000 (09:08 -0600)
committerRobert Griesemer <gri@golang.org>
Tue, 1 May 2018 00:04:28 +0000 (00:04 +0000)
Currently, there is no check for a negative modulus in ModInverse.
Negative moduli are passed internally to GCD, which returns 0 for
negative arguments. Mod is symmetric with respect to negative moduli,
so the calculation can be done by just negating the modulus before
passing the arguments to GCD.

Fixes #24949

Change-Id: Ifd1e64c9b2343f0489c04ab65504e73a623378c7
Reviewed-on: https://go-review.googlesource.com/108115
Reviewed-by: Robert Griesemer <gri@golang.org>
Run-TryBot: Robert Griesemer <gri@golang.org>

src/math/big/int.go
src/math/big/int_test.go

index efd3e33bfa9aae399ed1a7c60fe1d51ec95015a5..caebde92fa847a2a88c98da2e9400dd0888de025 100644 (file)
@@ -663,8 +663,12 @@ func (z *Int) Rand(rnd *rand.Rand, n *Int) *Int {
 // inverse in the ring ℤ/nℤ.  In this case, z is unchanged and the return value
 // is nil.
 func (z *Int) ModInverse(g, n *Int) *Int {
+       // GCD expects parameters a and b to be > 0.
+       if n.neg {
+               var n2 Int
+               n = n2.Neg(n)
+       }
        if g.neg {
-               // GCD expects parameters a and b to be > 0.
                var g2 Int
                g = g2.Mod(g, n)
        }
index dd587a8a9edbd0517ea9f4f27cdbe4ed802293b0..b660d535235dc6d750fb445a16d3c14252761c56 100644 (file)
@@ -1409,19 +1409,21 @@ var modInverseTests = []struct {
        {"1234567", "458948883992"},
        {"239487239847", "2410312426921032588552076022197566074856950548502459942654116941958108831682612228890093858261341614673227141477904012196503648957050582631942730706805009223062734745341073406696246014589361659774041027169249453200378729434170325843778659198143763193776859869524088940195577346119843545301547043747207749969763750084308926339295559968882457872412993810129130294592999947926365264059284647209730384947211681434464714438488520940127459844288859336526896320919633919"},
        {"-10", "13"}, // issue #16984
+       {"10", "-13"},
+       {"-17", "-13"},
 }
 
 func TestModInverse(t *testing.T) {
        var element, modulus, gcd, inverse Int
        one := NewInt(1)
-       for i, test := range modInverseTests {
+       for _, test := range modInverseTests {
                (&element).SetString(test.element, 10)
                (&modulus).SetString(test.modulus, 10)
                (&inverse).ModInverse(&element, &modulus)
                (&inverse).Mul(&inverse, &element)
                (&inverse).Mod(&inverse, &modulus)
                if (&inverse).Cmp(one) != 0 {
-                       t.Errorf("#%d: failed (e·e^(-1)=%s)", i, &inverse)
+                       t.Errorf("ModInverse(%d,%d)*%d%%%d=%d, not 1", &element, &modulus, &element, &modulus, &inverse)
                }
        }
        // exhaustive test for small values