diff options
author | Ian Lance Taylor <iant@golang.org> | 2018-01-09 01:23:08 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2018-01-09 01:23:08 +0000 |
commit | 1a2f01efa63036a5104f203a4789e682c0e0915d (patch) | |
tree | 373e15778dc8295354584e1f86915ae493b604ff /libgo/go/crypto/elliptic | |
parent | 8799df67f2dab88f9fda11739c501780a85575e2 (diff) | |
download | gcc-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.go | 11 | ||||
-rw-r--r-- | libgo/go/crypto/elliptic/elliptic_test.go | 129 | ||||
-rw-r--r-- | libgo/go/crypto/elliptic/p256_amd64.go | 64 | ||||
-rw-r--r-- | libgo/go/crypto/elliptic/p256_s390x.go | 49 |
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) |