Skip to content

Commit

Permalink
crypto/(ec)dsa: use Fermat's inversion.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
agl committed Apr 8, 2014
1 parent c5f14c5 commit f23d3ea
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 2 deletions.
12 changes: 11 additions & 1 deletion src/pkg/crypto/dsa/dsa.go
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
12 changes: 11 additions & 1 deletion src/pkg/crypto/ecdsa/ecdsa.go
Expand Up @@ -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
Expand All @@ -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 {
Expand Down

0 comments on commit f23d3ea

Please sign in to comment.