1
0
mirror of https://github.com/golang/go synced 2024-09-24 05:10:13 -06:00

crypto/elliptic: upgrade from generic curve impl to specific if available

This change alters the CurveParam methods to upgrade from the generic
curve implementation to the specific P224 or P256 implementations when
called on the embedded CurveParams. This removes the trap of using
elliptic.P224().Params() instead of elliptic.P224(), for example, which
results in using the generic implementation instead of the optimized
constant time one. For P224 this is done for all of the CurveParams
methods, except Params, as the optimized implementation covers all
these methods. For P256 this is only done for ScalarMult and
ScalarBaseMult, as despite having implementations of addition and
doubling they aren't exposed and instead the generic implementation is
used. For P256 an additional check that there actually is a specific
implementation is added, as unlike the P224 implementation the P256 one
is only available on certain platforms.

This change takes the simple, fast approach to checking this, it simply
compares pointers. This removes the most obvious class of mistakes
people make, but still allows edge cases where the embedded CurveParams
pointer has been dereferenced (as seen in the unit tests) or when someone
has manually constructed their own CurveParams that matches one of the
standard curves. A more complex approach could be taken to also address
these cases, but it would require directly comparing all of the
CurveParam fields which would, in the worst case, require comparing
against two standard CurveParam sets in the ScalarMult and
ScalarBaseMult paths, which are likely to be the hottest already.

Updates #34648

Change-Id: I82d752f979260394632905c15ffe4f65f4ffa376
Reviewed-on: https://go-review.googlesource.com/c/go/+/233939
Trust: Roland Shoemaker <roland@golang.org>
Trust: Katie Hockman <katie@golang.org>
Run-TryBot: Roland Shoemaker <roland@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Katie Hockman <katie@golang.org>
This commit is contained in:
Roland Shoemaker 2020-05-13 18:24:16 -07:00
parent 73d5aef4d1
commit dc50683bf7
4 changed files with 55 additions and 10 deletions

View File

@ -40,6 +40,15 @@ type Curve interface {
ScalarBaseMult(k []byte) (x, y *big.Int)
}
func matchesSpecificCurve(params *CurveParams, available ...Curve) (Curve, bool) {
for _, c := range available {
if params == c.Params() {
return c, true
}
}
return nil, false
}
// CurveParams contains the parameters of an elliptic curve and also provides
// a generic, non-constant time implementation of Curve.
type CurveParams struct {
@ -71,6 +80,12 @@ func (curve *CurveParams) polynomial(x *big.Int) *big.Int {
}
func (curve *CurveParams) IsOnCurve(x, y *big.Int) bool {
// If there is a dedicated constant-time implementation for this curve operation,
// use that instead of the generic one.
if specific, ok := matchesSpecificCurve(curve, p224, p521); ok {
return specific.IsOnCurve(x, y)
}
// y² = x³ - 3x + b
y2 := new(big.Int).Mul(y, y)
y2.Mod(y2, curve.P)
@ -108,6 +123,12 @@ func (curve *CurveParams) affineFromJacobian(x, y, z *big.Int) (xOut, yOut *big.
}
func (curve *CurveParams) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
// If there is a dedicated constant-time implementation for this curve operation,
// use that instead of the generic one.
if specific, ok := matchesSpecificCurve(curve, p224, p521); ok {
return specific.Add(x1, y1, x2, y2)
}
z1 := zForAffine(x1, y1)
z2 := zForAffine(x2, y2)
return curve.affineFromJacobian(curve.addJacobian(x1, y1, z1, x2, y2, z2))
@ -192,6 +213,12 @@ func (curve *CurveParams) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int
}
func (curve *CurveParams) Double(x1, y1 *big.Int) (*big.Int, *big.Int) {
// If there is a dedicated constant-time implementation for this curve operation,
// use that instead of the generic one.
if specific, ok := matchesSpecificCurve(curve, p224, p521); ok {
return specific.Double(x1, y1)
}
z1 := zForAffine(x1, y1)
return curve.affineFromJacobian(curve.doubleJacobian(x1, y1, z1))
}
@ -258,6 +285,12 @@ func (curve *CurveParams) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int,
}
func (curve *CurveParams) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) {
// If there is a dedicated constant-time implementation for this curve operation,
// use that instead of the generic one.
if specific, ok := matchesSpecificCurve(curve, p224, p256, p521); ok {
return specific.ScalarMult(Bx, By, k)
}
Bz := new(big.Int).SetInt64(1)
x, y, z := new(big.Int), new(big.Int), new(big.Int)
@ -275,6 +308,12 @@ func (curve *CurveParams) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.
}
func (curve *CurveParams) ScalarBaseMult(k []byte) (*big.Int, *big.Int) {
// If there is a dedicated constant-time implementation for this curve operation,
// use that instead of the generic one.
if specific, ok := matchesSpecificCurve(curve, p224, p256, p521); ok {
return specific.ScalarBaseMult(k)
}
return curve.ScalarMult(curve.Gx, curve.Gy, k)
}

View File

@ -12,19 +12,29 @@ import (
"testing"
)
// genericParamsForCurve returns the dereferenced CurveParams for
// the specified curve. This is used to avoid the logic for
// upgrading a curve to it's specific implementation, forcing
// usage of the generic implementation. This is only relevant
// for the P224, P256, and P521 curves.
func genericParamsForCurve(c Curve) *CurveParams {
d := *(c.Params())
return &d
}
func testAllCurves(t *testing.T, f func(*testing.T, Curve)) {
tests := []struct {
name string
curve Curve
}{
{"P256", P256()},
{"P256/Params", P256().Params()},
{"P256/Params", genericParamsForCurve(P256())},
{"P224", P224()},
{"P224/Params", P224().Params()},
{"P224/Params", genericParamsForCurve(P224())},
{"P384", P384()},
{"P384/Params", P384().Params()},
{"P384/Params", genericParamsForCurve(P384())},
{"P521", P521()},
{"P521/Params", P521().Params()},
{"P521/Params", genericParamsForCurve(P521())},
}
if testing.Short() {
tests = tests[:1]

View File

@ -29,9 +29,7 @@ type (
}
)
var (
p256 p256Curve
)
var p256 p256Curve
func initP256() {
// See FIPS 186-3, section D.2.3

View File

@ -7,9 +7,7 @@
package elliptic
var (
p256 p256Curve
)
var p256 p256Curve
func initP256Arch() {
// Use pure Go implementation.