go/src/crypto/ecdsa/ecdsa_test.go

368 lines
8.1 KiB
Go
Raw Normal View History

// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ecdsa
import (
"bufio"
"compress/bzip2"
"crypto/elliptic"
"crypto/rand"
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"encoding/hex"
"hash"
"io"
"math/big"
"os"
"strings"
"testing"
)
func testKeyGeneration(t *testing.T, c elliptic.Curve, tag string) {
priv, err := GenerateKey(c, rand.Reader)
if err != nil {
t.Errorf("%s: error: %s", tag, err)
return
}
if !c.IsOnCurve(priv.PublicKey.X, priv.PublicKey.Y) {
t.Errorf("%s: public key invalid: %s", tag, err)
}
}
func TestKeyGeneration(t *testing.T) {
testKeyGeneration(t, elliptic.P224(), "p224")
if testing.Short() {
return
}
testKeyGeneration(t, elliptic.P256(), "p256")
testKeyGeneration(t, elliptic.P384(), "p384")
testKeyGeneration(t, elliptic.P521(), "p521")
}
func BenchmarkSignP256(b *testing.B) {
b.ResetTimer()
p256 := elliptic.P256()
hashed := []byte("testing")
priv, _ := GenerateKey(p256, rand.Reader)
crypto/elliptic: reduce allocations on amd64 This is inspired by https://blog.cloudflare.com/go-dont-collect-my-garbage/ This CL adds allocation tracking and parallelizes p256-related benchmarks. Amount of allocations can be significantly reduced by marking amd64 asm functions as noescape. This exposes a bug in p256MovCond: PANDN with memory argument will fault if memory is not aligned, so they are replaced with MOVDQU (which is ok with unaligned memory) and register version of PANDN. Results on 88-thread machine (2x 22 cores) below: crypto/elliptic: name old time/op new time/op delta BaseMultP256-88 1.50µs ±11% 1.19µs ± 5% -20.20% (p=0.000 n=10+10) ScalarMultP256-88 5.47µs ± 5% 3.63µs ±10% -33.66% (p=0.000 n=9+10) name old alloc/op new alloc/op delta BaseMultP256-88 800B ± 0% 288B ± 0% -64.00% (p=0.000 n=10+10) ScalarMultP256-88 2.59kB ± 0% 0.26kB ± 0% -90.12% (p=0.000 n=10+10) name old allocs/op new allocs/op delta BaseMultP256-88 13.0 ± 0% 6.0 ± 0% -53.85% (p=0.000 n=10+10) ScalarMultP256-88 16.0 ± 0% 5.0 ± 0% -68.75% (p=0.000 n=10+10) crypto/ecdsa: name old time/op new time/op delta SignP256-88 8.63µs ±37% 7.55µs ±38% ~ (p=0.393 n=10+10) VerifyP256-88 13.9µs ± 8% 7.0µs ± 7% -49.29% (p=0.000 n=10+9) KeyGeneration-88 2.77µs ±11% 2.34µs ±11% -15.57% (p=0.000 n=10+10) name old alloc/op new alloc/op delta SignP256-88 4.14kB ± 1% 2.98kB ± 2% -27.94% (p=0.000 n=10+10) VerifyP256-88 4.47kB ± 0% 0.99kB ± 0% -77.84% (p=0.000 n=9+10) KeyGeneration-88 1.21kB ± 0% 0.69kB ± 0% -42.78% (p=0.000 n=10+10) name old allocs/op new allocs/op delta SignP256-88 47.0 ± 0% 34.0 ± 0% -27.66% (p=0.000 n=10+10) VerifyP256-88 38.0 ± 0% 17.0 ± 0% -55.26% (p=0.000 n=10+10) KeyGeneration-88 20.0 ± 0% 13.0 ± 0% -35.00% (p=0.000 n=10+10) On machine with only 4 cores, results are much less impressive: around 2% performance gain. Change-Id: I8a2f8168f83d27ad9ace1b4b1a1e11cb83edf717 Reviewed-on: https://go-review.googlesource.com/80757 Run-TryBot: Ilya Tocar <ilya.tocar@intel.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
2017-11-29 13:20:08 -06:00
b.ReportAllocs()
b.ResetTimer()
crypto/elliptic: reduce allocations on amd64 This is inspired by https://blog.cloudflare.com/go-dont-collect-my-garbage/ This CL adds allocation tracking and parallelizes p256-related benchmarks. Amount of allocations can be significantly reduced by marking amd64 asm functions as noescape. This exposes a bug in p256MovCond: PANDN with memory argument will fault if memory is not aligned, so they are replaced with MOVDQU (which is ok with unaligned memory) and register version of PANDN. Results on 88-thread machine (2x 22 cores) below: crypto/elliptic: name old time/op new time/op delta BaseMultP256-88 1.50µs ±11% 1.19µs ± 5% -20.20% (p=0.000 n=10+10) ScalarMultP256-88 5.47µs ± 5% 3.63µs ±10% -33.66% (p=0.000 n=9+10) name old alloc/op new alloc/op delta BaseMultP256-88 800B ± 0% 288B ± 0% -64.00% (p=0.000 n=10+10) ScalarMultP256-88 2.59kB ± 0% 0.26kB ± 0% -90.12% (p=0.000 n=10+10) name old allocs/op new allocs/op delta BaseMultP256-88 13.0 ± 0% 6.0 ± 0% -53.85% (p=0.000 n=10+10) ScalarMultP256-88 16.0 ± 0% 5.0 ± 0% -68.75% (p=0.000 n=10+10) crypto/ecdsa: name old time/op new time/op delta SignP256-88 8.63µs ±37% 7.55µs ±38% ~ (p=0.393 n=10+10) VerifyP256-88 13.9µs ± 8% 7.0µs ± 7% -49.29% (p=0.000 n=10+9) KeyGeneration-88 2.77µs ±11% 2.34µs ±11% -15.57% (p=0.000 n=10+10) name old alloc/op new alloc/op delta SignP256-88 4.14kB ± 1% 2.98kB ± 2% -27.94% (p=0.000 n=10+10) VerifyP256-88 4.47kB ± 0% 0.99kB ± 0% -77.84% (p=0.000 n=9+10) KeyGeneration-88 1.21kB ± 0% 0.69kB ± 0% -42.78% (p=0.000 n=10+10) name old allocs/op new allocs/op delta SignP256-88 47.0 ± 0% 34.0 ± 0% -27.66% (p=0.000 n=10+10) VerifyP256-88 38.0 ± 0% 17.0 ± 0% -55.26% (p=0.000 n=10+10) KeyGeneration-88 20.0 ± 0% 13.0 ± 0% -35.00% (p=0.000 n=10+10) On machine with only 4 cores, results are much less impressive: around 2% performance gain. Change-Id: I8a2f8168f83d27ad9ace1b4b1a1e11cb83edf717 Reviewed-on: https://go-review.googlesource.com/80757 Run-TryBot: Ilya Tocar <ilya.tocar@intel.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
2017-11-29 13:20:08 -06:00
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_, _, _ = Sign(rand.Reader, priv, hashed)
}
})
}
func BenchmarkSignP384(b *testing.B) {
b.ResetTimer()
p384 := elliptic.P384()
hashed := []byte("testing")
priv, _ := GenerateKey(p384, rand.Reader)
crypto/elliptic: reduce allocations on amd64 This is inspired by https://blog.cloudflare.com/go-dont-collect-my-garbage/ This CL adds allocation tracking and parallelizes p256-related benchmarks. Amount of allocations can be significantly reduced by marking amd64 asm functions as noescape. This exposes a bug in p256MovCond: PANDN with memory argument will fault if memory is not aligned, so they are replaced with MOVDQU (which is ok with unaligned memory) and register version of PANDN. Results on 88-thread machine (2x 22 cores) below: crypto/elliptic: name old time/op new time/op delta BaseMultP256-88 1.50µs ±11% 1.19µs ± 5% -20.20% (p=0.000 n=10+10) ScalarMultP256-88 5.47µs ± 5% 3.63µs ±10% -33.66% (p=0.000 n=9+10) name old alloc/op new alloc/op delta BaseMultP256-88 800B ± 0% 288B ± 0% -64.00% (p=0.000 n=10+10) ScalarMultP256-88 2.59kB ± 0% 0.26kB ± 0% -90.12% (p=0.000 n=10+10) name old allocs/op new allocs/op delta BaseMultP256-88 13.0 ± 0% 6.0 ± 0% -53.85% (p=0.000 n=10+10) ScalarMultP256-88 16.0 ± 0% 5.0 ± 0% -68.75% (p=0.000 n=10+10) crypto/ecdsa: name old time/op new time/op delta SignP256-88 8.63µs ±37% 7.55µs ±38% ~ (p=0.393 n=10+10) VerifyP256-88 13.9µs ± 8% 7.0µs ± 7% -49.29% (p=0.000 n=10+9) KeyGeneration-88 2.77µs ±11% 2.34µs ±11% -15.57% (p=0.000 n=10+10) name old alloc/op new alloc/op delta SignP256-88 4.14kB ± 1% 2.98kB ± 2% -27.94% (p=0.000 n=10+10) VerifyP256-88 4.47kB ± 0% 0.99kB ± 0% -77.84% (p=0.000 n=9+10) KeyGeneration-88 1.21kB ± 0% 0.69kB ± 0% -42.78% (p=0.000 n=10+10) name old allocs/op new allocs/op delta SignP256-88 47.0 ± 0% 34.0 ± 0% -27.66% (p=0.000 n=10+10) VerifyP256-88 38.0 ± 0% 17.0 ± 0% -55.26% (p=0.000 n=10+10) KeyGeneration-88 20.0 ± 0% 13.0 ± 0% -35.00% (p=0.000 n=10+10) On machine with only 4 cores, results are much less impressive: around 2% performance gain. Change-Id: I8a2f8168f83d27ad9ace1b4b1a1e11cb83edf717 Reviewed-on: https://go-review.googlesource.com/80757 Run-TryBot: Ilya Tocar <ilya.tocar@intel.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
2017-11-29 13:20:08 -06:00
b.ReportAllocs()
b.ResetTimer()
crypto/elliptic: reduce allocations on amd64 This is inspired by https://blog.cloudflare.com/go-dont-collect-my-garbage/ This CL adds allocation tracking and parallelizes p256-related benchmarks. Amount of allocations can be significantly reduced by marking amd64 asm functions as noescape. This exposes a bug in p256MovCond: PANDN with memory argument will fault if memory is not aligned, so they are replaced with MOVDQU (which is ok with unaligned memory) and register version of PANDN. Results on 88-thread machine (2x 22 cores) below: crypto/elliptic: name old time/op new time/op delta BaseMultP256-88 1.50µs ±11% 1.19µs ± 5% -20.20% (p=0.000 n=10+10) ScalarMultP256-88 5.47µs ± 5% 3.63µs ±10% -33.66% (p=0.000 n=9+10) name old alloc/op new alloc/op delta BaseMultP256-88 800B ± 0% 288B ± 0% -64.00% (p=0.000 n=10+10) ScalarMultP256-88 2.59kB ± 0% 0.26kB ± 0% -90.12% (p=0.000 n=10+10) name old allocs/op new allocs/op delta BaseMultP256-88 13.0 ± 0% 6.0 ± 0% -53.85% (p=0.000 n=10+10) ScalarMultP256-88 16.0 ± 0% 5.0 ± 0% -68.75% (p=0.000 n=10+10) crypto/ecdsa: name old time/op new time/op delta SignP256-88 8.63µs ±37% 7.55µs ±38% ~ (p=0.393 n=10+10) VerifyP256-88 13.9µs ± 8% 7.0µs ± 7% -49.29% (p=0.000 n=10+9) KeyGeneration-88 2.77µs ±11% 2.34µs ±11% -15.57% (p=0.000 n=10+10) name old alloc/op new alloc/op delta SignP256-88 4.14kB ± 1% 2.98kB ± 2% -27.94% (p=0.000 n=10+10) VerifyP256-88 4.47kB ± 0% 0.99kB ± 0% -77.84% (p=0.000 n=9+10) KeyGeneration-88 1.21kB ± 0% 0.69kB ± 0% -42.78% (p=0.000 n=10+10) name old allocs/op new allocs/op delta SignP256-88 47.0 ± 0% 34.0 ± 0% -27.66% (p=0.000 n=10+10) VerifyP256-88 38.0 ± 0% 17.0 ± 0% -55.26% (p=0.000 n=10+10) KeyGeneration-88 20.0 ± 0% 13.0 ± 0% -35.00% (p=0.000 n=10+10) On machine with only 4 cores, results are much less impressive: around 2% performance gain. Change-Id: I8a2f8168f83d27ad9ace1b4b1a1e11cb83edf717 Reviewed-on: https://go-review.googlesource.com/80757 Run-TryBot: Ilya Tocar <ilya.tocar@intel.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
2017-11-29 13:20:08 -06:00
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_, _, _ = Sign(rand.Reader, priv, hashed)
}
})
}
func BenchmarkVerifyP256(b *testing.B) {
b.ResetTimer()
p256 := elliptic.P256()
hashed := []byte("testing")
priv, _ := GenerateKey(p256, rand.Reader)
r, s, _ := Sign(rand.Reader, priv, hashed)
crypto/elliptic: reduce allocations on amd64 This is inspired by https://blog.cloudflare.com/go-dont-collect-my-garbage/ This CL adds allocation tracking and parallelizes p256-related benchmarks. Amount of allocations can be significantly reduced by marking amd64 asm functions as noescape. This exposes a bug in p256MovCond: PANDN with memory argument will fault if memory is not aligned, so they are replaced with MOVDQU (which is ok with unaligned memory) and register version of PANDN. Results on 88-thread machine (2x 22 cores) below: crypto/elliptic: name old time/op new time/op delta BaseMultP256-88 1.50µs ±11% 1.19µs ± 5% -20.20% (p=0.000 n=10+10) ScalarMultP256-88 5.47µs ± 5% 3.63µs ±10% -33.66% (p=0.000 n=9+10) name old alloc/op new alloc/op delta BaseMultP256-88 800B ± 0% 288B ± 0% -64.00% (p=0.000 n=10+10) ScalarMultP256-88 2.59kB ± 0% 0.26kB ± 0% -90.12% (p=0.000 n=10+10) name old allocs/op new allocs/op delta BaseMultP256-88 13.0 ± 0% 6.0 ± 0% -53.85% (p=0.000 n=10+10) ScalarMultP256-88 16.0 ± 0% 5.0 ± 0% -68.75% (p=0.000 n=10+10) crypto/ecdsa: name old time/op new time/op delta SignP256-88 8.63µs ±37% 7.55µs ±38% ~ (p=0.393 n=10+10) VerifyP256-88 13.9µs ± 8% 7.0µs ± 7% -49.29% (p=0.000 n=10+9) KeyGeneration-88 2.77µs ±11% 2.34µs ±11% -15.57% (p=0.000 n=10+10) name old alloc/op new alloc/op delta SignP256-88 4.14kB ± 1% 2.98kB ± 2% -27.94% (p=0.000 n=10+10) VerifyP256-88 4.47kB ± 0% 0.99kB ± 0% -77.84% (p=0.000 n=9+10) KeyGeneration-88 1.21kB ± 0% 0.69kB ± 0% -42.78% (p=0.000 n=10+10) name old allocs/op new allocs/op delta SignP256-88 47.0 ± 0% 34.0 ± 0% -27.66% (p=0.000 n=10+10) VerifyP256-88 38.0 ± 0% 17.0 ± 0% -55.26% (p=0.000 n=10+10) KeyGeneration-88 20.0 ± 0% 13.0 ± 0% -35.00% (p=0.000 n=10+10) On machine with only 4 cores, results are much less impressive: around 2% performance gain. Change-Id: I8a2f8168f83d27ad9ace1b4b1a1e11cb83edf717 Reviewed-on: https://go-review.googlesource.com/80757 Run-TryBot: Ilya Tocar <ilya.tocar@intel.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
2017-11-29 13:20:08 -06:00
b.ReportAllocs()
b.ResetTimer()
crypto/elliptic: reduce allocations on amd64 This is inspired by https://blog.cloudflare.com/go-dont-collect-my-garbage/ This CL adds allocation tracking and parallelizes p256-related benchmarks. Amount of allocations can be significantly reduced by marking amd64 asm functions as noescape. This exposes a bug in p256MovCond: PANDN with memory argument will fault if memory is not aligned, so they are replaced with MOVDQU (which is ok with unaligned memory) and register version of PANDN. Results on 88-thread machine (2x 22 cores) below: crypto/elliptic: name old time/op new time/op delta BaseMultP256-88 1.50µs ±11% 1.19µs ± 5% -20.20% (p=0.000 n=10+10) ScalarMultP256-88 5.47µs ± 5% 3.63µs ±10% -33.66% (p=0.000 n=9+10) name old alloc/op new alloc/op delta BaseMultP256-88 800B ± 0% 288B ± 0% -64.00% (p=0.000 n=10+10) ScalarMultP256-88 2.59kB ± 0% 0.26kB ± 0% -90.12% (p=0.000 n=10+10) name old allocs/op new allocs/op delta BaseMultP256-88 13.0 ± 0% 6.0 ± 0% -53.85% (p=0.000 n=10+10) ScalarMultP256-88 16.0 ± 0% 5.0 ± 0% -68.75% (p=0.000 n=10+10) crypto/ecdsa: name old time/op new time/op delta SignP256-88 8.63µs ±37% 7.55µs ±38% ~ (p=0.393 n=10+10) VerifyP256-88 13.9µs ± 8% 7.0µs ± 7% -49.29% (p=0.000 n=10+9) KeyGeneration-88 2.77µs ±11% 2.34µs ±11% -15.57% (p=0.000 n=10+10) name old alloc/op new alloc/op delta SignP256-88 4.14kB ± 1% 2.98kB ± 2% -27.94% (p=0.000 n=10+10) VerifyP256-88 4.47kB ± 0% 0.99kB ± 0% -77.84% (p=0.000 n=9+10) KeyGeneration-88 1.21kB ± 0% 0.69kB ± 0% -42.78% (p=0.000 n=10+10) name old allocs/op new allocs/op delta SignP256-88 47.0 ± 0% 34.0 ± 0% -27.66% (p=0.000 n=10+10) VerifyP256-88 38.0 ± 0% 17.0 ± 0% -55.26% (p=0.000 n=10+10) KeyGeneration-88 20.0 ± 0% 13.0 ± 0% -35.00% (p=0.000 n=10+10) On machine with only 4 cores, results are much less impressive: around 2% performance gain. Change-Id: I8a2f8168f83d27ad9ace1b4b1a1e11cb83edf717 Reviewed-on: https://go-review.googlesource.com/80757 Run-TryBot: Ilya Tocar <ilya.tocar@intel.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
2017-11-29 13:20:08 -06:00
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
Verify(&priv.PublicKey, hashed, r, s)
}
})
}
func BenchmarkKeyGeneration(b *testing.B) {
b.ResetTimer()
p256 := elliptic.P256()
crypto/elliptic: reduce allocations on amd64 This is inspired by https://blog.cloudflare.com/go-dont-collect-my-garbage/ This CL adds allocation tracking and parallelizes p256-related benchmarks. Amount of allocations can be significantly reduced by marking amd64 asm functions as noescape. This exposes a bug in p256MovCond: PANDN with memory argument will fault if memory is not aligned, so they are replaced with MOVDQU (which is ok with unaligned memory) and register version of PANDN. Results on 88-thread machine (2x 22 cores) below: crypto/elliptic: name old time/op new time/op delta BaseMultP256-88 1.50µs ±11% 1.19µs ± 5% -20.20% (p=0.000 n=10+10) ScalarMultP256-88 5.47µs ± 5% 3.63µs ±10% -33.66% (p=0.000 n=9+10) name old alloc/op new alloc/op delta BaseMultP256-88 800B ± 0% 288B ± 0% -64.00% (p=0.000 n=10+10) ScalarMultP256-88 2.59kB ± 0% 0.26kB ± 0% -90.12% (p=0.000 n=10+10) name old allocs/op new allocs/op delta BaseMultP256-88 13.0 ± 0% 6.0 ± 0% -53.85% (p=0.000 n=10+10) ScalarMultP256-88 16.0 ± 0% 5.0 ± 0% -68.75% (p=0.000 n=10+10) crypto/ecdsa: name old time/op new time/op delta SignP256-88 8.63µs ±37% 7.55µs ±38% ~ (p=0.393 n=10+10) VerifyP256-88 13.9µs ± 8% 7.0µs ± 7% -49.29% (p=0.000 n=10+9) KeyGeneration-88 2.77µs ±11% 2.34µs ±11% -15.57% (p=0.000 n=10+10) name old alloc/op new alloc/op delta SignP256-88 4.14kB ± 1% 2.98kB ± 2% -27.94% (p=0.000 n=10+10) VerifyP256-88 4.47kB ± 0% 0.99kB ± 0% -77.84% (p=0.000 n=9+10) KeyGeneration-88 1.21kB ± 0% 0.69kB ± 0% -42.78% (p=0.000 n=10+10) name old allocs/op new allocs/op delta SignP256-88 47.0 ± 0% 34.0 ± 0% -27.66% (p=0.000 n=10+10) VerifyP256-88 38.0 ± 0% 17.0 ± 0% -55.26% (p=0.000 n=10+10) KeyGeneration-88 20.0 ± 0% 13.0 ± 0% -35.00% (p=0.000 n=10+10) On machine with only 4 cores, results are much less impressive: around 2% performance gain. Change-Id: I8a2f8168f83d27ad9ace1b4b1a1e11cb83edf717 Reviewed-on: https://go-review.googlesource.com/80757 Run-TryBot: Ilya Tocar <ilya.tocar@intel.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
2017-11-29 13:20:08 -06:00
b.ReportAllocs()
b.ResetTimer()
crypto/elliptic: reduce allocations on amd64 This is inspired by https://blog.cloudflare.com/go-dont-collect-my-garbage/ This CL adds allocation tracking and parallelizes p256-related benchmarks. Amount of allocations can be significantly reduced by marking amd64 asm functions as noescape. This exposes a bug in p256MovCond: PANDN with memory argument will fault if memory is not aligned, so they are replaced with MOVDQU (which is ok with unaligned memory) and register version of PANDN. Results on 88-thread machine (2x 22 cores) below: crypto/elliptic: name old time/op new time/op delta BaseMultP256-88 1.50µs ±11% 1.19µs ± 5% -20.20% (p=0.000 n=10+10) ScalarMultP256-88 5.47µs ± 5% 3.63µs ±10% -33.66% (p=0.000 n=9+10) name old alloc/op new alloc/op delta BaseMultP256-88 800B ± 0% 288B ± 0% -64.00% (p=0.000 n=10+10) ScalarMultP256-88 2.59kB ± 0% 0.26kB ± 0% -90.12% (p=0.000 n=10+10) name old allocs/op new allocs/op delta BaseMultP256-88 13.0 ± 0% 6.0 ± 0% -53.85% (p=0.000 n=10+10) ScalarMultP256-88 16.0 ± 0% 5.0 ± 0% -68.75% (p=0.000 n=10+10) crypto/ecdsa: name old time/op new time/op delta SignP256-88 8.63µs ±37% 7.55µs ±38% ~ (p=0.393 n=10+10) VerifyP256-88 13.9µs ± 8% 7.0µs ± 7% -49.29% (p=0.000 n=10+9) KeyGeneration-88 2.77µs ±11% 2.34µs ±11% -15.57% (p=0.000 n=10+10) name old alloc/op new alloc/op delta SignP256-88 4.14kB ± 1% 2.98kB ± 2% -27.94% (p=0.000 n=10+10) VerifyP256-88 4.47kB ± 0% 0.99kB ± 0% -77.84% (p=0.000 n=9+10) KeyGeneration-88 1.21kB ± 0% 0.69kB ± 0% -42.78% (p=0.000 n=10+10) name old allocs/op new allocs/op delta SignP256-88 47.0 ± 0% 34.0 ± 0% -27.66% (p=0.000 n=10+10) VerifyP256-88 38.0 ± 0% 17.0 ± 0% -55.26% (p=0.000 n=10+10) KeyGeneration-88 20.0 ± 0% 13.0 ± 0% -35.00% (p=0.000 n=10+10) On machine with only 4 cores, results are much less impressive: around 2% performance gain. Change-Id: I8a2f8168f83d27ad9ace1b4b1a1e11cb83edf717 Reviewed-on: https://go-review.googlesource.com/80757 Run-TryBot: Ilya Tocar <ilya.tocar@intel.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
2017-11-29 13:20:08 -06:00
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
GenerateKey(p256, rand.Reader)
}
})
}
func testSignAndVerify(t *testing.T, c elliptic.Curve, tag string) {
priv, _ := GenerateKey(c, rand.Reader)
hashed := []byte("testing")
r, s, err := Sign(rand.Reader, priv, hashed)
if err != nil {
t.Errorf("%s: error signing: %s", tag, err)
return
}
if !Verify(&priv.PublicKey, hashed, r, s) {
t.Errorf("%s: Verify failed", tag)
}
hashed[0] ^= 0xff
if Verify(&priv.PublicKey, hashed, r, s) {
t.Errorf("%s: Verify always works!", tag)
}
}
func TestSignAndVerify(t *testing.T) {
testSignAndVerify(t, elliptic.P224(), "p224")
if testing.Short() {
return
}
testSignAndVerify(t, elliptic.P256(), "p256")
testSignAndVerify(t, elliptic.P384(), "p384")
testSignAndVerify(t, elliptic.P521(), "p521")
}
crypto/ecdsa: make Sign safe with broken entropy sources ECDSA is unsafe to use if an entropy source produces predictable output for the ephemeral nonces. E.g., [Nguyen]. A simple countermeasure is to hash the secret key, the message, and entropy together to seed a CSPRNG, from which the ephemeral key is derived. Fixes #9452 -- This is a minimalist (in terms of patch size) solution, though not the most parsimonious in its use of primitives: - csprng_key = ChopMD-256(SHA2-512(priv.D||entropy||hash)) - reader = AES-256-CTR(k=csprng_key) This, however, provides at most 128-bit collision-resistance, so that Adv will have a term related to the number of messages signed that is significantly worse than plain ECDSA. This does not seem to be of any practical importance. ChopMD-256(SHA2-512(x)) is used, rather than SHA2-256(x), for two sets of reasons: *Practical:* SHA2-512 has a larger state and 16 more rounds; it is likely non-generically stronger than SHA2-256. And, AFAIK, cryptanalysis backs this up. (E.g., [Biryukov] gives a distinguisher on 47-round SHA2-256 with cost < 2^85.) This is well below a reasonable security-strength target. *Theoretical:* [Coron] and [Chang] show that Chop-MD(F(x)) is indifferentiable from a random oracle for slightly beyond the birthday barrier. It seems likely that this makes a generic security proof that this construction remains UF-CMA is possible in the indifferentiability framework. -- Many thanks to Payman Mohassel for reviewing this construction; any mistakes are mine, however. And, as he notes, reusing the private key in this way means that the generic-group (non-RO) proof of ECDSA's security given in [Brown] no longer directly applies. -- [Brown]: http://www.cacr.math.uwaterloo.ca/techreports/2000/corr2000-54.ps "Brown. The exact security of ECDSA. 2000" [Coron]: https://www.cs.nyu.edu/~puniya/papers/merkle.pdf "Coron et al. Merkle-Damgard revisited. 2005" [Chang]: https://www.iacr.org/archive/fse2008/50860436/50860436.pdf "Chang and Nandi. Improved indifferentiability security analysis of chopMD hash function. 2008" [Biryukov]: http://www.iacr.org/archive/asiacrypt2011/70730269/70730269.pdf "Biryukov et al. Second-order differential collisions for reduced SHA-256. 2011" [Nguyen]: ftp://ftp.di.ens.fr/pub/users/pnguyen/PubECDSA.ps "Nguyen and Shparlinski. The insecurity of the elliptic curve digital signature algorithm with partially known nonces. 2003" New tests: TestNonceSafety: Check that signatures are safe even with a broken entropy source. TestINDCCA: Check that signatures remain non-deterministic with a functional entropy source. Updated "golden" KATs in crypto/tls/testdata that use ECDSA suites. Change-Id: I55337a2fbec2e42a36ce719bd2184793682d678a Reviewed-on: https://go-review.googlesource.com/3340 Reviewed-by: Adam Langley <agl@golang.org>
2015-01-26 23:00:21 -08:00
func testNonceSafety(t *testing.T, c elliptic.Curve, tag string) {
priv, _ := GenerateKey(c, rand.Reader)
hashed := []byte("testing")
r0, s0, err := Sign(zeroReader, priv, hashed)
if err != nil {
t.Errorf("%s: error signing: %s", tag, err)
return
}
hashed = []byte("testing...")
r1, s1, err := Sign(zeroReader, priv, hashed)
if err != nil {
t.Errorf("%s: error signing: %s", tag, err)
return
}
if s0.Cmp(s1) == 0 {
// This should never happen.
t.Errorf("%s: the signatures on two different messages were the same", tag)
crypto/ecdsa: make Sign safe with broken entropy sources ECDSA is unsafe to use if an entropy source produces predictable output for the ephemeral nonces. E.g., [Nguyen]. A simple countermeasure is to hash the secret key, the message, and entropy together to seed a CSPRNG, from which the ephemeral key is derived. Fixes #9452 -- This is a minimalist (in terms of patch size) solution, though not the most parsimonious in its use of primitives: - csprng_key = ChopMD-256(SHA2-512(priv.D||entropy||hash)) - reader = AES-256-CTR(k=csprng_key) This, however, provides at most 128-bit collision-resistance, so that Adv will have a term related to the number of messages signed that is significantly worse than plain ECDSA. This does not seem to be of any practical importance. ChopMD-256(SHA2-512(x)) is used, rather than SHA2-256(x), for two sets of reasons: *Practical:* SHA2-512 has a larger state and 16 more rounds; it is likely non-generically stronger than SHA2-256. And, AFAIK, cryptanalysis backs this up. (E.g., [Biryukov] gives a distinguisher on 47-round SHA2-256 with cost < 2^85.) This is well below a reasonable security-strength target. *Theoretical:* [Coron] and [Chang] show that Chop-MD(F(x)) is indifferentiable from a random oracle for slightly beyond the birthday barrier. It seems likely that this makes a generic security proof that this construction remains UF-CMA is possible in the indifferentiability framework. -- Many thanks to Payman Mohassel for reviewing this construction; any mistakes are mine, however. And, as he notes, reusing the private key in this way means that the generic-group (non-RO) proof of ECDSA's security given in [Brown] no longer directly applies. -- [Brown]: http://www.cacr.math.uwaterloo.ca/techreports/2000/corr2000-54.ps "Brown. The exact security of ECDSA. 2000" [Coron]: https://www.cs.nyu.edu/~puniya/papers/merkle.pdf "Coron et al. Merkle-Damgard revisited. 2005" [Chang]: https://www.iacr.org/archive/fse2008/50860436/50860436.pdf "Chang and Nandi. Improved indifferentiability security analysis of chopMD hash function. 2008" [Biryukov]: http://www.iacr.org/archive/asiacrypt2011/70730269/70730269.pdf "Biryukov et al. Second-order differential collisions for reduced SHA-256. 2011" [Nguyen]: ftp://ftp.di.ens.fr/pub/users/pnguyen/PubECDSA.ps "Nguyen and Shparlinski. The insecurity of the elliptic curve digital signature algorithm with partially known nonces. 2003" New tests: TestNonceSafety: Check that signatures are safe even with a broken entropy source. TestINDCCA: Check that signatures remain non-deterministic with a functional entropy source. Updated "golden" KATs in crypto/tls/testdata that use ECDSA suites. Change-Id: I55337a2fbec2e42a36ce719bd2184793682d678a Reviewed-on: https://go-review.googlesource.com/3340 Reviewed-by: Adam Langley <agl@golang.org>
2015-01-26 23:00:21 -08:00
}
if r0.Cmp(r1) == 0 {
t.Errorf("%s: the nonce used for two different messages was the same", tag)
crypto/ecdsa: make Sign safe with broken entropy sources ECDSA is unsafe to use if an entropy source produces predictable output for the ephemeral nonces. E.g., [Nguyen]. A simple countermeasure is to hash the secret key, the message, and entropy together to seed a CSPRNG, from which the ephemeral key is derived. Fixes #9452 -- This is a minimalist (in terms of patch size) solution, though not the most parsimonious in its use of primitives: - csprng_key = ChopMD-256(SHA2-512(priv.D||entropy||hash)) - reader = AES-256-CTR(k=csprng_key) This, however, provides at most 128-bit collision-resistance, so that Adv will have a term related to the number of messages signed that is significantly worse than plain ECDSA. This does not seem to be of any practical importance. ChopMD-256(SHA2-512(x)) is used, rather than SHA2-256(x), for two sets of reasons: *Practical:* SHA2-512 has a larger state and 16 more rounds; it is likely non-generically stronger than SHA2-256. And, AFAIK, cryptanalysis backs this up. (E.g., [Biryukov] gives a distinguisher on 47-round SHA2-256 with cost < 2^85.) This is well below a reasonable security-strength target. *Theoretical:* [Coron] and [Chang] show that Chop-MD(F(x)) is indifferentiable from a random oracle for slightly beyond the birthday barrier. It seems likely that this makes a generic security proof that this construction remains UF-CMA is possible in the indifferentiability framework. -- Many thanks to Payman Mohassel for reviewing this construction; any mistakes are mine, however. And, as he notes, reusing the private key in this way means that the generic-group (non-RO) proof of ECDSA's security given in [Brown] no longer directly applies. -- [Brown]: http://www.cacr.math.uwaterloo.ca/techreports/2000/corr2000-54.ps "Brown. The exact security of ECDSA. 2000" [Coron]: https://www.cs.nyu.edu/~puniya/papers/merkle.pdf "Coron et al. Merkle-Damgard revisited. 2005" [Chang]: https://www.iacr.org/archive/fse2008/50860436/50860436.pdf "Chang and Nandi. Improved indifferentiability security analysis of chopMD hash function. 2008" [Biryukov]: http://www.iacr.org/archive/asiacrypt2011/70730269/70730269.pdf "Biryukov et al. Second-order differential collisions for reduced SHA-256. 2011" [Nguyen]: ftp://ftp.di.ens.fr/pub/users/pnguyen/PubECDSA.ps "Nguyen and Shparlinski. The insecurity of the elliptic curve digital signature algorithm with partially known nonces. 2003" New tests: TestNonceSafety: Check that signatures are safe even with a broken entropy source. TestINDCCA: Check that signatures remain non-deterministic with a functional entropy source. Updated "golden" KATs in crypto/tls/testdata that use ECDSA suites. Change-Id: I55337a2fbec2e42a36ce719bd2184793682d678a Reviewed-on: https://go-review.googlesource.com/3340 Reviewed-by: Adam Langley <agl@golang.org>
2015-01-26 23:00:21 -08:00
}
}
func TestNonceSafety(t *testing.T) {
testNonceSafety(t, elliptic.P224(), "p224")
if testing.Short() {
return
}
testNonceSafety(t, elliptic.P256(), "p256")
testNonceSafety(t, elliptic.P384(), "p384")
testNonceSafety(t, elliptic.P521(), "p521")
}
func testINDCCA(t *testing.T, c elliptic.Curve, tag string) {
priv, _ := GenerateKey(c, rand.Reader)
hashed := []byte("testing")
r0, s0, err := Sign(rand.Reader, priv, hashed)
if err != nil {
t.Errorf("%s: error signing: %s", tag, err)
return
}
r1, s1, err := Sign(rand.Reader, priv, hashed)
if err != nil {
t.Errorf("%s: error signing: %s", tag, err)
return
}
if s0.Cmp(s1) == 0 {
t.Errorf("%s: two signatures of the same message produced the same result", tag)
crypto/ecdsa: make Sign safe with broken entropy sources ECDSA is unsafe to use if an entropy source produces predictable output for the ephemeral nonces. E.g., [Nguyen]. A simple countermeasure is to hash the secret key, the message, and entropy together to seed a CSPRNG, from which the ephemeral key is derived. Fixes #9452 -- This is a minimalist (in terms of patch size) solution, though not the most parsimonious in its use of primitives: - csprng_key = ChopMD-256(SHA2-512(priv.D||entropy||hash)) - reader = AES-256-CTR(k=csprng_key) This, however, provides at most 128-bit collision-resistance, so that Adv will have a term related to the number of messages signed that is significantly worse than plain ECDSA. This does not seem to be of any practical importance. ChopMD-256(SHA2-512(x)) is used, rather than SHA2-256(x), for two sets of reasons: *Practical:* SHA2-512 has a larger state and 16 more rounds; it is likely non-generically stronger than SHA2-256. And, AFAIK, cryptanalysis backs this up. (E.g., [Biryukov] gives a distinguisher on 47-round SHA2-256 with cost < 2^85.) This is well below a reasonable security-strength target. *Theoretical:* [Coron] and [Chang] show that Chop-MD(F(x)) is indifferentiable from a random oracle for slightly beyond the birthday barrier. It seems likely that this makes a generic security proof that this construction remains UF-CMA is possible in the indifferentiability framework. -- Many thanks to Payman Mohassel for reviewing this construction; any mistakes are mine, however. And, as he notes, reusing the private key in this way means that the generic-group (non-RO) proof of ECDSA's security given in [Brown] no longer directly applies. -- [Brown]: http://www.cacr.math.uwaterloo.ca/techreports/2000/corr2000-54.ps "Brown. The exact security of ECDSA. 2000" [Coron]: https://www.cs.nyu.edu/~puniya/papers/merkle.pdf "Coron et al. Merkle-Damgard revisited. 2005" [Chang]: https://www.iacr.org/archive/fse2008/50860436/50860436.pdf "Chang and Nandi. Improved indifferentiability security analysis of chopMD hash function. 2008" [Biryukov]: http://www.iacr.org/archive/asiacrypt2011/70730269/70730269.pdf "Biryukov et al. Second-order differential collisions for reduced SHA-256. 2011" [Nguyen]: ftp://ftp.di.ens.fr/pub/users/pnguyen/PubECDSA.ps "Nguyen and Shparlinski. The insecurity of the elliptic curve digital signature algorithm with partially known nonces. 2003" New tests: TestNonceSafety: Check that signatures are safe even with a broken entropy source. TestINDCCA: Check that signatures remain non-deterministic with a functional entropy source. Updated "golden" KATs in crypto/tls/testdata that use ECDSA suites. Change-Id: I55337a2fbec2e42a36ce719bd2184793682d678a Reviewed-on: https://go-review.googlesource.com/3340 Reviewed-by: Adam Langley <agl@golang.org>
2015-01-26 23:00:21 -08:00
}
if r0.Cmp(r1) == 0 {
t.Errorf("%s: two signatures of the same message produced the same nonce", tag)
crypto/ecdsa: make Sign safe with broken entropy sources ECDSA is unsafe to use if an entropy source produces predictable output for the ephemeral nonces. E.g., [Nguyen]. A simple countermeasure is to hash the secret key, the message, and entropy together to seed a CSPRNG, from which the ephemeral key is derived. Fixes #9452 -- This is a minimalist (in terms of patch size) solution, though not the most parsimonious in its use of primitives: - csprng_key = ChopMD-256(SHA2-512(priv.D||entropy||hash)) - reader = AES-256-CTR(k=csprng_key) This, however, provides at most 128-bit collision-resistance, so that Adv will have a term related to the number of messages signed that is significantly worse than plain ECDSA. This does not seem to be of any practical importance. ChopMD-256(SHA2-512(x)) is used, rather than SHA2-256(x), for two sets of reasons: *Practical:* SHA2-512 has a larger state and 16 more rounds; it is likely non-generically stronger than SHA2-256. And, AFAIK, cryptanalysis backs this up. (E.g., [Biryukov] gives a distinguisher on 47-round SHA2-256 with cost < 2^85.) This is well below a reasonable security-strength target. *Theoretical:* [Coron] and [Chang] show that Chop-MD(F(x)) is indifferentiable from a random oracle for slightly beyond the birthday barrier. It seems likely that this makes a generic security proof that this construction remains UF-CMA is possible in the indifferentiability framework. -- Many thanks to Payman Mohassel for reviewing this construction; any mistakes are mine, however. And, as he notes, reusing the private key in this way means that the generic-group (non-RO) proof of ECDSA's security given in [Brown] no longer directly applies. -- [Brown]: http://www.cacr.math.uwaterloo.ca/techreports/2000/corr2000-54.ps "Brown. The exact security of ECDSA. 2000" [Coron]: https://www.cs.nyu.edu/~puniya/papers/merkle.pdf "Coron et al. Merkle-Damgard revisited. 2005" [Chang]: https://www.iacr.org/archive/fse2008/50860436/50860436.pdf "Chang and Nandi. Improved indifferentiability security analysis of chopMD hash function. 2008" [Biryukov]: http://www.iacr.org/archive/asiacrypt2011/70730269/70730269.pdf "Biryukov et al. Second-order differential collisions for reduced SHA-256. 2011" [Nguyen]: ftp://ftp.di.ens.fr/pub/users/pnguyen/PubECDSA.ps "Nguyen and Shparlinski. The insecurity of the elliptic curve digital signature algorithm with partially known nonces. 2003" New tests: TestNonceSafety: Check that signatures are safe even with a broken entropy source. TestINDCCA: Check that signatures remain non-deterministic with a functional entropy source. Updated "golden" KATs in crypto/tls/testdata that use ECDSA suites. Change-Id: I55337a2fbec2e42a36ce719bd2184793682d678a Reviewed-on: https://go-review.googlesource.com/3340 Reviewed-by: Adam Langley <agl@golang.org>
2015-01-26 23:00:21 -08:00
}
}
func TestINDCCA(t *testing.T) {
testINDCCA(t, elliptic.P224(), "p224")
if testing.Short() {
return
}
testINDCCA(t, elliptic.P256(), "p256")
testINDCCA(t, elliptic.P384(), "p384")
testINDCCA(t, elliptic.P521(), "p521")
}
func fromHex(s string) *big.Int {
r, ok := new(big.Int).SetString(s, 16)
if !ok {
panic("bad hex")
}
return r
}
func TestVectors(t *testing.T) {
// This test runs the full set of NIST test vectors from
// https://csrc.nist.gov/groups/STM/cavp/documents/dss/186-3ecdsatestvectors.zip
//
// The SigVer.rsp file has been edited to remove test vectors for
// unsupported algorithms and has been compressed.
if testing.Short() {
return
}
f, err := os.Open("testdata/SigVer.rsp.bz2")
if err != nil {
t.Fatal(err)
}
buf := bufio.NewReader(bzip2.NewReader(f))
lineNo := 1
var h hash.Hash
var msg []byte
var hashed []byte
var r, s *big.Int
pub := new(PublicKey)
for {
line, err := buf.ReadString('\n')
if len(line) == 0 {
if err == io.EOF {
break
}
t.Fatalf("error reading from input: %s", err)
}
lineNo++
// Need to remove \r\n from the end of the line.
if !strings.HasSuffix(line, "\r\n") {
t.Fatalf("bad line ending (expected \\r\\n) on line %d", lineNo)
}
line = line[:len(line)-2]
if len(line) == 0 || line[0] == '#' {
continue
}
if line[0] == '[' {
line = line[1 : len(line)-1]
parts := strings.SplitN(line, ",", 2)
switch parts[0] {
case "P-224":
pub.Curve = elliptic.P224()
case "P-256":
pub.Curve = elliptic.P256()
case "P-384":
pub.Curve = elliptic.P384()
case "P-521":
pub.Curve = elliptic.P521()
default:
pub.Curve = nil
}
switch parts[1] {
case "SHA-1":
h = sha1.New()
case "SHA-224":
h = sha256.New224()
case "SHA-256":
h = sha256.New()
case "SHA-384":
h = sha512.New384()
case "SHA-512":
h = sha512.New()
default:
h = nil
}
continue
}
if h == nil || pub.Curve == nil {
continue
}
switch {
case strings.HasPrefix(line, "Msg = "):
if msg, err = hex.DecodeString(line[6:]); err != nil {
t.Fatalf("failed to decode message on line %d: %s", lineNo, err)
}
case strings.HasPrefix(line, "Qx = "):
pub.X = fromHex(line[5:])
case strings.HasPrefix(line, "Qy = "):
pub.Y = fromHex(line[5:])
case strings.HasPrefix(line, "R = "):
r = fromHex(line[4:])
case strings.HasPrefix(line, "S = "):
s = fromHex(line[4:])
case strings.HasPrefix(line, "Result = "):
expected := line[9] == 'P'
h.Reset()
h.Write(msg)
hashed := h.Sum(hashed[:0])
if Verify(pub, hashed, r, s) != expected {
t.Fatalf("incorrect result on line %d", lineNo)
}
default:
t.Fatalf("unknown variable on line %d: %s", lineNo, line)
}
}
}
func testNegativeInputs(t *testing.T, curve elliptic.Curve, tag string) {
key, err := GenerateKey(curve, rand.Reader)
if err != nil {
t.Errorf("failed to generate key for %q", tag)
}
var hash [32]byte
r := new(big.Int).SetInt64(1)
r.Lsh(r, 550 /* larger than any supported curve */)
r.Neg(r)
if Verify(&key.PublicKey, hash[:], r, r) {
t.Errorf("bogus signature accepted for %q", tag)
}
}
func TestNegativeInputs(t *testing.T) {
testNegativeInputs(t, elliptic.P224(), "p224")
testNegativeInputs(t, elliptic.P256(), "p256")
testNegativeInputs(t, elliptic.P384(), "p384")
testNegativeInputs(t, elliptic.P521(), "p521")
}
func TestZeroHashSignature(t *testing.T) {
zeroHash := make([]byte, 64)
for _, curve := range []elliptic.Curve{elliptic.P224(), elliptic.P256(), elliptic.P384(), elliptic.P521()} {
privKey, err := GenerateKey(curve, rand.Reader)
if err != nil {
panic(err)
}
// Sign a hash consisting of all zeros.
r, s, err := Sign(rand.Reader, privKey, zeroHash)
if err != nil {
panic(err)
}
// Confirm that it can be verified.
if !Verify(&privKey.PublicKey, zeroHash, r, s) {
t.Errorf("zero hash signature verify failed for %T", curve)
}
}
}