aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/math/big/nat.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/math/big/nat.go')
-rw-r--r--libgo/go/math/big/nat.go120
1 files changed, 64 insertions, 56 deletions
diff --git a/libgo/go/math/big/nat.go b/libgo/go/math/big/nat.go
index 6545bc17ed3..79cf6e07f7f 100644
--- a/libgo/go/math/big/nat.go
+++ b/libgo/go/math/big/nat.go
@@ -2,31 +2,11 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package big implements multi-precision arithmetic (big numbers).
-// The following numeric types are supported:
-//
-// Int signed integers
-// Rat rational numbers
-// Float floating-point numbers
-//
-// Methods are typically of the form:
-//
-// func (z *T) Unary(x *T) *T // z = op x
-// func (z *T) Binary(x, y *T) *T // z = x op y
-// func (x *T) M() T1 // v = x.M()
-//
-// with T one of Int, Rat, or Float. For unary and binary operations, the
-// result is the receiver (usually named z in that case); if it is one of
-// the operands x or y it may be overwritten (and its memory reused).
-// To enable chaining of operations, the result is also returned. Methods
-// returning a result other than *Int, *Rat, or *Float take an operand as
-// the receiver (usually named x in that case).
-//
-package big
+// This file implements unsigned multi-precision integers (natural
+// numbers). They are the building blocks for the implementation
+// of signed integers, rationals, and floating-point numbers.
-// This file contains operations on unsigned multi-precision integers.
-// These are the building blocks for the operations on signed integers
-// and rationals.
+package big
import "math/rand"
@@ -216,29 +196,42 @@ func basicMul(z, x, y nat) {
}
}
-// montgomery computes x*y*2^(-n*_W) mod m,
-// assuming k = -1/m mod 2^_W.
+// montgomery computes z mod m = x*y*2**(-n*_W) mod m,
+// assuming k = -1/m mod 2**_W.
// z is used for storing the result which is returned;
// z must not alias x, y or m.
+// See Gueron, "Efficient Software Implementations of Modular Exponentiation".
+// https://eprint.iacr.org/2011/239.pdf
+// In the terminology of that paper, this is an "Almost Montgomery Multiplication":
+// x and y are required to satisfy 0 <= z < 2**(n*_W) and then the result
+// z is guaranteed to satisfy 0 <= z < 2**(n*_W), but it may not be < m.
func (z nat) montgomery(x, y, m nat, k Word, n int) nat {
- var c1, c2 Word
+ // This code assumes x, y, m are all the same length, n.
+ // (required by addMulVVW and the for loop).
+ // It also assumes that x, y are already reduced mod m,
+ // or else the result will not be properly reduced.
+ if len(x) != n || len(y) != n || len(m) != n {
+ panic("math/big: mismatched montgomery number lengths")
+ }
z = z.make(n)
z.clear()
+ var c Word
for i := 0; i < n; i++ {
d := y[i]
- c1 += addMulVVW(z, x, d)
+ c2 := addMulVVW(z, x, d)
t := z[0] * k
- c2 = addMulVVW(z, m, t)
-
+ c3 := addMulVVW(z, m, t)
copy(z, z[1:])
- z[n-1] = c1 + c2
- if z[n-1] < c1 {
- c1 = 1
+ cx := c + c2
+ cy := cx + c3
+ z[n-1] = cy
+ if cx < c2 || cy < c3 {
+ c = 1
} else {
- c1 = 0
+ c = 0
}
}
- if c1 != 0 {
+ if c != 0 {
subVV(z, z, m)
}
return z
@@ -1063,26 +1056,22 @@ func (z nat) expNNWindowed(x, y, m nat) nat {
// expNNMontgomery calculates x**y mod m using a fixed, 4-bit window.
// Uses Montgomery representation.
func (z nat) expNNMontgomery(x, y, m nat) nat {
- var zz, one, rr, RR nat
-
numWords := len(m)
// We want the lengths of x and m to be equal.
+ // It is OK if x >= m as long as len(x) == len(m).
if len(x) > numWords {
- _, rr = rr.div(rr, x, m)
- } else if len(x) < numWords {
- rr = rr.make(numWords)
- rr.clear()
- for i := range x {
- rr[i] = x[i]
- }
- } else {
- rr = x
+ _, x = nat(nil).div(nil, x, m)
+ // Note: now len(x) <= numWords, not guaranteed ==.
+ }
+ if len(x) < numWords {
+ rr := make(nat, numWords)
+ copy(rr, x)
+ x = rr
}
- x = rr
// Ideally the precomputations would be performed outside, and reused
- // k0 = -mˆ-1 mod 2ˆ_W. Algorithm from: Dumas, J.G. "On Newton–Raphson
+ // k0 = -m**-1 mod 2**_W. Algorithm from: Dumas, J.G. "On Newton–Raphson
// Iteration for Multiplicative Inverses Modulo Prime Powers".
k0 := 2 - m[0]
t := m[0] - 1
@@ -1092,9 +1081,9 @@ func (z nat) expNNMontgomery(x, y, m nat) nat {
}
k0 = -k0
- // RR = 2ˆ(2*_W*len(m)) mod m
- RR = RR.setWord(1)
- zz = zz.shl(RR, uint(2*numWords*_W))
+ // RR = 2**(2*_W*len(m)) mod m
+ RR := nat(nil).setWord(1)
+ zz := nat(nil).shl(RR, uint(2*numWords*_W))
_, RR = RR.div(RR, zz, m)
if len(RR) < numWords {
zz = zz.make(numWords)
@@ -1102,8 +1091,7 @@ func (z nat) expNNMontgomery(x, y, m nat) nat {
RR = zz
}
// one = 1, with equal length to that of m
- one = one.make(numWords)
- one.clear()
+ one := make(nat, numWords)
one[0] = 1
const n = 4
@@ -1138,12 +1126,32 @@ func (z nat) expNNMontgomery(x, y, m nat) nat {
}
// convert to regular number
zz = zz.montgomery(z, one, m, k0, numWords)
+
+ // One last reduction, just in case.
+ // See golang.org/issue/13907.
+ if zz.cmp(m) >= 0 {
+ // Common case is m has high bit set; in that case,
+ // since zz is the same length as m, there can be just
+ // one multiple of m to remove. Just subtract.
+ // We think that the subtract should be sufficient in general,
+ // so do that unconditionally, but double-check,
+ // in case our beliefs are wrong.
+ // The div is not expected to be reached.
+ zz = zz.sub(zz, m)
+ if zz.cmp(m) >= 0 {
+ _, zz = nat(nil).div(nil, zz, m)
+ }
+ }
+
return zz.norm()
}
-// probablyPrime performs reps Miller-Rabin tests to check whether n is prime.
-// If it returns true, n is prime with probability 1 - 1/4^reps.
-// If it returns false, n is not prime.
+// probablyPrime performs n Miller-Rabin tests to check whether x is prime.
+// If x is prime, it returns true.
+// If x is not prime, it returns false with probability at least 1 - ¼ⁿ.
+//
+// It is not suitable for judging primes that an adversary may have crafted
+// to fool this test.
func (n nat) probablyPrime(reps int) bool {
if len(n) == 0 {
return false