aboutsummaryrefslogtreecommitdiffstats
path: root/crypto/secp256k1
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/secp256k1')
-rw-r--r--crypto/secp256k1/curve.go335
-rw-r--r--crypto/secp256k1/curve_test.go39
-rw-r--r--crypto/secp256k1/pubkey_scalar_mul.h56
-rw-r--r--crypto/secp256k1/secp256.go28
-rw-r--r--crypto/secp256k1/secp256_test.go2
5 files changed, 454 insertions, 6 deletions
diff --git a/crypto/secp256k1/curve.go b/crypto/secp256k1/curve.go
new file mode 100644
index 000000000..6e44a6771
--- /dev/null
+++ b/crypto/secp256k1/curve.go
@@ -0,0 +1,335 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Copyright 2011 ThePiachu. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+// * The name of ThePiachu may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package secp256k1
+
+import (
+ "crypto/elliptic"
+ "io"
+ "math/big"
+ "sync"
+ "unsafe"
+)
+
+/*
+#include "libsecp256k1/include/secp256k1.h"
+extern int secp256k1_pubkey_scalar_mul(const secp256k1_context* ctx, const unsigned char *point, const unsigned char *scalar);
+*/
+import "C"
+
+// This code is from https://github.com/ThePiachu/GoBit and implements
+// several Koblitz elliptic curves over prime fields.
+//
+// The curve methods, internally, on Jacobian coordinates. For a given
+// (x, y) position on the curve, the Jacobian coordinates are (x1, y1,
+// z1) where x = x1/z1² and y = y1/z1³. The greatest speedups come
+// when the whole calculation can be performed within the transform
+// (as in ScalarMult and ScalarBaseMult). But even for Add and Double,
+// it's faster to apply and reverse the transform than to operate in
+// affine coordinates.
+
+// A BitCurve represents a Koblitz Curve with a=0.
+// See http://www.hyperelliptic.org/EFD/g1p/auto-shortw.html
+type BitCurve struct {
+ P *big.Int // the order of the underlying field
+ N *big.Int // the order of the base point
+ B *big.Int // the constant of the BitCurve equation
+ Gx, Gy *big.Int // (x,y) of the base point
+ BitSize int // the size of the underlying field
+}
+
+func (BitCurve *BitCurve) Params() *elliptic.CurveParams {
+ return &elliptic.CurveParams{
+ P: BitCurve.P,
+ N: BitCurve.N,
+ B: BitCurve.B,
+ Gx: BitCurve.Gx,
+ Gy: BitCurve.Gy,
+ BitSize: BitCurve.BitSize,
+ }
+}
+
+// IsOnBitCurve returns true if the given (x,y) lies on the BitCurve.
+func (BitCurve *BitCurve) IsOnCurve(x, y *big.Int) bool {
+ // y² = x³ + b
+ y2 := new(big.Int).Mul(y, y) //y²
+ y2.Mod(y2, BitCurve.P) //y²%P
+
+ x3 := new(big.Int).Mul(x, x) //x²
+ x3.Mul(x3, x) //x³
+
+ x3.Add(x3, BitCurve.B) //x³+B
+ x3.Mod(x3, BitCurve.P) //(x³+B)%P
+
+ return x3.Cmp(y2) == 0
+}
+
+//TODO: double check if the function is okay
+// affineFromJacobian reverses the Jacobian transform. See the comment at the
+// top of the file.
+func (BitCurve *BitCurve) affineFromJacobian(x, y, z *big.Int) (xOut, yOut *big.Int) {
+ zinv := new(big.Int).ModInverse(z, BitCurve.P)
+ zinvsq := new(big.Int).Mul(zinv, zinv)
+
+ xOut = new(big.Int).Mul(x, zinvsq)
+ xOut.Mod(xOut, BitCurve.P)
+ zinvsq.Mul(zinvsq, zinv)
+ yOut = new(big.Int).Mul(y, zinvsq)
+ yOut.Mod(yOut, BitCurve.P)
+ return
+}
+
+// Add returns the sum of (x1,y1) and (x2,y2)
+func (BitCurve *BitCurve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
+ z := new(big.Int).SetInt64(1)
+ return BitCurve.affineFromJacobian(BitCurve.addJacobian(x1, y1, z, x2, y2, z))
+}
+
+// addJacobian takes two points in Jacobian coordinates, (x1, y1, z1) and
+// (x2, y2, z2) and returns their sum, also in Jacobian form.
+func (BitCurve *BitCurve) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int, *big.Int, *big.Int) {
+ // See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl
+ z1z1 := new(big.Int).Mul(z1, z1)
+ z1z1.Mod(z1z1, BitCurve.P)
+ z2z2 := new(big.Int).Mul(z2, z2)
+ z2z2.Mod(z2z2, BitCurve.P)
+
+ u1 := new(big.Int).Mul(x1, z2z2)
+ u1.Mod(u1, BitCurve.P)
+ u2 := new(big.Int).Mul(x2, z1z1)
+ u2.Mod(u2, BitCurve.P)
+ h := new(big.Int).Sub(u2, u1)
+ if h.Sign() == -1 {
+ h.Add(h, BitCurve.P)
+ }
+ i := new(big.Int).Lsh(h, 1)
+ i.Mul(i, i)
+ j := new(big.Int).Mul(h, i)
+
+ s1 := new(big.Int).Mul(y1, z2)
+ s1.Mul(s1, z2z2)
+ s1.Mod(s1, BitCurve.P)
+ s2 := new(big.Int).Mul(y2, z1)
+ s2.Mul(s2, z1z1)
+ s2.Mod(s2, BitCurve.P)
+ r := new(big.Int).Sub(s2, s1)
+ if r.Sign() == -1 {
+ r.Add(r, BitCurve.P)
+ }
+ r.Lsh(r, 1)
+ v := new(big.Int).Mul(u1, i)
+
+ x3 := new(big.Int).Set(r)
+ x3.Mul(x3, x3)
+ x3.Sub(x3, j)
+ x3.Sub(x3, v)
+ x3.Sub(x3, v)
+ x3.Mod(x3, BitCurve.P)
+
+ y3 := new(big.Int).Set(r)
+ v.Sub(v, x3)
+ y3.Mul(y3, v)
+ s1.Mul(s1, j)
+ s1.Lsh(s1, 1)
+ y3.Sub(y3, s1)
+ y3.Mod(y3, BitCurve.P)
+
+ z3 := new(big.Int).Add(z1, z2)
+ z3.Mul(z3, z3)
+ z3.Sub(z3, z1z1)
+ if z3.Sign() == -1 {
+ z3.Add(z3, BitCurve.P)
+ }
+ z3.Sub(z3, z2z2)
+ if z3.Sign() == -1 {
+ z3.Add(z3, BitCurve.P)
+ }
+ z3.Mul(z3, h)
+ z3.Mod(z3, BitCurve.P)
+
+ return x3, y3, z3
+}
+
+// Double returns 2*(x,y)
+func (BitCurve *BitCurve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) {
+ z1 := new(big.Int).SetInt64(1)
+ return BitCurve.affineFromJacobian(BitCurve.doubleJacobian(x1, y1, z1))
+}
+
+// doubleJacobian takes a point in Jacobian coordinates, (x, y, z), and
+// returns its double, also in Jacobian form.
+func (BitCurve *BitCurve) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, *big.Int) {
+ // See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l
+
+ a := new(big.Int).Mul(x, x) //X1²
+ b := new(big.Int).Mul(y, y) //Y1²
+ c := new(big.Int).Mul(b, b) //B²
+
+ d := new(big.Int).Add(x, b) //X1+B
+ d.Mul(d, d) //(X1+B)²
+ d.Sub(d, a) //(X1+B)²-A
+ d.Sub(d, c) //(X1+B)²-A-C
+ d.Mul(d, big.NewInt(2)) //2*((X1+B)²-A-C)
+
+ e := new(big.Int).Mul(big.NewInt(3), a) //3*A
+ f := new(big.Int).Mul(e, e) //E²
+
+ x3 := new(big.Int).Mul(big.NewInt(2), d) //2*D
+ x3.Sub(f, x3) //F-2*D
+ x3.Mod(x3, BitCurve.P)
+
+ y3 := new(big.Int).Sub(d, x3) //D-X3
+ y3.Mul(e, y3) //E*(D-X3)
+ y3.Sub(y3, new(big.Int).Mul(big.NewInt(8), c)) //E*(D-X3)-8*C
+ y3.Mod(y3, BitCurve.P)
+
+ z3 := new(big.Int).Mul(y, z) //Y1*Z1
+ z3.Mul(big.NewInt(2), z3) //3*Y1*Z1
+ z3.Mod(z3, BitCurve.P)
+
+ return x3, y3, z3
+}
+
+func (BitCurve *BitCurve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, *big.Int) {
+ // Ensure scalar is exactly 32 bytes. We pad always, even if
+ // scalar is 32 bytes long, to avoid a timing side channel.
+ if len(scalar) > 32 {
+ panic("can't handle scalars > 256 bits")
+ }
+ padded := make([]byte, 32)
+ copy(padded[32-len(scalar):], scalar)
+ scalar = padded
+
+ // Do the multiplication in C, updating point.
+ point := make([]byte, 64)
+ readBits(point[:32], Bx)
+ readBits(point[32:], By)
+ pointPtr := (*C.uchar)(unsafe.Pointer(&point[0]))
+ scalarPtr := (*C.uchar)(unsafe.Pointer(&scalar[0]))
+ res := C.secp256k1_pubkey_scalar_mul(context, pointPtr, scalarPtr)
+
+ // Unpack the result and clear temporaries.
+ x := new(big.Int).SetBytes(point[:32])
+ y := new(big.Int).SetBytes(point[32:])
+ for i := range point {
+ point[i] = 0
+ }
+ for i := range padded {
+ scalar[i] = 0
+ }
+ if res != 1 {
+ return nil, nil
+ }
+ return x, y
+}
+
+// ScalarBaseMult returns k*G, where G is the base point of the group and k is
+// an integer in big-endian form.
+func (BitCurve *BitCurve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) {
+ return BitCurve.ScalarMult(BitCurve.Gx, BitCurve.Gy, k)
+}
+
+var mask = []byte{0xff, 0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f}
+
+//TODO: double check if it is okay
+// GenerateKey returns a public/private key pair. The private key is generated
+// using the given reader, which must return random data.
+func (BitCurve *BitCurve) GenerateKey(rand io.Reader) (priv []byte, x, y *big.Int, err error) {
+ byteLen := (BitCurve.BitSize + 7) >> 3
+ priv = make([]byte, byteLen)
+
+ for x == nil {
+ _, err = io.ReadFull(rand, priv)
+ if err != nil {
+ return
+ }
+ // We have to mask off any excess bits in the case that the size of the
+ // underlying field is not a whole number of bytes.
+ priv[0] &= mask[BitCurve.BitSize%8]
+ // This is because, in tests, rand will return all zeros and we don't
+ // want to get the point at infinity and loop forever.
+ priv[1] ^= 0x42
+ x, y = BitCurve.ScalarBaseMult(priv)
+ }
+ return
+}
+
+// Marshal converts a point into the form specified in section 4.3.6 of ANSI
+// X9.62.
+func (BitCurve *BitCurve) Marshal(x, y *big.Int) []byte {
+ byteLen := (BitCurve.BitSize + 7) >> 3
+
+ ret := make([]byte, 1+2*byteLen)
+ ret[0] = 4 // uncompressed point
+
+ xBytes := x.Bytes()
+ copy(ret[1+byteLen-len(xBytes):], xBytes)
+ yBytes := y.Bytes()
+ copy(ret[1+2*byteLen-len(yBytes):], yBytes)
+ return ret
+}
+
+// Unmarshal converts a point, serialised by Marshal, into an x, y pair. On
+// error, x = nil.
+func (BitCurve *BitCurve) Unmarshal(data []byte) (x, y *big.Int) {
+ byteLen := (BitCurve.BitSize + 7) >> 3
+ if len(data) != 1+2*byteLen {
+ return
+ }
+ if data[0] != 4 { // uncompressed form
+ return
+ }
+ x = new(big.Int).SetBytes(data[1 : 1+byteLen])
+ y = new(big.Int).SetBytes(data[1+byteLen:])
+ return
+}
+
+var (
+ initonce sync.Once
+ theCurve *BitCurve
+)
+
+// S256 returns a BitCurve which implements secp256k1 (see SEC 2 section 2.7.1)
+func S256() *BitCurve {
+ initonce.Do(func() {
+ // See SEC 2 section 2.7.1
+ // curve parameters taken from:
+ // http://www.secg.org/collateral/sec2_final.pdf
+ theCurve = new(BitCurve)
+ theCurve.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16)
+ theCurve.N, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16)
+ theCurve.B, _ = new(big.Int).SetString("0000000000000000000000000000000000000000000000000000000000000007", 16)
+ theCurve.Gx, _ = new(big.Int).SetString("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", 16)
+ theCurve.Gy, _ = new(big.Int).SetString("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", 16)
+ theCurve.BitSize = 256
+ })
+ return theCurve
+}
diff --git a/crypto/secp256k1/curve_test.go b/crypto/secp256k1/curve_test.go
new file mode 100644
index 000000000..d915ee852
--- /dev/null
+++ b/crypto/secp256k1/curve_test.go
@@ -0,0 +1,39 @@
+// Copyright 2015 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package secp256k1
+
+import (
+ "bytes"
+ "encoding/hex"
+ "math/big"
+ "testing"
+)
+
+func TestReadBits(t *testing.T) {
+ check := func(input string) {
+ want, _ := hex.DecodeString(input)
+ int, _ := new(big.Int).SetString(input, 16)
+ buf := make([]byte, len(want))
+ readBits(buf, int)
+ if !bytes.Equal(buf, want) {
+ t.Errorf("have: %x\nwant: %x", buf, want)
+ }
+ }
+ check("000000000000000000000000000000000000000000000000000000FEFCF3F8F0")
+ check("0000000000012345000000000000000000000000000000000000FEFCF3F8F0")
+ check("18F8F8F1000111000110011100222004330052300000000000000000FEFCF3F8F0")
+}
diff --git a/crypto/secp256k1/pubkey_scalar_mul.h b/crypto/secp256k1/pubkey_scalar_mul.h
new file mode 100644
index 000000000..0511545ec
--- /dev/null
+++ b/crypto/secp256k1/pubkey_scalar_mul.h
@@ -0,0 +1,56 @@
+// Copyright 2015 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+/** Multiply point by scalar in constant time.
+ * Returns: 1: multiplication was successful
+ * 0: scalar was invalid (zero or overflow)
+ * Args: ctx: pointer to a context object (cannot be NULL)
+ * Out: point: the multiplied point (usually secret)
+ * In: point: pointer to a 64-byte bytepublic point,
+ encoded as two 256bit big-endian numbers.
+ * scalar: a 32-byte scalar with which to multiply the point
+ */
+int secp256k1_pubkey_scalar_mul(const secp256k1_context* ctx, unsigned char *point, const unsigned char *scalar) {
+ int ret = 0;
+ int overflow = 0;
+ secp256k1_fe feX, feY;
+ secp256k1_gej res;
+ secp256k1_ge ge;
+ secp256k1_scalar s;
+ ARG_CHECK(point != NULL);
+ ARG_CHECK(scalar != NULL);
+ (void)ctx;
+
+ secp256k1_fe_set_b32(&feX, point);
+ secp256k1_fe_set_b32(&feY, point+32);
+ secp256k1_ge_set_xy(&ge, &feX, &feY);
+ secp256k1_scalar_set_b32(&s, scalar, &overflow);
+ if (overflow || secp256k1_scalar_is_zero(&s)) {
+ ret = 0;
+ } else {
+ secp256k1_ecmult_const(&res, &ge, &s);
+ secp256k1_ge_set_gej(&ge, &res);
+ /* Note: can't use secp256k1_pubkey_save here because it is not constant time. */
+ secp256k1_fe_normalize(&ge.x);
+ secp256k1_fe_normalize(&ge.y);
+ secp256k1_fe_get_b32(point, &ge.x);
+ secp256k1_fe_get_b32(point+32, &ge.y);
+ ret = 1;
+ }
+ secp256k1_scalar_clear(&s);
+ return ret;
+}
+
diff --git a/crypto/secp256k1/secp256.go b/crypto/secp256k1/secp256.go
index 7f26f307c..8dc248145 100644
--- a/crypto/secp256k1/secp256.go
+++ b/crypto/secp256k1/secp256.go
@@ -20,6 +20,7 @@ package secp256k1
/*
#cgo CFLAGS: -I./libsecp256k1
+#cgo CFLAGS: -I./libsecp256k1/src/
#cgo darwin CFLAGS: -I/usr/local/include
#cgo freebsd CFLAGS: -I/usr/local/include
#cgo linux,arm CFLAGS: -I/usr/local/arm/include
@@ -35,6 +36,7 @@ package secp256k1
#define NDEBUG
#include "./libsecp256k1/src/secp256k1.c"
#include "./libsecp256k1/src/modules/recovery/main_impl.h"
+#include "pubkey_scalar_mul.h"
typedef void (*callbackFunc) (const char* msg, void* data);
extern void secp256k1GoPanicIllegal(const char* msg, void* data);
@@ -44,6 +46,7 @@ import "C"
import (
"errors"
+ "math/big"
"unsafe"
"github.com/ethereum/go-ethereum/crypto/randentropy"
@@ -56,13 +59,16 @@ import (
> store private keys in buffer and shuffle (deters persistance on swap disc)
> byte permutation (changing)
> xor with chaning random block (to deter scanning memory for 0x63) (stream cipher?)
- > on disk: store keys in wallets
*/
// holds ptr to secp256k1_context_struct (see secp256k1/include/secp256k1.h)
-var context *C.secp256k1_context
+var (
+ context *C.secp256k1_context
+ N *big.Int
+)
func init() {
+ N, _ = new(big.Int).SetString("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16)
// around 20 ms on a modern CPU.
context = C.secp256k1_context_create(3) // SECP256K1_START_SIGN | SECP256K1_START_VERIFY
C.secp256k1_context_set_illegal_callback(context, C.callbackFunc(C.secp256k1GoPanicIllegal), nil)
@@ -78,7 +84,6 @@ var (
func GenerateKeyPair() ([]byte, []byte) {
var seckey []byte = randentropy.GetEntropyCSPRNG(32)
var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0]))
-
var pubkey64 []byte = make([]byte, 64) // secp256k1_pubkey
var pubkey65 []byte = make([]byte, 65) // 65 byte uncompressed pubkey
pubkey64_ptr := (*C.secp256k1_pubkey)(unsafe.Pointer(&pubkey64[0]))
@@ -96,7 +101,7 @@ func GenerateKeyPair() ([]byte, []byte) {
var output_len C.size_t
- _ = C.secp256k1_ec_pubkey_serialize( // always returns 1
+ C.secp256k1_ec_pubkey_serialize( // always returns 1
context,
pubkey65_ptr,
&output_len,
@@ -163,7 +168,7 @@ func Sign(msg []byte, seckey []byte) ([]byte, error) {
sig_serialized_ptr := (*C.uchar)(unsafe.Pointer(&sig_serialized[0]))
var recid C.int
- _ = C.secp256k1_ecdsa_recoverable_signature_serialize_compact(
+ C.secp256k1_ecdsa_recoverable_signature_serialize_compact(
context,
sig_serialized_ptr, // 64 byte compact signature
&recid,
@@ -254,3 +259,16 @@ func checkSignature(sig []byte) error {
}
return nil
}
+
+// reads num into buf as big-endian bytes.
+func readBits(buf []byte, num *big.Int) {
+ const wordLen = int(unsafe.Sizeof(big.Word(0)))
+ i := len(buf)
+ for _, d := range num.Bits() {
+ for j := 0; j < wordLen && i > 0; j++ {
+ i--
+ buf[i] = byte(d)
+ d >>= 8
+ }
+ }
+}
diff --git a/crypto/secp256k1/secp256_test.go b/crypto/secp256k1/secp256_test.go
index d3ff2223d..fc6fc9b32 100644
--- a/crypto/secp256k1/secp256_test.go
+++ b/crypto/secp256k1/secp256_test.go
@@ -24,7 +24,7 @@ import (
"github.com/ethereum/go-ethereum/crypto/randentropy"
)
-const TestCount = 10000
+const TestCount = 1000
func TestPrivkeyGenerate(t *testing.T) {
_, seckey := GenerateKeyPair()