diff --git a/crypto/crypto.go b/crypto/crypto.go
index 8685d62d3eb20c2d7dc7cd87707ceb16015696cd..7d7623753223506c34a18a8350d8cefe7352bc8e 100644
--- a/crypto/crypto.go
+++ b/crypto/crypto.go
@@ -43,14 +43,6 @@ import (
 	"golang.org/x/crypto/ripemd160"
 )
 
-var secp256k1n *big.Int
-
-func init() {
-	// specify the params for the s256 curve
-	ecies.AddParamsForCurve(S256(), ecies.ECIES_AES128_SHA256)
-	secp256k1n = common.String2Big("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141")
-}
-
 func Sha3(data ...[]byte) []byte {
 	d := sha3.NewKeccak256()
 	for _, b := range data {
@@ -99,9 +91,9 @@ func ToECDSA(prv []byte) *ecdsa.PrivateKey {
 	}
 
 	priv := new(ecdsa.PrivateKey)
-	priv.PublicKey.Curve = S256()
+	priv.PublicKey.Curve = secp256k1.S256()
 	priv.D = common.BigD(prv)
-	priv.PublicKey.X, priv.PublicKey.Y = S256().ScalarBaseMult(prv)
+	priv.PublicKey.X, priv.PublicKey.Y = secp256k1.S256().ScalarBaseMult(prv)
 	return priv
 }
 
@@ -116,15 +108,15 @@ func ToECDSAPub(pub []byte) *ecdsa.PublicKey {
 	if len(pub) == 0 {
 		return nil
 	}
-	x, y := elliptic.Unmarshal(S256(), pub)
-	return &ecdsa.PublicKey{S256(), x, y}
+	x, y := elliptic.Unmarshal(secp256k1.S256(), pub)
+	return &ecdsa.PublicKey{secp256k1.S256(), x, y}
 }
 
 func FromECDSAPub(pub *ecdsa.PublicKey) []byte {
 	if pub == nil || pub.X == nil || pub.Y == nil {
 		return nil
 	}
-	return elliptic.Marshal(S256(), pub.X, pub.Y)
+	return elliptic.Marshal(secp256k1.S256(), pub.X, pub.Y)
 }
 
 // HexToECDSA parses a secp256k1 private key.
@@ -168,7 +160,7 @@ func SaveECDSA(file string, key *ecdsa.PrivateKey) error {
 }
 
 func GenerateKey() (*ecdsa.PrivateKey, error) {
-	return ecdsa.GenerateKey(S256(), rand.Reader)
+	return ecdsa.GenerateKey(secp256k1.S256(), rand.Reader)
 }
 
 func ValidateSignatureValues(v byte, r, s *big.Int) bool {
@@ -176,7 +168,7 @@ func ValidateSignatureValues(v byte, r, s *big.Int) bool {
 		return false
 	}
 	vint := uint32(v)
-	if r.Cmp(secp256k1n) < 0 && s.Cmp(secp256k1n) < 0 && (vint == 27 || vint == 28) {
+	if r.Cmp(secp256k1.N) < 0 && s.Cmp(secp256k1.N) < 0 && (vint == 27 || vint == 28) {
 		return true
 	} else {
 		return false
@@ -189,8 +181,8 @@ func SigToPub(hash, sig []byte) (*ecdsa.PublicKey, error) {
 		return nil, err
 	}
 
-	x, y := elliptic.Unmarshal(S256(), s)
-	return &ecdsa.PublicKey{S256(), x, y}, nil
+	x, y := elliptic.Unmarshal(secp256k1.S256(), s)
+	return &ecdsa.PublicKey{secp256k1.S256(), x, y}, nil
 }
 
 func Sign(hash []byte, prv *ecdsa.PrivateKey) (sig []byte, err error) {
diff --git a/crypto/crypto_test.go b/crypto/crypto_test.go
index fdd9c1ee85b83cb2b7741da4692b85dd96f5e4ff..d5e19a4bb22c6f6a422b595d77526bebdd595f45 100644
--- a/crypto/crypto_test.go
+++ b/crypto/crypto_test.go
@@ -181,7 +181,7 @@ func TestValidateSignatureValues(t *testing.T) {
 	minusOne := big.NewInt(-1)
 	one := common.Big1
 	zero := common.Big0
-	secp256k1nMinus1 := new(big.Int).Sub(secp256k1n, common.Big1)
+	secp256k1nMinus1 := new(big.Int).Sub(secp256k1.N, common.Big1)
 
 	// correct v,r,s
 	check(true, 27, one, one)
@@ -208,9 +208,9 @@ func TestValidateSignatureValues(t *testing.T) {
 	// correct sig with max r,s
 	check(true, 27, secp256k1nMinus1, secp256k1nMinus1)
 	// correct v, combinations of incorrect r,s at upper limit
-	check(false, 27, secp256k1n, secp256k1nMinus1)
-	check(false, 27, secp256k1nMinus1, secp256k1n)
-	check(false, 27, secp256k1n, secp256k1n)
+	check(false, 27, secp256k1.N, secp256k1nMinus1)
+	check(false, 27, secp256k1nMinus1, secp256k1.N)
+	check(false, 27, secp256k1.N, secp256k1.N)
 
 	// current callers ensures r,s cannot be negative, but let's test for that too
 	// as crypto package could be used stand-alone
diff --git a/crypto/ecies/asn1.go b/crypto/ecies/asn1.go
index 6eaf3d2ca3e9808da26e8f495b7004bcb9504e9b..40dabd329bb6ce609ee7f4d434173c8f6f50ac0d 100644
--- a/crypto/ecies/asn1.go
+++ b/crypto/ecies/asn1.go
@@ -41,6 +41,8 @@ import (
 	"fmt"
 	"hash"
 	"math/big"
+
+	"github.com/ethereum/go-ethereum/crypto/secp256k1"
 )
 
 var (
@@ -81,6 +83,7 @@ func doScheme(base, v []int) asn1.ObjectIdentifier {
 type secgNamedCurve asn1.ObjectIdentifier
 
 var (
+	secgNamedCurveS256 = secgNamedCurve{1, 3, 132, 0, 10}
 	secgNamedCurveP256 = secgNamedCurve{1, 2, 840, 10045, 3, 1, 7}
 	secgNamedCurveP384 = secgNamedCurve{1, 3, 132, 0, 34}
 	secgNamedCurveP521 = secgNamedCurve{1, 3, 132, 0, 35}
@@ -116,6 +119,8 @@ func (curve secgNamedCurve) Equal(curve2 secgNamedCurve) bool {
 
 func namedCurveFromOID(curve secgNamedCurve) elliptic.Curve {
 	switch {
+	case curve.Equal(secgNamedCurveS256):
+		return secp256k1.S256()
 	case curve.Equal(secgNamedCurveP256):
 		return elliptic.P256()
 	case curve.Equal(secgNamedCurveP384):
@@ -134,6 +139,8 @@ func oidFromNamedCurve(curve elliptic.Curve) (secgNamedCurve, bool) {
 		return secgNamedCurveP384, true
 	case elliptic.P521():
 		return secgNamedCurveP521, true
+	case secp256k1.S256():
+		return secgNamedCurveS256, true
 	}
 
 	return nil, false
diff --git a/crypto/ecies/ecies.go b/crypto/ecies/ecies.go
index a3b520dd5ccdbac0178ca488cd6d74be10dab63c..65dc5b38bac741b2d9b42ecf6d66b62473b3a5c8 100644
--- a/crypto/ecies/ecies.go
+++ b/crypto/ecies/ecies.go
@@ -125,6 +125,7 @@ func (prv *PrivateKey) GenerateShared(pub *PublicKey, skLen, macLen int) (sk []b
 	if skLen+macLen > MaxSharedKeyLength(pub) {
 		return nil, ErrSharedKeyTooBig
 	}
+
 	x, _ := pub.Curve.ScalarMult(pub.X, pub.Y, prv.D.Bytes())
 	if x == nil {
 		return nil, ErrSharedKeyIsPointAtInfinity
diff --git a/crypto/ecies/ecies_test.go b/crypto/ecies/ecies_test.go
index 1c391f938dc06f8462d7f9e8380a00caa92f90c6..6a0ea3f022f0c371d7515b2c414894acbd9bffab 100644
--- a/crypto/ecies/ecies_test.go
+++ b/crypto/ecies/ecies_test.go
@@ -31,13 +31,18 @@ package ecies
 
 import (
 	"bytes"
+	"crypto/ecdsa"
 	"crypto/elliptic"
 	"crypto/rand"
 	"crypto/sha256"
+	"encoding/hex"
 	"flag"
 	"fmt"
 	"io/ioutil"
+	"math/big"
 	"testing"
+
+	"github.com/ethereum/go-ethereum/crypto/secp256k1"
 )
 
 var dumpEnc bool
@@ -65,7 +70,6 @@ func TestKDF(t *testing.T) {
 	}
 }
 
-var skLen int
 var ErrBadSharedKeys = fmt.Errorf("ecies: shared keys don't match")
 
 // cmpParams compares a set of ECIES parameters. We assume, as per the
@@ -117,7 +121,7 @@ func TestSharedKey(t *testing.T) {
 		fmt.Println(err.Error())
 		t.FailNow()
 	}
-	skLen = MaxSharedKeyLength(&prv1.PublicKey) / 2
+	skLen := MaxSharedKeyLength(&prv1.PublicKey) / 2
 
 	prv2, err := GenerateKey(rand.Reader, DefaultCurve, nil)
 	if err != nil {
@@ -143,6 +147,44 @@ func TestSharedKey(t *testing.T) {
 	}
 }
 
+func TestSharedKeyPadding(t *testing.T) {
+	// sanity checks
+	prv0 := hexKey("1adf5c18167d96a1f9a0b1ef63be8aa27eaf6032c233b2b38f7850cf5b859fd9")
+	prv1 := hexKey("97a076fc7fcd9208240668e31c9abee952cbb6e375d1b8febc7499d6e16f1a")
+	x0, _ := new(big.Int).SetString("1a8ed022ff7aec59dc1b440446bdda5ff6bcb3509a8b109077282b361efffbd8", 16)
+	x1, _ := new(big.Int).SetString("6ab3ac374251f638d0abb3ef596d1dc67955b507c104e5f2009724812dc027b8", 16)
+	y0, _ := new(big.Int).SetString("e040bd480b1deccc3bc40bd5b1fdcb7bfd352500b477cb9471366dbd4493f923", 16)
+	y1, _ := new(big.Int).SetString("8ad915f2b503a8be6facab6588731fefeb584fd2dfa9a77a5e0bba1ec439e4fa", 16)
+
+	if prv0.PublicKey.X.Cmp(x0) != 0 {
+		t.Errorf("mismatched prv0.X:\nhave: %x\nwant: %x\n", prv0.PublicKey.X.Bytes(), x0.Bytes())
+	}
+	if prv0.PublicKey.Y.Cmp(y0) != 0 {
+		t.Errorf("mismatched prv0.Y:\nhave: %x\nwant: %x\n", prv0.PublicKey.Y.Bytes(), y0.Bytes())
+	}
+	if prv1.PublicKey.X.Cmp(x1) != 0 {
+		t.Errorf("mismatched prv1.X:\nhave: %x\nwant: %x\n", prv1.PublicKey.X.Bytes(), x1.Bytes())
+	}
+	if prv1.PublicKey.Y.Cmp(y1) != 0 {
+		t.Errorf("mismatched prv1.Y:\nhave: %x\nwant: %x\n", prv1.PublicKey.Y.Bytes(), y1.Bytes())
+	}
+
+	// test shared secret generation
+	sk1, err := prv0.GenerateShared(&prv1.PublicKey, 16, 16)
+	if err != nil {
+		fmt.Println(err.Error())
+	}
+
+	sk2, err := prv1.GenerateShared(&prv0.PublicKey, 16, 16)
+	if err != nil {
+		t.Fatal(err.Error())
+	}
+
+	if !bytes.Equal(sk1, sk2) {
+		t.Fatal(ErrBadSharedKeys.Error())
+	}
+}
+
 // Verify that the key generation code fails when too much key data is
 // requested.
 func TestTooBigSharedKey(t *testing.T) {
@@ -158,13 +200,13 @@ func TestTooBigSharedKey(t *testing.T) {
 		t.FailNow()
 	}
 
-	_, err = prv1.GenerateShared(&prv2.PublicKey, skLen*2, skLen*2)
+	_, err = prv1.GenerateShared(&prv2.PublicKey, 32, 32)
 	if err != ErrSharedKeyTooBig {
 		fmt.Println("ecdh: shared key should be too large for curve")
 		t.FailNow()
 	}
 
-	_, err = prv2.GenerateShared(&prv1.PublicKey, skLen*2, skLen*2)
+	_, err = prv2.GenerateShared(&prv1.PublicKey, 32, 32)
 	if err != ErrSharedKeyTooBig {
 		fmt.Println("ecdh: shared key should be too large for curve")
 		t.FailNow()
@@ -176,25 +218,21 @@ func TestTooBigSharedKey(t *testing.T) {
 func TestMarshalPublic(t *testing.T) {
 	prv, err := GenerateKey(rand.Reader, DefaultCurve, nil)
 	if err != nil {
-		fmt.Println(err.Error())
-		t.FailNow()
+		t.Fatalf("GenerateKey error: %s", err)
 	}
 
 	out, err := MarshalPublic(&prv.PublicKey)
 	if err != nil {
-		fmt.Println(err.Error())
-		t.FailNow()
+		t.Fatalf("MarshalPublic error: %s", err)
 	}
 
 	pub, err := UnmarshalPublic(out)
 	if err != nil {
-		fmt.Println(err.Error())
-		t.FailNow()
+		t.Fatalf("UnmarshalPublic error: %s", err)
 	}
 
 	if !cmpPublic(prv.PublicKey, *pub) {
-		fmt.Println("ecies: failed to unmarshal public key")
-		t.FailNow()
+		t.Fatal("ecies: failed to unmarshal public key")
 	}
 }
 
@@ -304,9 +342,26 @@ func BenchmarkGenSharedKeyP256(b *testing.B) {
 		fmt.Println(err.Error())
 		b.FailNow()
 	}
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		_, err := prv.GenerateShared(&prv.PublicKey, 16, 16)
+		if err != nil {
+			fmt.Println(err.Error())
+			b.FailNow()
+		}
+	}
+}
 
+// Benchmark the generation of S256 shared keys.
+func BenchmarkGenSharedKeyS256(b *testing.B) {
+	prv, err := GenerateKey(rand.Reader, secp256k1.S256(), nil)
+	if err != nil {
+		fmt.Println(err.Error())
+		b.FailNow()
+	}
+	b.ResetTimer()
 	for i := 0; i < b.N; i++ {
-		_, err := prv.GenerateShared(&prv.PublicKey, skLen, skLen)
+		_, err := prv.GenerateShared(&prv.PublicKey, 16, 16)
 		if err != nil {
 			fmt.Println(err.Error())
 			b.FailNow()
@@ -511,3 +566,43 @@ func TestBasicKeyValidation(t *testing.T) {
 		}
 	}
 }
+
+// Verify GenerateShared against static values - useful when
+// debugging changes in underlying libs
+func TestSharedKeyStatic(t *testing.T) {
+	prv1 := hexKey("7ebbc6a8358bc76dd73ebc557056702c8cfc34e5cfcd90eb83af0347575fd2ad")
+	prv2 := hexKey("6a3d6396903245bba5837752b9e0348874e72db0c4e11e9c485a81b4ea4353b9")
+
+	skLen := MaxSharedKeyLength(&prv1.PublicKey) / 2
+
+	sk1, err := prv1.GenerateShared(&prv2.PublicKey, skLen, skLen)
+	if err != nil {
+		fmt.Println(err.Error())
+		t.FailNow()
+	}
+
+	sk2, err := prv2.GenerateShared(&prv1.PublicKey, skLen, skLen)
+	if err != nil {
+		fmt.Println(err.Error())
+		t.FailNow()
+	}
+
+	if !bytes.Equal(sk1, sk2) {
+		fmt.Println(ErrBadSharedKeys.Error())
+		t.FailNow()
+	}
+
+	sk, _ := hex.DecodeString("167ccc13ac5e8a26b131c3446030c60fbfac6aa8e31149d0869f93626a4cdf62")
+	if !bytes.Equal(sk1, sk) {
+		t.Fatalf("shared secret mismatch: want: %x have: %x", sk, sk1)
+	}
+}
+
+// TODO: remove after refactoring packages crypto and crypto/ecies
+func hexKey(prv string) *PrivateKey {
+	priv := new(ecdsa.PrivateKey)
+	priv.PublicKey.Curve = secp256k1.S256()
+	priv.D, _ = new(big.Int).SetString(prv, 16)
+	priv.PublicKey.X, priv.PublicKey.Y = secp256k1.S256().ScalarBaseMult(priv.D.Bytes())
+	return ImportECDSA(priv)
+}
diff --git a/crypto/ecies/params.go b/crypto/ecies/params.go
index 97ddb09730ade8af95b516856b359cee0fcf8482..511c53ebc0d9c4c805ad03b59b8a94ffff0cf464 100644
--- a/crypto/ecies/params.go
+++ b/crypto/ecies/params.go
@@ -41,13 +41,12 @@ import (
 	"crypto/sha512"
 	"fmt"
 	"hash"
-)
 
-// The default curve for this package is the NIST P256 curve, which
-// provides security equivalent to AES-128.
-var DefaultCurve = elliptic.P256()
+	"github.com/ethereum/go-ethereum/crypto/secp256k1"
+)
 
 var (
+	DefaultCurve                  = secp256k1.S256()
 	ErrUnsupportedECDHAlgorithm   = fmt.Errorf("ecies: unsupported ECDH algorithm")
 	ErrUnsupportedECIESParameters = fmt.Errorf("ecies: unsupported ECIES parameters")
 )
@@ -101,9 +100,10 @@ var (
 )
 
 var paramsFromCurve = map[elliptic.Curve]*ECIESParams{
-	elliptic.P256(): ECIES_AES128_SHA256,
-	elliptic.P384(): ECIES_AES256_SHA384,
-	elliptic.P521(): ECIES_AES256_SHA512,
+	secp256k1.S256(): ECIES_AES128_SHA256,
+	elliptic.P256():  ECIES_AES128_SHA256,
+	elliptic.P384():  ECIES_AES256_SHA384,
+	elliptic.P521():  ECIES_AES256_SHA512,
 }
 
 func AddParamsForCurve(curve elliptic.Curve, params *ECIESParams) {
diff --git a/crypto/key.go b/crypto/key.go
index 4ec43dfd74a0cfefd8d0e3bbd05ddd58a02a12fe..ccf284ad8d5eb000b9514274cd7e73de2b46a2ff 100644
--- a/crypto/key.go
+++ b/crypto/key.go
@@ -25,6 +25,7 @@ import (
 	"strings"
 
 	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/crypto/secp256k1"
 	"github.com/pborman/uuid"
 )
 
@@ -137,7 +138,7 @@ func NewKey(rand io.Reader) *Key {
 		panic("key generation: could not read from random source: " + err.Error())
 	}
 	reader := bytes.NewReader(randBytes)
-	privateKeyECDSA, err := ecdsa.GenerateKey(S256(), reader)
+	privateKeyECDSA, err := ecdsa.GenerateKey(secp256k1.S256(), reader)
 	if err != nil {
 		panic("key generation: ecdsa.GenerateKey failed: " + err.Error())
 	}
@@ -155,7 +156,7 @@ func NewKeyForDirectICAP(rand io.Reader) *Key {
 		panic("key generation: could not read from random source: " + err.Error())
 	}
 	reader := bytes.NewReader(randBytes)
-	privateKeyECDSA, err := ecdsa.GenerateKey(S256(), reader)
+	privateKeyECDSA, err := ecdsa.GenerateKey(secp256k1.S256(), reader)
 	if err != nil {
 		panic("key generation: ecdsa.GenerateKey failed: " + err.Error())
 	}
diff --git a/crypto/curve.go b/crypto/secp256k1/curve.go
similarity index 67%
rename from crypto/curve.go
rename to crypto/secp256k1/curve.go
index 48f3f5e9ce99a53e0a2f6f954d9d476357ed28a7..6e44a6771f7fd2bb84291648c2cb58a8a84ba85e 100644
--- a/crypto/curve.go
+++ b/crypto/secp256k1/curve.go
@@ -29,15 +29,22 @@
 // (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 crypto
+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.
 //
@@ -211,44 +218,37 @@ func (BitCurve *BitCurve) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int,
 	return x3, y3, z3
 }
 
-//TODO: double check if it is okay
-// ScalarMult returns k*(Bx,By) where k is a number in big-endian form.
-func (BitCurve *BitCurve) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) {
-	// We have a slight problem in that the identity of the group (the
-	// point at infinity) cannot be represented in (x, y) form on a finite
-	// machine. Thus the standard add/double algorithm has to be tweaked
-	// slightly: our initial state is not the identity, but x, and we
-	// ignore the first true bit in |k|.  If we don't find any true bits in
-	// |k|, then we return nil, nil, because we cannot return the identity
-	// element.
-
-	Bz := new(big.Int).SetInt64(1)
-	x := Bx
-	y := By
-	z := Bz
-
-	seenFirstTrue := false
-	for _, byte := range k {
-		for bitNum := 0; bitNum < 8; bitNum++ {
-			if seenFirstTrue {
-				x, y, z = BitCurve.doubleJacobian(x, y, z)
-			}
-			if byte&0x80 == 0x80 {
-				if !seenFirstTrue {
-					seenFirstTrue = true
-				} else {
-					x, y, z = BitCurve.addJacobian(Bx, By, Bz, x, y, z)
-				}
-			}
-			byte <<= 1
-		}
+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")
 	}
-
-	if !seenFirstTrue {
+	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 BitCurve.affineFromJacobian(x, y, z)
+	return x, y
 }
 
 // ScalarBaseMult returns k*G, where G is the base point of the group and k is
@@ -312,86 +312,24 @@ func (BitCurve *BitCurve) Unmarshal(data []byte) (x, y *big.Int) {
 	return
 }
 
-//curve parameters taken from:
-//http://www.secg.org/collateral/sec2_final.pdf
-
-var initonce sync.Once
-var ecp160k1 *BitCurve
-var ecp192k1 *BitCurve
-var ecp224k1 *BitCurve
-var ecp256k1 *BitCurve
-
-func initAll() {
-	initS160()
-	initS192()
-	initS224()
-	initS256()
-}
-
-func initS160() {
-	// See SEC 2 section 2.4.1
-	ecp160k1 = new(BitCurve)
-	ecp160k1.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73", 16)
-	ecp160k1.N, _ = new(big.Int).SetString("0100000000000000000001B8FA16DFAB9ACA16B6B3", 16)
-	ecp160k1.B, _ = new(big.Int).SetString("0000000000000000000000000000000000000007", 16)
-	ecp160k1.Gx, _ = new(big.Int).SetString("3B4C382CE37AA192A4019E763036F4F5DD4D7EBB", 16)
-	ecp160k1.Gy, _ = new(big.Int).SetString("938CF935318FDCED6BC28286531733C3F03C4FEE", 16)
-	ecp160k1.BitSize = 160
-}
-
-func initS192() {
-	// See SEC 2 section 2.5.1
-	ecp192k1 = new(BitCurve)
-	ecp192k1.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37", 16)
-	ecp192k1.N, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D", 16)
-	ecp192k1.B, _ = new(big.Int).SetString("000000000000000000000000000000000000000000000003", 16)
-	ecp192k1.Gx, _ = new(big.Int).SetString("DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D", 16)
-	ecp192k1.Gy, _ = new(big.Int).SetString("9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D", 16)
-	ecp192k1.BitSize = 192
-}
-
-func initS224() {
-	// See SEC 2 section 2.6.1
-	ecp224k1 = new(BitCurve)
-	ecp224k1.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D", 16)
-	ecp224k1.N, _ = new(big.Int).SetString("010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7", 16)
-	ecp224k1.B, _ = new(big.Int).SetString("00000000000000000000000000000000000000000000000000000005", 16)
-	ecp224k1.Gx, _ = new(big.Int).SetString("A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C", 16)
-	ecp224k1.Gy, _ = new(big.Int).SetString("7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5", 16)
-	ecp224k1.BitSize = 224
-}
-
-func initS256() {
-	// See SEC 2 section 2.7.1
-	ecp256k1 = new(BitCurve)
-	ecp256k1.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16)
-	ecp256k1.N, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16)
-	ecp256k1.B, _ = new(big.Int).SetString("0000000000000000000000000000000000000000000000000000000000000007", 16)
-	ecp256k1.Gx, _ = new(big.Int).SetString("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", 16)
-	ecp256k1.Gy, _ = new(big.Int).SetString("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", 16)
-	ecp256k1.BitSize = 256
-}
-
-// S160 returns a BitCurve which implements secp160k1 (see SEC 2 section 2.4.1)
-func S160() *BitCurve {
-	initonce.Do(initAll)
-	return ecp160k1
-}
-
-// S192 returns a BitCurve which implements secp192k1 (see SEC 2 section 2.5.1)
-func S192() *BitCurve {
-	initonce.Do(initAll)
-	return ecp192k1
-}
-
-// S224 returns a BitCurve which implements secp224k1 (see SEC 2 section 2.6.1)
-func S224() *BitCurve {
-	initonce.Do(initAll)
-	return ecp224k1
-}
+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(initAll)
-	return ecp256k1
+	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 0000000000000000000000000000000000000000..d915ee8525d6b56a3f0f959b981dba53e9aeb6e1
--- /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 0000000000000000000000000000000000000000..0511545ec09f3d1bc33e3aec3d769f926f376d49
--- /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 41a5608a54b0a6a4e9dcb1b73e5c3d633705d223..8dc2481454d3c24e0c6e5e5fa8d1e7d2e414cae2 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]))
@@ -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 cb71ea5e7d2ee431d375ff713883397b8ab129fe..fc6fc9b32e2a625f5a9c37a8333e848d4018f16c 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()
@@ -86,10 +86,7 @@ func TestSignAndRecover(t *testing.T) {
 func TestRandomMessagesWithSameKey(t *testing.T) {
 	pubkey, seckey := GenerateKeyPair()
 	keys := func() ([]byte, []byte) {
-		// Sign function zeroes the privkey so we need a new one in each call
-		newkey := make([]byte, len(seckey))
-		copy(newkey, seckey)
-		return pubkey, newkey
+		return pubkey, seckey
 	}
 	signAndRecoverWithRandomMessages(t, keys)
 }
@@ -209,30 +206,32 @@ func compactSigCheck(t *testing.T, sig []byte) {
 	}
 }
 
-// godep go test -v -run=XXX -bench=BenchmarkSignRandomInputEachRound
+// godep go test -v -run=XXX -bench=BenchmarkSign
 // add -benchtime=10s to benchmark longer for more accurate average
-func BenchmarkSignRandomInputEachRound(b *testing.B) {
+
+// to avoid compiler optimizing the benchmarked function call
+var err error
+
+func BenchmarkSign(b *testing.B) {
 	for i := 0; i < b.N; i++ {
-		b.StopTimer()
 		_, seckey := GenerateKeyPair()
 		msg := randentropy.GetEntropyCSPRNG(32)
 		b.StartTimer()
-		if _, err := Sign(msg, seckey); err != nil {
-			b.Fatal(err)
-		}
+		_, e := Sign(msg, seckey)
+		err = e
+		b.StopTimer()
 	}
 }
 
-//godep go test -v -run=XXX -bench=BenchmarkRecoverRandomInputEachRound
-func BenchmarkRecoverRandomInputEachRound(b *testing.B) {
+//godep go test -v -run=XXX -bench=BenchmarkECRec
+func BenchmarkRecover(b *testing.B) {
 	for i := 0; i < b.N; i++ {
-		b.StopTimer()
 		_, seckey := GenerateKeyPair()
 		msg := randentropy.GetEntropyCSPRNG(32)
 		sig, _ := Sign(msg, seckey)
 		b.StartTimer()
-		if _, err := RecoverPubkey(msg, sig); err != nil {
-			b.Fatal(err)
-		}
+		_, e := RecoverPubkey(msg, sig)
+		err = e
+		b.StopTimer()
 	}
 }
diff --git a/p2p/discover/node.go b/p2p/discover/node.go
index a14f294249717ab381144f5281a7cbc7d9dc1b81..dd19df3a2c97a041d07eef74c56d180e6ae3d325 100644
--- a/p2p/discover/node.go
+++ b/p2p/discover/node.go
@@ -210,7 +210,7 @@ func PubkeyID(pub *ecdsa.PublicKey) NodeID {
 // Pubkey returns the public key represented by the node ID.
 // It returns an error if the ID is not a point on the curve.
 func (id NodeID) Pubkey() (*ecdsa.PublicKey, error) {
-	p := &ecdsa.PublicKey{Curve: crypto.S256(), X: new(big.Int), Y: new(big.Int)}
+	p := &ecdsa.PublicKey{Curve: secp256k1.S256(), X: new(big.Int), Y: new(big.Int)}
 	half := len(id) / 2
 	p.X.SetBytes(id[:half])
 	p.Y.SetBytes(id[half:])
diff --git a/p2p/rlpx.go b/p2p/rlpx.go
index aaa7338547618cd1f51b6b9848791deaaa4c6cad..8f429d6ec19d38ef59ab4ac9fffdff52f4a1d375 100644
--- a/p2p/rlpx.go
+++ b/p2p/rlpx.go
@@ -277,7 +277,7 @@ func newInitiatorHandshake(remoteID discover.NodeID) (*encHandshake, error) {
 		return nil, err
 	}
 	// generate random keypair to use for signing
-	randpriv, err := ecies.GenerateKey(rand.Reader, crypto.S256(), nil)
+	randpriv, err := ecies.GenerateKey(rand.Reader, secp256k1.S256(), nil)
 	if err != nil {
 		return nil, err
 	}
@@ -376,7 +376,7 @@ func decodeAuthMsg(prv *ecdsa.PrivateKey, token []byte, auth []byte) (*encHandsh
 	var err error
 	h := new(encHandshake)
 	// generate random keypair for session
-	h.randomPrivKey, err = ecies.GenerateKey(rand.Reader, crypto.S256(), nil)
+	h.randomPrivKey, err = ecies.GenerateKey(rand.Reader, secp256k1.S256(), nil)
 	if err != nil {
 		return nil, err
 	}
diff --git a/p2p/rlpx_test.go b/p2p/rlpx_test.go
index 900353f0ee9c1d212478e2eab9c83a166b3e2b4c..7cc7548e2b05b304bca05700c8ccc019ae48a0f2 100644
--- a/p2p/rlpx_test.go
+++ b/p2p/rlpx_test.go
@@ -93,6 +93,7 @@ func testEncHandshake(token []byte) error {
 	go func() {
 		r := result{side: "initiator"}
 		defer func() { output <- r }()
+		defer fd0.Close()
 
 		dest := &discover.Node{ID: discover.PubkeyID(&prv1.PublicKey)}
 		r.id, r.err = c0.doEncHandshake(prv0, dest)
@@ -107,6 +108,7 @@ func testEncHandshake(token []byte) error {
 	go func() {
 		r := result{side: "receiver"}
 		defer func() { output <- r }()
+		defer fd1.Close()
 
 		r.id, r.err = c1.doEncHandshake(prv1, nil)
 		if r.err != nil {
diff --git a/whisper/message_test.go b/whisper/message_test.go
index 6ff95efff564b3e2fe1c5593eb2636b4a38bf1d2..d70da40a4a4ccc023726992bbf7664dbde2adfef 100644
--- a/whisper/message_test.go
+++ b/whisper/message_test.go
@@ -23,6 +23,7 @@ import (
 	"time"
 
 	"github.com/ethereum/go-ethereum/crypto"
+	"github.com/ethereum/go-ethereum/crypto/secp256k1"
 )
 
 // Tests whether a message can be wrapped without any identity or encryption.
@@ -72,8 +73,8 @@ func TestMessageCleartextSignRecover(t *testing.T) {
 	if pubKey == nil {
 		t.Fatalf("failed to recover public key")
 	}
-	p1 := elliptic.Marshal(crypto.S256(), key.PublicKey.X, key.PublicKey.Y)
-	p2 := elliptic.Marshal(crypto.S256(), pubKey.X, pubKey.Y)
+	p1 := elliptic.Marshal(secp256k1.S256(), key.PublicKey.X, key.PublicKey.Y)
+	p2 := elliptic.Marshal(secp256k1.S256(), pubKey.X, pubKey.Y)
 	if !bytes.Equal(p1, p2) {
 		t.Fatalf("public key mismatch: have 0x%x, want 0x%x", p2, p1)
 	}
@@ -150,8 +151,8 @@ func TestMessageFullCrypto(t *testing.T) {
 	if pubKey == nil {
 		t.Fatalf("failed to recover public key")
 	}
-	p1 := elliptic.Marshal(crypto.S256(), fromKey.PublicKey.X, fromKey.PublicKey.Y)
-	p2 := elliptic.Marshal(crypto.S256(), pubKey.X, pubKey.Y)
+	p1 := elliptic.Marshal(secp256k1.S256(), fromKey.PublicKey.X, fromKey.PublicKey.Y)
+	p2 := elliptic.Marshal(secp256k1.S256(), pubKey.X, pubKey.Y)
 	if !bytes.Equal(p1, p2) {
 		t.Fatalf("public key mismatch: have 0x%x, want 0x%x", p2, p1)
 	}