Skip to content

Commit

Permalink
crypto/secp256k1: remove external LGPL dependencies (ethereum#17239)
Browse files Browse the repository at this point in the history
  • Loading branch information
karalabe authored and fjl committed Jul 26, 2018
1 parent 11a402f commit d9575e9
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 72 deletions.
17 changes: 12 additions & 5 deletions accounts/keystore/keystore_passphrase.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,18 @@ package keystore
import (
"bytes"
"crypto/aes"
crand "crypto/rand"
"crypto/rand"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"path/filepath"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/randentropy"
"github.com/pborman/uuid"
"golang.org/x/crypto/pbkdf2"
"golang.org/x/crypto/scrypt"
Expand Down Expand Up @@ -93,7 +93,7 @@ func (ks keyStorePassphrase) GetKey(addr common.Address, filename, auth string)

// StoreKey generates a key, encrypts with 'auth' and stores in the given directory
func StoreKey(dir, auth string, scryptN, scryptP int) (common.Address, error) {
_, a, err := storeNewKey(&keyStorePassphrase{dir, scryptN, scryptP}, crand.Reader, auth)
_, a, err := storeNewKey(&keyStorePassphrase{dir, scryptN, scryptP}, rand.Reader, auth)
return a.Address, err
}

Expand All @@ -116,15 +116,22 @@ func (ks keyStorePassphrase) JoinPath(filename string) string {
// blob that can be decrypted later on.
func EncryptKey(key *Key, auth string, scryptN, scryptP int) ([]byte, error) {
authArray := []byte(auth)
salt := randentropy.GetEntropyCSPRNG(32)

salt := make([]byte, 32)
if _, err := io.ReadFull(rand.Reader, salt); err != nil {
panic("reading from crypto/rand failed: " + err.Error())
}
derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptR, scryptP, scryptDKLen)
if err != nil {
return nil, err
}
encryptKey := derivedKey[:16]
keyBytes := math.PaddedBigBytes(key.PrivateKey.D, 32)

iv := randentropy.GetEntropyCSPRNG(aes.BlockSize) // 16
iv := make([]byte, aes.BlockSize) // 16
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic("reading from crypto/rand failed: " + err.Error())
}
cipherText, err := aesCTRXOR(encryptKey, keyBytes, iv)
if err != nil {
return nil, err
Expand Down
42 changes: 0 additions & 42 deletions crypto/randentropy/rand_entropy.go

This file was deleted.

43 changes: 32 additions & 11 deletions crypto/secp256k1/curve.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright 2010 The Go Authors. All rights reserved.
// Copyright 2011 ThePiachu. All rights reserved.
// Copyright 2015 Jeffrey Wilcke, Felix Lange, Gustav Simonsson. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
Expand Down Expand Up @@ -35,8 +36,6 @@ import (
"crypto/elliptic"
"math/big"
"unsafe"

"github.com/ethereum/go-ethereum/common/math"
)

/*
Expand All @@ -45,6 +44,27 @@ extern int secp256k1_ext_scalar_mul(const secp256k1_context* ctx, const unsigned
*/
import "C"

const (
// number of bits in a big.Word
wordBits = 32 << (uint64(^big.Word(0)) >> 63)
// number of bytes in a big.Word
wordBytes = wordBits / 8
)

// readBits encodes the absolute value of bigint as big-endian bytes. Callers
// must ensure that buf has enough space. If buf is too short the result will
// be incomplete.
func readBits(bigint *big.Int, buf []byte) {
i := len(buf)
for _, d := range bigint.Bits() {
for j := 0; j < wordBytes && i > 0; j++ {
i--
buf[i] = byte(d)
d >>= 8
}
}
}

// This code is from https://github.com/ThePiachu/GoBit and implements
// several Koblitz elliptic curves over prime fields.
//
Expand Down Expand Up @@ -231,8 +251,9 @@ func (BitCurve *BitCurve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int,

// Do the multiplication in C, updating point.
point := make([]byte, 64)
math.ReadBits(Bx, point[:32])
math.ReadBits(By, point[32:])
readBits(Bx, point[:32])
readBits(By, point[32:])

pointPtr := (*C.uchar)(unsafe.Pointer(&point[0]))
scalarPtr := (*C.uchar)(unsafe.Pointer(&scalar[0]))
res := C.secp256k1_ext_scalar_mul(context, pointPtr, scalarPtr)
Expand Down Expand Up @@ -264,8 +285,8 @@ 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 flag
math.ReadBits(x, ret[1:1+byteLen])
math.ReadBits(y, ret[1+byteLen:])
readBits(x, ret[1:1+byteLen])
readBits(y, ret[1+byteLen:])
return ret
}

Expand All @@ -290,11 +311,11 @@ 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.P, _ = new(big.Int).SetString("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 0)
theCurve.N, _ = new(big.Int).SetString("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 0)
theCurve.B, _ = new(big.Int).SetString("0x0000000000000000000000000000000000000000000000000000000000000007", 0)
theCurve.Gx, _ = new(big.Int).SetString("0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", 0)
theCurve.Gy, _ = new(big.Int).SetString("0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", 0)
theCurve.BitSize = 256
}

Expand Down
39 changes: 25 additions & 14 deletions crypto/secp256k1/secp256_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,8 @@ import (
"crypto/elliptic"
"crypto/rand"
"encoding/hex"
"io"
"testing"

"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/crypto/randentropy"
)

const TestCount = 1000
Expand All @@ -24,11 +22,24 @@ func generateKeyPair() (pubkey, privkey []byte) {
panic(err)
}
pubkey = elliptic.Marshal(S256(), key.X, key.Y)
return pubkey, math.PaddedBigBytes(key.D, 32)

privkey = make([]byte, 32)
blob := key.D.Bytes()
copy(privkey[32-len(blob):], blob)

return pubkey, privkey
}

func csprngEntropy(n int) []byte {
buf := make([]byte, n)
if _, err := io.ReadFull(rand.Reader, buf); err != nil {
panic("reading from crypto/rand failed: " + err.Error())
}
return buf
}

func randSig() []byte {
sig := randentropy.GetEntropyCSPRNG(65)
sig := csprngEntropy(65)
sig[32] &= 0x70
sig[64] %= 4
return sig
Expand All @@ -51,7 +62,7 @@ func compactSigCheck(t *testing.T, sig []byte) {

func TestSignatureValidity(t *testing.T) {
pubkey, seckey := generateKeyPair()
msg := randentropy.GetEntropyCSPRNG(32)
msg := csprngEntropy(32)
sig, err := Sign(msg, seckey)
if err != nil {
t.Errorf("signature error: %s", err)
Expand All @@ -74,7 +85,7 @@ func TestSignatureValidity(t *testing.T) {

func TestInvalidRecoveryID(t *testing.T) {
_, seckey := generateKeyPair()
msg := randentropy.GetEntropyCSPRNG(32)
msg := csprngEntropy(32)
sig, _ := Sign(msg, seckey)
sig[64] = 99
_, err := RecoverPubkey(msg, sig)
Expand All @@ -85,7 +96,7 @@ func TestInvalidRecoveryID(t *testing.T) {

func TestSignAndRecover(t *testing.T) {
pubkey1, seckey := generateKeyPair()
msg := randentropy.GetEntropyCSPRNG(32)
msg := csprngEntropy(32)
sig, err := Sign(msg, seckey)
if err != nil {
t.Errorf("signature error: %s", err)
Expand Down Expand Up @@ -136,7 +147,7 @@ func TestRandomMessagesWithRandomKeys(t *testing.T) {
func signAndRecoverWithRandomMessages(t *testing.T, keys func() ([]byte, []byte)) {
for i := 0; i < TestCount; i++ {
pubkey1, seckey := keys()
msg := randentropy.GetEntropyCSPRNG(32)
msg := csprngEntropy(32)
sig, err := Sign(msg, seckey)
if err != nil {
t.Fatalf("signature error: %s", err)
Expand Down Expand Up @@ -164,7 +175,7 @@ func signAndRecoverWithRandomMessages(t *testing.T, keys func() ([]byte, []byte)

func TestRecoveryOfRandomSignature(t *testing.T) {
pubkey1, _ := generateKeyPair()
msg := randentropy.GetEntropyCSPRNG(32)
msg := csprngEntropy(32)

for i := 0; i < TestCount; i++ {
// recovery can sometimes work, but if so should always give wrong pubkey
Expand All @@ -177,11 +188,11 @@ func TestRecoveryOfRandomSignature(t *testing.T) {

func TestRandomMessagesAgainstValidSig(t *testing.T) {
pubkey1, seckey := generateKeyPair()
msg := randentropy.GetEntropyCSPRNG(32)
msg := csprngEntropy(32)
sig, _ := Sign(msg, seckey)

for i := 0; i < TestCount; i++ {
msg = randentropy.GetEntropyCSPRNG(32)
msg = csprngEntropy(32)
pubkey2, _ := RecoverPubkey(msg, sig)
// recovery can sometimes work, but if so should always give wrong pubkey
if bytes.Equal(pubkey1, pubkey2) {
Expand All @@ -207,7 +218,7 @@ func TestRecoverSanity(t *testing.T) {

func BenchmarkSign(b *testing.B) {
_, seckey := generateKeyPair()
msg := randentropy.GetEntropyCSPRNG(32)
msg := csprngEntropy(32)
b.ResetTimer()

for i := 0; i < b.N; i++ {
Expand All @@ -216,7 +227,7 @@ func BenchmarkSign(b *testing.B) {
}

func BenchmarkRecover(b *testing.B) {
msg := randentropy.GetEntropyCSPRNG(32)
msg := csprngEntropy(32)
_, seckey := generateKeyPair()
sig, _ := Sign(msg, seckey)
b.ResetTimer()
Expand Down

0 comments on commit d9575e9

Please sign in to comment.