]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/(ec)dsa: use Fermat's inversion.
authorAdam Langley <agl@golang.org>
Tue, 8 Apr 2014 23:32:48 +0000 (16:32 -0700)
committerAdam Langley <agl@golang.org>
Tue, 8 Apr 2014 23:32:48 +0000 (16:32 -0700)
Now that we have a constant-time P-256 implementation, it's worth
paying more attention elsewhere.

The inversion of k in (EC)DSA was using Euclid's algorithm which isn't
constant-time. This change switches to Fermat's algorithm, which is
much better. However, it's important to note that math/big itself isn't
constant time and is using a 4-bit window for exponentiation with
variable memory access patterns.

(Since math/big depends quite deeply on its values being in minimal (as
opposed to fixed-length) represetation, perhaps crypto/elliptic should
grow a constant-time implementation of exponentiation in the scalar
field.)

R=bradfitz
Fixes #7652.

LGTM=rsc
R=golang-codereviews, bradfitz, rsc
CC=golang-codereviews
https://golang.org/cl/82740043

src/pkg/crypto/dsa/dsa.go
src/pkg/crypto/ecdsa/ecdsa.go

index 5a2a65744ed301e79bbf83653cf9601b6217966f..b7565a61b0293899a9fd8e722f6d66fafb3471eb 100644 (file)
@@ -173,6 +173,16 @@ func GenerateKey(priv *PrivateKey, rand io.Reader) error {
        return nil
 }
 
+// fermatInverse calculates the inverse of k in GF(P) using Fermat's method.
+// This has better constant-time properties than Euclid's method (implemented
+// in math/big.Int.ModInverse) although math/big itself isn't strictly
+// constant-time so it's not perfect.
+func fermatInverse(k, P *big.Int) *big.Int {
+       two := big.NewInt(2)
+       pMinus2 := new(big.Int).Sub(P, two)
+       return new(big.Int).Exp(k, pMinus2, P)
+}
+
 // Sign signs an arbitrary length hash (which should be the result of hashing a
 // larger message) using the private key, priv. It returns the signature as a
 // pair of integers. The security of the private key depends on the entropy of
@@ -205,7 +215,7 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err err
                        }
                }
 
-               kInv := new(big.Int).ModInverse(k, priv.Q)
+               kInv := fermatInverse(k, priv.Q)
 
                r = new(big.Int).Exp(priv.G, k, priv.P)
                r.Mod(r, priv.Q)
index d02f15c34d9ab8eab9f2016e6a011c052eec6211..1bec7437a5368d1a3bf61a5c888dce95e012fbe2 100644 (file)
@@ -84,6 +84,16 @@ func hashToInt(hash []byte, c elliptic.Curve) *big.Int {
        return ret
 }
 
+// fermatInverse calculates the inverse of k in GF(P) using Fermat's method.
+// This has better constant-time properties than Euclid's method (implemented
+// in math/big.Int.ModInverse) although math/big itself isn't strictly
+// constant-time so it's not perfect.
+func fermatInverse(k, N *big.Int) *big.Int {
+       two := big.NewInt(2)
+       nMinus2 := new(big.Int).Sub(N, two)
+       return new(big.Int).Exp(k, nMinus2, N)
+}
+
 // Sign signs an arbitrary length hash (which should be the result of hashing a
 // larger message) using the private key, priv. It returns the signature as a
 // pair of integers. The security of the private key depends on the entropy of
@@ -102,7 +112,7 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err err
                                return
                        }
 
-                       kInv = new(big.Int).ModInverse(k, N)
+                       kInv = fermatInverse(k, N)
                        r, _ = priv.Curve.ScalarBaseMult(k.Bytes())
                        r.Mod(r, N)
                        if r.Sign() != 0 {