]> Cypherpunks repositories - gostls13.git/commitdiff
math/big: speed up GCD x, y calculation
authorBrian Kessler <brian.m.kessler@gmail.com>
Fri, 21 Jul 2017 06:31:51 +0000 (23:31 -0700)
committerRobert Griesemer <gri@golang.org>
Wed, 16 Aug 2017 09:13:12 +0000 (09:13 +0000)
The current implementation of the extended Euclidean GCD algorithm
calculates both cosequences x and y inside the division loop. This
is unneccessary since the second Bezout coefficient can be obtained
at the end of calculation via a multiplication, subtraction and a
division.  In case only one coefficient is needed, e.g. ModInverse
this calculation can be skipped entirely.  This is a standard
optimization, see e.g.

"Handbook of Elliptic and Hyperelliptic Curve Cryptography"
Cohen et al pp 191
Available at:
http://cs.ucsb.edu/~koc/ccs130h/2013/EllipticHyperelliptic-CohenFrey.pdf

Updates #15833

Change-Id: I1e0d2e63567cfed97fd955048fe6373d36f22757
Reviewed-on: https://go-review.googlesource.com/50530
Reviewed-by: Robert Griesemer <gri@golang.org>
src/math/big/int.go

index 62f7fc53203d3642ad39a564a1b37c0e576a9734..52b6423dfe25ee57fec4e5cc80009b42d5121292 100644 (file)
@@ -447,7 +447,7 @@ func (z *Int) Exp(x, y, m *Int) *Int {
 
 // GCD sets z to the greatest common divisor of a and b, which both must
 // be > 0, and returns z.
-// If x and y are not nil, GCD sets x and y such that z = a*x + b*y.
+// If x or y are not nil, GCD sets their value such that z = a*x + b*y.
 // If either a or b is <= 0, GCD sets z = x = y = 0.
 func (z *Int) GCD(x, y, a, b *Int) *Int {
        if a.Sign() <= 0 || b.Sign() <= 0 {
@@ -468,10 +468,7 @@ func (z *Int) GCD(x, y, a, b *Int) *Int {
        B := new(Int).Set(b)
 
        X := new(Int)
-       Y := new(Int).SetInt64(1)
-
        lastX := new(Int).SetInt64(1)
-       lastY := new(Int)
 
        q := new(Int)
        temp := new(Int)
@@ -484,15 +481,8 @@ func (z *Int) GCD(x, y, a, b *Int) *Int {
 
                temp.Set(X)
                X.Mul(X, q)
-               X.neg = !X.neg
-               X.Add(X, lastX)
+               X.Sub(lastX, X)
                lastX.Set(temp)
-
-               temp.Set(Y)
-               Y.Mul(Y, q)
-               Y.neg = !Y.neg
-               Y.Add(Y, lastY)
-               lastY.Set(temp)
        }
 
        if x != nil {
@@ -500,7 +490,10 @@ func (z *Int) GCD(x, y, a, b *Int) *Int {
        }
 
        if y != nil {
-               *y = *lastY
+               // y = (z - a*x)/b
+               y.Mul(a, lastX)
+               y.Sub(A, y)
+               y.Div(y, b)
        }
 
        *z = *A