aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/crypto/elliptic
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2018-01-09 01:23:08 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2018-01-09 01:23:08 +0000
commit1a2f01efa63036a5104f203a4789e682c0e0915d (patch)
tree373e15778dc8295354584e1f86915ae493b604ff /libgo/go/crypto/elliptic
parent8799df67f2dab88f9fda11739c501780a85575e2 (diff)
downloadgcc-1a2f01efa63036a5104f203a4789e682c0e0915d.zip
gcc-1a2f01efa63036a5104f203a4789e682c0e0915d.tar.gz
gcc-1a2f01efa63036a5104f203a4789e682c0e0915d.tar.bz2
libgo: update to Go1.10beta1
Update the Go library to the 1.10beta1 release. Requires a few changes to the compiler for modifications to the map runtime code, and to handle some nowritebarrier cases in the runtime. Reviewed-on: https://go-review.googlesource.com/86455 gotools/: * Makefile.am (go_cmd_vet_files): New variable. (go_cmd_buildid_files, go_cmd_test2json_files): New variables. (s-zdefaultcc): Change from constants to functions. (noinst_PROGRAMS): Add vet, buildid, and test2json. (cgo$(EXEEXT)): Link against $(LIBGOTOOL). (vet$(EXEEXT)): New target. (buildid$(EXEEXT)): New target. (test2json$(EXEEXT)): New target. (install-exec-local): Install all $(noinst_PROGRAMS). (uninstall-local): Uninstasll all $(noinst_PROGRAMS). (check-go-tool): Depend on $(noinst_PROGRAMS). Copy down objabi.go. (check-runtime): Depend on $(noinst_PROGRAMS). (check-cgo-test, check-carchive-test): Likewise. (check-vet): New target. (check): Depend on check-vet. Look at cmd_vet-testlog. (.PHONY): Add check-vet. * Makefile.in: Rebuild. From-SVN: r256365
Diffstat (limited to 'libgo/go/crypto/elliptic')
-rw-r--r--libgo/go/crypto/elliptic/elliptic.go11
-rw-r--r--libgo/go/crypto/elliptic/elliptic_test.go129
-rw-r--r--libgo/go/crypto/elliptic/p256_amd64.go64
-rw-r--r--libgo/go/crypto/elliptic/p256_s390x.go49
4 files changed, 233 insertions, 20 deletions
diff --git a/libgo/go/crypto/elliptic/elliptic.go b/libgo/go/crypto/elliptic/elliptic.go
index d352724..35aacf2 100644
--- a/libgo/go/crypto/elliptic/elliptic.go
+++ b/libgo/go/crypto/elliptic/elliptic.go
@@ -301,7 +301,7 @@ func GenerateKey(curve Curve, rand io.Reader) (priv []byte, x, y *big.Int, err e
return
}
-// Marshal converts a point into the form specified in section 4.3.6 of ANSI X9.62.
+// Marshal converts a point into the uncompressed form specified in section 4.3.6 of ANSI X9.62.
func Marshal(curve Curve, x, y *big.Int) []byte {
byteLen := (curve.Params().BitSize + 7) >> 3
@@ -316,7 +316,8 @@ func Marshal(curve Curve, x, y *big.Int) []byte {
}
// Unmarshal converts a point, serialized by Marshal, into an x, y pair.
-// It is an error if the point is not on the curve. On error, x = nil.
+// It is an error if the point is not in uncompressed form or is not on the curve.
+// On error, x = nil.
func Unmarshal(curve Curve, data []byte) (x, y *big.Int) {
byteLen := (curve.Params().BitSize + 7) >> 3
if len(data) != 1+2*byteLen {
@@ -325,10 +326,14 @@ func Unmarshal(curve Curve, data []byte) (x, y *big.Int) {
if data[0] != 4 { // uncompressed form
return
}
+ p := curve.Params().P
x = new(big.Int).SetBytes(data[1 : 1+byteLen])
y = new(big.Int).SetBytes(data[1+byteLen:])
+ if x.Cmp(p) >= 0 || y.Cmp(p) >= 0 {
+ return nil, nil
+ }
if !curve.IsOnCurve(x, y) {
- x, y = nil, nil
+ return nil, nil
}
return
}
diff --git a/libgo/go/crypto/elliptic/elliptic_test.go b/libgo/go/crypto/elliptic/elliptic_test.go
index c3e4c17..f661359 100644
--- a/libgo/go/crypto/elliptic/elliptic_test.go
+++ b/libgo/go/crypto/elliptic/elliptic_test.go
@@ -455,15 +455,81 @@ func TestInfinity(t *testing.T) {
}
}
+type synthCombinedMult struct {
+ Curve
+}
+
+func (s synthCombinedMult) CombinedMult(bigX, bigY *big.Int, baseScalar, scalar []byte) (x, y *big.Int) {
+ x1, y1 := s.ScalarBaseMult(baseScalar)
+ x2, y2 := s.ScalarMult(bigX, bigY, scalar)
+ return s.Add(x1, y1, x2, y2)
+}
+
+func TestCombinedMult(t *testing.T) {
+ type combinedMult interface {
+ Curve
+ CombinedMult(bigX, bigY *big.Int, baseScalar, scalar []byte) (x, y *big.Int)
+ }
+
+ p256, ok := P256().(combinedMult)
+ if !ok {
+ p256 = &synthCombinedMult{P256()}
+ }
+
+ gx := p256.Params().Gx
+ gy := p256.Params().Gy
+
+ zero := make([]byte, 32)
+ one := make([]byte, 32)
+ one[31] = 1
+ two := make([]byte, 32)
+ two[31] = 2
+
+ // 0×G + 0×G = ∞
+ x, y := p256.CombinedMult(gx, gy, zero, zero)
+ if x.Sign() != 0 || y.Sign() != 0 {
+ t.Errorf("0×G + 0×G = (%d, %d), should be ∞", x, y)
+ }
+
+ // 1×G + 0×G = G
+ x, y = p256.CombinedMult(gx, gy, one, zero)
+ if x.Cmp(gx) != 0 || y.Cmp(gy) != 0 {
+ t.Errorf("1×G + 0×G = (%d, %d), should be (%d, %d)", x, y, gx, gy)
+ }
+
+ // 0×G + 1×G = G
+ x, y = p256.CombinedMult(gx, gy, zero, one)
+ if x.Cmp(gx) != 0 || y.Cmp(gy) != 0 {
+ t.Errorf("0×G + 1×G = (%d, %d), should be (%d, %d)", x, y, gx, gy)
+ }
+
+ // 1×G + 1×G = 2×G
+ x, y = p256.CombinedMult(gx, gy, one, one)
+ ggx, ggy := p256.ScalarBaseMult(two)
+ if x.Cmp(ggx) != 0 || y.Cmp(ggy) != 0 {
+ t.Errorf("1×G + 1×G = (%d, %d), should be (%d, %d)", x, y, ggx, ggy)
+ }
+
+ minusOne := new(big.Int).Sub(p256.Params().N, big.NewInt(1))
+ // 1×G + (-1)×G = ∞
+ x, y = p256.CombinedMult(gx, gy, one, minusOne.Bytes())
+ if x.Sign() != 0 || y.Sign() != 0 {
+ t.Errorf("1×G + (-1)×G = (%d, %d), should be ∞", x, y)
+ }
+}
+
func BenchmarkBaseMult(b *testing.B) {
b.ResetTimer()
p224 := P224()
e := p224BaseMultTests[25]
k, _ := new(big.Int).SetString(e.k, 10)
+ b.ReportAllocs()
b.StartTimer()
- for i := 0; i < b.N; i++ {
- p224.ScalarBaseMult(k.Bytes())
- }
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ p224.ScalarBaseMult(k.Bytes())
+ }
+ })
}
func BenchmarkBaseMultP256(b *testing.B) {
@@ -471,10 +537,13 @@ func BenchmarkBaseMultP256(b *testing.B) {
p256 := P256()
e := p224BaseMultTests[25]
k, _ := new(big.Int).SetString(e.k, 10)
+ b.ReportAllocs()
b.StartTimer()
- for i := 0; i < b.N; i++ {
- p256.ScalarBaseMult(k.Bytes())
- }
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ p256.ScalarBaseMult(k.Bytes())
+ }
+ })
}
func BenchmarkScalarMultP256(b *testing.B) {
@@ -483,10 +552,13 @@ func BenchmarkScalarMultP256(b *testing.B) {
_, x, y, _ := GenerateKey(p256, rand.Reader)
priv, _, _, _ := GenerateKey(p256, rand.Reader)
+ b.ReportAllocs()
b.StartTimer()
- for i := 0; i < b.N; i++ {
- p256.ScalarMult(x, y, priv)
- }
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ p256.ScalarMult(x, y, priv)
+ }
+ })
}
func TestMarshal(t *testing.T) {
@@ -517,3 +589,42 @@ func TestP224Overflow(t *testing.T) {
t.Error("P224 failed to validate a correct point")
}
}
+
+// See https://golang.org/issues/20482
+func TestUnmarshalToLargeCoordinates(t *testing.T) {
+ curve := P256()
+ p := curve.Params().P
+
+ invalidX, invalidY := make([]byte, 65), make([]byte, 65)
+ invalidX[0], invalidY[0] = 4, 4 // uncompressed encoding
+
+ // Set x to be greater than curve's parameter P – specifically, to P+5.
+ // Set y to mod_sqrt(x^3 - 3x + B)) so that (x mod P = 5 , y) is on the
+ // curve.
+ x := new(big.Int).Add(p, big.NewInt(5))
+ y, _ := new(big.Int).SetString("31468013646237722594854082025316614106172411895747863909393730389177298123724", 10)
+
+ copy(invalidX[1:], x.Bytes())
+ copy(invalidX[33:], y.Bytes())
+
+ if X, Y := Unmarshal(curve, invalidX); X != nil || Y != nil {
+ t.Errorf("Unmarshal accpets invalid X coordinate")
+ }
+
+ // This is a point on the curve with a small y value, small enough that we can add p and still be within 32 bytes.
+ x, _ = new(big.Int).SetString("31931927535157963707678568152204072984517581467226068221761862915403492091210", 10)
+ y, _ = new(big.Int).SetString("5208467867388784005506817585327037698770365050895731383201516607147", 10)
+ y.Add(y, p)
+
+ if p.Cmp(y) > 0 || y.BitLen() != 256 {
+ t.Fatal("y not within expected range")
+ }
+
+ // marshal
+ copy(invalidY[1:], x.Bytes())
+ copy(invalidY[33:], y.Bytes())
+
+ if X, Y := Unmarshal(curve, invalidY); X != nil || Y != nil {
+ t.Errorf("Unmarshal accpets invalid Y coordinate")
+ }
+}
diff --git a/libgo/go/crypto/elliptic/p256_amd64.go b/libgo/go/crypto/elliptic/p256_amd64.go
index 8f3db07..f108e73 100644
--- a/libgo/go/crypto/elliptic/p256_amd64.go
+++ b/libgo/go/crypto/elliptic/p256_amd64.go
@@ -53,44 +53,62 @@ func (curve p256Curve) Params() *CurveParams {
// Functions implemented in p256_asm_amd64.s
// Montgomery multiplication modulo P256
+//go:noescape
func p256Mul(res, in1, in2 []uint64)
// Montgomery square modulo P256
+//go:noescape
func p256Sqr(res, in []uint64)
// Montgomery multiplication by 1
+//go:noescape
func p256FromMont(res, in []uint64)
// iff cond == 1 val <- -val
+//go:noescape
func p256NegCond(val []uint64, cond int)
// if cond == 0 res <- b; else res <- a
+//go:noescape
func p256MovCond(res, a, b []uint64, cond int)
// Endianness swap
+//go:noescape
func p256BigToLittle(res []uint64, in []byte)
+
+//go:noescape
func p256LittleToBig(res []byte, in []uint64)
// Constant time table access
+//go:noescape
func p256Select(point, table []uint64, idx int)
+
+//go:noescape
func p256SelectBase(point, table []uint64, idx int)
// Montgomery multiplication modulo Ord(G)
+//go:noescape
func p256OrdMul(res, in1, in2 []uint64)
// Montgomery square modulo Ord(G), repeated n times
+//go:noescape
func p256OrdSqr(res, in []uint64, n int)
// Point add with in2 being affine point
// If sign == 1 -> in2 = -in2
// If sel == 0 -> res = in1
// if zero == 0 -> res = in2
+//go:noescape
func p256PointAddAffineAsm(res, in1, in2 []uint64, sign, sel, zero int)
-// Point add
-func p256PointAddAsm(res, in1, in2 []uint64)
+// Point add. Returns one if the two input points were equal and zero
+// otherwise. (Note that, due to the way that the equations work out, some
+// representations of ∞ are considered equal to everything by this function.)
+//go:noescape
+func p256PointAddAsm(res, in1, in2 []uint64) int
// Point double
+//go:noescape
func p256PointDoubleAsm(res, in []uint64)
func (curve p256Curve) Inverse(k *big.Int) *big.Int {
@@ -214,9 +232,11 @@ func (curve p256Curve) CombinedMult(bigX, bigY *big.Int, baseScalar, scalar []by
scalarReversed := make([]uint64, 4)
var r1, r2 p256Point
p256GetScalar(scalarReversed, baseScalar)
+ r1IsInfinity := scalarIsZero(scalarReversed)
r1.p256BaseMult(scalarReversed)
p256GetScalar(scalarReversed, scalar)
+ r2IsInfinity := scalarIsZero(scalarReversed)
fromBig(r2.xyz[0:4], maybeReduceModP(bigX))
fromBig(r2.xyz[4:8], maybeReduceModP(bigY))
p256Mul(r2.xyz[0:4], r2.xyz[0:4], rr[:])
@@ -229,8 +249,15 @@ func (curve p256Curve) CombinedMult(bigX, bigY *big.Int, baseScalar, scalar []by
r2.xyz[11] = 0x00000000fffffffe
r2.p256ScalarMult(scalarReversed)
- p256PointAddAsm(r1.xyz[:], r1.xyz[:], r2.xyz[:])
- return r1.p256PointToAffine()
+
+ var sum, double p256Point
+ pointsEqual := p256PointAddAsm(sum.xyz[:], r1.xyz[:], r2.xyz[:])
+ p256PointDoubleAsm(double.xyz[:], r1.xyz[:])
+ sum.CopyConditional(&double, pointsEqual)
+ sum.CopyConditional(&r1, r2IsInfinity)
+ sum.CopyConditional(&r2, r1IsInfinity)
+
+ return sum.p256PointToAffine()
}
func (curve p256Curve) ScalarBaseMult(scalar []byte) (x, y *big.Int) {
@@ -261,6 +288,24 @@ func (curve p256Curve) ScalarMult(bigX, bigY *big.Int, scalar []byte) (x, y *big
return r.p256PointToAffine()
}
+// uint64IsZero returns 1 if x is zero and zero otherwise.
+func uint64IsZero(x uint64) int {
+ x = ^x
+ x &= x >> 32
+ x &= x >> 16
+ x &= x >> 8
+ x &= x >> 4
+ x &= x >> 2
+ x &= x >> 1
+ return int(x & 1)
+}
+
+// scalarIsZero returns 1 if scalar represents the zero value, and zero
+// otherwise.
+func scalarIsZero(scalar []uint64) int {
+ return uint64IsZero(scalar[0] | scalar[1] | scalar[2] | scalar[3])
+}
+
func (p *p256Point) p256PointToAffine() (x, y *big.Int) {
zInv := make([]uint64, 4)
zInvSq := make([]uint64, 4)
@@ -282,6 +327,17 @@ func (p *p256Point) p256PointToAffine() (x, y *big.Int) {
return new(big.Int).SetBytes(xOut), new(big.Int).SetBytes(yOut)
}
+// CopyConditional copies overwrites p with src if v == 1, and leaves p
+// unchanged if v == 0.
+func (p *p256Point) CopyConditional(src *p256Point, v int) {
+ pMask := uint64(v) - 1
+ srcMask := ^pMask
+
+ for i, n := range p.xyz {
+ p.xyz[i] = (n & pMask) | (src.xyz[i] & srcMask)
+ }
+}
+
// p256Inverse sets out to in^-1 mod p.
func p256Inverse(out, in []uint64) {
var stack [6 * 4]uint64
diff --git a/libgo/go/crypto/elliptic/p256_s390x.go b/libgo/go/crypto/elliptic/p256_s390x.go
index 5f99e71..43e19e9 100644
--- a/libgo/go/crypto/elliptic/p256_s390x.go
+++ b/libgo/go/crypto/elliptic/p256_s390x.go
@@ -8,6 +8,7 @@
package elliptic
import (
+ "crypto/subtle"
"math/big"
)
@@ -50,6 +51,8 @@ func (curve p256CurveFast) Params() *CurveParams {
// Functions implemented in p256_asm_s390x.s
// Montgomery multiplication modulo P256
+//
+//go:noescape
func p256MulAsm(res, in1, in2 []byte)
// Montgomery square modulo P256
@@ -58,19 +61,31 @@ func p256Sqr(res, in []byte) {
}
// Montgomery multiplication by 1
+//
+//go:noescape
func p256FromMont(res, in []byte)
// iff cond == 1 val <- -val
+//
+//go:noescape
func p256NegCond(val *p256Point, cond int)
// if cond == 0 res <- b; else res <- a
+//
+//go:noescape
func p256MovCond(res, a, b *p256Point, cond int)
// Constant time table access
+//
+//go:noescape
func p256Select(point *p256Point, table []p256Point, idx int)
+
+//go:noescape
func p256SelectBase(point *p256Point, table []p256Point, idx int)
// Montgomery multiplication modulo Ord(G)
+//
+//go:noescape
func p256OrdMul(res, in1, in2 []byte)
// Montgomery square modulo Ord(G), repeated n times
@@ -85,10 +100,16 @@ func p256OrdSqr(res, in []byte, n int) {
// If sign == 1 -> P2 = -P2
// If sel == 0 -> P3 = P1
// if zero == 0 -> P3 = P2
+//
+//go:noescape
func p256PointAddAffineAsm(P3, P1, P2 *p256Point, sign, sel, zero int)
// Point add
-func p256PointAddAsm(P3, P1, P2 *p256Point)
+//
+//go:noescape
+func p256PointAddAsm(P3, P1, P2 *p256Point) int
+
+//go:noescape
func p256PointDoubleAsm(P3, P1 *p256Point)
func (curve p256CurveFast) Inverse(k *big.Int) *big.Int {
@@ -203,7 +224,9 @@ func maybeReduceModP(in *big.Int) *big.Int {
func (curve p256CurveFast) CombinedMult(bigX, bigY *big.Int, baseScalar, scalar []byte) (x, y *big.Int) {
var r1, r2 p256Point
- r1.p256BaseMult(p256GetMultiplier(baseScalar))
+ scalarReduced := p256GetMultiplier(baseScalar)
+ r1IsInfinity := scalarIsZero(scalarReduced)
+ r1.p256BaseMult(scalarReduced)
copy(r2.x[:], fromBig(maybeReduceModP(bigX)))
copy(r2.y[:], fromBig(maybeReduceModP(bigY)))
@@ -211,9 +234,17 @@ func (curve p256CurveFast) CombinedMult(bigX, bigY *big.Int, baseScalar, scalar
p256MulAsm(r2.x[:], r2.x[:], rr[:])
p256MulAsm(r2.y[:], r2.y[:], rr[:])
+ scalarReduced = p256GetMultiplier(scalar)
+ r2IsInfinity := scalarIsZero(scalarReduced)
r2.p256ScalarMult(p256GetMultiplier(scalar))
- p256PointAddAsm(&r1, &r1, &r2)
- return r1.p256PointToAffine()
+
+ var sum, double p256Point
+ pointsEqual := p256PointAddAsm(&sum, &r1, &r2)
+ p256PointDoubleAsm(&double, &r1)
+ p256MovCond(&sum, &double, &sum, pointsEqual)
+ p256MovCond(&sum, &r1, &sum, r2IsInfinity)
+ p256MovCond(&sum, &r2, &sum, r1IsInfinity)
+ return sum.p256PointToAffine()
}
func (curve p256CurveFast) ScalarBaseMult(scalar []byte) (x, y *big.Int) {
@@ -233,6 +264,16 @@ func (curve p256CurveFast) ScalarMult(bigX, bigY *big.Int, scalar []byte) (x, y
return r.p256PointToAffine()
}
+// scalarIsZero returns 1 if scalar represents the zero value, and zero
+// otherwise.
+func scalarIsZero(scalar []byte) int {
+ b := byte(0)
+ for _, s := range scalar {
+ b |= s
+ }
+ return subtle.ConstantTimeByteEq(b, 0)
+}
+
func (p *p256Point) p256PointToAffine() (x, y *big.Int) {
zInv := make([]byte, 32)
zInvSq := make([]byte, 32)