Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 28 additions & 2 deletions client/cmd/bootnode/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"crypto/ecdsa"
"flag"
"fmt"
"net"
"os"

"github.com/kowala-tech/kcoin/client/cmd/utils"
Expand Down Expand Up @@ -79,12 +80,37 @@ func main() {
}
}

addr, err := net.ResolveUDPAddr("udp", *listenAddr)
if err != nil {
utils.Fatalf("-ResolveUDPAddr: %v", err)
}
conn, err := net.ListenUDP("udp", addr)
if err != nil {
utils.Fatalf("-ListenUDP: %v", err)
}

realaddr := conn.LocalAddr().(*net.UDPAddr)
if natm != nil {
if !realaddr.IP.IsLoopback() {
go nat.Map(natm, nil, "udp", realaddr.Port, realaddr.Port, "ethereum discovery")
}
// TODO: react to external IP changes over time.
if ext, err := natm.ExternalIP(); err == nil {
realaddr = &net.UDPAddr{IP: ext, Port: realaddr.Port}
}
}

if *runv5 {
if _, err := discv5.ListenUDP(nodeKey, *listenAddr, natm, "", restrictList); err != nil {
if _, err := discv5.ListenUDP(nodeKey, conn, realaddr, "", restrictList); err != nil {
utils.Fatalf("%v", err)
}
} else {
if _, err := discover.ListenUDP(nodeKey, *listenAddr, natm, "", restrictList); err != nil {
cfg := discover.Config{
PrivateKey: nodeKey,
AnnounceAddr: realaddr,
NetRestrict: restrictList,
}
if _, err := discover.ListenUDP(conn, cfg); err != nil {
utils.Fatalf("%v", err)
}
}
Expand Down
25 changes: 19 additions & 6 deletions client/crypto/crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ import (
)

var (
secp256k1_N, _ = new(big.Int).SetString("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16)
secp256k1_halfN = new(big.Int).Div(secp256k1_N, big.NewInt(2))
secp256k1N, _ = new(big.Int).SetString("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16)
secp256k1halfN = new(big.Int).Div(secp256k1N, big.NewInt(2))
)

// Keccak256 calculates and returns the Keccak256 hash of the input data.
Expand Down Expand Up @@ -68,7 +68,7 @@ func Keccak512(data ...[]byte) []byte {
return d.Sum(nil)
}

// Creates an ethereum address given the bytes and the nonce
// CreateAddress creates an ethereum address given the bytes and the nonce
func CreateAddress(b common.Address, nonce uint64) common.Address {
data, _ := rlp.EncodeToBytes([]interface{}{b, nonce})
return common.BytesToAddress(Keccak256(data)[12:])
Expand All @@ -79,7 +79,7 @@ func ToECDSA(d []byte) (*ecdsa.PrivateKey, error) {
return toECDSA(d, true)
}

// ToECDSAUnsafe blidly converts a binary blob to a private key. It should almost
// ToECDSAUnsafe blindly converts a binary blob to a private key. It should almost
// never be used unless you are sure the input is valid and want to avoid hitting
// errors due to bad origin encoding (0 prefixes cut off).
func ToECDSAUnsafe(d []byte) *ecdsa.PrivateKey {
Expand All @@ -97,7 +97,20 @@ func toECDSA(d []byte, strict bool) (*ecdsa.PrivateKey, error) {
return nil, fmt.Errorf("invalid length, need %d bits", priv.Params().BitSize)
}
priv.D = new(big.Int).SetBytes(d)

// The priv.D must < N
if priv.D.Cmp(secp256k1N) >= 0 {
return nil, fmt.Errorf("invalid private key, >=N")
}
// The priv.D must not be zero or negative.
if priv.D.Sign() <= 0 {
return nil, fmt.Errorf("invalid private key, zero or negative")
}

priv.PublicKey.X, priv.PublicKey.Y = priv.PublicKey.Curve.ScalarBaseMult(d)
if priv.PublicKey.X == nil {
return nil, errors.New("invalid private key")
}
return priv, nil
}

Expand Down Expand Up @@ -171,11 +184,11 @@ func ValidateSignatureValues(v byte, r, s *big.Int, homestead bool) bool {
}
// reject upper range of s values (ECDSA malleability)
// see discussion in secp256k1/libsecp256k1/include/secp256k1.h
if homestead && s.Cmp(secp256k1_halfN) > 0 {
if homestead && s.Cmp(secp256k1halfN) > 0 {
return false
}
// Frontier: allow s to be in full N range
return r.Cmp(secp256k1_N) < 0 && s.Cmp(secp256k1_N) < 0 && (v == 0 || v == 1)
return r.Cmp(secp256k1N) < 0 && s.Cmp(secp256k1N) < 0 && (v == 0 || v == 1)
}

func PubkeyToAddress(p ecdsa.PublicKey) common.Address {
Expand Down
25 changes: 14 additions & 11 deletions client/crypto/crypto_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,10 @@ import (
"bytes"
"crypto/ecdsa"
"encoding/hex"
"fmt"
"io/ioutil"
"math/big"
"os"
"testing"
"time"

"github.com/kowala-tech/kcoin/client/common"
)
Expand All @@ -42,15 +40,20 @@ func TestKeccak256Hash(t *testing.T) {
checkhash(t, "Sha3-256-array", func(in []byte) []byte { h := Keccak256Hash(in); return h[:] }, msg, exp)
}

func TestToECDSAErrors(t *testing.T) {
if _, err := HexToECDSA("0000000000000000000000000000000000000000000000000000000000000000"); err == nil {
t.Fatal("HexToECDSA should've returned error")
}
if _, err := HexToECDSA("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); err == nil {
t.Fatal("HexToECDSA should've returned error")
}
}

func BenchmarkSha3(b *testing.B) {
a := []byte("hello world")
amount := 1000000
start := time.Now()
for i := 0; i < amount; i++ {
for i := 0; i < b.N; i++ {
Keccak256(a)
}

fmt.Println(amount, ":", time.Since(start))
}

func TestSign(t *testing.T) {
Expand Down Expand Up @@ -151,7 +154,7 @@ func TestValidateSignatureValues(t *testing.T) {
minusOne := big.NewInt(-1)
one := common.Big1
zero := common.Big0
secp256k1nMinus1 := new(big.Int).Sub(secp256k1_N, common.Big1)
secp256k1nMinus1 := new(big.Int).Sub(secp256k1N, common.Big1)

// correct v,r,s
check(true, 0, one, one)
Expand All @@ -178,9 +181,9 @@ func TestValidateSignatureValues(t *testing.T) {
// correct sig with max r,s
check(true, 0, secp256k1nMinus1, secp256k1nMinus1)
// correct v, combinations of incorrect r,s at upper limit
check(false, 0, secp256k1_N, secp256k1nMinus1)
check(false, 0, secp256k1nMinus1, secp256k1_N)
check(false, 0, secp256k1_N, secp256k1_N)
check(false, 0, secp256k1N, secp256k1nMinus1)
check(false, 0, secp256k1nMinus1, secp256k1N)
check(false, 0, secp256k1N, secp256k1N)

// current callers ensures r,s cannot be negative, but let's test for that too
// as crypto package could be used stand-alone
Expand Down
8 changes: 4 additions & 4 deletions client/crypto/ecies/ecies.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ func symEncrypt(rand io.Reader, params *ECIESParams, key, m []byte) (ct []byte,

// symDecrypt carries out CTR decryption using the block cipher specified in
// the parameters
func symDecrypt(rand io.Reader, params *ECIESParams, key, ct []byte) (m []byte, err error) {
func symDecrypt(params *ECIESParams, key, ct []byte) (m []byte, err error) {
c, err := params.Cipher(key)
if err != nil {
return
Expand Down Expand Up @@ -292,7 +292,7 @@ func Encrypt(rand io.Reader, pub *PublicKey, m, s1, s2 []byte) (ct []byte, err e
}

// Decrypt decrypts an ECIES ciphertext.
func (prv *PrivateKey) Decrypt(rand io.Reader, c, s1, s2 []byte) (m []byte, err error) {
func (prv *PrivateKey) Decrypt(c, s1, s2 []byte) (m []byte, err error) {
if len(c) == 0 {
return nil, ErrInvalidMessage
}
Expand All @@ -314,7 +314,7 @@ func (prv *PrivateKey) Decrypt(rand io.Reader, c, s1, s2 []byte) (m []byte, err

switch c[0] {
case 2, 3, 4:
rLen = ((prv.PublicKey.Curve.Params().BitSize + 7) / 4)
rLen = (prv.PublicKey.Curve.Params().BitSize + 7) / 4
if len(c) < (rLen + hLen + 1) {
err = ErrInvalidMessage
return
Expand Down Expand Up @@ -361,6 +361,6 @@ func (prv *PrivateKey) Decrypt(rand io.Reader, c, s1, s2 []byte) (m []byte, err
return
}

m, err = symDecrypt(rand, params, Ke, c[mStart:mEnd])
m, err = symDecrypt(params, Ke, c[mStart:mEnd])
return
}
48 changes: 20 additions & 28 deletions client/crypto/secp256k1/curve.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,14 @@ package secp256k1
import (
"crypto/elliptic"
"math/big"
"sync"
"unsafe"

"github.com/kowala-tech/kcoin/client/common/math"
)

/*
#include "libsecp256k1/include/secp256k1.h"
extern int secp256k1_pubkey_scalar_mul(const secp256k1_context* ctx, const unsigned char *point, const unsigned char *scalar);
extern int secp256k1_ext_scalar_mul(const secp256k1_context* ctx, const unsigned char *point, const unsigned char *scalar);
*/
import "C"

Expand Down Expand Up @@ -78,7 +77,7 @@ func (BitCurve *BitCurve) Params() *elliptic.CurveParams {
}
}

// IsOnBitCurve returns true if the given (x,y) lies on the BitCurve.
// IsOnCurve 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²
Expand Down Expand Up @@ -236,7 +235,7 @@ func (BitCurve *BitCurve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int,
math.ReadBits(By, point[32:])
pointPtr := (*C.uchar)(unsafe.Pointer(&point[0]))
scalarPtr := (*C.uchar)(unsafe.Pointer(&scalar[0]))
res := C.secp256k1_pubkey_scalar_mul(context, pointPtr, scalarPtr)
res := C.secp256k1_ext_scalar_mul(context, pointPtr, scalarPtr)

// Unpack the result and clear temporaries.
x := new(big.Int).SetBytes(point[:32])
Expand All @@ -263,14 +262,10 @@ func (BitCurve *BitCurve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) {
// 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)
ret[0] = 4 // uncompressed point flag
math.ReadBits(x, ret[1:1+byteLen])
math.ReadBits(y, ret[1+byteLen:])
return ret
}

Expand All @@ -289,24 +284,21 @@ func (BitCurve *BitCurve) Unmarshal(data []byte) (x, y *big.Int) {
return
}

var (
initonce sync.Once
theCurve *BitCurve
)
var theCurve = new(BitCurve)

func init() {
// See SEC 2 section 2.7.1
// curve parameters taken from:
// http://www.secg.org/collateral/sec2_final.pdf
theCurve.P = math.MustParseBig256("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F")
theCurve.N = math.MustParseBig256("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141")
theCurve.B = math.MustParseBig256("0x0000000000000000000000000000000000000000000000000000000000000007")
theCurve.Gx = math.MustParseBig256("0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798")
theCurve.Gy = math.MustParseBig256("0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8")
theCurve.BitSize = 256
}

// S256 returns a BitCurve which implements secp256k1 (see SEC 2 section 2.7.1)
// S256 returns a BitCurve which implements secp256k1.
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
}
63 changes: 59 additions & 4 deletions client/crypto/secp256k1/ext.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ static secp256k1_context* secp256k1_context_create_sign_verify() {
return secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
}

// secp256k1_ecdsa_recover_pubkey recovers the public key of an encoded compact signature.
// secp256k1_ext_ecdsa_recover recovers the public key of an encoded compact signature.
//
// Returns: 1: recovery was successful
// 0: recovery was not successful
// Args: ctx: pointer to a context object (cannot be NULL)
// Out: pubkey_out: the serialized 65-byte public key of the signer (cannot be NULL)
// In: sigdata: pointer to a 65-byte signature with the recovery id at the end (cannot be NULL)
// msgdata: pointer to a 32-byte message (cannot be NULL)
static int secp256k1_ecdsa_recover_pubkey(
static int secp256k1_ext_ecdsa_recover(
const secp256k1_context* ctx,
unsigned char *pubkey_out,
const unsigned char *sigdata,
Expand All @@ -46,7 +46,62 @@ static int secp256k1_ecdsa_recover_pubkey(
return secp256k1_ec_pubkey_serialize(ctx, pubkey_out, &outputlen, &pubkey, SECP256K1_EC_UNCOMPRESSED);
}

// secp256k1_pubkey_scalar_mul multiplies a point by a scalar in constant time.
// secp256k1_ext_ecdsa_verify verifies an encoded compact signature.
//
// Returns: 1: signature is valid
// 0: signature is invalid
// Args: ctx: pointer to a context object (cannot be NULL)
// In: sigdata: pointer to a 64-byte signature (cannot be NULL)
// msgdata: pointer to a 32-byte message (cannot be NULL)
// pubkeydata: pointer to public key data (cannot be NULL)
// pubkeylen: length of pubkeydata
static int secp256k1_ext_ecdsa_verify(
const secp256k1_context* ctx,
const unsigned char *sigdata,
const unsigned char *msgdata,
const unsigned char *pubkeydata,
size_t pubkeylen
) {
secp256k1_ecdsa_signature sig;
secp256k1_pubkey pubkey;

if (!secp256k1_ecdsa_signature_parse_compact(ctx, &sig, sigdata)) {
return 0;
}
if (!secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeydata, pubkeylen)) {
return 0;
}
return secp256k1_ecdsa_verify(ctx, &sig, msgdata, &pubkey);
}

// secp256k1_ext_reencode_pubkey decodes then encodes a public key. It can be used to
// convert between public key formats. The input/output formats are chosen depending on the
// length of the input/output buffers.
//
// Returns: 1: conversion successful
// 0: conversion unsuccessful
// Args: ctx: pointer to a context object (cannot be NULL)
// Out: out: output buffer that will contain the reencoded key (cannot be NULL)
// In: outlen: length of out (33 for compressed keys, 65 for uncompressed keys)
// pubkeydata: the input public key (cannot be NULL)
// pubkeylen: length of pubkeydata
static int secp256k1_ext_reencode_pubkey(
const secp256k1_context* ctx,
unsigned char *out,
size_t outlen,
const unsigned char *pubkeydata,
size_t pubkeylen
) {
secp256k1_pubkey pubkey;

if (!secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeydata, pubkeylen)) {
return 0;
}
unsigned int flag = (outlen == 33) ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED;
return secp256k1_ec_pubkey_serialize(ctx, out, &outlen, &pubkey, flag);
}

// secp256k1_ext_scalar_mul multiplies a point by a scalar in constant time.
//
// Returns: 1: multiplication was successful
// 0: scalar was invalid (zero or overflow)
Expand All @@ -55,7 +110,7 @@ static int secp256k1_ecdsa_recover_pubkey(
// In: point: pointer to a 64-byte public 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 secp256k1_ext_scalar_mul(const secp256k1_context* ctx, unsigned char *point, const unsigned char *scalar) {
int ret = 0;
int overflow = 0;
secp256k1_fe feX, feY;
Expand Down
Loading