mirror of https://github.com/golang/go.git
math/big: handle negative moduli in ModInverse
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>
This commit is contained in:
parent
4d44a87243
commit
6f7ec484f6
|
|
@ -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
|
// inverse in the ring ℤ/nℤ. In this case, z is unchanged and the return value
|
||||||
// is nil.
|
// is nil.
|
||||||
func (z *Int) ModInverse(g, n *Int) *Int {
|
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 {
|
if g.neg {
|
||||||
// GCD expects parameters a and b to be > 0.
|
|
||||||
var g2 Int
|
var g2 Int
|
||||||
g = g2.Mod(g, n)
|
g = g2.Mod(g, n)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1409,19 +1409,21 @@ var modInverseTests = []struct {
|
||||||
{"1234567", "458948883992"},
|
{"1234567", "458948883992"},
|
||||||
{"239487239847", "2410312426921032588552076022197566074856950548502459942654116941958108831682612228890093858261341614673227141477904012196503648957050582631942730706805009223062734745341073406696246014589361659774041027169249453200378729434170325843778659198143763193776859869524088940195577346119843545301547043747207749969763750084308926339295559968882457872412993810129130294592999947926365264059284647209730384947211681434464714438488520940127459844288859336526896320919633919"},
|
{"239487239847", "2410312426921032588552076022197566074856950548502459942654116941958108831682612228890093858261341614673227141477904012196503648957050582631942730706805009223062734745341073406696246014589361659774041027169249453200378729434170325843778659198143763193776859869524088940195577346119843545301547043747207749969763750084308926339295559968882457872412993810129130294592999947926365264059284647209730384947211681434464714438488520940127459844288859336526896320919633919"},
|
||||||
{"-10", "13"}, // issue #16984
|
{"-10", "13"}, // issue #16984
|
||||||
|
{"10", "-13"},
|
||||||
|
{"-17", "-13"},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestModInverse(t *testing.T) {
|
func TestModInverse(t *testing.T) {
|
||||||
var element, modulus, gcd, inverse Int
|
var element, modulus, gcd, inverse Int
|
||||||
one := NewInt(1)
|
one := NewInt(1)
|
||||||
for i, test := range modInverseTests {
|
for _, test := range modInverseTests {
|
||||||
(&element).SetString(test.element, 10)
|
(&element).SetString(test.element, 10)
|
||||||
(&modulus).SetString(test.modulus, 10)
|
(&modulus).SetString(test.modulus, 10)
|
||||||
(&inverse).ModInverse(&element, &modulus)
|
(&inverse).ModInverse(&element, &modulus)
|
||||||
(&inverse).Mul(&inverse, &element)
|
(&inverse).Mul(&inverse, &element)
|
||||||
(&inverse).Mod(&inverse, &modulus)
|
(&inverse).Mod(&inverse, &modulus)
|
||||||
if (&inverse).Cmp(one) != 0 {
|
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
|
// exhaustive test for small values
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue