all: use elliptic.Curve implementation from btcec

Also remove our patched-together Curve implementation
in package secp256k1.
This commit is contained in:
Felix Lange 2016-06-09 12:37:44 +02:00
parent b067649bb0
commit 2de36c2694
15 changed files with 72 additions and 519 deletions

View file

@ -29,9 +29,9 @@ import (
"strings" "strings"
"time" "time"
"github.com/btcsuite/btcd/btcec"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/secp256k1"
"github.com/pborman/uuid" "github.com/pborman/uuid"
) )
@ -156,7 +156,7 @@ func NewKeyForDirectICAP(rand io.Reader) *Key {
panic("key generation: could not read from random source: " + err.Error()) panic("key generation: could not read from random source: " + err.Error())
} }
reader := bytes.NewReader(randBytes) reader := bytes.NewReader(randBytes)
privateKeyECDSA, err := ecdsa.GenerateKey(secp256k1.S256(), reader) privateKeyECDSA, err := ecdsa.GenerateKey(btcec.S256(), reader)
if err != nil { if err != nil {
panic("key generation: ecdsa.GenerateKey failed: " + err.Error()) panic("key generation: ecdsa.GenerateKey failed: " + err.Error())
} }
@ -168,7 +168,7 @@ func NewKeyForDirectICAP(rand io.Reader) *Key {
} }
func newKey(rand io.Reader) (*Key, error) { func newKey(rand io.Reader) (*Key, error) {
privateKeyECDSA, err := ecdsa.GenerateKey(secp256k1.S256(), rand) privateKeyECDSA, err := ecdsa.GenerateKey(btcec.S256(), rand)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -48,7 +48,6 @@ var (
"Godeps/", "tests/files/", "build/", "Godeps/", "tests/files/", "build/",
// don't relicense vendored sources // don't relicense vendored sources
"crypto/sha3/", "crypto/ecies/", "logger/glog/", "crypto/sha3/", "crypto/ecies/", "logger/glog/",
"crypto/secp256k1/curve.go",
"trie/arc.go", "trie/arc.go",
} }

View file

@ -21,15 +21,15 @@ import (
"crypto/elliptic" "crypto/elliptic"
"crypto/rand" "crypto/rand"
"crypto/sha256" "crypto/sha256"
"encoding/hex"
"errors"
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"math/big" "math/big"
"os" "os"
"encoding/hex" "github.com/btcsuite/btcd/btcec"
"errors"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto/ecies" "github.com/ethereum/go-ethereum/crypto/ecies"
"github.com/ethereum/go-ethereum/crypto/secp256k1" "github.com/ethereum/go-ethereum/crypto/secp256k1"
@ -38,6 +38,11 @@ import (
"golang.org/x/crypto/ripemd160" "golang.org/x/crypto/ripemd160"
) )
var (
secp256k1N, _ = new(big.Int).SetString("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16)
secp256k1HalfN, _ = new(big.Int).SetString("7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0", 16)
)
func Keccak256(data ...[]byte) []byte { func Keccak256(data ...[]byte) []byte {
d := sha3.NewKeccak256() d := sha3.NewKeccak256()
for _, b := range data { for _, b := range data {
@ -83,16 +88,12 @@ func Ecrecover(hash, sig []byte) ([]byte, error) {
} }
// New methods using proper ecdsa keys from the stdlib // New methods using proper ecdsa keys from the stdlib
func ToECDSA(prv []byte) *ecdsa.PrivateKey { func ToECDSA(key []byte) *ecdsa.PrivateKey {
if len(prv) == 0 { if len(key) == 0 {
return nil return nil
} }
priv, _ := btcec.PrivKeyFromBytes(btcec.S256(), key)
priv := new(ecdsa.PrivateKey) return priv.ToECDSA()
priv.PublicKey.Curve = secp256k1.S256()
priv.D = common.BigD(prv)
priv.PublicKey.X, priv.PublicKey.Y = secp256k1.S256().ScalarBaseMult(prv)
return priv
} }
func FromECDSA(prv *ecdsa.PrivateKey) []byte { func FromECDSA(prv *ecdsa.PrivateKey) []byte {
@ -106,15 +107,15 @@ func ToECDSAPub(pub []byte) *ecdsa.PublicKey {
if len(pub) == 0 { if len(pub) == 0 {
return nil return nil
} }
x, y := elliptic.Unmarshal(secp256k1.S256(), pub) x, y := elliptic.Unmarshal(btcec.S256(), pub)
return &ecdsa.PublicKey{Curve: secp256k1.S256(), X: x, Y: y} return &ecdsa.PublicKey{Curve: btcec.S256(), X: x, Y: y}
} }
func FromECDSAPub(pub *ecdsa.PublicKey) []byte { func FromECDSAPub(pub *ecdsa.PublicKey) []byte {
if pub == nil || pub.X == nil || pub.Y == nil { if pub == nil || pub.X == nil || pub.Y == nil {
return nil return nil
} }
return elliptic.Marshal(secp256k1.S256(), pub.X, pub.Y) return elliptic.Marshal(btcec.S256(), pub.X, pub.Y)
} }
// HexToECDSA parses a secp256k1 private key. // HexToECDSA parses a secp256k1 private key.
@ -158,7 +159,7 @@ func SaveECDSA(file string, key *ecdsa.PrivateKey) error {
} }
func GenerateKey() (*ecdsa.PrivateKey, error) { func GenerateKey() (*ecdsa.PrivateKey, error) {
return ecdsa.GenerateKey(secp256k1.S256(), rand.Reader) return ecdsa.GenerateKey(btcec.S256(), rand.Reader)
} }
func ValidateSignatureValues(v byte, r, s *big.Int, homestead bool) bool { func ValidateSignatureValues(v byte, r, s *big.Int, homestead bool) bool {
@ -168,14 +169,14 @@ func ValidateSignatureValues(v byte, r, s *big.Int, homestead bool) bool {
vint := uint32(v) vint := uint32(v)
// reject upper range of s values (ECDSA malleability) // reject upper range of s values (ECDSA malleability)
// see discussion in secp256k1/libsecp256k1/include/secp256k1.h // see discussion in secp256k1/libsecp256k1/include/secp256k1.h
if homestead && s.Cmp(secp256k1.HalfN) > 0 { if homestead && s.Cmp(secp256k1HalfN) > 0 {
return false return false
} }
// Frontier: allow s to be in full N range // Frontier: allow s to be in full N range
if s.Cmp(secp256k1.N) >= 0 { if s.Cmp(secp256k1N) >= 0 {
return false return false
} }
if r.Cmp(secp256k1.N) < 0 && (vint == 27 || vint == 28) { if r.Cmp(secp256k1N) < 0 && (vint == 27 || vint == 28) {
return true return true
} else { } else {
return false return false
@ -188,8 +189,8 @@ func SigToPub(hash, sig []byte) (*ecdsa.PublicKey, error) {
return nil, err return nil, err
} }
x, y := elliptic.Unmarshal(secp256k1.S256(), s) x, y := elliptic.Unmarshal(btcec.S256(), s)
return &ecdsa.PublicKey{Curve: secp256k1.S256(), X: x, Y: y}, nil return &ecdsa.PublicKey{Curve: btcec.S256(), X: x, Y: y}, nil
} }
func Sign(hash []byte, prv *ecdsa.PrivateKey) (sig []byte, err error) { func Sign(hash []byte, prv *ecdsa.PrivateKey) (sig []byte, err error) {

View file

@ -28,7 +28,6 @@ import (
"time" "time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto/secp256k1"
) )
var testAddrHex = "970e8128ab834e8eac17ab8e3812f010678cf791" var testAddrHex = "970e8128ab834e8eac17ab8e3812f010678cf791"
@ -72,14 +71,6 @@ func BenchmarkSha3(b *testing.B) {
fmt.Println(amount, ":", time.Since(start)) fmt.Println(amount, ":", time.Since(start))
} }
func Test0Key(t *testing.T) {
key := common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000000")
_, err := secp256k1.GeneratePubKey(key)
if err == nil {
t.Errorf("expected error due to zero privkey")
}
}
func TestSign(t *testing.T) { func TestSign(t *testing.T) {
key, _ := HexToECDSA(testPrivHex) key, _ := HexToECDSA(testPrivHex)
addr := common.HexToAddress(testAddrHex) addr := common.HexToAddress(testAddrHex)
@ -87,11 +78,11 @@ func TestSign(t *testing.T) {
msg := Keccak256([]byte("foo")) msg := Keccak256([]byte("foo"))
sig, err := Sign(msg, key) sig, err := Sign(msg, key)
if err != nil { if err != nil {
t.Errorf("Sign error: %s", err) t.Fatal("Sign error:", err)
} }
recoveredPub, err := Ecrecover(msg, sig) recoveredPub, err := Ecrecover(msg, sig)
if err != nil { if err != nil {
t.Errorf("ECRecover error: %s", err) t.Fatal("ECRecover error:", err)
} }
recoveredAddr := PubkeyToAddress(*ToECDSAPub(recoveredPub)) recoveredAddr := PubkeyToAddress(*ToECDSAPub(recoveredPub))
if addr != recoveredAddr { if addr != recoveredAddr {
@ -101,7 +92,7 @@ func TestSign(t *testing.T) {
// should be equal to SigToPub // should be equal to SigToPub
recoveredPub2, err := SigToPub(msg, sig) recoveredPub2, err := SigToPub(msg, sig)
if err != nil { if err != nil {
t.Errorf("ECRecover error: %s", err) t.Fatal("SigToPub error:", err)
} }
recoveredAddr2 := PubkeyToAddress(*recoveredPub2) recoveredAddr2 := PubkeyToAddress(*recoveredPub2)
if addr != recoveredAddr2 { if addr != recoveredAddr2 {
@ -181,7 +172,7 @@ func TestValidateSignatureValues(t *testing.T) {
minusOne := big.NewInt(-1) minusOne := big.NewInt(-1)
one := common.Big1 one := common.Big1
zero := common.Big0 zero := common.Big0
secp256k1nMinus1 := new(big.Int).Sub(secp256k1.N, common.Big1) secp256k1nMinus1 := new(big.Int).Sub(secp256k1N, common.Big1)
// correct v,r,s // correct v,r,s
check(true, 27, one, one) check(true, 27, one, one)
@ -208,9 +199,9 @@ func TestValidateSignatureValues(t *testing.T) {
// correct sig with max r,s // correct sig with max r,s
check(true, 27, secp256k1nMinus1, secp256k1nMinus1) check(true, 27, secp256k1nMinus1, secp256k1nMinus1)
// correct v, combinations of incorrect r,s at upper limit // correct v, combinations of incorrect r,s at upper limit
check(false, 27, secp256k1.N, secp256k1nMinus1) check(false, 27, secp256k1N, secp256k1nMinus1)
check(false, 27, secp256k1nMinus1, secp256k1.N) check(false, 27, secp256k1nMinus1, secp256k1N)
check(false, 27, secp256k1.N, secp256k1.N) check(false, 27, secp256k1N, secp256k1N)
// current callers ensures r,s cannot be negative, but let's test for that too // current callers ensures r,s cannot be negative, but let's test for that too
// as crypto package could be used stand-alone // as crypto package could be used stand-alone
@ -230,20 +221,3 @@ func checkAddr(t *testing.T, addr0, addr1 common.Address) {
t.Fatalf("address mismatch: want: %x have: %x", addr0, addr1) t.Fatalf("address mismatch: want: %x have: %x", addr0, addr1)
} }
} }
// test to help Python team with integration of libsecp256k1
// skip but keep it after they are done
func TestPythonIntegration(t *testing.T) {
kh := "289c2857d4598e37fb9647507e47a309d6133539bf21a8b9cb6df88fd5232032"
k0, _ := HexToECDSA(kh)
k1 := FromECDSA(k0)
msg0 := Keccak256([]byte("foo"))
sig0, _ := secp256k1.Sign(msg0, k1)
msg1 := common.FromHex("00000000000000000000000000000000")
sig1, _ := secp256k1.Sign(msg0, k1)
fmt.Printf("msg: %x, privkey: %x sig: %x\n", msg0, k1, sig0)
fmt.Printf("msg: %x, privkey: %x sig: %x\n", msg1, k1, sig1)
}

View file

@ -42,7 +42,7 @@ import (
"hash" "hash"
"math/big" "math/big"
"github.com/ethereum/go-ethereum/crypto/secp256k1" "github.com/btcsuite/btcd/btcec"
) )
var ( var (
@ -120,7 +120,7 @@ func (curve secgNamedCurve) Equal(curve2 secgNamedCurve) bool {
func namedCurveFromOID(curve secgNamedCurve) elliptic.Curve { func namedCurveFromOID(curve secgNamedCurve) elliptic.Curve {
switch { switch {
case curve.Equal(secgNamedCurveS256): case curve.Equal(secgNamedCurveS256):
return secp256k1.S256() return btcec.S256()
case curve.Equal(secgNamedCurveP256): case curve.Equal(secgNamedCurveP256):
return elliptic.P256() return elliptic.P256()
case curve.Equal(secgNamedCurveP384): case curve.Equal(secgNamedCurveP384):
@ -139,7 +139,7 @@ func oidFromNamedCurve(curve elliptic.Curve) (secgNamedCurve, bool) {
return secgNamedCurveP384, true return secgNamedCurveP384, true
case elliptic.P521(): case elliptic.P521():
return secgNamedCurveP521, true return secgNamedCurveP521, true
case secp256k1.S256(): case btcec.S256():
return secgNamedCurveS256, true return secgNamedCurveS256, true
} }

View file

@ -42,7 +42,7 @@ import (
"math/big" "math/big"
"testing" "testing"
"github.com/ethereum/go-ethereum/crypto/secp256k1" "github.com/btcsuite/btcd/btcec"
) )
var dumpEnc bool var dumpEnc bool
@ -354,7 +354,7 @@ func BenchmarkGenSharedKeyP256(b *testing.B) {
// Benchmark the generation of S256 shared keys. // Benchmark the generation of S256 shared keys.
func BenchmarkGenSharedKeyS256(b *testing.B) { func BenchmarkGenSharedKeyS256(b *testing.B) {
prv, err := GenerateKey(rand.Reader, secp256k1.S256(), nil) prv, err := GenerateKey(rand.Reader, btcec.S256(), nil)
if err != nil { if err != nil {
fmt.Println(err.Error()) fmt.Println(err.Error())
b.FailNow() b.FailNow()
@ -631,8 +631,8 @@ func TestSharedKeyStatic(t *testing.T) {
// TODO: remove after refactoring packages crypto and crypto/ecies // TODO: remove after refactoring packages crypto and crypto/ecies
func hexKey(prv string) *PrivateKey { func hexKey(prv string) *PrivateKey {
priv := new(ecdsa.PrivateKey) priv := new(ecdsa.PrivateKey)
priv.PublicKey.Curve = secp256k1.S256() priv.PublicKey.Curve = btcec.S256()
priv.D, _ = new(big.Int).SetString(prv, 16) priv.D, _ = new(big.Int).SetString(prv, 16)
priv.PublicKey.X, priv.PublicKey.Y = secp256k1.S256().ScalarBaseMult(priv.D.Bytes()) priv.PublicKey.X, priv.PublicKey.Y = btcec.S256().ScalarBaseMult(priv.D.Bytes())
return ImportECDSA(priv) return ImportECDSA(priv)
} }

View file

@ -42,11 +42,11 @@ import (
"fmt" "fmt"
"hash" "hash"
"github.com/ethereum/go-ethereum/crypto/secp256k1" "github.com/btcsuite/btcd/btcec"
) )
var ( var (
DefaultCurve = secp256k1.S256() DefaultCurve = btcec.S256()
ErrUnsupportedECDHAlgorithm = fmt.Errorf("ecies: unsupported ECDH algorithm") ErrUnsupportedECDHAlgorithm = fmt.Errorf("ecies: unsupported ECDH algorithm")
ErrUnsupportedECIESParameters = fmt.Errorf("ecies: unsupported ECIES parameters") ErrUnsupportedECIESParameters = fmt.Errorf("ecies: unsupported ECIES parameters")
) )
@ -100,10 +100,10 @@ var (
) )
var paramsFromCurve = map[elliptic.Curve]*ECIESParams{ var paramsFromCurve = map[elliptic.Curve]*ECIESParams{
secp256k1.S256(): ECIES_AES128_SHA256, btcec.S256(): ECIES_AES128_SHA256,
elliptic.P256(): ECIES_AES128_SHA256, elliptic.P256(): ECIES_AES128_SHA256,
elliptic.P384(): ECIES_AES256_SHA384, elliptic.P384(): ECIES_AES256_SHA384,
elliptic.P521(): ECIES_AES256_SHA512, elliptic.P521(): ECIES_AES256_SHA512,
} }
func AddParamsForCurve(curve elliptic.Curve, params *ECIESParams) { func AddParamsForCurve(curve elliptic.Curve, params *ECIESParams) {

View file

@ -1,335 +0,0 @@
// 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
}

View file

@ -1,39 +0,0 @@
// 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")
}

View file

@ -1,56 +0,0 @@
// 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;
}

View file

@ -29,7 +29,6 @@ package secp256k1
#define NDEBUG #define NDEBUG
#include "./libsecp256k1/src/secp256k1.c" #include "./libsecp256k1/src/secp256k1.c"
#include "./libsecp256k1/src/modules/recovery/main_impl.h" #include "./libsecp256k1/src/modules/recovery/main_impl.h"
#include "pubkey_scalar_mul.h"
typedef void (*callbackFunc) (const char* msg, void* data); typedef void (*callbackFunc) (const char* msg, void* data);
extern void secp256k1GoPanicIllegal(const char* msg, void* data); extern void secp256k1GoPanicIllegal(const char* msg, void* data);
@ -57,15 +56,9 @@ import (
// holds ptr to secp256k1_context_struct (see secp256k1/include/secp256k1.h) // holds ptr to secp256k1_context_struct (see secp256k1/include/secp256k1.h)
var ( var (
context *C.secp256k1_context context *C.secp256k1_context
N *big.Int
HalfN *big.Int
) )
func init() { func init() {
N, _ = new(big.Int).SetString("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16)
// N / 2 == 57896044618658097711785492504343953926418782139537452191302581570759080747168
HalfN, _ = new(big.Int).SetString("7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0", 16)
// around 20 ms on a modern CPU. // around 20 ms on a modern CPU.
context = C.secp256k1_context_create(3) // SECP256K1_START_SIGN | SECP256K1_START_VERIFY context = C.secp256k1_context_create(3) // SECP256K1_START_SIGN | SECP256K1_START_VERIFY
C.secp256k1_context_set_illegal_callback(context, C.callbackFunc(C.secp256k1GoPanicIllegal), nil) C.secp256k1_context_set_illegal_callback(context, C.callbackFunc(C.secp256k1GoPanicIllegal), nil)

View file

@ -19,6 +19,7 @@ package secp256k1
import ( import (
"bytes" "bytes"
"encoding/hex" "encoding/hex"
"math/big"
"testing" "testing"
"github.com/ethereum/go-ethereum/crypto/randentropy" "github.com/ethereum/go-ethereum/crypto/randentropy"
@ -191,6 +192,21 @@ func TestRecoverSanity(t *testing.T) {
} }
} }
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")
}
// tests for malleability // tests for malleability
// highest bit of signature ECDSA s value must be 0, in the 33th byte // highest bit of signature ECDSA s value must be 0, in the 33th byte
func compactSigCheck(t *testing.T, sig []byte) { func compactSigCheck(t *testing.T, sig []byte) {

View file

@ -30,9 +30,9 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/btcsuite/btcd/btcec"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/secp256k1"
) )
const nodeIDBits = 512 const nodeIDBits = 512
@ -262,7 +262,7 @@ func PubkeyID(pub *ecdsa.PublicKey) NodeID {
// Pubkey returns the public key represented by the node ID. // Pubkey returns the public key represented by the node ID.
// It returns an error if the ID is not a point on the curve. // It returns an error if the ID is not a point on the curve.
func (id NodeID) Pubkey() (*ecdsa.PublicKey, error) { func (id NodeID) Pubkey() (*ecdsa.PublicKey, error) {
p := &ecdsa.PublicKey{Curve: secp256k1.S256(), X: new(big.Int), Y: new(big.Int)} p := &ecdsa.PublicKey{Curve: btcec.S256(), X: new(big.Int), Y: new(big.Int)}
half := len(id) / 2 half := len(id) / 2
p.X.SetBytes(id[:half]) p.X.SetBytes(id[:half])
p.Y.SetBytes(id[half:]) p.Y.SetBytes(id[half:])
@ -275,7 +275,7 @@ func (id NodeID) Pubkey() (*ecdsa.PublicKey, error) {
// recoverNodeID computes the public key used to sign the // recoverNodeID computes the public key used to sign the
// given hash from the signature. // given hash from the signature.
func recoverNodeID(hash, sig []byte) (id NodeID, err error) { func recoverNodeID(hash, sig []byte) (id NodeID, err error) {
pubkey, err := secp256k1.RecoverPubkey(hash, sig) pubkey, err := crypto.Ecrecover(hash, sig)
if err != nil { if err != nil {
return id, err return id, err
} }

View file

@ -34,9 +34,9 @@ import (
"sync" "sync"
"time" "time"
"github.com/btcsuite/btcd/btcec"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/ecies" "github.com/ethereum/go-ethereum/crypto/ecies"
"github.com/ethereum/go-ethereum/crypto/secp256k1"
"github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/p2p/discover" "github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
@ -303,7 +303,7 @@ func (h *encHandshake) makeAuthMsg(prv *ecdsa.PrivateKey, token []byte) (*authMs
return nil, err return nil, err
} }
// Generate random keypair to for ECDH. // Generate random keypair to for ECDH.
h.randomPrivKey, err = ecies.GenerateKey(rand.Reader, secp256k1.S256(), nil) h.randomPrivKey, err = ecies.GenerateKey(rand.Reader, btcec.S256(), nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -381,7 +381,7 @@ func (h *encHandshake) handleAuthMsg(msg *authMsgV4, prv *ecdsa.PrivateKey) erro
// Generate random keypair for ECDH. // Generate random keypair for ECDH.
// If a private key is already set, use it instead of generating one (for testing). // If a private key is already set, use it instead of generating one (for testing).
if h.randomPrivKey == nil { if h.randomPrivKey == nil {
h.randomPrivKey, err = ecies.GenerateKey(rand.Reader, secp256k1.S256(), nil) h.randomPrivKey, err = ecies.GenerateKey(rand.Reader, btcec.S256(), nil)
if err != nil { if err != nil {
return err return err
} }
@ -393,7 +393,7 @@ func (h *encHandshake) handleAuthMsg(msg *authMsgV4, prv *ecdsa.PrivateKey) erro
return err return err
} }
signedMsg := xor(token, h.initNonce) signedMsg := xor(token, h.initNonce)
remoteRandomPub, err := secp256k1.RecoverPubkey(signedMsg, msg.Signature[:]) remoteRandomPub, err := crypto.Ecrecover(signedMsg, msg.Signature[:])
if err != nil { if err != nil {
return err return err
} }

View file

@ -22,8 +22,8 @@ import (
"testing" "testing"
"time" "time"
"github.com/btcsuite/btcd/btcec"
"github.com/ethereum/go-ethereum/crypto" "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. // Tests whether a message can be wrapped without any identity or encryption.
@ -73,8 +73,8 @@ func TestMessageCleartextSignRecover(t *testing.T) {
if pubKey == nil { if pubKey == nil {
t.Fatalf("failed to recover public key") t.Fatalf("failed to recover public key")
} }
p1 := elliptic.Marshal(secp256k1.S256(), key.PublicKey.X, key.PublicKey.Y) p1 := elliptic.Marshal(btcec.S256(), key.PublicKey.X, key.PublicKey.Y)
p2 := elliptic.Marshal(secp256k1.S256(), pubKey.X, pubKey.Y) p2 := elliptic.Marshal(btcec.S256(), pubKey.X, pubKey.Y)
if !bytes.Equal(p1, p2) { if !bytes.Equal(p1, p2) {
t.Fatalf("public key mismatch: have 0x%x, want 0x%x", p2, p1) t.Fatalf("public key mismatch: have 0x%x, want 0x%x", p2, p1)
} }
@ -151,8 +151,8 @@ func TestMessageFullCrypto(t *testing.T) {
if pubKey == nil { if pubKey == nil {
t.Fatalf("failed to recover public key") t.Fatalf("failed to recover public key")
} }
p1 := elliptic.Marshal(secp256k1.S256(), fromKey.PublicKey.X, fromKey.PublicKey.Y) p1 := elliptic.Marshal(btcec.S256(), fromKey.PublicKey.X, fromKey.PublicKey.Y)
p2 := elliptic.Marshal(secp256k1.S256(), pubKey.X, pubKey.Y) p2 := elliptic.Marshal(btcec.S256(), pubKey.X, pubKey.Y)
if !bytes.Equal(p1, p2) { if !bytes.Equal(p1, p2) {
t.Fatalf("public key mismatch: have 0x%x, want 0x%x", p2, p1) t.Fatalf("public key mismatch: have 0x%x, want 0x%x", p2, p1)
} }