aboutsummaryrefslogtreecommitdiffstats
path: root/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'crypto')
-rw-r--r--crypto/crypto.go259
-rw-r--r--crypto/crypto_test.go74
-rw-r--r--crypto/curve.go363
-rw-r--r--crypto/ecies/.gitignore24
-rw-r--r--crypto/ecies/LICENSE28
-rw-r--r--crypto/ecies/README94
-rw-r--r--crypto/ecies/asn1.go556
-rw-r--r--crypto/ecies/ecies.go331
-rw-r--r--crypto/ecies/ecies_test.go489
-rw-r--r--crypto/ecies/params.go181
-rw-r--r--crypto/encrypt_decrypt_test.go40
-rw-r--r--crypto/key.go110
-rw-r--r--crypto/key_manager.go134
-rw-r--r--crypto/key_store.go113
-rw-r--r--crypto/key_store_passphrase.go198
-rw-r--r--crypto/key_store_plain.go133
-rw-r--r--crypto/key_store_test.go98
-rw-r--r--crypto/keypair.go58
-rw-r--r--crypto/keyring.go123
-rw-r--r--crypto/keys_test.go122
-rw-r--r--crypto/mnemonic.go60
-rw-r--r--crypto/mnemonic_test.go74
-rw-r--r--crypto/mnemonic_words.go1630
-rw-r--r--crypto/randentropy/rand_entropy.go84
-rw-r--r--crypto/secp256k1/.gitignore24
-rw-r--r--crypto/secp256k1/README.md22
-rw-r--r--crypto/secp256k1/notes.go192
-rw-r--r--crypto/secp256k1/secp256.go301
-rw-r--r--crypto/secp256k1/secp256_test.go229
-rw-r--r--crypto/secp256k1/secp256k1/COPYING19
-rw-r--r--crypto/secp256k1/secp256k1/Makefile55
-rw-r--r--crypto/secp256k1/secp256k1/TODO3
-rw-r--r--crypto/secp256k1/secp256k1/config.mk9
-rwxr-xr-xcrypto/secp256k1/secp256k1/configure175
-rw-r--r--crypto/secp256k1/secp256k1/include/secp256k1.h121
-rw-r--r--crypto/secp256k1/secp256k1/src/bench.c64
-rw-r--r--crypto/secp256k1/secp256k1/src/ecdsa.h28
-rw-r--r--crypto/secp256k1/secp256k1/src/ecmult.h19
-rw-r--r--crypto/secp256k1/secp256k1/src/field.h101
-rw-r--r--crypto/secp256k1/secp256k1/src/field_10x26.h19
-rw-r--r--crypto/secp256k1/secp256k1/src/field_5x52.h19
-rw-r--r--crypto/secp256k1/secp256k1/src/field_5x52_asm.asm463
-rw-r--r--crypto/secp256k1/secp256k1/src/field_5x64.h19
-rw-r--r--crypto/secp256k1/secp256k1/src/field_5x64_asm.asm332
-rw-r--r--crypto/secp256k1/secp256k1/src/field_gmp.h16
-rw-r--r--crypto/secp256k1/secp256k1/src/group.h108
-rw-r--r--crypto/secp256k1/secp256k1/src/impl/ecdsa.h309
-rw-r--r--crypto/secp256k1/secp256k1/src/impl/ecmult.h238
-rw-r--r--crypto/secp256k1/secp256k1/src/impl/field.h175
-rw-r--r--crypto/secp256k1/secp256k1/src/impl/field_10x26.h487
-rw-r--r--crypto/secp256k1/secp256k1/src/impl/field_5x52.h196
-rw-r--r--crypto/secp256k1/secp256k1/src/impl/field_5x52_asm.h11
-rw-r--r--crypto/secp256k1/secp256k1/src/impl/field_5x52_int128.h105
-rw-r--r--crypto/secp256k1/secp256k1/src/impl/field_5x64.h371
-rw-r--r--crypto/secp256k1/secp256k1/src/impl/field_5x64_asm.h11
-rw-r--r--crypto/secp256k1/secp256k1/src/impl/field_gmp.h155
-rw-r--r--crypto/secp256k1/secp256k1/src/impl/group.h397
-rw-r--r--crypto/secp256k1/secp256k1/src/impl/num.h18
-rw-r--r--crypto/secp256k1/secp256k1/src/impl/num_gmp.h346
-rw-r--r--crypto/secp256k1/secp256k1/src/impl/num_openssl.h145
-rw-r--r--crypto/secp256k1/secp256k1/src/impl/util.h45
-rw-r--r--crypto/secp256k1/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java60
-rw-r--r--crypto/secp256k1/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c23
-rw-r--r--crypto/secp256k1/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h21
-rw-r--r--crypto/secp256k1/secp256k1/src/num.h93
-rw-r--r--crypto/secp256k1/secp256k1/src/num_gmp.h18
-rw-r--r--crypto/secp256k1/secp256k1/src/num_openssl.h14
-rw-r--r--crypto/secp256k1/secp256k1/src/secp256k1.c269
-rw-r--r--crypto/secp256k1/secp256k1/src/tests.c465
-rw-r--r--crypto/secp256k1/secp256k1/src/util.h19
-rw-r--r--crypto/sha3/keccakf.go171
-rw-r--r--crypto/sha3/sha3.go216
72 files changed, 12092 insertions, 0 deletions
diff --git a/crypto/crypto.go b/crypto/crypto.go
new file mode 100644
index 000000000..2c8f82977
--- /dev/null
+++ b/crypto/crypto.go
@@ -0,0 +1,259 @@
+package crypto
+
+import (
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/rand"
+ "crypto/sha256"
+ "fmt"
+ "io"
+ "os"
+
+ "encoding/hex"
+ "encoding/json"
+ "errors"
+
+ "code.google.com/p/go-uuid/uuid"
+ "code.google.com/p/go.crypto/pbkdf2"
+ "code.google.com/p/go.crypto/ripemd160"
+ "github.com/ethereum/go-ethereum/crypto/secp256k1"
+ "github.com/ethereum/go-ethereum/crypto/sha3"
+ "github.com/ethereum/go-ethereum/ethutil"
+ "github.com/obscuren/ecies"
+)
+
+func init() {
+ // specify the params for the s256 curve
+ ecies.AddParamsForCurve(S256(), ecies.ECIES_AES128_SHA256)
+}
+
+func Sha3(data ...[]byte) []byte {
+ d := sha3.NewKeccak256()
+ for _, b := range data {
+ d.Write(b)
+ }
+ return d.Sum(nil)
+}
+
+// Creates an ethereum address given the bytes and the nonce
+func CreateAddress(b []byte, nonce uint64) []byte {
+ return Sha3(ethutil.NewValue([]interface{}{b, nonce}).Encode())[12:]
+}
+
+func Sha256(data []byte) []byte {
+ hash := sha256.Sum256(data)
+
+ return hash[:]
+}
+
+func Ripemd160(data []byte) []byte {
+ ripemd := ripemd160.New()
+ ripemd.Write(data)
+
+ return ripemd.Sum(nil)
+}
+
+func Ecrecover(data []byte) []byte {
+ var in = struct {
+ hash []byte
+ sig []byte
+ }{data[:32], data[32:]}
+
+ r, _ := secp256k1.RecoverPubkey(in.hash, in.sig)
+
+ return r
+}
+
+// New methods using proper ecdsa keys from the stdlib
+func ToECDSA(prv []byte) *ecdsa.PrivateKey {
+ if len(prv) == 0 {
+ return nil
+ }
+
+ priv := new(ecdsa.PrivateKey)
+ priv.PublicKey.Curve = S256()
+ priv.D = ethutil.BigD(prv)
+ priv.PublicKey.X, priv.PublicKey.Y = S256().ScalarBaseMult(prv)
+ return priv
+}
+
+func FromECDSA(prv *ecdsa.PrivateKey) []byte {
+ if prv == nil {
+ return nil
+ }
+ return prv.D.Bytes()
+}
+
+func ToECDSAPub(pub []byte) *ecdsa.PublicKey {
+ if len(pub) == 0 {
+ return nil
+ }
+ x, y := elliptic.Unmarshal(S256(), pub)
+ return &ecdsa.PublicKey{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)
+}
+
+// HexToECDSA parses a secp256k1 private key.
+func HexToECDSA(hexkey string) (*ecdsa.PrivateKey, error) {
+ b, err := hex.DecodeString(hexkey)
+ if err != nil {
+ return nil, errors.New("invalid hex string")
+ }
+ if len(b) != 32 {
+ return nil, errors.New("invalid length, need 256 bits")
+ }
+ return ToECDSA(b), nil
+}
+
+// LoadECDSA loads a secp256k1 private key from the given file.
+func LoadECDSA(file string) (*ecdsa.PrivateKey, error) {
+ buf := make([]byte, 32)
+ fd, err := os.Open(file)
+ if err != nil {
+ return nil, err
+ }
+ defer fd.Close()
+ if _, err := io.ReadFull(fd, buf); err != nil {
+ return nil, err
+ }
+ return ToECDSA(buf), nil
+}
+
+func GenerateKey() (*ecdsa.PrivateKey, error) {
+ return ecdsa.GenerateKey(S256(), rand.Reader)
+}
+
+func SigToPub(hash, sig []byte) *ecdsa.PublicKey {
+ s := Ecrecover(append(hash, sig...))
+ x, y := elliptic.Unmarshal(S256(), s)
+
+ return &ecdsa.PublicKey{S256(), x, y}
+}
+
+func Sign(hash []byte, prv *ecdsa.PrivateKey) (sig []byte, err error) {
+ if len(hash) != 32 {
+ return nil, fmt.Errorf("hash is required to be exactly 32 bytes (%d)", len(hash))
+ }
+
+ sig, err = secp256k1.Sign(hash, ethutil.LeftPadBytes(prv.D.Bytes(), prv.Params().BitSize/8))
+ return
+}
+
+func Encrypt(pub *ecdsa.PublicKey, message []byte) ([]byte, error) {
+ return ecies.Encrypt(rand.Reader, ecies.ImportECDSAPublic(pub), message, nil, nil)
+}
+
+func Decrypt(prv *ecdsa.PrivateKey, ct []byte) ([]byte, error) {
+ key := ecies.ImportECDSA(prv)
+ return key.Decrypt(rand.Reader, ct, nil, nil)
+}
+
+// creates a Key and stores that in the given KeyStore by decrypting a presale key JSON
+func ImportPreSaleKey(keyStore KeyStore2, keyJSON []byte, password string) (*Key, error) {
+ key, err := decryptPreSaleKey(keyJSON, password)
+ if err != nil {
+ return nil, err
+ }
+ key.Id = uuid.NewRandom()
+ err = keyStore.StoreKey(key, password)
+ return key, err
+}
+
+func decryptPreSaleKey(fileContent []byte, password string) (key *Key, err error) {
+ preSaleKeyStruct := struct {
+ EncSeed string
+ EthAddr string
+ Email string
+ BtcAddr string
+ }{}
+ err = json.Unmarshal(fileContent, &preSaleKeyStruct)
+ if err != nil {
+ return nil, err
+ }
+ encSeedBytes, err := hex.DecodeString(preSaleKeyStruct.EncSeed)
+ iv := encSeedBytes[:16]
+ cipherText := encSeedBytes[16:]
+ /*
+ See https://github.com/ethereum/pyethsaletool
+
+ pyethsaletool generates the encryption key from password by
+ 2000 rounds of PBKDF2 with HMAC-SHA-256 using password as salt (:().
+ 16 byte key length within PBKDF2 and resulting key is used as AES key
+ */
+ passBytes := []byte(password)
+ derivedKey := pbkdf2.Key(passBytes, passBytes, 2000, 16, sha256.New)
+ plainText, err := aesCBCDecrypt(derivedKey, cipherText, iv)
+ ethPriv := Sha3(plainText)
+ ecKey := ToECDSA(ethPriv)
+ key = &Key{
+ Id: nil,
+ Address: PubkeyToAddress(ecKey.PublicKey),
+ PrivateKey: ecKey,
+ }
+ derivedAddr := ethutil.Bytes2Hex(key.Address)
+ expectedAddr := preSaleKeyStruct.EthAddr
+ if derivedAddr != expectedAddr {
+ err = errors.New("decrypted addr not equal to expected addr")
+ }
+ return key, err
+}
+
+func aesCBCDecrypt(key []byte, cipherText []byte, iv []byte) (plainText []byte, err error) {
+ aesBlock, err := aes.NewCipher(key)
+ if err != nil {
+ return plainText, err
+ }
+ decrypter := cipher.NewCBCDecrypter(aesBlock, iv)
+ paddedPlainText := make([]byte, len(cipherText))
+ decrypter.CryptBlocks(paddedPlainText, cipherText)
+ plainText = PKCS7Unpad(paddedPlainText)
+ if plainText == nil {
+ err = errors.New("Decryption failed: PKCS7Unpad failed after decryption")
+ }
+ return plainText, err
+}
+
+// From https://leanpub.com/gocrypto/read#leanpub-auto-block-cipher-modes
+func PKCS7Pad(in []byte) []byte {
+ padding := 16 - (len(in) % 16)
+ if padding == 0 {
+ padding = 16
+ }
+ for i := 0; i < padding; i++ {
+ in = append(in, byte(padding))
+ }
+ return in
+}
+
+func PKCS7Unpad(in []byte) []byte {
+ if len(in) == 0 {
+ return nil
+ }
+
+ padding := in[len(in)-1]
+ if int(padding) > len(in) || padding > aes.BlockSize {
+ return nil
+ } else if padding == 0 {
+ return nil
+ }
+
+ for i := len(in) - 1; i > len(in)-int(padding)-1; i-- {
+ if in[i] != padding {
+ return nil
+ }
+ }
+ return in[:len(in)-int(padding)]
+}
+
+func PubkeyToAddress(p ecdsa.PublicKey) []byte {
+ pubBytes := FromECDSAPub(&p)
+ return Sha3(pubBytes[1:])[12:]
+}
diff --git a/crypto/crypto_test.go b/crypto/crypto_test.go
new file mode 100644
index 000000000..c68856622
--- /dev/null
+++ b/crypto/crypto_test.go
@@ -0,0 +1,74 @@
+package crypto
+
+import (
+ "bytes"
+ "encoding/hex"
+ "fmt"
+ "testing"
+ "time"
+
+ "github.com/ethereum/go-ethereum/crypto/secp256k1"
+ "github.com/ethereum/go-ethereum/ethutil"
+)
+
+// These tests are sanity checks.
+// They should ensure that we don't e.g. use Sha3-224 instead of Sha3-256
+// and that the sha3 library uses keccak-f permutation.
+
+func TestSha3(t *testing.T) {
+ msg := []byte("abc")
+ exp, _ := hex.DecodeString("4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45")
+ checkhash(t, "Sha3-256", func(in []byte) []byte { return Sha3(in) }, msg, exp)
+}
+
+func TestSha256(t *testing.T) {
+ msg := []byte("abc")
+ exp, _ := hex.DecodeString("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad")
+ checkhash(t, "Sha256", Sha256, msg, exp)
+}
+
+func TestRipemd160(t *testing.T) {
+ msg := []byte("abc")
+ exp, _ := hex.DecodeString("8eb208f7e05d987a9b044a8e98c6b087f15a0bfc")
+ checkhash(t, "Ripemd160", Ripemd160, msg, exp)
+}
+
+func checkhash(t *testing.T, name string, f func([]byte) []byte, msg, exp []byte) {
+ sum := f(msg)
+ if bytes.Compare(exp, sum) != 0 {
+ t.Errorf("hash %s returned wrong result.\ngot: %x\nwant: %x", name, sum, exp)
+ }
+}
+
+func BenchmarkSha3(b *testing.B) {
+ a := []byte("hello world")
+ amount := 1000000
+ start := time.Now()
+ for i := 0; i < amount; i++ {
+ Sha3(a)
+ }
+
+ fmt.Println(amount, ":", time.Since(start))
+}
+
+func Test0Key(t *testing.T) {
+ t.Skip()
+ key := ethutil.Hex2Bytes("1111111111111111111111111111111111111111111111111111111111111111")
+
+ p, err := secp256k1.GeneratePubKey(key)
+ addr := Sha3(p[1:])[12:]
+ fmt.Printf("%x\n", p)
+ fmt.Printf("%v %x\n", err, addr)
+}
+
+func TestInvalidSign(t *testing.T) {
+ _, err := Sign(make([]byte, 1), nil)
+ if err == nil {
+ t.Errorf("expected sign with hash 1 byte to error")
+ }
+
+ _, err = Sign(make([]byte, 33), nil)
+ if err == nil {
+ t.Errorf("expected sign with hash 33 byte to error")
+ }
+}
diff --git a/crypto/curve.go b/crypto/curve.go
new file mode 100644
index 000000000..131a0dd2f
--- /dev/null
+++ b/crypto/curve.go
@@ -0,0 +1,363 @@
+package crypto
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Copyright 2011 ThePiachu. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package bitelliptic implements several Koblitz elliptic curves over prime
+// fields.
+
+// This package operates, 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.
+
+import (
+ "crypto/elliptic"
+ "io"
+ "math/big"
+ "sync"
+)
+
+// 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{BitCurve.P, BitCurve.N, BitCurve.B, BitCurve.Gx, BitCurve.Gy, 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
+}
+
+//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
+ }
+ }
+
+ if !seenFirstTrue {
+ return nil, nil
+ }
+
+ return BitCurve.affineFromJacobian(x, y, z)
+}
+
+// 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
+}
+
+//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
+}
+
+// S256 returns a BitCurve which implements secp256k1 (see SEC 2 section 2.7.1)
+func S256() *BitCurve {
+ initonce.Do(initAll)
+ return ecp256k1
+}
diff --git a/crypto/ecies/.gitignore b/crypto/ecies/.gitignore
new file mode 100644
index 000000000..802b6744a
--- /dev/null
+++ b/crypto/ecies/.gitignore
@@ -0,0 +1,24 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+
+*~
diff --git a/crypto/ecies/LICENSE b/crypto/ecies/LICENSE
new file mode 100644
index 000000000..e1ed19a27
--- /dev/null
+++ b/crypto/ecies/LICENSE
@@ -0,0 +1,28 @@
+Copyright (c) 2013 Kyle Isom <kyle@tyrfingr.is>
+Copyright (c) 2012 The Go Authors. 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.
+
+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.
diff --git a/crypto/ecies/README b/crypto/ecies/README
new file mode 100644
index 000000000..2650c7b9f
--- /dev/null
+++ b/crypto/ecies/README
@@ -0,0 +1,94 @@
+# NOTE
+
+This implementation is direct fork of Kylom's implementation. I claim no authorship over this code apart from some minor modifications.
+Please be aware this code **has not yet been reviewed**.
+
+ecies implements the Elliptic Curve Integrated Encryption Scheme.
+
+The package is designed to be compliant with the appropriate NIST
+standards, and therefore doesn't support the full SEC 1 algorithm set.
+
+
+STATUS:
+
+ecies should be ready for use. The ASN.1 support is only complete so
+far as to supported the listed algorithms before.
+
+
+CAVEATS
+
+1. CMAC support is currently not present.
+
+
+SUPPORTED ALGORITHMS
+
+ SYMMETRIC CIPHERS HASH FUNCTIONS
+ AES128 SHA-1
+ AES192 SHA-224
+ AES256 SHA-256
+ SHA-384
+ ELLIPTIC CURVE SHA-512
+ P256
+ P384 KEY DERIVATION FUNCTION
+ P521 NIST SP 800-65a Concatenation KDF
+
+Curve P224 isn't supported because it does not provide a minimum security
+level of AES128 with HMAC-SHA1. According to NIST SP 800-57, the security
+level of P224 is 112 bits of security. Symmetric ciphers use CTR-mode;
+message tags are computed using HMAC-<HASH> function.
+
+
+CURVE SELECTION
+
+According to NIST SP 800-57, the following curves should be selected:
+
+ +----------------+-------+
+ | SYMMETRIC SIZE | CURVE |
+ +----------------+-------+
+ | 128-bit | P256 |
+ +----------------+-------+
+ | 192-bit | P384 |
+ +----------------+-------+
+ | 256-bit | P521 |
+ +----------------+-------+
+
+
+TODO
+
+1. Look at serialising the parameters with the SEC 1 ASN.1 module.
+2. Validate ASN.1 formats with SEC 1.
+
+
+TEST VECTORS
+
+The only test vectors I've found so far date from 1993, predating AES
+and including only 163-bit curves. Therefore, there are no published
+test vectors to compare to.
+
+
+LICENSE
+
+ecies is released under the same license as the Go source code. See the
+LICENSE file for details.
+
+
+REFERENCES
+
+* SEC (Standard for Efficient Cryptography) 1, version 2.0: Elliptic
+ Curve Cryptography; Certicom, May 2009.
+ http://www.secg.org/sec1-v2.pdf
+* GEC (Guidelines for Efficient Cryptography) 2, version 0.3: Test
+ Vectors for SEC 1; Certicom, September 1999.
+ http://read.pudn.com/downloads168/doc/772358/TestVectorsforSEC%201-gec2.pdf
+* NIST SP 800-56a: Recommendation for Pair-Wise Key Establishment Schemes
+ Using Discrete Logarithm Cryptography. National Institute of Standards
+ and Technology, May 2007.
+ http://csrc.nist.gov/publications/nistpubs/800-56A/SP800-56A_Revision1_Mar08-2007.pdf
+* Suite B Implementer’s Guide to NIST SP 800-56A. National Security
+ Agency, July 28, 2009.
+ http://www.nsa.gov/ia/_files/SuiteB_Implementer_G-113808.pdf
+* NIST SP 800-57: Recommendation for Key Management – Part 1: General
+ (Revision 3). National Institute of Standards and Technology, July
+ 2012.
+ http://csrc.nist.gov/publications/nistpubs/800-57/sp800-57_part1_rev3_general.pdf
+
diff --git a/crypto/ecies/asn1.go b/crypto/ecies/asn1.go
new file mode 100644
index 000000000..3ef194ea0
--- /dev/null
+++ b/crypto/ecies/asn1.go
@@ -0,0 +1,556 @@
+package ecies
+
+import (
+ "bytes"
+ "crypto"
+ "crypto/elliptic"
+ "crypto/sha1"
+ "crypto/sha256"
+ "crypto/sha512"
+ "encoding/asn1"
+ "encoding/pem"
+ "fmt"
+ "hash"
+ "math/big"
+)
+
+var (
+ secgScheme = []int{1, 3, 132, 1}
+ shaScheme = []int{2, 16, 840, 1, 101, 3, 4, 2}
+ ansiX962Scheme = []int{1, 2, 840, 10045}
+ x963Scheme = []int{1, 2, 840, 63, 0}
+)
+
+var ErrInvalidPrivateKey = fmt.Errorf("ecies: invalid private key")
+
+func doScheme(base, v []int) asn1.ObjectIdentifier {
+ var oidInts asn1.ObjectIdentifier
+ oidInts = append(oidInts, base...)
+ return append(oidInts, v...)
+}
+
+// curve OID code taken from crypto/x509, including
+// - oidNameCurve*
+// - namedCurveFromOID
+// - oidFromNamedCurve
+// RFC 5480, 2.1.1.1. Named Curve
+//
+// secp224r1 OBJECT IDENTIFIER ::= {
+// iso(1) identified-organization(3) certicom(132) curve(0) 33 }
+//
+// secp256r1 OBJECT IDENTIFIER ::= {
+// iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3)
+// prime(1) 7 }
+//
+// secp384r1 OBJECT IDENTIFIER ::= {
+// iso(1) identified-organization(3) certicom(132) curve(0) 34 }
+//
+// secp521r1 OBJECT IDENTIFIER ::= {
+// iso(1) identified-organization(3) certicom(132) curve(0) 35 }
+//
+// NB: secp256r1 is equivalent to prime256v1
+type secgNamedCurve asn1.ObjectIdentifier
+
+var (
+ secgNamedCurveP224 = secgNamedCurve{1, 3, 132, 0, 33}
+ secgNamedCurveP256 = secgNamedCurve{1, 2, 840, 10045, 3, 1, 7}
+ secgNamedCurveP384 = secgNamedCurve{1, 3, 132, 0, 34}
+ secgNamedCurveP521 = secgNamedCurve{1, 3, 132, 0, 35}
+ rawCurveP224 = []byte{6, 5, 4, 3, 1, 2, 9, 4, 0, 3, 3}
+ rawCurveP256 = []byte{6, 8, 4, 2, 1, 3, 4, 7, 2, 2, 0, 6, 6, 1, 3, 1, 7}
+ rawCurveP384 = []byte{6, 5, 4, 3, 1, 2, 9, 4, 0, 3, 4}
+ rawCurveP521 = []byte{6, 5, 4, 3, 1, 2, 9, 4, 0, 3, 5}
+)
+
+func rawCurve(curve elliptic.Curve) []byte {
+ switch curve {
+ case elliptic.P224():
+ return rawCurveP224
+ case elliptic.P256():
+ return rawCurveP256
+ case elliptic.P384():
+ return rawCurveP384
+ case elliptic.P521():
+ return rawCurveP521
+ default:
+ return nil
+ }
+}
+
+func (curve secgNamedCurve) Equal(curve2 secgNamedCurve) bool {
+ if len(curve) != len(curve2) {
+ return false
+ }
+ for i, _ := range curve {
+ if curve[i] != curve2[i] {
+ return false
+ }
+ }
+ return true
+}
+
+func namedCurveFromOID(curve secgNamedCurve) elliptic.Curve {
+ switch {
+ case curve.Equal(secgNamedCurveP224):
+ return elliptic.P224()
+ case curve.Equal(secgNamedCurveP256):
+ return elliptic.P256()
+ case curve.Equal(secgNamedCurveP384):
+ return elliptic.P384()
+ case curve.Equal(secgNamedCurveP521):
+ return elliptic.P521()
+ }
+ return nil
+}
+
+func oidFromNamedCurve(curve elliptic.Curve) (secgNamedCurve, bool) {
+ switch curve {
+ case elliptic.P224():
+ return secgNamedCurveP224, true
+ case elliptic.P256():
+ return secgNamedCurveP256, true
+ case elliptic.P384():
+ return secgNamedCurveP384, true
+ case elliptic.P521():
+ return secgNamedCurveP521, true
+ }
+
+ return nil, false
+}
+
+// asnAlgorithmIdentifier represents the ASN.1 structure of the same name. See RFC
+// 5280, section 4.1.1.2.
+type asnAlgorithmIdentifier struct {
+ Algorithm asn1.ObjectIdentifier
+ Parameters asn1.RawValue `asn1:"optional"`
+}
+
+func (a asnAlgorithmIdentifier) Cmp(b asnAlgorithmIdentifier) bool {
+ if len(a.Algorithm) != len(b.Algorithm) {
+ return false
+ }
+ for i, _ := range a.Algorithm {
+ if a.Algorithm[i] != b.Algorithm[i] {
+ return false
+ }
+ }
+ return true
+}
+
+type asnHashFunction asnAlgorithmIdentifier
+
+var (
+ oidSHA1 = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 26}
+ oidSHA224 = doScheme(shaScheme, []int{4})
+ oidSHA256 = doScheme(shaScheme, []int{1})
+ oidSHA384 = doScheme(shaScheme, []int{2})
+ oidSHA512 = doScheme(shaScheme, []int{3})
+)
+
+func hashFromOID(oid asn1.ObjectIdentifier) func() hash.Hash {
+ switch {
+ case oid.Equal(oidSHA1):
+ return sha1.New
+ case oid.Equal(oidSHA224):
+ return sha256.New224
+ case oid.Equal(oidSHA256):
+ return sha256.New
+ case oid.Equal(oidSHA384):
+ return sha512.New384
+ case oid.Equal(oidSHA512):
+ return sha512.New
+ }
+ return nil
+}
+
+func oidFromHash(hash crypto.Hash) (asn1.ObjectIdentifier, bool) {
+ switch hash {
+ case crypto.SHA1:
+ return oidSHA1, true
+ case crypto.SHA224:
+ return oidSHA224, true
+ case crypto.SHA256:
+ return oidSHA256, true
+ case crypto.SHA384:
+ return oidSHA384, true
+ case crypto.SHA512:
+ return oidSHA512, true
+ default:
+ return nil, false
+ }
+}
+
+var (
+ asnAlgoSHA1 = asnHashFunction{
+ Algorithm: oidSHA1,
+ }
+ asnAlgoSHA224 = asnHashFunction{
+ Algorithm: oidSHA224,
+ }
+ asnAlgoSHA256 = asnHashFunction{
+ Algorithm: oidSHA256,
+ }
+ asnAlgoSHA384 = asnHashFunction{
+ Algorithm: oidSHA384,
+ }
+ asnAlgoSHA512 = asnHashFunction{
+ Algorithm: oidSHA512,
+ }
+)
+
+// type ASNasnSubjectPublicKeyInfo struct {
+//
+// }
+//
+
+type asnSubjectPublicKeyInfo struct {
+ Algorithm asn1.ObjectIdentifier
+ PublicKey asn1.BitString
+ Supplements ecpksSupplements `asn1:"optional"`
+}
+
+type asnECPKAlgorithms struct {
+ Type asn1.ObjectIdentifier
+}
+
+var idPublicKeyType = doScheme(ansiX962Scheme, []int{2})
+var idEcPublicKey = doScheme(idPublicKeyType, []int{1})
+var idEcPublicKeySupplemented = doScheme(idPublicKeyType, []int{0})
+
+func curveToRaw(curve elliptic.Curve) (rv asn1.RawValue, ok bool) {
+ switch curve {
+ case elliptic.P224(), elliptic.P256(), elliptic.P384(), elliptic.P521():
+ raw := rawCurve(curve)
+ return asn1.RawValue{
+ Tag: 30,
+ Bytes: raw[2:],
+ FullBytes: raw,
+ }, true
+ default:
+ return rv, false
+ }
+}
+
+func asnECPublicKeyType(curve elliptic.Curve) (algo asnAlgorithmIdentifier, ok bool) {
+ raw, ok := curveToRaw(curve)
+ if !ok {
+ return
+ } else {
+ return asnAlgorithmIdentifier{Algorithm: idEcPublicKey,
+ Parameters: raw}, true
+ }
+}
+
+type asnECPrivKeyVer int
+
+var asnECPrivKeyVer1 asnECPrivKeyVer = 1
+
+type asnPrivateKey struct {
+ Version asnECPrivKeyVer
+ Private []byte
+ Curve secgNamedCurve `asn1:"optional"`
+ Public asn1.BitString
+}
+
+var asnECDH = doScheme(secgScheme, []int{12})
+
+type asnECDHAlgorithm asnAlgorithmIdentifier
+
+var (
+ dhSinglePass_stdDH_sha1kdf = asnECDHAlgorithm{
+ Algorithm: doScheme(x963Scheme, []int{2}),
+ }
+ dhSinglePass_stdDH_sha256kdf = asnECDHAlgorithm{
+ Algorithm: doScheme(secgScheme, []int{11, 1}),
+ }
+ dhSinglePass_stdDH_sha384kdf = asnECDHAlgorithm{
+ Algorithm: doScheme(secgScheme, []int{11, 2}),
+ }
+ dhSinglePass_stdDH_sha224kdf = asnECDHAlgorithm{
+ Algorithm: doScheme(secgScheme, []int{11, 0}),
+ }
+ dhSinglePass_stdDH_sha512kdf = asnECDHAlgorithm{
+ Algorithm: doScheme(secgScheme, []int{11, 3}),
+ }
+)
+
+func (a asnECDHAlgorithm) Cmp(b asnECDHAlgorithm) bool {
+ if len(a.Algorithm) != len(b.Algorithm) {
+ return false
+ }
+ for i, _ := range a.Algorithm {
+ if a.Algorithm[i] != b.Algorithm[i] {
+ return false
+ }
+ }
+ return true
+}
+
+// asnNISTConcatenation is the only supported KDF at this time.
+type asnKeyDerivationFunction asnAlgorithmIdentifier
+
+var asnNISTConcatenationKDF = asnKeyDerivationFunction{
+ Algorithm: doScheme(secgScheme, []int{17, 1}),
+}
+
+func (a asnKeyDerivationFunction) Cmp(b asnKeyDerivationFunction) bool {
+ if len(a.Algorithm) != len(b.Algorithm) {
+ return false
+ }
+ for i, _ := range a.Algorithm {
+ if a.Algorithm[i] != b.Algorithm[i] {
+ return false
+ }
+ }
+ return true
+}
+
+var eciesRecommendedParameters = doScheme(secgScheme, []int{7})
+var eciesSpecifiedParameters = doScheme(secgScheme, []int{8})
+
+type asnECIESParameters struct {
+ KDF asnKeyDerivationFunction `asn1:"optional"`
+ Sym asnSymmetricEncryption `asn1:"optional"`
+ MAC asnMessageAuthenticationCode `asn1:"optional"`
+}
+
+type asnSymmetricEncryption asnAlgorithmIdentifier
+
+var (
+ aes128CTRinECIES = asnSymmetricEncryption{
+ Algorithm: doScheme(secgScheme, []int{21, 0}),
+ }
+ aes192CTRinECIES = asnSymmetricEncryption{
+ Algorithm: doScheme(secgScheme, []int{21, 1}),
+ }
+ aes256CTRinECIES = asnSymmetricEncryption{
+ Algorithm: doScheme(secgScheme, []int{21, 2}),
+ }
+)
+
+func (a asnSymmetricEncryption) Cmp(b asnSymmetricEncryption) bool {
+ if len(a.Algorithm) != len(b.Algorithm) {
+ return false
+ }
+ for i, _ := range a.Algorithm {
+ if a.Algorithm[i] != b.Algorithm[i] {
+ return false
+ }
+ }
+ return true
+}
+
+type asnMessageAuthenticationCode asnAlgorithmIdentifier
+
+var (
+ hmacFull = asnMessageAuthenticationCode{
+ Algorithm: doScheme(secgScheme, []int{22}),
+ }
+)
+
+func (a asnMessageAuthenticationCode) Cmp(b asnMessageAuthenticationCode) bool {
+ if len(a.Algorithm) != len(b.Algorithm) {
+ return false
+ }
+ for i, _ := range a.Algorithm {
+ if a.Algorithm[i] != b.Algorithm[i] {
+ return false
+ }
+ }
+ return true
+}
+
+type ecpksSupplements struct {
+ ECDomain secgNamedCurve
+ ECCAlgorithms eccAlgorithmSet
+}
+
+type eccAlgorithmSet struct {
+ ECDH asnECDHAlgorithm `asn1:"optional"`
+ ECIES asnECIESParameters `asn1:"optional"`
+}
+
+func marshalSubjectPublicKeyInfo(pub *PublicKey) (subj asnSubjectPublicKeyInfo, err error) {
+ subj.Algorithm = idEcPublicKeySupplemented
+ curve, ok := oidFromNamedCurve(pub.Curve)
+ if !ok {
+ err = ErrInvalidPublicKey
+ return
+ }
+ subj.Supplements.ECDomain = curve
+ if pub.Params != nil {
+ subj.Supplements.ECCAlgorithms.ECDH = paramsToASNECDH(pub.Params)
+ subj.Supplements.ECCAlgorithms.ECIES = paramsToASNECIES(pub.Params)
+ }
+ pubkey := elliptic.Marshal(pub.Curve, pub.X, pub.Y)
+ subj.PublicKey = asn1.BitString{
+ BitLength: len(pubkey) * 8,
+ Bytes: pubkey,
+ }
+ return
+}
+
+// Encode a public key to DER format.
+func MarshalPublic(pub *PublicKey) ([]byte, error) {
+ subj, err := marshalSubjectPublicKeyInfo(pub)
+ if err != nil {
+ return nil, err
+ }
+ return asn1.Marshal(subj)
+}
+
+// Decode a DER-encoded public key.
+func UnmarshalPublic(in []byte) (pub *PublicKey, err error) {
+ var subj asnSubjectPublicKeyInfo
+
+ if _, err = asn1.Unmarshal(in, &subj); err != nil {
+ return
+ }
+ if !subj.Algorithm.Equal(idEcPublicKeySupplemented) {
+ err = ErrInvalidPublicKey
+ return
+ }
+ pub = new(PublicKey)
+ pub.Curve = namedCurveFromOID(subj.Supplements.ECDomain)
+ x, y := elliptic.Unmarshal(pub.Curve, subj.PublicKey.Bytes)
+ if x == nil {
+ err = ErrInvalidPublicKey
+ return
+ }
+ pub.X = x
+ pub.Y = y
+ pub.Params = new(ECIESParams)
+ asnECIEStoParams(subj.Supplements.ECCAlgorithms.ECIES, pub.Params)
+ asnECDHtoParams(subj.Supplements.ECCAlgorithms.ECDH, pub.Params)
+ if pub.Params == nil {
+ if pub.Params = ParamsFromCurve(pub.Curve); pub.Params == nil {
+ err = ErrInvalidPublicKey
+ }
+ }
+ return
+}
+
+func marshalPrivateKey(prv *PrivateKey) (ecprv asnPrivateKey, err error) {
+ ecprv.Version = asnECPrivKeyVer1
+ ecprv.Private = prv.D.Bytes()
+
+ var ok bool
+ ecprv.Curve, ok = oidFromNamedCurve(prv.PublicKey.Curve)
+ if !ok {
+ err = ErrInvalidPrivateKey
+ return
+ }
+
+ var pub []byte
+ if pub, err = MarshalPublic(&prv.PublicKey); err != nil {
+ return
+ } else {
+ ecprv.Public = asn1.BitString{
+ BitLength: len(pub) * 8,
+ Bytes: pub,
+ }
+ }
+ return
+}
+
+// Encode a private key to DER format.
+func MarshalPrivate(prv *PrivateKey) ([]byte, error) {
+ ecprv, err := marshalPrivateKey(prv)
+ if err != nil {
+ return nil, err
+ }
+ return asn1.Marshal(ecprv)
+}
+
+// Decode a private key from a DER-encoded format.
+func UnmarshalPrivate(in []byte) (prv *PrivateKey, err error) {
+ var ecprv asnPrivateKey
+
+ if _, err = asn1.Unmarshal(in, &ecprv); err != nil {
+ return
+ } else if ecprv.Version != asnECPrivKeyVer1 {
+ err = ErrInvalidPrivateKey
+ return
+ }
+
+ privateCurve := namedCurveFromOID(ecprv.Curve)
+ if privateCurve == nil {
+ err = ErrInvalidPrivateKey
+ return
+ }
+
+ prv = new(PrivateKey)
+ prv.D = new(big.Int).SetBytes(ecprv.Private)
+
+ if pub, err := UnmarshalPublic(ecprv.Public.Bytes); err != nil {
+ return nil, err
+ } else {
+ prv.PublicKey = *pub
+ }
+
+ return
+}
+
+// Export a public key to PEM format.
+func ExportPublicPEM(pub *PublicKey) (out []byte, err error) {
+ der, err := MarshalPublic(pub)
+ if err != nil {
+ return
+ }
+
+ var block pem.Block
+ block.Type = "ELLIPTIC CURVE PUBLIC KEY"
+ block.Bytes = der
+
+ buf := new(bytes.Buffer)
+ err = pem.Encode(buf, &block)
+ if err != nil {
+ return
+ } else {
+ out = buf.Bytes()
+ }
+ return
+}
+
+// Export a private key to PEM format.
+func ExportPrivatePEM(prv *PrivateKey) (out []byte, err error) {
+ der, err := MarshalPrivate(prv)
+ if err != nil {
+ return
+ }
+
+ var block pem.Block
+ block.Type = "ELLIPTIC CURVE PRIVATE KEY"
+ block.Bytes = der
+
+ buf := new(bytes.Buffer)
+ err = pem.Encode(buf, &block)
+ if err != nil {
+ return
+ } else {
+ out = buf.Bytes()
+ }
+ return
+}
+
+// Import a PEM-encoded public key.
+func ImportPublicPEM(in []byte) (pub *PublicKey, err error) {
+ p, _ := pem.Decode(in)
+ if p == nil || p.Type != "ELLIPTIC CURVE PUBLIC KEY" {
+ return nil, ErrInvalidPublicKey
+ }
+
+ pub, err = UnmarshalPublic(p.Bytes)
+ return
+}
+
+// Import a PEM-encoded private key.
+func ImportPrivatePEM(in []byte) (prv *PrivateKey, err error) {
+ p, _ := pem.Decode(in)
+ if p == nil || p.Type != "ELLIPTIC CURVE PRIVATE KEY" {
+ return nil, ErrInvalidPrivateKey
+ }
+
+ prv, err = UnmarshalPrivate(p.Bytes)
+ return
+}
diff --git a/crypto/ecies/ecies.go b/crypto/ecies/ecies.go
new file mode 100644
index 000000000..18952fc0b
--- /dev/null
+++ b/crypto/ecies/ecies.go
@@ -0,0 +1,331 @@
+package ecies
+
+import (
+ "crypto/cipher"
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/hmac"
+ "crypto/subtle"
+ "fmt"
+ "hash"
+ "io"
+ "math/big"
+)
+
+var (
+ ErrImport = fmt.Errorf("ecies: failed to import key")
+ ErrInvalidCurve = fmt.Errorf("ecies: invalid elliptic curve")
+ ErrInvalidParams = fmt.Errorf("ecies: invalid ECIES parameters")
+ ErrInvalidPublicKey = fmt.Errorf("ecies: invalid public key")
+ ErrSharedKeyIsPointAtInfinity = fmt.Errorf("ecies: shared key is point at infinity")
+ ErrSharedKeyTooBig = fmt.Errorf("ecies: shared key params are too big")
+)
+
+// PublicKey is a representation of an elliptic curve public key.
+type PublicKey struct {
+ X *big.Int
+ Y *big.Int
+ elliptic.Curve
+ Params *ECIESParams
+}
+
+// Export an ECIES public key as an ECDSA public key.
+func (pub *PublicKey) ExportECDSA() *ecdsa.PublicKey {
+ return &ecdsa.PublicKey{pub.Curve, pub.X, pub.Y}
+}
+
+// Import an ECDSA public key as an ECIES public key.
+func ImportECDSAPublic(pub *ecdsa.PublicKey) *PublicKey {
+ return &PublicKey{
+ X: pub.X,
+ Y: pub.Y,
+ Curve: pub.Curve,
+ Params: ParamsFromCurve(pub.Curve),
+ }
+}
+
+// PrivateKey is a representation of an elliptic curve private key.
+type PrivateKey struct {
+ PublicKey
+ D *big.Int
+}
+
+// Export an ECIES private key as an ECDSA private key.
+func (prv *PrivateKey) ExportECDSA() *ecdsa.PrivateKey {
+ pub := &prv.PublicKey
+ pubECDSA := pub.ExportECDSA()
+ return &ecdsa.PrivateKey{*pubECDSA, prv.D}
+}
+
+// Import an ECDSA private key as an ECIES private key.
+func ImportECDSA(prv *ecdsa.PrivateKey) *PrivateKey {
+ pub := ImportECDSAPublic(&prv.PublicKey)
+ return &PrivateKey{*pub, prv.D}
+}
+
+// Generate an elliptic curve public / private keypair. If params is nil,
+// the recommended default paramters for the key will be chosen.
+func GenerateKey(rand io.Reader, curve elliptic.Curve, params *ECIESParams) (prv *PrivateKey, err error) {
+ pb, x, y, err := elliptic.GenerateKey(curve, rand)
+ if err != nil {
+ return
+ }
+ prv = new(PrivateKey)
+ prv.PublicKey.X = x
+ prv.PublicKey.Y = y
+ prv.PublicKey.Curve = curve
+ prv.D = new(big.Int).SetBytes(pb)
+ if params == nil {
+ params = ParamsFromCurve(curve)
+ }
+ prv.PublicKey.Params = params
+ return
+}
+
+// MaxSharedKeyLength returns the maximum length of the shared key the
+// public key can produce.
+func MaxSharedKeyLength(pub *PublicKey) int {
+ return (pub.Curve.Params().BitSize + 7) / 8
+}
+
+// ECDH key agreement method used to establish secret keys for encryption.
+func (prv *PrivateKey) GenerateShared(pub *PublicKey, skLen, macLen int) (sk []byte, err error) {
+ if prv.PublicKey.Curve != pub.Curve {
+ return nil, ErrInvalidCurve
+ }
+ 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
+ }
+
+ sk = make([]byte, skLen+macLen)
+ skBytes := x.Bytes()
+ copy(sk[len(sk)-len(skBytes):], skBytes)
+ return sk, nil
+}
+
+var (
+ ErrKeyDataTooLong = fmt.Errorf("ecies: can't supply requested key data")
+ ErrSharedTooLong = fmt.Errorf("ecies: shared secret is too long")
+ ErrInvalidMessage = fmt.Errorf("ecies: invalid message")
+)
+
+var (
+ big2To32 = new(big.Int).Exp(big.NewInt(2), big.NewInt(32), nil)
+ big2To32M1 = new(big.Int).Sub(big2To32, big.NewInt(1))
+)
+
+func incCounter(ctr []byte) {
+ if ctr[3]++; ctr[3] != 0 {
+ return
+ } else if ctr[2]++; ctr[2] != 0 {
+ return
+ } else if ctr[1]++; ctr[1] != 0 {
+ return
+ } else if ctr[0]++; ctr[0] != 0 {
+ return
+ }
+ return
+}
+
+// NIST SP 800-56 Concatenation Key Derivation Function (see section 5.8.1).
+func concatKDF(hash hash.Hash, z, s1 []byte, kdLen int) (k []byte, err error) {
+ if s1 == nil {
+ s1 = make([]byte, 0)
+ }
+
+ reps := ((kdLen + 7) * 8) / (hash.BlockSize() * 8)
+ if big.NewInt(int64(reps)).Cmp(big2To32M1) > 0 {
+ fmt.Println(big2To32M1)
+ return nil, ErrKeyDataTooLong
+ }
+
+ counter := []byte{0, 0, 0, 1}
+ k = make([]byte, 0)
+
+ for i := 0; i <= reps; i++ {
+ hash.Write(counter)
+ hash.Write(z)
+ hash.Write(s1)
+ k = append(k, hash.Sum(nil)...)
+ hash.Reset()
+ incCounter(counter)
+ }
+
+ k = k[:kdLen]
+ return
+}
+
+// messageTag computes the MAC of a message (called the tag) as per
+// SEC 1, 3.5.
+func messageTag(hash func() hash.Hash, km, msg, shared []byte) []byte {
+ if shared == nil {
+ shared = make([]byte, 0)
+ }
+ mac := hmac.New(hash, km)
+ mac.Write(msg)
+ tag := mac.Sum(nil)
+ return tag
+}
+
+// Generate an initialisation vector for CTR mode.
+func generateIV(params *ECIESParams, rand io.Reader) (iv []byte, err error) {
+ iv = make([]byte, params.BlockSize)
+ _, err = io.ReadFull(rand, iv)
+ return
+}
+
+// symEncrypt carries out CTR encryption using the block cipher specified in the
+// parameters.
+func symEncrypt(rand io.Reader, params *ECIESParams, key, m []byte) (ct []byte, err error) {
+ c, err := params.Cipher(key)
+ if err != nil {
+ return
+ }
+
+ iv, err := generateIV(params, rand)
+ if err != nil {
+ return
+ }
+ ctr := cipher.NewCTR(c, iv)
+
+ ct = make([]byte, len(m)+params.BlockSize)
+ copy(ct, iv)
+ ctr.XORKeyStream(ct[params.BlockSize:], m)
+ return
+}
+
+// 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) {
+ c, err := params.Cipher(key)
+ if err != nil {
+ return
+ }
+
+ ctr := cipher.NewCTR(c, ct[:params.BlockSize])
+
+ m = make([]byte, len(ct)-params.BlockSize)
+ ctr.XORKeyStream(m, ct[params.BlockSize:])
+ return
+}
+
+// Encrypt encrypts a message using ECIES as specified in SEC 1, 5.1. If
+// the shared information parameters aren't being used, they should be
+// nil.
+func Encrypt(rand io.Reader, pub *PublicKey, m, s1, s2 []byte) (ct []byte, err error) {
+ params := pub.Params
+ if params == nil {
+ if params = ParamsFromCurve(pub.Curve); params == nil {
+ err = ErrUnsupportedECIESParameters
+ return
+ }
+ }
+ R, err := GenerateKey(rand, pub.Curve, params)
+ if err != nil {
+ return
+ }
+
+ hash := params.Hash()
+ z, err := R.GenerateShared(pub, params.KeyLen, params.KeyLen)
+ if err != nil {
+ return
+ }
+ K, err := concatKDF(hash, z, s1, params.KeyLen+params.KeyLen)
+ if err != nil {
+ return
+ }
+ Ke := K[:params.KeyLen]
+ Km := K[params.KeyLen:]
+ hash.Write(Km)
+ Km = hash.Sum(nil)
+ hash.Reset()
+
+ em, err := symEncrypt(rand, params, Ke, m)
+ if err != nil || len(em) <= params.BlockSize {
+ return
+ }
+
+ d := messageTag(params.Hash, Km, em, s2)
+
+ Rb := elliptic.Marshal(pub.Curve, R.PublicKey.X, R.PublicKey.Y)
+ ct = make([]byte, len(Rb)+len(em)+len(d))
+ copy(ct, Rb)
+ copy(ct[len(Rb):], em)
+ copy(ct[len(Rb)+len(em):], d)
+ return
+}
+
+// Decrypt decrypts an ECIES ciphertext.
+func (prv *PrivateKey) Decrypt(rand io.Reader, c, s1, s2 []byte) (m []byte, err error) {
+ if c == nil || len(c) == 0 {
+ err = ErrInvalidMessage
+ return
+ }
+ params := prv.PublicKey.Params
+ if params == nil {
+ if params = ParamsFromCurve(prv.PublicKey.Curve); params == nil {
+ err = ErrUnsupportedECIESParameters
+ return
+ }
+ }
+ hash := params.Hash()
+
+ var (
+ rLen int
+ hLen int = hash.Size()
+ mStart int
+ mEnd int
+ )
+
+ switch c[0] {
+ case 2, 3, 4:
+ rLen = ((prv.PublicKey.Curve.Params().BitSize + 7) / 4)
+ if len(c) < (rLen + hLen + 1) {
+ err = ErrInvalidMessage
+ return
+ }
+ default:
+ err = ErrInvalidPublicKey
+ return
+ }
+
+ mStart = rLen
+ mEnd = len(c) - hLen
+
+ R := new(PublicKey)
+ R.Curve = prv.PublicKey.Curve
+ R.X, R.Y = elliptic.Unmarshal(R.Curve, c[:rLen])
+ if R.X == nil {
+ err = ErrInvalidPublicKey
+ return
+ }
+
+ z, err := prv.GenerateShared(R, params.KeyLen, params.KeyLen)
+ if err != nil {
+ return
+ }
+
+ K, err := concatKDF(hash, z, s1, params.KeyLen+params.KeyLen)
+ if err != nil {
+ return
+ }
+
+ Ke := K[:params.KeyLen]
+ Km := K[params.KeyLen:]
+ hash.Write(Km)
+ Km = hash.Sum(nil)
+ hash.Reset()
+
+ d := messageTag(params.Hash, Km, c[mStart:mEnd], s2)
+ if subtle.ConstantTimeCompare(c[mEnd:], d) != 1 {
+ err = ErrInvalidMessage
+ return
+ }
+
+ m, err = symDecrypt(rand, params, Ke, c[mStart:mEnd])
+ return
+}
diff --git a/crypto/ecies/ecies_test.go b/crypto/ecies/ecies_test.go
new file mode 100644
index 000000000..943e4488e
--- /dev/null
+++ b/crypto/ecies/ecies_test.go
@@ -0,0 +1,489 @@
+package ecies
+
+import (
+ "bytes"
+ "crypto/elliptic"
+ "crypto/rand"
+ "crypto/sha256"
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "testing"
+)
+
+var dumpEnc bool
+
+func init() {
+ flDump := flag.Bool("dump", false, "write encrypted test message to file")
+ flag.Parse()
+ dumpEnc = *flDump
+}
+
+// Ensure the KDF generates appropriately sized keys.
+func TestKDF(t *testing.T) {
+ msg := []byte("Hello, world")
+ h := sha256.New()
+
+ k, err := concatKDF(h, msg, nil, 64)
+ if err != nil {
+ fmt.Println(err.Error())
+ t.FailNow()
+ }
+ if len(k) != 64 {
+ fmt.Printf("KDF: generated key is the wrong size (%d instead of 64\n",
+ len(k))
+ t.FailNow()
+ }
+}
+
+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
+// docs, that AES is the only supported symmetric encryption algorithm.
+func cmpParams(p1, p2 *ECIESParams) bool {
+ if p1.hashAlgo != p2.hashAlgo {
+ return false
+ } else if p1.KeyLen != p2.KeyLen {
+ return false
+ } else if p1.BlockSize != p2.BlockSize {
+ return false
+ }
+ return true
+}
+
+// cmpPublic returns true if the two public keys represent the same pojnt.
+func cmpPublic(pub1, pub2 PublicKey) bool {
+ if pub1.X == nil || pub1.Y == nil {
+ fmt.Println(ErrInvalidPublicKey.Error())
+ return false
+ }
+ if pub2.X == nil || pub2.Y == nil {
+ fmt.Println(ErrInvalidPublicKey.Error())
+ return false
+ }
+ pub1Out := elliptic.Marshal(pub1.Curve, pub1.X, pub1.Y)
+ pub2Out := elliptic.Marshal(pub2.Curve, pub2.X, pub2.Y)
+
+ return bytes.Equal(pub1Out, pub2Out)
+}
+
+// cmpPrivate returns true if the two private keys are the same.
+func cmpPrivate(prv1, prv2 *PrivateKey) bool {
+ if prv1 == nil || prv1.D == nil {
+ return false
+ } else if prv2 == nil || prv2.D == nil {
+ return false
+ } else if prv1.D.Cmp(prv2.D) != 0 {
+ return false
+ } else {
+ return cmpPublic(prv1.PublicKey, prv2.PublicKey)
+ }
+}
+
+// Validate the ECDH component.
+func TestSharedKey(t *testing.T) {
+ prv1, err := GenerateKey(rand.Reader, DefaultCurve, nil)
+ if err != nil {
+ fmt.Println(err.Error())
+ t.FailNow()
+ }
+ skLen = MaxSharedKeyLength(&prv1.PublicKey) / 2
+
+ prv2, err := GenerateKey(rand.Reader, DefaultCurve, nil)
+ if err != nil {
+ fmt.Println(err.Error())
+ t.FailNow()
+ }
+
+ 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()
+ }
+}
+
+// Verify that the key generation code fails when too much key data is
+// requested.
+func TestTooBigSharedKey(t *testing.T) {
+ prv1, err := GenerateKey(rand.Reader, DefaultCurve, nil)
+ if err != nil {
+ fmt.Println(err.Error())
+ t.FailNow()
+ }
+
+ prv2, err := GenerateKey(rand.Reader, DefaultCurve, nil)
+ if err != nil {
+ fmt.Println(err.Error())
+ t.FailNow()
+ }
+
+ _, err = prv1.GenerateShared(&prv2.PublicKey, skLen*2, skLen*2)
+ 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)
+ if err != ErrSharedKeyTooBig {
+ fmt.Println("ecdh: shared key should be too large for curve")
+ t.FailNow()
+ }
+}
+
+// Ensure a public key can be successfully marshalled and unmarshalled, and
+// that the decoded key is the same as the original.
+func TestMarshalPublic(t *testing.T) {
+ prv, err := GenerateKey(rand.Reader, DefaultCurve, nil)
+ if err != nil {
+ fmt.Println(err.Error())
+ t.FailNow()
+ }
+
+ out, err := MarshalPublic(&prv.PublicKey)
+ if err != nil {
+ fmt.Println(err.Error())
+ t.FailNow()
+ }
+
+ pub, err := UnmarshalPublic(out)
+ if err != nil {
+ fmt.Println(err.Error())
+ t.FailNow()
+ }
+
+ if !cmpPublic(prv.PublicKey, *pub) {
+ fmt.Println("ecies: failed to unmarshal public key")
+ t.FailNow()
+ }
+}
+
+// Ensure that a private key can be encoded into DER format, and that
+// the resulting key is properly parsed back into a public key.
+func TestMarshalPrivate(t *testing.T) {
+ prv, err := GenerateKey(rand.Reader, DefaultCurve, nil)
+ if err != nil {
+ fmt.Println(err.Error())
+ t.FailNow()
+ }
+
+ out, err := MarshalPrivate(prv)
+ if err != nil {
+ fmt.Println(err.Error())
+ t.FailNow()
+ }
+
+ if dumpEnc {
+ ioutil.WriteFile("test.out", out, 0644)
+ }
+
+ prv2, err := UnmarshalPrivate(out)
+ if err != nil {
+ fmt.Println(err.Error())
+ t.FailNow()
+ }
+
+ if !cmpPrivate(prv, prv2) {
+ fmt.Println("ecdh: private key import failed")
+ t.FailNow()
+ }
+}
+
+// Ensure that a private key can be successfully encoded to PEM format, and
+// the resulting key is properly parsed back in.
+func TestPrivatePEM(t *testing.T) {
+ prv, err := GenerateKey(rand.Reader, DefaultCurve, nil)
+ if err != nil {
+ fmt.Println(err.Error())
+ t.FailNow()
+ }
+
+ out, err := ExportPrivatePEM(prv)
+ if err != nil {
+ fmt.Println(err.Error())
+ t.FailNow()
+ }
+
+ if dumpEnc {
+ ioutil.WriteFile("test.key", out, 0644)
+ }
+
+ prv2, err := ImportPrivatePEM(out)
+ if err != nil {
+ fmt.Println(err.Error())
+ t.FailNow()
+ } else if !cmpPrivate(prv, prv2) {
+ fmt.Println("ecdh: import from PEM failed")
+ t.FailNow()
+ }
+}
+
+// Ensure that a public key can be successfully encoded to PEM format, and
+// the resulting key is properly parsed back in.
+func TestPublicPEM(t *testing.T) {
+ prv, err := GenerateKey(rand.Reader, DefaultCurve, nil)
+ if err != nil {
+ fmt.Println(err.Error())
+ t.FailNow()
+ }
+
+ out, err := ExportPublicPEM(&prv.PublicKey)
+ if err != nil {
+ fmt.Println(err.Error())
+ t.FailNow()
+ }
+
+ if dumpEnc {
+ ioutil.WriteFile("test.pem", out, 0644)
+ }
+
+ pub2, err := ImportPublicPEM(out)
+ if err != nil {
+ fmt.Println(err.Error())
+ t.FailNow()
+ } else if !cmpPublic(prv.PublicKey, *pub2) {
+ fmt.Println("ecdh: import from PEM failed")
+ t.FailNow()
+ }
+}
+
+// Benchmark the generation of P256 keys.
+func BenchmarkGenerateKeyP256(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ if _, err := GenerateKey(rand.Reader, elliptic.P256(), nil); err != nil {
+ fmt.Println(err.Error())
+ b.FailNow()
+ }
+ }
+}
+
+// Benchmark the generation of P256 shared keys.
+func BenchmarkGenSharedKeyP256(b *testing.B) {
+ prv, err := GenerateKey(rand.Reader, elliptic.P256(), nil)
+ if err != nil {
+ fmt.Println(err.Error())
+ b.FailNow()
+ }
+
+ for i := 0; i < b.N; i++ {
+ _, err := prv.GenerateShared(&prv.PublicKey, skLen, skLen)
+ if err != nil {
+ fmt.Println(err.Error())
+ b.FailNow()
+ }
+ }
+}
+
+// Verify that an encrypted message can be successfully decrypted.
+func TestEncryptDecrypt(t *testing.T) {
+ prv1, err := GenerateKey(rand.Reader, DefaultCurve, nil)
+ if err != nil {
+ fmt.Println(err.Error())
+ t.FailNow()
+ }
+
+ prv2, err := GenerateKey(rand.Reader, DefaultCurve, nil)
+ if err != nil {
+ fmt.Println(err.Error())
+ t.FailNow()
+ }
+
+ message := []byte("Hello, world.")
+ ct, err := Encrypt(rand.Reader, &prv2.PublicKey, message, nil, nil)
+ if err != nil {
+ fmt.Println(err.Error())
+ t.FailNow()
+ }
+
+ pt, err := prv2.Decrypt(rand.Reader, ct, nil, nil)
+ if err != nil {
+ fmt.Println(err.Error())
+ t.FailNow()
+ }
+
+ if !bytes.Equal(pt, message) {
+ fmt.Println("ecies: plaintext doesn't match message")
+ t.FailNow()
+ }
+
+ _, err = prv1.Decrypt(rand.Reader, ct, nil, nil)
+ if err == nil {
+ fmt.Println("ecies: encryption should not have succeeded")
+ t.FailNow()
+ }
+}
+
+// TestMarshalEncryption validates the encode/decode produces a valid
+// ECIES encryption key.
+func TestMarshalEncryption(t *testing.T) {
+ prv1, err := GenerateKey(rand.Reader, DefaultCurve, nil)
+ if err != nil {
+ fmt.Println(err.Error())
+ t.FailNow()
+ }
+
+ out, err := MarshalPrivate(prv1)
+ if err != nil {
+ fmt.Println(err.Error())
+ t.FailNow()
+ }
+
+ prv2, err := UnmarshalPrivate(out)
+ if err != nil {
+ fmt.Println(err.Error())
+ t.FailNow()
+ }
+
+ message := []byte("Hello, world.")
+ ct, err := Encrypt(rand.Reader, &prv2.PublicKey, message, nil, nil)
+ if err != nil {
+ fmt.Println(err.Error())
+ t.FailNow()
+ }
+
+ pt, err := prv2.Decrypt(rand.Reader, ct, nil, nil)
+ if err != nil {
+ fmt.Println(err.Error())
+ t.FailNow()
+ }
+
+ if !bytes.Equal(pt, message) {
+ fmt.Println("ecies: plaintext doesn't match message")
+ t.FailNow()
+ }
+
+ _, err = prv1.Decrypt(rand.Reader, ct, nil, nil)
+ if err != nil {
+ fmt.Println(err.Error())
+ t.FailNow()
+ }
+
+}
+
+type testCase struct {
+ Curve elliptic.Curve
+ Name string
+ Expected bool
+}
+
+var testCases = []testCase{
+ testCase{
+ Curve: elliptic.P224(),
+ Name: "P224",
+ Expected: false,
+ },
+ testCase{
+ Curve: elliptic.P256(),
+ Name: "P256",
+ Expected: true,
+ },
+ testCase{
+ Curve: elliptic.P384(),
+ Name: "P384",
+ Expected: true,
+ },
+ testCase{
+ Curve: elliptic.P521(),
+ Name: "P521",
+ Expected: true,
+ },
+}
+
+// Test parameter selection for each curve, and that P224 fails automatic
+// parameter selection (see README for a discussion of P224). Ensures that
+// selecting a set of parameters automatically for the given curve works.
+func TestParamSelection(t *testing.T) {
+ for _, c := range testCases {
+ testParamSelection(t, c)
+ }
+}
+
+func testParamSelection(t *testing.T, c testCase) {
+ params := ParamsFromCurve(c.Curve)
+ if params == nil && c.Expected {
+ fmt.Printf("%s (%s)\n", ErrInvalidParams.Error(), c.Name)
+ t.FailNow()
+ } else if params != nil && !c.Expected {
+ fmt.Printf("ecies: parameters should be invalid (%s)\n",
+ c.Name)
+ t.FailNow()
+ }
+
+ prv1, err := GenerateKey(rand.Reader, DefaultCurve, nil)
+ if err != nil {
+ fmt.Printf("%s (%s)\n", err.Error(), c.Name)
+ t.FailNow()
+ }
+
+ prv2, err := GenerateKey(rand.Reader, DefaultCurve, nil)
+ if err != nil {
+ fmt.Printf("%s (%s)\n", err.Error(), c.Name)
+ t.FailNow()
+ }
+
+ message := []byte("Hello, world.")
+ ct, err := Encrypt(rand.Reader, &prv2.PublicKey, message, nil, nil)
+ if err != nil {
+ fmt.Printf("%s (%s)\n", err.Error(), c.Name)
+ t.FailNow()
+ }
+
+ pt, err := prv2.Decrypt(rand.Reader, ct, nil, nil)
+ if err != nil {
+ fmt.Printf("%s (%s)\n", err.Error(), c.Name)
+ t.FailNow()
+ }
+
+ if !bytes.Equal(pt, message) {
+ fmt.Printf("ecies: plaintext doesn't match message (%s)\n",
+ c.Name)
+ t.FailNow()
+ }
+
+ _, err = prv1.Decrypt(rand.Reader, ct, nil, nil)
+ if err == nil {
+ fmt.Printf("ecies: encryption should not have succeeded (%s)\n",
+ c.Name)
+ t.FailNow()
+ }
+
+}
+
+// Ensure that the basic public key validation in the decryption operation
+// works.
+func TestBasicKeyValidation(t *testing.T) {
+ badBytes := []byte{0, 1, 5, 6, 7, 8, 9}
+
+ prv, err := GenerateKey(rand.Reader, DefaultCurve, nil)
+ if err != nil {
+ fmt.Println(err.Error())
+ t.FailNow()
+ }
+
+ message := []byte("Hello, world.")
+ ct, err := Encrypt(rand.Reader, &prv.PublicKey, message, nil, nil)
+ if err != nil {
+ fmt.Println(err.Error())
+ t.FailNow()
+ }
+
+ for _, b := range badBytes {
+ ct[0] = b
+ _, err := prv.Decrypt(rand.Reader, ct, nil, nil)
+ if err != ErrInvalidPublicKey {
+ fmt.Println("ecies: validated an invalid key")
+ t.FailNow()
+ }
+ }
+}
diff --git a/crypto/ecies/params.go b/crypto/ecies/params.go
new file mode 100644
index 000000000..fd1ceedd0
--- /dev/null
+++ b/crypto/ecies/params.go
@@ -0,0 +1,181 @@
+package ecies
+
+// This file contains parameters for ECIES encryption, specifying the
+// symmetric encryption and HMAC parameters.
+
+import (
+ "crypto"
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/elliptic"
+ "crypto/sha256"
+ "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()
+
+var (
+ ErrUnsupportedECDHAlgorithm = fmt.Errorf("ecies: unsupported ECDH algorithm")
+ ErrUnsupportedECIESParameters = fmt.Errorf("ecies: unsupported ECIES parameters")
+)
+
+type ECIESParams struct {
+ Hash func() hash.Hash // hash function
+ hashAlgo crypto.Hash
+ Cipher func([]byte) (cipher.Block, error) // symmetric cipher
+ BlockSize int // block size of symmetric cipher
+ KeyLen int // length of symmetric key
+}
+
+// Standard ECIES parameters:
+// * ECIES using AES128 and HMAC-SHA-256-16
+// * ECIES using AES256 and HMAC-SHA-256-32
+// * ECIES using AES256 and HMAC-SHA-384-48
+// * ECIES using AES256 and HMAC-SHA-512-64
+
+var (
+ ECIES_AES128_SHA256 = &ECIESParams{
+ Hash: sha256.New,
+ hashAlgo: crypto.SHA256,
+ Cipher: aes.NewCipher,
+ BlockSize: aes.BlockSize,
+ KeyLen: 16,
+ }
+
+ ECIES_AES256_SHA256 = &ECIESParams{
+ Hash: sha256.New,
+ hashAlgo: crypto.SHA256,
+ Cipher: aes.NewCipher,
+ BlockSize: aes.BlockSize,
+ KeyLen: 32,
+ }
+
+ ECIES_AES256_SHA384 = &ECIESParams{
+ Hash: sha512.New384,
+ hashAlgo: crypto.SHA384,
+ Cipher: aes.NewCipher,
+ BlockSize: aes.BlockSize,
+ KeyLen: 32,
+ }
+
+ ECIES_AES256_SHA512 = &ECIESParams{
+ Hash: sha512.New,
+ hashAlgo: crypto.SHA512,
+ Cipher: aes.NewCipher,
+ BlockSize: aes.BlockSize,
+ KeyLen: 32,
+ }
+)
+
+var paramsFromCurve = map[elliptic.Curve]*ECIESParams{
+ elliptic.P256(): ECIES_AES128_SHA256,
+ elliptic.P384(): ECIES_AES256_SHA384,
+ elliptic.P521(): ECIES_AES256_SHA512,
+}
+
+func AddParamsForCurve(curve elliptic.Curve, params *ECIESParams) {
+ paramsFromCurve[curve] = params
+}
+
+// ParamsFromCurve selects parameters optimal for the selected elliptic curve.
+// Only the curves P256, P384, and P512 are supported.
+func ParamsFromCurve(curve elliptic.Curve) (params *ECIESParams) {
+ return paramsFromCurve[curve]
+
+ /*
+ switch curve {
+ case elliptic.P256():
+ return ECIES_AES128_SHA256
+ case elliptic.P384():
+ return ECIES_AES256_SHA384
+ case elliptic.P521():
+ return ECIES_AES256_SHA512
+ default:
+ return nil
+ }
+ */
+}
+
+// ASN.1 encode the ECIES parameters relevant to the encryption operations.
+func paramsToASNECIES(params *ECIESParams) (asnParams asnECIESParameters) {
+ if nil == params {
+ return
+ }
+ asnParams.KDF = asnNISTConcatenationKDF
+ asnParams.MAC = hmacFull
+ switch params.KeyLen {
+ case 16:
+ asnParams.Sym = aes128CTRinECIES
+ case 24:
+ asnParams.Sym = aes192CTRinECIES
+ case 32:
+ asnParams.Sym = aes256CTRinECIES
+ }
+ return
+}
+
+// ASN.1 encode the ECIES parameters relevant to ECDH.
+func paramsToASNECDH(params *ECIESParams) (algo asnECDHAlgorithm) {
+ switch params.hashAlgo {
+ case crypto.SHA224:
+ algo = dhSinglePass_stdDH_sha224kdf
+ case crypto.SHA256:
+ algo = dhSinglePass_stdDH_sha256kdf
+ case crypto.SHA384:
+ algo = dhSinglePass_stdDH_sha384kdf
+ case crypto.SHA512:
+ algo = dhSinglePass_stdDH_sha512kdf
+ }
+ return
+}
+
+// ASN.1 decode the ECIES parameters relevant to the encryption stage.
+func asnECIEStoParams(asnParams asnECIESParameters, params *ECIESParams) {
+ if !asnParams.KDF.Cmp(asnNISTConcatenationKDF) {
+ params = nil
+ return
+ } else if !asnParams.MAC.Cmp(hmacFull) {
+ params = nil
+ return
+ }
+
+ switch {
+ case asnParams.Sym.Cmp(aes128CTRinECIES):
+ params.KeyLen = 16
+ params.BlockSize = 16
+ params.Cipher = aes.NewCipher
+ case asnParams.Sym.Cmp(aes192CTRinECIES):
+ params.KeyLen = 24
+ params.BlockSize = 16
+ params.Cipher = aes.NewCipher
+ case asnParams.Sym.Cmp(aes256CTRinECIES):
+ params.KeyLen = 32
+ params.BlockSize = 16
+ params.Cipher = aes.NewCipher
+ default:
+ params = nil
+ }
+}
+
+// ASN.1 decode the ECIES parameters relevant to ECDH.
+func asnECDHtoParams(asnParams asnECDHAlgorithm, params *ECIESParams) {
+ if asnParams.Cmp(dhSinglePass_stdDH_sha224kdf) {
+ params.hashAlgo = crypto.SHA224
+ params.Hash = sha256.New224
+ } else if asnParams.Cmp(dhSinglePass_stdDH_sha256kdf) {
+ params.hashAlgo = crypto.SHA256
+ params.Hash = sha256.New
+ } else if asnParams.Cmp(dhSinglePass_stdDH_sha384kdf) {
+ params.hashAlgo = crypto.SHA384
+ params.Hash = sha512.New384
+ } else if asnParams.Cmp(dhSinglePass_stdDH_sha512kdf) {
+ params.hashAlgo = crypto.SHA512
+ params.Hash = sha512.New
+ } else {
+ params = nil
+ }
+}
diff --git a/crypto/encrypt_decrypt_test.go b/crypto/encrypt_decrypt_test.go
new file mode 100644
index 000000000..85b43c406
--- /dev/null
+++ b/crypto/encrypt_decrypt_test.go
@@ -0,0 +1,40 @@
+package crypto
+
+import (
+ "bytes"
+ "fmt"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/ethutil"
+)
+
+func TestBox(t *testing.T) {
+ prv1 := ToECDSA(ethutil.Hex2Bytes("4b50fa71f5c3eeb8fdc452224b2395af2fcc3d125e06c32c82e048c0559db03f"))
+ prv2 := ToECDSA(ethutil.Hex2Bytes("d0b043b4c5d657670778242d82d68a29d25d7d711127d17b8e299f156dad361a"))
+ pub2 := ToECDSAPub(ethutil.Hex2Bytes("04bd27a63c91fe3233c5777e6d3d7b39204d398c8f92655947eb5a373d46e1688f022a1632d264725cbc7dc43ee1cfebde42fa0a86d08b55d2acfbb5e9b3b48dc5"))
+
+ message := []byte("Hello, world.")
+ ct, err := Encrypt(pub2, message)
+ if err != nil {
+ fmt.Println(err.Error())
+ t.FailNow()
+ }
+
+ pt, err := Decrypt(prv2, ct)
+ if err != nil {
+ fmt.Println(err.Error())
+ t.FailNow()
+ }
+
+ if !bytes.Equal(pt, message) {
+ fmt.Println("ecies: plaintext doesn't match message")
+ t.FailNow()
+ }
+
+ _, err = Decrypt(prv1, pt)
+ if err == nil {
+ fmt.Println("ecies: encryption should not have succeeded")
+ t.FailNow()
+ }
+
+}
diff --git a/crypto/key.go b/crypto/key.go
new file mode 100644
index 000000000..ec4908c30
--- /dev/null
+++ b/crypto/key.go
@@ -0,0 +1,110 @@
+/*
+ This file is part of go-ethereum
+
+ go-ethereum 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.
+
+ go-ethereum 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 General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @authors
+ * Gustav Simonsson <gustav.simonsson@gmail.com>
+ * @date 2015
+ *
+ */
+
+package crypto
+
+import (
+ "bytes"
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "encoding/json"
+ "io"
+
+ "code.google.com/p/go-uuid/uuid"
+)
+
+type Key struct {
+ Id uuid.UUID // Version 4 "random" for unique id not derived from key data
+ // to simplify lookups we also store the address
+ Address []byte
+ // we only store privkey as pubkey/address can be derived from it
+ // privkey in this struct is always in plaintext
+ PrivateKey *ecdsa.PrivateKey
+}
+
+type plainKeyJSON struct {
+ Id []byte
+ Address []byte
+ PrivateKey []byte
+}
+
+type cipherJSON struct {
+ Salt []byte
+ IV []byte
+ CipherText []byte
+}
+
+type encryptedKeyJSON struct {
+ Id []byte
+ Address []byte
+ Crypto cipherJSON
+}
+
+func (k *Key) MarshalJSON() (j []byte, err error) {
+ jStruct := plainKeyJSON{
+ k.Id,
+ k.Address,
+ FromECDSA(k.PrivateKey),
+ }
+ j, err = json.Marshal(jStruct)
+ return j, err
+}
+
+func (k *Key) UnmarshalJSON(j []byte) (err error) {
+ keyJSON := new(plainKeyJSON)
+ err = json.Unmarshal(j, &keyJSON)
+ if err != nil {
+ return err
+ }
+
+ u := new(uuid.UUID)
+ *u = keyJSON.Id
+ k.Id = *u
+ k.Address = keyJSON.Address
+ k.PrivateKey = ToECDSA(keyJSON.PrivateKey)
+
+ return err
+}
+
+func NewKey(rand io.Reader) *Key {
+ randBytes := make([]byte, 32)
+ _, err := rand.Read(randBytes)
+ if err != nil {
+ panic("key generation: could not read from random source: " + err.Error())
+ }
+ reader := bytes.NewReader(randBytes)
+ _, x, y, err := elliptic.GenerateKey(S256(), reader)
+ if err != nil {
+ panic("key generation: elliptic.GenerateKey failed: " + err.Error())
+ }
+ privateKeyMarshalled := elliptic.Marshal(S256(), x, y)
+ privateKeyECDSA := ToECDSA(privateKeyMarshalled)
+
+ id := uuid.NewRandom()
+ key := &Key{
+ Id: id,
+ Address: PubkeyToAddress(privateKeyECDSA.PublicKey),
+ PrivateKey: privateKeyECDSA,
+ }
+ return key
+}
diff --git a/crypto/key_manager.go b/crypto/key_manager.go
new file mode 100644
index 000000000..326e559e0
--- /dev/null
+++ b/crypto/key_manager.go
@@ -0,0 +1,134 @@
+package crypto
+
+import (
+ "fmt"
+ "sync"
+
+ "github.com/ethereum/go-ethereum/ethutil"
+ "github.com/ethereum/go-ethereum/logger"
+)
+
+var keylogger = logger.NewLogger("KEY")
+
+type KeyManager struct {
+ keyRing *KeyRing
+ session string
+ keyStore KeyStore // interface
+ keyRings map[string]*KeyRing // cache
+ keyPair *KeyPair
+}
+
+func NewDBKeyManager(db ethutil.Database) *KeyManager {
+ return &KeyManager{keyStore: &DBKeyStore{db: db}, keyRings: make(map[string]*KeyRing)}
+}
+
+func NewFileKeyManager(basedir string) *KeyManager {
+ return &KeyManager{keyStore: &FileKeyStore{basedir: basedir}, keyRings: make(map[string]*KeyRing)}
+}
+
+func (k *KeyManager) KeyPair() *KeyPair {
+ return k.keyPair
+}
+
+func (k *KeyManager) KeyRing() *KeyPair {
+ return k.keyPair
+}
+
+func (k *KeyManager) PrivateKey() []byte {
+ return k.keyPair.PrivateKey
+}
+
+func (k *KeyManager) PublicKey() []byte {
+ return k.keyPair.PublicKey
+}
+
+func (k *KeyManager) Address() []byte {
+ return k.keyPair.Address()
+}
+
+func (k *KeyManager) save(session string, keyRing *KeyRing) error {
+ err := k.keyStore.Save(session, keyRing)
+ if err != nil {
+ return err
+ }
+ k.keyRings[session] = keyRing
+ return nil
+}
+
+func (k *KeyManager) load(session string) (*KeyRing, error) {
+ keyRing, found := k.keyRings[session]
+ if !found {
+ var err error
+ keyRing, err = k.keyStore.Load(session)
+ if err != nil {
+ return nil, err
+ }
+ }
+ return keyRing, nil
+}
+
+func cursorError(cursor int, len int) error {
+ return fmt.Errorf("cursor %d out of range (0..%d)", cursor, len)
+}
+
+func (k *KeyManager) reset(session string, cursor int, keyRing *KeyRing) error {
+ if cursor >= keyRing.Len() {
+ return cursorError(cursor, keyRing.Len())
+ }
+ lock := &sync.Mutex{}
+ lock.Lock()
+ defer lock.Unlock()
+ err := k.save(session, keyRing)
+ if err != nil {
+ return err
+ }
+ k.session = session
+ k.keyRing = keyRing
+ k.keyPair = keyRing.GetKeyPair(cursor)
+ return nil
+}
+
+func (k *KeyManager) SetCursor(cursor int) error {
+ if cursor >= k.keyRing.Len() {
+ return cursorError(cursor, k.keyRing.Len())
+ }
+ k.keyPair = k.keyRing.GetKeyPair(cursor)
+ return nil
+}
+
+func (k *KeyManager) Init(session string, cursor int, force bool) error {
+ var keyRing *KeyRing
+ if !force {
+ var err error
+ keyRing, err = k.load(session)
+ if err != nil {
+ return err
+ }
+ }
+ if keyRing == nil {
+ keyRing = NewGeneratedKeyRing(1)
+ keylogger.Infof("Created keypair. Private key: %x\n", keyRing.keys[0].PrivateKey)
+ }
+ return k.reset(session, cursor, keyRing)
+}
+
+func (k *KeyManager) InitFromSecretsFile(session string, cursor int, secretsfile string) error {
+ keyRing, err := NewKeyRingFromFile(secretsfile)
+ if err != nil {
+ return err
+ }
+ return k.reset(session, cursor, keyRing)
+}
+
+func (k *KeyManager) InitFromString(session string, cursor int, secrets string) error {
+ keyRing, err := NewKeyRingFromString(secrets)
+ if err != nil {
+ return err
+ }
+ return k.reset(session, cursor, keyRing)
+}
+
+func (k *KeyManager) Export(dir string) error {
+ fileKeyStore := FileKeyStore{dir}
+ return fileKeyStore.Save(k.session, k.keyRing)
+}
diff --git a/crypto/key_store.go b/crypto/key_store.go
new file mode 100644
index 000000000..04560a04e
--- /dev/null
+++ b/crypto/key_store.go
@@ -0,0 +1,113 @@
+package crypto
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path"
+ "strings"
+
+ "github.com/ethereum/go-ethereum/ethutil"
+)
+
+type KeyStore interface {
+ Load(string) (*KeyRing, error)
+ Save(string, *KeyRing) error
+}
+
+type DBKeyStore struct {
+ db ethutil.Database
+}
+
+const dbKeyPrefix = "KeyRing"
+
+func (k *DBKeyStore) dbKey(session string) []byte {
+ return []byte(fmt.Sprintf("%s%s", dbKeyPrefix, session))
+}
+
+func (k *DBKeyStore) Save(session string, keyRing *KeyRing) error {
+ k.db.Put(k.dbKey(session), keyRing.RlpEncode())
+ return nil
+}
+
+func (k *DBKeyStore) Load(session string) (*KeyRing, error) {
+ data, err := k.db.Get(k.dbKey(session))
+ if err != nil {
+ return nil, nil
+ }
+ var keyRing *KeyRing
+ keyRing, err = NewKeyRingFromBytes(data)
+ if err != nil {
+ return nil, err
+ }
+ // if empty keyRing is found we return nil, no error
+ if keyRing.Len() == 0 {
+ return nil, nil
+ }
+ return keyRing, nil
+}
+
+type FileKeyStore struct {
+ basedir string
+}
+
+func (k *FileKeyStore) Save(session string, keyRing *KeyRing) error {
+ var content []byte
+ var err error
+ var privateKeys []string
+ var publicKeys []string
+ var mnemonics []string
+ var addresses []string
+ keyRing.Each(func(keyPair *KeyPair) {
+ privateKeys = append(privateKeys, ethutil.Bytes2Hex(keyPair.PrivateKey))
+ publicKeys = append(publicKeys, ethutil.Bytes2Hex(keyPair.PublicKey))
+ addresses = append(addresses, ethutil.Bytes2Hex(keyPair.Address()))
+ mnemonics = append(mnemonics, keyPair.Mnemonic())
+ })
+
+ basename := session
+ if session == "" {
+ basename = "default"
+ }
+
+ path := path.Join(k.basedir, basename)
+ content = []byte(strings.Join(privateKeys, "\n"))
+ err = ioutil.WriteFile(path+".prv", content, 0600)
+ if err != nil {
+ return err
+ }
+
+ content = []byte(strings.Join(publicKeys, "\n"))
+ err = ioutil.WriteFile(path+".pub", content, 0644)
+ if err != nil {
+ return err
+ }
+
+ content = []byte(strings.Join(addresses, "\n"))
+ err = ioutil.WriteFile(path+".addr", content, 0644)
+ if err != nil {
+ return err
+ }
+
+ content = []byte(strings.Join(mnemonics, "\n"))
+ err = ioutil.WriteFile(path+".mne", content, 0600)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (k *FileKeyStore) Load(session string) (*KeyRing, error) {
+ basename := session
+ if session == "" {
+ basename = "default"
+ }
+ secfile := path.Join(k.basedir, basename+".prv")
+ _, err := os.Stat(secfile)
+ // if file is not found then we return nil, no error
+ if err != nil {
+ return nil, nil
+ }
+ return NewKeyRingFromFile(secfile)
+}
diff --git a/crypto/key_store_passphrase.go b/crypto/key_store_passphrase.go
new file mode 100644
index 000000000..74408f874
--- /dev/null
+++ b/crypto/key_store_passphrase.go
@@ -0,0 +1,198 @@
+/*
+ This file is part of go-ethereum
+
+ go-ethereum 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.
+
+ go-ethereum 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 General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @authors
+ * Gustav Simonsson <gustav.simonsson@gmail.com>
+ * @date 2015
+ *
+ */
+/*
+
+This key store behaves as KeyStorePlain with the difference that
+the private key is encrypted and on disk uses another JSON encoding.
+
+Cryptography:
+
+1. Encryption key is scrypt derived key from user passphrase. Scrypt parameters
+ (work factors) [1][2] are defined as constants below.
+2. Scrypt salt is 32 random bytes from CSPRNG. It is appended to ciphertext.
+3. Checksum is SHA3 of the private key bytes.
+4. Plaintext is concatenation of private key bytes and checksum.
+5. Encryption algo is AES 256 CBC [3][4]
+6. CBC IV is 16 random bytes from CSPRNG. It is appended to ciphertext.
+7. Plaintext padding is PKCS #7 [5][6]
+
+Encoding:
+
+1. On disk, ciphertext, salt and IV are encoded in a nested JSON object.
+ cat a key file to see the structure.
+2. byte arrays are base64 JSON strings.
+3. The EC private key bytes are in uncompressed form [7].
+ They are a big-endian byte slice of the absolute value of D [8][9].
+4. The checksum is the last 32 bytes of the plaintext byte array and the
+ private key is the preceeding bytes.
+
+References:
+
+1. http://www.tarsnap.com/scrypt/scrypt-slides.pdf
+2. http://stackoverflow.com/questions/11126315/what-are-optimal-scrypt-work-factors
+3. http://en.wikipedia.org/wiki/Advanced_Encryption_Standard
+4. http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher-block_chaining_.28CBC.29
+5. https://leanpub.com/gocrypto/read#leanpub-auto-block-cipher-modes
+6. http://tools.ietf.org/html/rfc2315
+7. http://bitcoin.stackexchange.com/questions/3059/what-is-a-compressed-bitcoin-key
+8. http://golang.org/pkg/crypto/ecdsa/#PrivateKey
+9. https://golang.org/pkg/math/big/#Int.Bytes
+
+*/
+
+package crypto
+
+import (
+ "bytes"
+ "code.google.com/p/go-uuid/uuid"
+ "code.google.com/p/go.crypto/scrypt"
+ "crypto/aes"
+ "crypto/cipher"
+ "encoding/hex"
+ "encoding/json"
+ "errors"
+ "github.com/ethereum/go-ethereum/crypto/randentropy"
+ "io"
+ "os"
+ "path"
+)
+
+const (
+ // 2^18 / 8 / 1 uses 256MB memory and approx 1s CPU time on a modern CPU.
+ scryptN = 1 << 18
+ scryptr = 8
+ scryptp = 1
+ scryptdkLen = 32
+)
+
+type keyStorePassphrase struct {
+ keysDirPath string
+}
+
+func NewKeyStorePassphrase(path string) KeyStore2 {
+ return &keyStorePassphrase{path}
+}
+
+func (ks keyStorePassphrase) GenerateNewKey(rand io.Reader, auth string) (key *Key, err error) {
+ return GenerateNewKeyDefault(ks, rand, auth)
+}
+
+func (ks keyStorePassphrase) GetKey(keyAddr []byte, auth string) (key *Key, err error) {
+ keyBytes, keyId, err := DecryptKey(ks, keyAddr, auth)
+ if err != nil {
+ return nil, err
+ }
+ key = &Key{
+ Id: uuid.UUID(keyId),
+ Address: keyAddr,
+ PrivateKey: ToECDSA(keyBytes),
+ }
+ return key, err
+}
+
+func (ks keyStorePassphrase) GetKeyAddresses() (addresses [][]byte, err error) {
+ return GetKeyAddresses(ks.keysDirPath)
+}
+
+func (ks keyStorePassphrase) StoreKey(key *Key, auth string) (err error) {
+ authArray := []byte(auth)
+ salt := randentropy.GetEntropyMixed(32)
+ derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptr, scryptp, scryptdkLen)
+ if err != nil {
+ return err
+ }
+
+ keyBytes := FromECDSA(key.PrivateKey)
+ keyBytesHash := Sha3(keyBytes)
+ toEncrypt := PKCS7Pad(append(keyBytes, keyBytesHash...))
+
+ AES256Block, err := aes.NewCipher(derivedKey)
+ if err != nil {
+ return err
+ }
+
+ iv := randentropy.GetEntropyMixed(aes.BlockSize) // 16
+ AES256CBCEncrypter := cipher.NewCBCEncrypter(AES256Block, iv)
+ cipherText := make([]byte, len(toEncrypt))
+ AES256CBCEncrypter.CryptBlocks(cipherText, toEncrypt)
+
+ cipherStruct := cipherJSON{
+ salt,
+ iv,
+ cipherText,
+ }
+ keyStruct := encryptedKeyJSON{
+ key.Id,
+ key.Address,
+ cipherStruct,
+ }
+ keyJSON, err := json.Marshal(keyStruct)
+ if err != nil {
+ return err
+ }
+
+ return WriteKeyFile(key.Address, ks.keysDirPath, keyJSON)
+}
+
+func (ks keyStorePassphrase) DeleteKey(keyAddr []byte, auth string) (err error) {
+ // only delete if correct passphrase is given
+ _, _, err = DecryptKey(ks, keyAddr, auth)
+ if err != nil {
+ return err
+ }
+
+ keyDirPath := path.Join(ks.keysDirPath, hex.EncodeToString(keyAddr))
+ return os.RemoveAll(keyDirPath)
+}
+
+func DecryptKey(ks keyStorePassphrase, keyAddr []byte, auth string) (keyBytes []byte, keyId []byte, err error) {
+ fileContent, err := GetKeyFile(ks.keysDirPath, keyAddr)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ keyProtected := new(encryptedKeyJSON)
+ err = json.Unmarshal(fileContent, keyProtected)
+
+ keyId = keyProtected.Id
+ salt := keyProtected.Crypto.Salt
+ iv := keyProtected.Crypto.IV
+ cipherText := keyProtected.Crypto.CipherText
+
+ authArray := []byte(auth)
+ derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptr, scryptp, scryptdkLen)
+ if err != nil {
+ return nil, nil, err
+ }
+ plainText, err := aesCBCDecrypt(derivedKey, cipherText, iv)
+ if err != nil {
+ return nil, nil, err
+ }
+ keyBytes = plainText[:len(plainText)-32]
+ keyBytesHash := plainText[len(plainText)-32:]
+ if !bytes.Equal(Sha3(keyBytes), keyBytesHash) {
+ err = errors.New("Decryption failed: checksum mismatch")
+ return nil, nil, err
+ }
+ return keyBytes, keyId, err
+}
diff --git a/crypto/key_store_plain.go b/crypto/key_store_plain.go
new file mode 100644
index 000000000..6b76962a0
--- /dev/null
+++ b/crypto/key_store_plain.go
@@ -0,0 +1,133 @@
+/*
+ This file is part of go-ethereum
+
+ go-ethereum 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.
+
+ go-ethereum 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 General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @authors
+ * Gustav Simonsson <gustav.simonsson@gmail.com>
+ * @date 2015
+ *
+ */
+
+package crypto
+
+import (
+ "encoding/hex"
+ "encoding/json"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "os/user"
+ "path"
+)
+
+// TODO: rename to KeyStore when replacing existing KeyStore
+type KeyStore2 interface {
+ // create new key using io.Reader entropy source and optionally using auth string
+ GenerateNewKey(io.Reader, string) (*Key, error)
+ GetKey([]byte, string) (*Key, error) // key from addr and auth string
+ GetKeyAddresses() ([][]byte, error) // get all addresses
+ StoreKey(*Key, string) error // store key optionally using auth string
+ DeleteKey([]byte, string) error // delete key by addr and auth string
+}
+
+type keyStorePlain struct {
+ keysDirPath string
+}
+
+// TODO: copied from cmd/ethereum/flags.go
+func DefaultDataDir() string {
+ usr, _ := user.Current()
+ return path.Join(usr.HomeDir, ".ethereum")
+}
+
+func NewKeyStorePlain(path string) KeyStore2 {
+ return &keyStorePlain{path}
+}
+
+func (ks keyStorePlain) GenerateNewKey(rand io.Reader, auth string) (key *Key, err error) {
+ return GenerateNewKeyDefault(ks, rand, auth)
+}
+
+func GenerateNewKeyDefault(ks KeyStore2, rand io.Reader, auth string) (key *Key, err error) {
+ defer func() {
+ if r := recover(); r != nil {
+ err = fmt.Errorf("GenerateNewKey error: %v", r)
+ }
+ }()
+ key = NewKey(rand)
+ err = ks.StoreKey(key, auth)
+ return key, err
+}
+
+func (ks keyStorePlain) GetKey(keyAddr []byte, auth string) (key *Key, err error) {
+ fileContent, err := GetKeyFile(ks.keysDirPath, keyAddr)
+ if err != nil {
+ return nil, err
+ }
+
+ key = new(Key)
+ err = json.Unmarshal(fileContent, key)
+ return key, err
+}
+
+func (ks keyStorePlain) GetKeyAddresses() (addresses [][]byte, err error) {
+ return GetKeyAddresses(ks.keysDirPath)
+}
+
+func (ks keyStorePlain) StoreKey(key *Key, auth string) (err error) {
+ keyJSON, err := json.Marshal(key)
+ if err != nil {
+ return err
+ }
+ err = WriteKeyFile(key.Address, ks.keysDirPath, keyJSON)
+ return err
+}
+
+func (ks keyStorePlain) DeleteKey(keyAddr []byte, auth string) (err error) {
+ keyDirPath := path.Join(ks.keysDirPath, hex.EncodeToString(keyAddr))
+ err = os.RemoveAll(keyDirPath)
+ return err
+}
+
+func GetKeyFile(keysDirPath string, keyAddr []byte) (fileContent []byte, err error) {
+ fileName := hex.EncodeToString(keyAddr)
+ return ioutil.ReadFile(path.Join(keysDirPath, fileName, fileName))
+}
+
+func WriteKeyFile(addr []byte, keysDirPath string, content []byte) (err error) {
+ addrHex := hex.EncodeToString(addr)
+ keyDirPath := path.Join(keysDirPath, addrHex)
+ keyFilePath := path.Join(keyDirPath, addrHex)
+ err = os.MkdirAll(keyDirPath, 0700) // read, write and dir search for user
+ if err != nil {
+ return err
+ }
+ return ioutil.WriteFile(keyFilePath, content, 0600) // read, write for user
+}
+
+func GetKeyAddresses(keysDirPath string) (addresses [][]byte, err error) {
+ fileInfos, err := ioutil.ReadDir(keysDirPath)
+ if err != nil {
+ return nil, err
+ }
+ addresses = make([][]byte, len(fileInfos))
+ for i, fileInfo := range fileInfos {
+ addresses[i] = make([]byte, 40)
+ addresses[i] = []byte(fileInfo.Name())
+ }
+ return addresses, err
+}
diff --git a/crypto/key_store_test.go b/crypto/key_store_test.go
new file mode 100644
index 000000000..485d8f536
--- /dev/null
+++ b/crypto/key_store_test.go
@@ -0,0 +1,98 @@
+package crypto
+
+import (
+ "github.com/ethereum/go-ethereum/crypto/randentropy"
+ "reflect"
+ "testing"
+)
+
+func TestKeyStorePlain(t *testing.T) {
+ ks := NewKeyStorePlain(DefaultDataDir())
+ pass := "" // not used but required by API
+ k1, err := ks.GenerateNewKey(randentropy.Reader, pass)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ k2 := new(Key)
+ k2, err = ks.GetKey(k1.Address, pass)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if !reflect.DeepEqual(k1.Address, k2.Address) {
+ t.Fatal(err)
+ }
+
+ if !reflect.DeepEqual(k1.PrivateKey, k2.PrivateKey) {
+ t.Fatal(err)
+ }
+
+ err = ks.DeleteKey(k2.Address, pass)
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestKeyStorePassphrase(t *testing.T) {
+ ks := NewKeyStorePassphrase(DefaultDataDir())
+ pass := "foo"
+ k1, err := ks.GenerateNewKey(randentropy.Reader, pass)
+ if err != nil {
+ t.Fatal(err)
+ }
+ k2 := new(Key)
+ k2, err = ks.GetKey(k1.Address, pass)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !reflect.DeepEqual(k1.Address, k2.Address) {
+ t.Fatal(err)
+ }
+
+ if !reflect.DeepEqual(k1.PrivateKey, k2.PrivateKey) {
+ t.Fatal(err)
+ }
+
+ err = ks.DeleteKey(k2.Address, pass) // also to clean up created files
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestKeyStorePassphraseDecryptionFail(t *testing.T) {
+ ks := NewKeyStorePassphrase(DefaultDataDir())
+ pass := "foo"
+ k1, err := ks.GenerateNewKey(randentropy.Reader, pass)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = ks.GetKey(k1.Address, "bar") // wrong passphrase
+ if err == nil {
+ t.Fatal(err)
+ }
+
+ err = ks.DeleteKey(k1.Address, "bar") // wrong passphrase
+ if err == nil {
+ t.Fatal(err)
+ }
+
+ err = ks.DeleteKey(k1.Address, pass) // to clean up
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestImportPreSaleKey(t *testing.T) {
+ // file content of a presale key file generated with:
+ // python pyethsaletool.py genwallet
+ // with password "foo"
+ fileContent := "{\"encseed\": \"26d87f5f2bf9835f9a47eefae571bc09f9107bb13d54ff12a4ec095d01f83897494cf34f7bed2ed34126ecba9db7b62de56c9d7cd136520a0427bfb11b8954ba7ac39b90d4650d3448e31185affcd74226a68f1e94b1108e6e0a4a91cdd83eba\", \"ethaddr\": \"d4584b5f6229b7be90727b0fc8c6b91bb427821f\", \"email\": \"gustav.simonsson@gmail.com\", \"btcaddr\": \"1EVknXyFC68kKNLkh6YnKzW41svSRoaAcx\"}"
+ ks := NewKeyStorePassphrase(DefaultDataDir())
+ pass := "foo"
+ _, err := ImportPreSaleKey(ks, []byte(fileContent), pass)
+ if err != nil {
+ t.Fatal(err)
+ }
+}
diff --git a/crypto/keypair.go b/crypto/keypair.go
new file mode 100644
index 000000000..da5788437
--- /dev/null
+++ b/crypto/keypair.go
@@ -0,0 +1,58 @@
+package crypto
+
+import (
+ "strings"
+
+ "github.com/ethereum/go-ethereum/crypto/secp256k1"
+ "github.com/ethereum/go-ethereum/ethutil"
+)
+
+type KeyPair struct {
+ PrivateKey []byte
+ PublicKey []byte
+ address []byte
+ mnemonic string
+ // The associated account
+ // account *StateObject
+}
+
+func GenerateNewKeyPair() *KeyPair {
+ _, prv := secp256k1.GenerateKeyPair()
+ keyPair, _ := NewKeyPairFromSec(prv) // swallow error, this one cannot err
+ return keyPair
+}
+
+func NewKeyPairFromSec(seckey []byte) (*KeyPair, error) {
+ pubkey, err := secp256k1.GeneratePubKey(seckey)
+ if err != nil {
+ return nil, err
+ }
+
+ return &KeyPair{PrivateKey: seckey, PublicKey: pubkey}, nil
+}
+
+func (k *KeyPair) Address() []byte {
+ if k.address == nil {
+ k.address = Sha3(k.PublicKey[1:])[12:]
+ }
+ return k.address
+}
+
+func (k *KeyPair) Mnemonic() string {
+ if k.mnemonic == "" {
+ k.mnemonic = strings.Join(MnemonicEncode(ethutil.Bytes2Hex(k.PrivateKey)), " ")
+ }
+ return k.mnemonic
+}
+
+func (k *KeyPair) AsStrings() (string, string, string, string) {
+ return k.Mnemonic(), ethutil.Bytes2Hex(k.Address()), ethutil.Bytes2Hex(k.PrivateKey), ethutil.Bytes2Hex(k.PublicKey)
+}
+
+func (k *KeyPair) RlpEncode() []byte {
+ return k.RlpValue().Encode()
+}
+
+func (k *KeyPair) RlpValue() *ethutil.Value {
+ return ethutil.NewValue(k.PrivateKey)
+}
diff --git a/crypto/keyring.go b/crypto/keyring.go
new file mode 100644
index 000000000..eab13dbc4
--- /dev/null
+++ b/crypto/keyring.go
@@ -0,0 +1,123 @@
+package crypto
+
+import (
+ "fmt"
+ "io/ioutil"
+ "strings"
+
+ "github.com/ethereum/go-ethereum/ethutil"
+)
+
+type KeyRing struct {
+ keys []*KeyPair
+}
+
+func NewKeyRing() *KeyRing {
+ return &KeyRing{}
+}
+
+func (k *KeyRing) AddKeyPair(keyPair *KeyPair) {
+ k.keys = append(k.keys, keyPair)
+}
+
+func (k *KeyRing) GetKeyPair(i int) *KeyPair {
+ if len(k.keys) > i {
+ return k.keys[i]
+ }
+
+ return nil
+}
+
+func (k *KeyRing) Empty() bool {
+ return k.Len() == 0
+}
+
+func (k *KeyRing) Len() int {
+ return len(k.keys)
+}
+
+func (k *KeyRing) Each(f func(*KeyPair)) {
+ for _, keyPair := range k.keys {
+ f(keyPair)
+ }
+}
+
+func NewGeneratedKeyRing(len int) *KeyRing {
+ keyRing := NewKeyRing()
+ for i := 0; i < len; i++ {
+ keyRing.AddKeyPair(GenerateNewKeyPair())
+ }
+ return keyRing
+}
+
+func NewKeyRingFromFile(secfile string) (*KeyRing, error) {
+ var content []byte
+ var err error
+ content, err = ioutil.ReadFile(secfile)
+ if err != nil {
+ return nil, err
+ }
+ keyRing, err := NewKeyRingFromString(string(content))
+ if err != nil {
+ return nil, err
+ }
+ return keyRing, nil
+}
+
+func NewKeyRingFromString(content string) (*KeyRing, error) {
+ secretStrings := strings.Split(content, "\n")
+ var secrets [][]byte
+ for _, secretString := range secretStrings {
+ secret := secretString
+ words := strings.Split(secretString, " ")
+ if len(words) == 24 {
+ secret = MnemonicDecode(words)
+ } else if len(words) != 1 {
+ return nil, fmt.Errorf("Unrecognised key format")
+ }
+
+ if len(secret) != 0 {
+ secrets = append(secrets, ethutil.Hex2Bytes(secret))
+ }
+ }
+
+ return NewKeyRingFromSecrets(secrets)
+}
+
+func NewKeyRingFromSecrets(secs [][]byte) (*KeyRing, error) {
+ keyRing := NewKeyRing()
+ for _, sec := range secs {
+ keyPair, err := NewKeyPairFromSec(sec)
+ if err != nil {
+ return nil, err
+ }
+ keyRing.AddKeyPair(keyPair)
+ }
+ return keyRing, nil
+}
+
+func NewKeyRingFromBytes(data []byte) (*KeyRing, error) {
+ var secrets [][]byte
+ it := ethutil.NewValueFromBytes(data).NewIterator()
+ for it.Next() {
+ secret := it.Value().Bytes()
+ secrets = append(secrets, secret)
+ }
+ keyRing, err := NewKeyRingFromSecrets(secrets)
+ if err != nil {
+ return nil, err
+ }
+ return keyRing, nil
+}
+
+func (k *KeyRing) RlpEncode() []byte {
+ return k.RlpValue().Encode()
+}
+
+func (k *KeyRing) RlpValue() *ethutil.Value {
+ v := ethutil.EmptyValue()
+ k.Each(func(keyPair *KeyPair) {
+ v.Append(keyPair.RlpValue())
+ })
+ return v
+}
diff --git a/crypto/keys_test.go b/crypto/keys_test.go
new file mode 100644
index 000000000..56e851969
--- /dev/null
+++ b/crypto/keys_test.go
@@ -0,0 +1,122 @@
+package crypto
+
+// import (
+// "github.com/ethereum/go-ethereum/ethdb"
+// // "io/ioutil"
+// "fmt"
+// "os"
+// "path"
+// "testing"
+// )
+
+// // test if persistence layer works
+// func TestDBKeyManager(t *testing.T) {
+// memdb, _ := ethdb.NewMemDatabase()
+// keyManager0 := NewDBKeyManager(memdb)
+// err := keyManager0.Init("", 0, false)
+// if err != nil {
+// t.Error("Unexpected error: ", err)
+// }
+// keyManager1 := NewDBKeyManager(memdb)
+// err = keyManager1.Init("", 0, false)
+// if err != nil {
+// t.Error("Unexpected error: ", err)
+// }
+// if string(keyManager0.PrivateKey()) != string(keyManager1.PrivateKey()) {
+// t.Error("Expected private keys %x, %x, to be identical via db persistence", keyManager0.PrivateKey(), keyManager1.PrivateKey())
+// }
+// err = keyManager1.Init("", 0, true)
+// if err != nil {
+// t.Error("Unexpected error: ", err)
+// }
+// if string(keyManager0.PrivateKey()) == string(keyManager1.PrivateKey()) {
+// t.Error("Expected private keys %x, %x, to be be different despite db persistence if force generate", keyManager0.PrivateKey(), keyManager1.PrivateKey())
+// }
+// }
+
+// func TestFileKeyManager(t *testing.T) {
+// basedir0 := "/tmp/ethtest0"
+// os.RemoveAll(basedir0)
+// os.Mkdir(basedir0, 0777)
+
+// keyManager0 := NewFileKeyManager(basedir0)
+// err := keyManager0.Init("", 0, false)
+// if err != nil {
+// t.Error("Unexpected error: ", err)
+// }
+
+// keyManager1 := NewFileKeyManager(basedir0)
+
+// err = keyManager1.Init("", 0, false)
+// if err != nil {
+// t.Error("Unexpected error: ", err)
+// }
+// if string(keyManager0.PrivateKey()) != string(keyManager1.PrivateKey()) {
+// t.Error("Expected private keys %x, %x, to be identical via db persistence", keyManager0.PrivateKey(), keyManager1.PrivateKey())
+// }
+
+// err = keyManager1.Init("", 0, true)
+// if err != nil {
+// t.Error("Unexpected error: ", err)
+// }
+// if string(keyManager0.PrivateKey()) == string(keyManager1.PrivateKey()) {
+// t.Error("Expected private keys %x, %x, to be be different despite db persistence if force generate", keyManager0.PrivateKey(), keyManager1.PrivateKey())
+// }
+// }
+
+// // cursor errors
+// func TestCursorErrors(t *testing.T) {
+// memdb, _ := ethdb.NewMemDatabase()
+// keyManager0 := NewDBKeyManager(memdb)
+// err := keyManager0.Init("", 0, false)
+// err = keyManager0.Init("", 1, false)
+// if err == nil {
+// t.Error("Expected cursor error")
+// }
+// err = keyManager0.SetCursor(1)
+// if err == nil {
+// t.Error("Expected cursor error")
+// }
+// }
+
+// func TestExportImport(t *testing.T) {
+// memdb, _ := ethdb.NewMemDatabase()
+// keyManager0 := NewDBKeyManager(memdb)
+// err := keyManager0.Init("", 0, false)
+// basedir0 := "/tmp/ethtest0"
+// os.RemoveAll(basedir0)
+// os.Mkdir(basedir0, 0777)
+// keyManager0.Export(basedir0)
+
+// keyManager1 := NewFileKeyManager(basedir0)
+// err = keyManager1.Init("", 0, false)
+// if err != nil {
+// t.Error("Unexpected error: ", err)
+// }
+// fmt.Printf("keyRing: %v\n", keyManager0.KeyPair())
+// fmt.Printf("keyRing: %v\n", keyManager1.KeyPair())
+// if string(keyManager0.PrivateKey()) != string(keyManager1.PrivateKey()) {
+// t.Error("Expected private keys %x, %x, to be identical via export to filestore basedir", keyManager0.PrivateKey(), keyManager1.PrivateKey())
+// }
+// path.Join("")
+
+// // memdb, _ = ethdb.NewMemDatabase()
+// // keyManager2 := NewDBKeyManager(memdb)
+// // err = keyManager2.InitFromSecretsFile("", 0, path.Join(basedir0, "default.prv"))
+// // if err != nil {
+// // t.Error("Unexpected error: ", err)
+// // }
+// // if string(keyManager0.PrivateKey()) != string(keyManager2.PrivateKey()) {
+// // t.Error("Expected private keys %s, %s, to be identical via export/import prv", keyManager0.PrivateKey(), keyManager1.PrivateKey())
+// // }
+
+// // memdb, _ = ethdb.NewMemDatabase()
+// // keyManager3 := NewDBKeyManager(memdb)
+// // err = keyManager3.InitFromSecretsFile("", 0, path.Join(basedir0, "default.mne"))
+// // if err != nil {
+// // t.Error("Unexpected error: ", err)
+// // }
+// // if string(keyManager0.PrivateKey()) != string(keyManager3.PrivateKey()) {
+// // t.Error("Expected private keys %s, %s, to be identical via export/import mnemonic file", keyManager0.PrivateKey(), keyManager1.PrivateKey())
+// // }
+// }
diff --git a/crypto/mnemonic.go b/crypto/mnemonic.go
new file mode 100644
index 000000000..0d690f245
--- /dev/null
+++ b/crypto/mnemonic.go
@@ -0,0 +1,60 @@
+package crypto
+
+import (
+ "fmt"
+ "strconv"
+)
+
+// TODO: See if we can refactor this into a shared util lib if we need it multiple times
+func IndexOf(slice []string, value string) int64 {
+ for p, v := range slice {
+ if v == value {
+ return int64(p)
+ }
+ }
+ return -1
+}
+
+func MnemonicEncode(message string) []string {
+ var out []string
+ n := int64(len(MnemonicWords))
+
+ for i := 0; i < len(message); i += (len(message) / 8) {
+ x := message[i : i+8]
+ bit, _ := strconv.ParseInt(x, 16, 64)
+ w1 := (bit % n)
+ w2 := ((bit / n) + w1) % n
+ w3 := ((bit / n / n) + w2) % n
+ out = append(out, MnemonicWords[w1], MnemonicWords[w2], MnemonicWords[w3])
+ }
+ return out
+}
+
+func MnemonicDecode(wordsar []string) string {
+ var out string
+ n := int64(len(MnemonicWords))
+
+ for i := 0; i < len(wordsar); i += 3 {
+ word1 := wordsar[i]
+ word2 := wordsar[i+1]
+ word3 := wordsar[i+2]
+ w1 := IndexOf(MnemonicWords, word1)
+ w2 := IndexOf(MnemonicWords, word2)
+ w3 := IndexOf(MnemonicWords, word3)
+
+ y := (w2 - w1) % n
+ z := (w3 - w2) % n
+
+ // Golang handles modulo with negative numbers different then most languages
+ // The modulo can be negative, we don't want that.
+ if z < 0 {
+ z += n
+ }
+ if y < 0 {
+ y += n
+ }
+ x := w1 + n*(y) + n*n*(z)
+ out += fmt.Sprintf("%08x", x)
+ }
+ return out
+}
diff --git a/crypto/mnemonic_test.go b/crypto/mnemonic_test.go
new file mode 100644
index 000000000..beff476e0
--- /dev/null
+++ b/crypto/mnemonic_test.go
@@ -0,0 +1,74 @@
+package crypto
+
+import (
+ "testing"
+)
+
+func TestMnDecode(t *testing.T) {
+ words := []string{
+ "ink",
+ "balance",
+ "gain",
+ "fear",
+ "happen",
+ "melt",
+ "mom",
+ "surface",
+ "stir",
+ "bottle",
+ "unseen",
+ "expression",
+ "important",
+ "curl",
+ "grant",
+ "fairy",
+ "across",
+ "back",
+ "figure",
+ "breast",
+ "nobody",
+ "scratch",
+ "worry",
+ "yesterday",
+ }
+ encode := "c61d43dc5bb7a4e754d111dae8105b6f25356492df5e50ecb33b858d94f8c338"
+ result := MnemonicDecode(words)
+ if encode != result {
+ t.Error("We expected", encode, "got", result, "instead")
+ }
+}
+func TestMnEncode(t *testing.T) {
+ encode := "c61d43dc5bb7a4e754d111dae8105b6f25356492df5e50ecb33b858d94f8c338"
+ result := []string{
+ "ink",
+ "balance",
+ "gain",
+ "fear",
+ "happen",
+ "melt",
+ "mom",
+ "surface",
+ "stir",
+ "bottle",
+ "unseen",
+ "expression",
+ "important",
+ "curl",
+ "grant",
+ "fairy",
+ "across",
+ "back",
+ "figure",
+ "breast",
+ "nobody",
+ "scratch",
+ "worry",
+ "yesterday",
+ }
+ words := MnemonicEncode(encode)
+ for i, word := range words {
+ if word != result[i] {
+ t.Error("Mnenonic does not match:", words, result)
+ }
+ }
+}
diff --git a/crypto/mnemonic_words.go b/crypto/mnemonic_words.go
new file mode 100644
index 000000000..ebd0d2690
--- /dev/null
+++ b/crypto/mnemonic_words.go
@@ -0,0 +1,1630 @@
+package crypto
+
+var MnemonicWords []string = []string{
+ "like",
+ "just",
+ "love",
+ "know",
+ "never",
+ "want",
+ "time",
+ "out",
+ "there",
+ "make",
+ "look",
+ "eye",
+ "down",
+ "only",
+ "think",
+ "heart",
+ "back",
+ "then",
+ "into",
+ "about",
+ "more",
+ "away",
+ "still",
+ "them",
+ "take",
+ "thing",
+ "even",
+ "through",
+ "long",
+ "always",
+ "world",
+ "too",
+ "friend",
+ "tell",
+ "try",
+ "hand",
+ "thought",
+ "over",
+ "here",
+ "other",
+ "need",
+ "smile",
+ "again",
+ "much",
+ "cry",
+ "been",
+ "night",
+ "ever",
+ "little",
+ "said",
+ "end",
+ "some",
+ "those",
+ "around",
+ "mind",
+ "people",
+ "girl",
+ "leave",
+ "dream",
+ "left",
+ "turn",
+ "myself",
+ "give",
+ "nothing",
+ "really",
+ "off",
+ "before",
+ "something",
+ "find",
+ "walk",
+ "wish",
+ "good",
+ "once",
+ "place",
+ "ask",
+ "stop",
+ "keep",
+ "watch",
+ "seem",
+ "everything",
+ "wait",
+ "got",
+ "yet",
+ "made",
+ "remember",
+ "start",
+ "alone",
+ "run",
+ "hope",
+ "maybe",
+ "believe",
+ "body",
+ "hate",
+ "after",
+ "close",
+ "talk",
+ "stand",
+ "own",
+ "each",
+ "hurt",
+ "help",
+ "home",
+ "god",
+ "soul",
+ "new",
+ "many",
+ "two",
+ "inside",
+ "should",
+ "true",
+ "first",
+ "fear",
+ "mean",
+ "better",
+ "play",
+ "another",
+ "gone",
+ "change",
+ "use",
+ "wonder",
+ "someone",
+ "hair",
+ "cold",
+ "open",
+ "best",
+ "any",
+ "behind",
+ "happen",
+ "water",
+ "dark",
+ "laugh",
+ "stay",
+ "forever",
+ "name",
+ "work",
+ "show",
+ "sky",
+ "break",
+ "came",
+ "deep",
+ "door",
+ "put",
+ "black",
+ "together",
+ "upon",
+ "happy",
+ "such",
+ "great",
+ "white",
+ "matter",
+ "fill",
+ "past",
+ "please",
+ "burn",
+ "cause",
+ "enough",
+ "touch",
+ "moment",
+ "soon",
+ "voice",
+ "scream",
+ "anything",
+ "stare",
+ "sound",
+ "red",
+ "everyone",
+ "hide",
+ "kiss",
+ "truth",
+ "death",
+ "beautiful",
+ "mine",
+ "blood",
+ "broken",
+ "very",
+ "pass",
+ "next",
+ "forget",
+ "tree",
+ "wrong",
+ "air",
+ "mother",
+ "understand",
+ "lip",
+ "hit",
+ "wall",
+ "memory",
+ "sleep",
+ "free",
+ "high",
+ "realize",
+ "school",
+ "might",
+ "skin",
+ "sweet",
+ "perfect",
+ "blue",
+ "kill",
+ "breath",
+ "dance",
+ "against",
+ "fly",
+ "between",
+ "grow",
+ "strong",
+ "under",
+ "listen",
+ "bring",
+ "sometimes",
+ "speak",
+ "pull",
+ "person",
+ "become",
+ "family",
+ "begin",
+ "ground",
+ "real",
+ "small",
+ "father",
+ "sure",
+ "feet",
+ "rest",
+ "young",
+ "finally",
+ "land",
+ "across",
+ "today",
+ "different",
+ "guy",
+ "line",
+ "fire",
+ "reason",
+ "reach",
+ "second",
+ "slowly",
+ "write",
+ "eat",
+ "smell",
+ "mouth",
+ "step",
+ "learn",
+ "three",
+ "floor",
+ "promise",
+ "breathe",
+ "darkness",
+ "push",
+ "earth",
+ "guess",
+ "save",
+ "song",
+ "above",
+ "along",
+ "both",
+ "color",
+ "house",
+ "almost",
+ "sorry",
+ "anymore",
+ "brother",
+ "okay",
+ "dear",
+ "game",
+ "fade",
+ "already",
+ "apart",
+ "warm",
+ "beauty",
+ "heard",
+ "notice",
+ "question",
+ "shine",
+ "began",
+ "piece",
+ "whole",
+ "shadow",
+ "secret",
+ "street",
+ "within",
+ "finger",
+ "point",
+ "morning",
+ "whisper",
+ "child",
+ "moon",
+ "green",
+ "story",
+ "glass",
+ "kid",
+ "silence",
+ "since",
+ "soft",
+ "yourself",
+ "empty",
+ "shall",
+ "angel",
+ "answer",
+ "baby",
+ "bright",
+ "dad",
+ "path",
+ "worry",
+ "hour",
+ "drop",
+ "follow",
+ "power",
+ "war",
+ "half",
+ "flow",
+ "heaven",
+ "act",
+ "chance",
+ "fact",
+ "least",
+ "tired",
+ "children",
+ "near",
+ "quite",
+ "afraid",
+ "rise",
+ "sea",
+ "taste",
+ "window",
+ "cover",
+ "nice",
+ "trust",
+ "lot",
+ "sad",
+ "cool",
+ "force",
+ "peace",
+ "return",
+ "blind",
+ "easy",
+ "ready",
+ "roll",
+ "rose",
+ "drive",
+ "held",
+ "music",
+ "beneath",
+ "hang",
+ "mom",
+ "paint",
+ "emotion",
+ "quiet",
+ "clear",
+ "cloud",
+ "few",
+ "pretty",
+ "bird",
+ "outside",
+ "paper",
+ "picture",
+ "front",
+ "rock",
+ "simple",
+ "anyone",
+ "meant",
+ "reality",
+ "road",
+ "sense",
+ "waste",
+ "bit",
+ "leaf",
+ "thank",
+ "happiness",
+ "meet",
+ "men",
+ "smoke",
+ "truly",
+ "decide",
+ "self",
+ "age",
+ "book",
+ "form",
+ "alive",
+ "carry",
+ "escape",
+ "damn",
+ "instead",
+ "able",
+ "ice",
+ "minute",
+ "throw",
+ "catch",
+ "leg",
+ "ring",
+ "course",
+ "goodbye",
+ "lead",
+ "poem",
+ "sick",
+ "corner",
+ "desire",
+ "known",
+ "problem",
+ "remind",
+ "shoulder",
+ "suppose",
+ "toward",
+ "wave",
+ "drink",
+ "jump",
+ "woman",
+ "pretend",
+ "sister",
+ "week",
+ "human",
+ "joy",
+ "crack",
+ "grey",
+ "pray",
+ "surprise",
+ "dry",
+ "knee",
+ "less",
+ "search",
+ "bleed",
+ "caught",
+ "clean",
+ "embrace",
+ "future",
+ "king",
+ "son",
+ "sorrow",
+ "chest",
+ "hug",
+ "remain",
+ "sat",
+ "worth",
+ "blow",
+ "daddy",
+ "final",
+ "parent",
+ "tight",
+ "also",
+ "create",
+ "lonely",
+ "safe",
+ "cross",
+ "dress",
+ "evil",
+ "silent",
+ "bone",
+ "fate",
+ "perhaps",
+ "anger",
+ "class",
+ "scar",
+ "snow",
+ "tiny",
+ "tonight",
+ "continue",
+ "control",
+ "dog",
+ "edge",
+ "mirror",
+ "month",
+ "suddenly",
+ "comfort",
+ "given",
+ "loud",
+ "quickly",
+ "gaze",
+ "plan",
+ "rush",
+ "stone",
+ "town",
+ "battle",
+ "ignore",
+ "spirit",
+ "stood",
+ "stupid",
+ "yours",
+ "brown",
+ "build",
+ "dust",
+ "hey",
+ "kept",
+ "pay",
+ "phone",
+ "twist",
+ "although",
+ "ball",
+ "beyond",
+ "hidden",
+ "nose",
+ "taken",
+ "fail",
+ "float",
+ "pure",
+ "somehow",
+ "wash",
+ "wrap",
+ "angry",
+ "cheek",
+ "creature",
+ "forgotten",
+ "heat",
+ "rip",
+ "single",
+ "space",
+ "special",
+ "weak",
+ "whatever",
+ "yell",
+ "anyway",
+ "blame",
+ "job",
+ "choose",
+ "country",
+ "curse",
+ "drift",
+ "echo",
+ "figure",
+ "grew",
+ "laughter",
+ "neck",
+ "suffer",
+ "worse",
+ "yeah",
+ "disappear",
+ "foot",
+ "forward",
+ "knife",
+ "mess",
+ "somewhere",
+ "stomach",
+ "storm",
+ "beg",
+ "idea",
+ "lift",
+ "offer",
+ "breeze",
+ "field",
+ "five",
+ "often",
+ "simply",
+ "stuck",
+ "win",
+ "allow",
+ "confuse",
+ "enjoy",
+ "except",
+ "flower",
+ "seek",
+ "strength",
+ "calm",
+ "grin",
+ "gun",
+ "heavy",
+ "hill",
+ "large",
+ "ocean",
+ "shoe",
+ "sigh",
+ "straight",
+ "summer",
+ "tongue",
+ "accept",
+ "crazy",
+ "everyday",
+ "exist",
+ "grass",
+ "mistake",
+ "sent",
+ "shut",
+ "surround",
+ "table",
+ "ache",
+ "brain",
+ "destroy",
+ "heal",
+ "nature",
+ "shout",
+ "sign",
+ "stain",
+ "choice",
+ "doubt",
+ "glance",
+ "glow",
+ "mountain",
+ "queen",
+ "stranger",
+ "throat",
+ "tomorrow",
+ "city",
+ "either",
+ "fish",
+ "flame",
+ "rather",
+ "shape",
+ "spin",
+ "spread",
+ "ash",
+ "distance",
+ "finish",
+ "image",
+ "imagine",
+ "important",
+ "nobody",
+ "shatter",
+ "warmth",
+ "became",
+ "feed",
+ "flesh",
+ "funny",
+ "lust",
+ "shirt",
+ "trouble",
+ "yellow",
+ "attention",
+ "bare",
+ "bite",
+ "money",
+ "protect",
+ "amaze",
+ "appear",
+ "born",
+ "choke",
+ "completely",
+ "daughter",
+ "fresh",
+ "friendship",
+ "gentle",
+ "probably",
+ "six",
+ "deserve",
+ "expect",
+ "grab",
+ "middle",
+ "nightmare",
+ "river",
+ "thousand",
+ "weight",
+ "worst",
+ "wound",
+ "barely",
+ "bottle",
+ "cream",
+ "regret",
+ "relationship",
+ "stick",
+ "test",
+ "crush",
+ "endless",
+ "fault",
+ "itself",
+ "rule",
+ "spill",
+ "art",
+ "circle",
+ "join",
+ "kick",
+ "mask",
+ "master",
+ "passion",
+ "quick",
+ "raise",
+ "smooth",
+ "unless",
+ "wander",
+ "actually",
+ "broke",
+ "chair",
+ "deal",
+ "favorite",
+ "gift",
+ "note",
+ "number",
+ "sweat",
+ "box",
+ "chill",
+ "clothes",
+ "lady",
+ "mark",
+ "park",
+ "poor",
+ "sadness",
+ "tie",
+ "animal",
+ "belong",
+ "brush",
+ "consume",
+ "dawn",
+ "forest",
+ "innocent",
+ "pen",
+ "pride",
+ "stream",
+ "thick",
+ "clay",
+ "complete",
+ "count",
+ "draw",
+ "faith",
+ "press",
+ "silver",
+ "struggle",
+ "surface",
+ "taught",
+ "teach",
+ "wet",
+ "bless",
+ "chase",
+ "climb",
+ "enter",
+ "letter",
+ "melt",
+ "metal",
+ "movie",
+ "stretch",
+ "swing",
+ "vision",
+ "wife",
+ "beside",
+ "crash",
+ "forgot",
+ "guide",
+ "haunt",
+ "joke",
+ "knock",
+ "plant",
+ "pour",
+ "prove",
+ "reveal",
+ "steal",
+ "stuff",
+ "trip",
+ "wood",
+ "wrist",
+ "bother",
+ "bottom",
+ "crawl",
+ "crowd",
+ "fix",
+ "forgive",
+ "frown",
+ "grace",
+ "loose",
+ "lucky",
+ "party",
+ "release",
+ "surely",
+ "survive",
+ "teacher",
+ "gently",
+ "grip",
+ "speed",
+ "suicide",
+ "travel",
+ "treat",
+ "vein",
+ "written",
+ "cage",
+ "chain",
+ "conversation",
+ "date",
+ "enemy",
+ "however",
+ "interest",
+ "million",
+ "page",
+ "pink",
+ "proud",
+ "sway",
+ "themselves",
+ "winter",
+ "church",
+ "cruel",
+ "cup",
+ "demon",
+ "experience",
+ "freedom",
+ "pair",
+ "pop",
+ "purpose",
+ "respect",
+ "shoot",
+ "softly",
+ "state",
+ "strange",
+ "bar",
+ "birth",
+ "curl",
+ "dirt",
+ "excuse",
+ "lord",
+ "lovely",
+ "monster",
+ "order",
+ "pack",
+ "pants",
+ "pool",
+ "scene",
+ "seven",
+ "shame",
+ "slide",
+ "ugly",
+ "among",
+ "blade",
+ "blonde",
+ "closet",
+ "creek",
+ "deny",
+ "drug",
+ "eternity",
+ "gain",
+ "grade",
+ "handle",
+ "key",
+ "linger",
+ "pale",
+ "prepare",
+ "swallow",
+ "swim",
+ "tremble",
+ "wheel",
+ "won",
+ "cast",
+ "cigarette",
+ "claim",
+ "college",
+ "direction",
+ "dirty",
+ "gather",
+ "ghost",
+ "hundred",
+ "loss",
+ "lung",
+ "orange",
+ "present",
+ "swear",
+ "swirl",
+ "twice",
+ "wild",
+ "bitter",
+ "blanket",
+ "doctor",
+ "everywhere",
+ "flash",
+ "grown",
+ "knowledge",
+ "numb",
+ "pressure",
+ "radio",
+ "repeat",
+ "ruin",
+ "spend",
+ "unknown",
+ "buy",
+ "clock",
+ "devil",
+ "early",
+ "false",
+ "fantasy",
+ "pound",
+ "precious",
+ "refuse",
+ "sheet",
+ "teeth",
+ "welcome",
+ "add",
+ "ahead",
+ "block",
+ "bury",
+ "caress",
+ "content",
+ "depth",
+ "despite",
+ "distant",
+ "marry",
+ "purple",
+ "threw",
+ "whenever",
+ "bomb",
+ "dull",
+ "easily",
+ "grasp",
+ "hospital",
+ "innocence",
+ "normal",
+ "receive",
+ "reply",
+ "rhyme",
+ "shade",
+ "someday",
+ "sword",
+ "toe",
+ "visit",
+ "asleep",
+ "bought",
+ "center",
+ "consider",
+ "flat",
+ "hero",
+ "history",
+ "ink",
+ "insane",
+ "muscle",
+ "mystery",
+ "pocket",
+ "reflection",
+ "shove",
+ "silently",
+ "smart",
+ "soldier",
+ "spot",
+ "stress",
+ "train",
+ "type",
+ "view",
+ "whether",
+ "bus",
+ "energy",
+ "explain",
+ "holy",
+ "hunger",
+ "inch",
+ "magic",
+ "mix",
+ "noise",
+ "nowhere",
+ "prayer",
+ "presence",
+ "shock",
+ "snap",
+ "spider",
+ "study",
+ "thunder",
+ "trail",
+ "admit",
+ "agree",
+ "bag",
+ "bang",
+ "bound",
+ "butterfly",
+ "cute",
+ "exactly",
+ "explode",
+ "familiar",
+ "fold",
+ "further",
+ "pierce",
+ "reflect",
+ "scent",
+ "selfish",
+ "sharp",
+ "sink",
+ "spring",
+ "stumble",
+ "universe",
+ "weep",
+ "women",
+ "wonderful",
+ "action",
+ "ancient",
+ "attempt",
+ "avoid",
+ "birthday",
+ "branch",
+ "chocolate",
+ "core",
+ "depress",
+ "drunk",
+ "especially",
+ "focus",
+ "fruit",
+ "honest",
+ "match",
+ "palm",
+ "perfectly",
+ "pillow",
+ "pity",
+ "poison",
+ "roar",
+ "shift",
+ "slightly",
+ "thump",
+ "truck",
+ "tune",
+ "twenty",
+ "unable",
+ "wipe",
+ "wrote",
+ "coat",
+ "constant",
+ "dinner",
+ "drove",
+ "egg",
+ "eternal",
+ "flight",
+ "flood",
+ "frame",
+ "freak",
+ "gasp",
+ "glad",
+ "hollow",
+ "motion",
+ "peer",
+ "plastic",
+ "root",
+ "screen",
+ "season",
+ "sting",
+ "strike",
+ "team",
+ "unlike",
+ "victim",
+ "volume",
+ "warn",
+ "weird",
+ "attack",
+ "await",
+ "awake",
+ "built",
+ "charm",
+ "crave",
+ "despair",
+ "fought",
+ "grant",
+ "grief",
+ "horse",
+ "limit",
+ "message",
+ "ripple",
+ "sanity",
+ "scatter",
+ "serve",
+ "split",
+ "string",
+ "trick",
+ "annoy",
+ "blur",
+ "boat",
+ "brave",
+ "clearly",
+ "cling",
+ "connect",
+ "fist",
+ "forth",
+ "imagination",
+ "iron",
+ "jock",
+ "judge",
+ "lesson",
+ "milk",
+ "misery",
+ "nail",
+ "naked",
+ "ourselves",
+ "poet",
+ "possible",
+ "princess",
+ "sail",
+ "size",
+ "snake",
+ "society",
+ "stroke",
+ "torture",
+ "toss",
+ "trace",
+ "wise",
+ "bloom",
+ "bullet",
+ "cell",
+ "check",
+ "cost",
+ "darling",
+ "during",
+ "footstep",
+ "fragile",
+ "hallway",
+ "hardly",
+ "horizon",
+ "invisible",
+ "journey",
+ "midnight",
+ "mud",
+ "nod",
+ "pause",
+ "relax",
+ "shiver",
+ "sudden",
+ "value",
+ "youth",
+ "abuse",
+ "admire",
+ "blink",
+ "breast",
+ "bruise",
+ "constantly",
+ "couple",
+ "creep",
+ "curve",
+ "difference",
+ "dumb",
+ "emptiness",
+ "gotta",
+ "honor",
+ "plain",
+ "planet",
+ "recall",
+ "rub",
+ "ship",
+ "slam",
+ "soar",
+ "somebody",
+ "tightly",
+ "weather",
+ "adore",
+ "approach",
+ "bond",
+ "bread",
+ "burst",
+ "candle",
+ "coffee",
+ "cousin",
+ "crime",
+ "desert",
+ "flutter",
+ "frozen",
+ "grand",
+ "heel",
+ "hello",
+ "language",
+ "level",
+ "movement",
+ "pleasure",
+ "powerful",
+ "random",
+ "rhythm",
+ "settle",
+ "silly",
+ "slap",
+ "sort",
+ "spoken",
+ "steel",
+ "threaten",
+ "tumble",
+ "upset",
+ "aside",
+ "awkward",
+ "bee",
+ "blank",
+ "board",
+ "button",
+ "card",
+ "carefully",
+ "complain",
+ "crap",
+ "deeply",
+ "discover",
+ "drag",
+ "dread",
+ "effort",
+ "entire",
+ "fairy",
+ "giant",
+ "gotten",
+ "greet",
+ "illusion",
+ "jeans",
+ "leap",
+ "liquid",
+ "march",
+ "mend",
+ "nervous",
+ "nine",
+ "replace",
+ "rope",
+ "spine",
+ "stole",
+ "terror",
+ "accident",
+ "apple",
+ "balance",
+ "boom",
+ "childhood",
+ "collect",
+ "demand",
+ "depression",
+ "eventually",
+ "faint",
+ "glare",
+ "goal",
+ "group",
+ "honey",
+ "kitchen",
+ "laid",
+ "limb",
+ "machine",
+ "mere",
+ "mold",
+ "murder",
+ "nerve",
+ "painful",
+ "poetry",
+ "prince",
+ "rabbit",
+ "shelter",
+ "shore",
+ "shower",
+ "soothe",
+ "stair",
+ "steady",
+ "sunlight",
+ "tangle",
+ "tease",
+ "treasure",
+ "uncle",
+ "begun",
+ "bliss",
+ "canvas",
+ "cheer",
+ "claw",
+ "clutch",
+ "commit",
+ "crimson",
+ "crystal",
+ "delight",
+ "doll",
+ "existence",
+ "express",
+ "fog",
+ "football",
+ "gay",
+ "goose",
+ "guard",
+ "hatred",
+ "illuminate",
+ "mass",
+ "math",
+ "mourn",
+ "rich",
+ "rough",
+ "skip",
+ "stir",
+ "student",
+ "style",
+ "support",
+ "thorn",
+ "tough",
+ "yard",
+ "yearn",
+ "yesterday",
+ "advice",
+ "appreciate",
+ "autumn",
+ "bank",
+ "beam",
+ "bowl",
+ "capture",
+ "carve",
+ "collapse",
+ "confusion",
+ "creation",
+ "dove",
+ "feather",
+ "girlfriend",
+ "glory",
+ "government",
+ "harsh",
+ "hop",
+ "inner",
+ "loser",
+ "moonlight",
+ "neighbor",
+ "neither",
+ "peach",
+ "pig",
+ "praise",
+ "screw",
+ "shield",
+ "shimmer",
+ "sneak",
+ "stab",
+ "subject",
+ "throughout",
+ "thrown",
+ "tower",
+ "twirl",
+ "wow",
+ "army",
+ "arrive",
+ "bathroom",
+ "bump",
+ "cease",
+ "cookie",
+ "couch",
+ "courage",
+ "dim",
+ "guilt",
+ "howl",
+ "hum",
+ "husband",
+ "insult",
+ "led",
+ "lunch",
+ "mock",
+ "mostly",
+ "natural",
+ "nearly",
+ "needle",
+ "nerd",
+ "peaceful",
+ "perfection",
+ "pile",
+ "price",
+ "remove",
+ "roam",
+ "sanctuary",
+ "serious",
+ "shiny",
+ "shook",
+ "sob",
+ "stolen",
+ "tap",
+ "vain",
+ "void",
+ "warrior",
+ "wrinkle",
+ "affection",
+ "apologize",
+ "blossom",
+ "bounce",
+ "bridge",
+ "cheap",
+ "crumble",
+ "decision",
+ "descend",
+ "desperately",
+ "dig",
+ "dot",
+ "flip",
+ "frighten",
+ "heartbeat",
+ "huge",
+ "lazy",
+ "lick",
+ "odd",
+ "opinion",
+ "process",
+ "puzzle",
+ "quietly",
+ "retreat",
+ "score",
+ "sentence",
+ "separate",
+ "situation",
+ "skill",
+ "soak",
+ "square",
+ "stray",
+ "taint",
+ "task",
+ "tide",
+ "underneath",
+ "veil",
+ "whistle",
+ "anywhere",
+ "bedroom",
+ "bid",
+ "bloody",
+ "burden",
+ "careful",
+ "compare",
+ "concern",
+ "curtain",
+ "decay",
+ "defeat",
+ "describe",
+ "double",
+ "dreamer",
+ "driver",
+ "dwell",
+ "evening",
+ "flare",
+ "flicker",
+ "grandma",
+ "guitar",
+ "harm",
+ "horrible",
+ "hungry",
+ "indeed",
+ "lace",
+ "melody",
+ "monkey",
+ "nation",
+ "object",
+ "obviously",
+ "rainbow",
+ "salt",
+ "scratch",
+ "shown",
+ "shy",
+ "stage",
+ "stun",
+ "third",
+ "tickle",
+ "useless",
+ "weakness",
+ "worship",
+ "worthless",
+ "afternoon",
+ "beard",
+ "boyfriend",
+ "bubble",
+ "busy",
+ "certain",
+ "chin",
+ "concrete",
+ "desk",
+ "diamond",
+ "doom",
+ "drawn",
+ "due",
+ "felicity",
+ "freeze",
+ "frost",
+ "garden",
+ "glide",
+ "harmony",
+ "hopefully",
+ "hunt",
+ "jealous",
+ "lightning",
+ "mama",
+ "mercy",
+ "peel",
+ "physical",
+ "position",
+ "pulse",
+ "punch",
+ "quit",
+ "rant",
+ "respond",
+ "salty",
+ "sane",
+ "satisfy",
+ "savior",
+ "sheep",
+ "slept",
+ "social",
+ "sport",
+ "tuck",
+ "utter",
+ "valley",
+ "wolf",
+ "aim",
+ "alas",
+ "alter",
+ "arrow",
+ "awaken",
+ "beaten",
+ "belief",
+ "brand",
+ "ceiling",
+ "cheese",
+ "clue",
+ "confidence",
+ "connection",
+ "daily",
+ "disguise",
+ "eager",
+ "erase",
+ "essence",
+ "everytime",
+ "expression",
+ "fan",
+ "flag",
+ "flirt",
+ "foul",
+ "fur",
+ "giggle",
+ "glorious",
+ "ignorance",
+ "law",
+ "lifeless",
+ "measure",
+ "mighty",
+ "muse",
+ "north",
+ "opposite",
+ "paradise",
+ "patience",
+ "patient",
+ "pencil",
+ "petal",
+ "plate",
+ "ponder",
+ "possibly",
+ "practice",
+ "slice",
+ "spell",
+ "stock",
+ "strife",
+ "strip",
+ "suffocate",
+ "suit",
+ "tender",
+ "tool",
+ "trade",
+ "velvet",
+ "verse",
+ "waist",
+ "witch",
+ "aunt",
+ "bench",
+ "bold",
+ "cap",
+ "certainly",
+ "click",
+ "companion",
+ "creator",
+ "dart",
+ "delicate",
+ "determine",
+ "dish",
+ "dragon",
+ "drama",
+ "drum",
+ "dude",
+ "everybody",
+ "feast",
+ "forehead",
+ "former",
+ "fright",
+ "fully",
+ "gas",
+ "hook",
+ "hurl",
+ "invite",
+ "juice",
+ "manage",
+ "moral",
+ "possess",
+ "raw",
+ "rebel",
+ "royal",
+ "scale",
+ "scary",
+ "several",
+ "slight",
+ "stubborn",
+ "swell",
+ "talent",
+ "tea",
+ "terrible",
+ "thread",
+ "torment",
+ "trickle",
+ "usually",
+ "vast",
+ "violence",
+ "weave",
+ "acid",
+ "agony",
+ "ashamed",
+ "awe",
+ "belly",
+ "blend",
+ "blush",
+ "character",
+ "cheat",
+ "common",
+ "company",
+ "coward",
+ "creak",
+ "danger",
+ "deadly",
+ "defense",
+ "define",
+ "depend",
+ "desperate",
+ "destination",
+ "dew",
+ "duck",
+ "dusty",
+ "embarrass",
+ "engine",
+ "example",
+ "explore",
+ "foe",
+ "freely",
+ "frustrate",
+ "generation",
+ "glove",
+ "guilty",
+ "health",
+ "hurry",
+ "idiot",
+ "impossible",
+ "inhale",
+ "jaw",
+ "kingdom",
+ "mention",
+ "mist",
+ "moan",
+ "mumble",
+ "mutter",
+ "observe",
+ "ode",
+ "pathetic",
+ "pattern",
+ "pie",
+ "prefer",
+ "puff",
+ "rape",
+ "rare",
+ "revenge",
+ "rude",
+ "scrape",
+ "spiral",
+ "squeeze",
+ "strain",
+ "sunset",
+ "suspend",
+ "sympathy",
+ "thigh",
+ "throne",
+ "total",
+ "unseen",
+ "weapon",
+ "weary",
+}
diff --git a/crypto/randentropy/rand_entropy.go b/crypto/randentropy/rand_entropy.go
new file mode 100644
index 000000000..b87fa564e
--- /dev/null
+++ b/crypto/randentropy/rand_entropy.go
@@ -0,0 +1,84 @@
+package randentropy
+
+import (
+ crand "crypto/rand"
+ "encoding/binary"
+ "github.com/ethereum/go-ethereum/crypto/sha3"
+ "io"
+ "os"
+ "strings"
+ "time"
+)
+
+var Reader io.Reader = &randEntropy{}
+
+type randEntropy struct {
+}
+
+func (*randEntropy) Read(bytes []byte) (n int, err error) {
+ readBytes := GetEntropyMixed(len(bytes))
+ copy(bytes, readBytes)
+ return len(bytes), nil
+}
+
+// TODO: copied from crypto.go , move to sha3 package?
+func Sha3(data []byte) []byte {
+ d := sha3.NewKeccak256()
+ d.Write(data)
+
+ return d.Sum(nil)
+}
+
+// TODO: verify. this needs to be audited
+// we start with crypt/rand, then XOR in additional entropy from OS
+func GetEntropyMixed(n int) []byte {
+ startTime := time.Now().UnixNano()
+ // for each source, we take SHA3 of the source and use it as seed to math/rand
+ // then read bytes from it and XOR them onto the bytes read from crypto/rand
+ mainBuff := GetEntropyCSPRNG(n)
+ // 1. OS entropy sources
+ startTimeBytes := make([]byte, 32)
+ binary.PutVarint(startTimeBytes, startTime)
+ startTimeHash := Sha3(startTimeBytes)
+ mixBytes(mainBuff, startTimeHash)
+
+ pid := os.Getpid()
+ pidBytes := make([]byte, 32)
+ binary.PutUvarint(pidBytes, uint64(pid))
+ pidHash := Sha3(pidBytes)
+ mixBytes(mainBuff, pidHash)
+
+ osEnv := os.Environ()
+ osEnvBytes := []byte(strings.Join(osEnv, ""))
+ osEnvHash := Sha3(osEnvBytes)
+ mixBytes(mainBuff, osEnvHash)
+
+ // not all OS have hostname in env variables
+ osHostName, err := os.Hostname()
+ if err != nil {
+ osHostNameBytes := []byte(osHostName)
+ osHostNameHash := Sha3(osHostNameBytes)
+ mixBytes(mainBuff, osHostNameHash)
+ }
+ return mainBuff
+}
+
+func GetEntropyCSPRNG(n int) []byte {
+ mainBuff := make([]byte, n)
+ _, err := io.ReadFull(crand.Reader, mainBuff)
+ if err != nil {
+ panic("reading from crypto/rand failed: " + err.Error())
+ }
+ return mainBuff
+}
+
+func mixBytes(buff []byte, mixBuff []byte) []byte {
+ bytesToMix := len(buff)
+ if bytesToMix > 32 {
+ bytesToMix = 32
+ }
+ for i := 0; i < bytesToMix; i++ {
+ buff[i] ^= mixBuff[i]
+ }
+ return buff
+}
diff --git a/crypto/secp256k1/.gitignore b/crypto/secp256k1/.gitignore
new file mode 100644
index 000000000..802b6744a
--- /dev/null
+++ b/crypto/secp256k1/.gitignore
@@ -0,0 +1,24 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+
+*~
diff --git a/crypto/secp256k1/README.md b/crypto/secp256k1/README.md
new file mode 100644
index 000000000..79cdccb38
--- /dev/null
+++ b/crypto/secp256k1/README.md
@@ -0,0 +1,22 @@
+secp256k1-go
+=======
+
+golang secp256k1 library
+
+Implements cryptographic operations for the secp256k1 ECDSA curve used by Bitcoin.
+
+Installing
+===
+```
+sudo apt-get install gmp-dev
+```
+
+Now compiles with cgo!
+
+Test
+===
+
+To run tests do
+```
+go tests
+``` \ No newline at end of file
diff --git a/crypto/secp256k1/notes.go b/crypto/secp256k1/notes.go
new file mode 100644
index 000000000..7ed16caab
--- /dev/null
+++ b/crypto/secp256k1/notes.go
@@ -0,0 +1,192 @@
+package secp256k1
+
+/*
+<HaltingState> sipa, int secp256k1_ecdsa_pubkey_create(unsigned char *pubkey, int *pubkeylen, const unsigned char *seckey, int compressed);
+<HaltingState> is that how i generate private/public keys?
+<sipa> HaltingState: you pass in a random 32-byte string as seckey
+<sipa> HaltingState: if it is valid, the corresponding pubkey is put in pubkey
+<sipa> and true is returned
+<sipa> otherwise, false is returned
+<sipa> around 1 in 2^128 32-byte strings are invalid, so the odds of even ever seeing one is extremely rare
+
+<sipa> private keys are mathematically numbers
+<sipa> each has a corresponding point on the curve as public key
+<sipa> a private key is just a number
+<sipa> a public key is a point with x/y coordinates
+<sipa> almost every 256-bit number is a valid private key (one with a point on the curve corresponding to it)
+<sipa> HaltingState: ok?
+
+<sipa> more than half of random points are not on the curve
+<sipa> and actually, it is less than the square root, not less than half, sorry :)
+!!!
+<sipa> a private key is a NUMBER
+<sipa> a public key is a POINT
+<gmaxwell> half the x,y values in the field are not on the curve, a private key is an integer.
+
+<sipa> HaltingState: yes, n,q = private keys; N,Q = corresponding public keys (N=n*G, Q=q*G); then it follows that n*Q = n*q*G = q*n*G = q*N
+<sipa> that's the reason ECDH works
+<sipa> multiplication is associative and commutativ
+*/
+
+/*
+<HaltingState> sipa, ok; i am doing compact signatures and I want to know; can someone change the signature to get another valid signature for same message without the private key
+<HaltingState> because i know they can do that for the normal 72 byte signatures that openssl was putting out
+<sipa> HaltingState: if you don't enforce non-malleability, yes
+<sipa> HaltingState: if you force the highest bit of t
+
+<sipa> it _creates_ signatures that already satisfy that condition
+<sipa> but it will accept ones that don't
+<sipa> maybe i should change that, and be strict
+<HaltingState> yes; i want some way to know signature is valid but fails malleability
+<sipa> well if the highest bit of S is 1, you can take its complement
+<sipa> and end up with a valid signature
+<sipa> that is canonical
+*/
+
+/*
+
+<HaltingState> sipa, I am signing messages and highest bit of the compact signature is 1!!!
+<HaltingState> if (b & 0x80) == 0x80 {
+<HaltingState> log.Panic("b= %v b2= %v \n", b, b&0x80)
+<HaltingState> }
+<sipa> what bit?
+* Pengoo has quit (Ping timeout: 272 seconds)
+<HaltingState> the highest bit of the first byte of signature
+<sipa> it's the highest bit of S
+<sipa> so the 32nd byte
+<HaltingState> wtf
+
+*/
+
+/*
+ For instance, nonces are used in HTTP digest access authentication to calculate an MD5 digest
+ of the password. The nonces are different each time the 401 authentication challenge
+ response code is presented, thus making replay attacks virtually impossible.
+
+can verify client/server match without sending password over network
+*/
+
+/*
+<hanihani> one thing I dont get about armory for instance,
+is how the hot-wallet can generate new addresses without
+knowing the master key
+*/
+
+/*
+<HaltingState> i am yelling at the telehash people for using secp256r1
+instead of secp256k1; they thing r1 is "more secure" despite fact that
+there is no implementation that works and wrapping it is now taking
+up massive time, lol
+<gmaxwell> ...
+
+<gmaxwell> You know that the *r curves are selected via an undisclosed
+secret process, right?
+<gmaxwell> HaltingState: telehash is offtopic for this channel.
+*/
+/*
+ For instance, nonces are used in HTTP digest access authentication to calculate an MD5 digest
+ of the password. The nonces are different each time the 401 authentication challenge
+ response code is presented, thus making replay attacks virtually impossible.
+
+can verify client/server match without sending password over network
+*/
+
+/*
+void secp256k1_start(void);
+void secp256k1_stop(void);
+
+ * Verify an ECDSA signature.
+ * Returns: 1: correct signature
+ * 0: incorrect signature
+ * -1: invalid public key
+ * -2: invalid signature
+ *
+int secp256k1_ecdsa_verify(const unsigned char *msg, int msglen,
+ const unsigned char *sig, int siglen,
+ const unsigned char *pubkey, int pubkeylen);
+
+http://www.nilsschneider.net/2013/01/28/recovering-bitcoin-private-keys.html
+
+Why did this work? ECDSA requires a random number for each signature. If this random
+number is ever used twice with the same private key it can be recovered.
+This transaction was generated by a hardware bitcoin wallet using a pseudo-random number
+generator that was returning the same “random” number every time.
+
+Nonce is 32 bytes?
+
+ * Create an ECDSA signature.
+ * Returns: 1: signature created
+ * 0: nonce invalid, try another one
+ * In: msg: the message being signed
+ * msglen: the length of the message being signed
+ * seckey: pointer to a 32-byte secret key (assumed to be valid)
+ * nonce: pointer to a 32-byte nonce (generated with a cryptographic PRNG)
+ * Out: sig: pointer to a 72-byte array where the signature will be placed.
+ * siglen: pointer to an int, which will be updated to the signature length (<=72).
+ *
+int secp256k1_ecdsa_sign(const unsigned char *msg, int msglen,
+ unsigned char *sig, int *siglen,
+ const unsigned char *seckey,
+ const unsigned char *nonce);
+
+
+ * Create a compact ECDSA signature (64 byte + recovery id).
+ * Returns: 1: signature created
+ * 0: nonce invalid, try another one
+ * In: msg: the message being signed
+ * msglen: the length of the message being signed
+ * seckey: pointer to a 32-byte secret key (assumed to be valid)
+ * nonce: pointer to a 32-byte nonce (generated with a cryptographic PRNG)
+ * Out: sig: pointer to a 64-byte array where the signature will be placed.
+ * recid: pointer to an int, which will be updated to contain the recovery id.
+ *
+int secp256k1_ecdsa_sign_compact(const unsigned char *msg, int msglen,
+ unsigned char *sig64,
+ const unsigned char *seckey,
+ const unsigned char *nonce,
+ int *recid);
+
+ * Recover an ECDSA public key from a compact signature.
+ * Returns: 1: public key succesfully recovered (which guarantees a correct signature).
+ * 0: otherwise.
+ * In: msg: the message assumed to be signed
+ * msglen: the length of the message
+ * compressed: whether to recover a compressed or uncompressed pubkey
+ * recid: the recovery id (as returned by ecdsa_sign_compact)
+ * Out: pubkey: pointer to a 33 or 65 byte array to put the pubkey.
+ * pubkeylen: pointer to an int that will contain the pubkey length.
+ *
+
+recovery id is between 0 and 3
+
+int secp256k1_ecdsa_recover_compact(const unsigned char *msg, int msglen,
+ const unsigned char *sig64,
+ unsigned char *pubkey, int *pubkeylen,
+ int compressed, int recid);
+
+
+ * Verify an ECDSA secret key.
+ * Returns: 1: secret key is valid
+ * 0: secret key is invalid
+ * In: seckey: pointer to a 32-byte secret key
+ *
+int secp256k1_ecdsa_seckey_verify(const unsigned char *seckey);
+
+** Just validate a public key.
+ * Returns: 1: valid public key
+ * 0: invalid public key
+ *
+int secp256k1_ecdsa_pubkey_verify(const unsigned char *pubkey, int pubkeylen);
+
+** Compute the public key for a secret key.
+ * In: compressed: whether the computed public key should be compressed
+ * seckey: pointer to a 32-byte private key.
+ * Out: pubkey: pointer to a 33-byte (if compressed) or 65-byte (if uncompressed)
+ * area to store the public key.
+ * pubkeylen: pointer to int that will be updated to contains the pubkey's
+ * length.
+ * Returns: 1: secret was valid, public key stores
+ * 0: secret was invalid, try again.
+ *
+int secp256k1_ecdsa_pubkey_create(unsigned char *pubkey, int *pubkeylen, const unsigned char *seckey, int compressed);
+*/
diff --git a/crypto/secp256k1/secp256.go b/crypto/secp256k1/secp256.go
new file mode 100644
index 000000000..c1e37629e
--- /dev/null
+++ b/crypto/secp256k1/secp256.go
@@ -0,0 +1,301 @@
+package secp256k1
+
+/*
+#cgo CFLAGS: -std=gnu99 -Wno-error
+#cgo darwin CFLAGS: -I/usr/local/include
+#cgo LDFLAGS: -lgmp
+#cgo darwin LDFLAGS: -L/usr/local/lib
+#define USE_FIELD_10X26
+#define USE_NUM_GMP
+#define USE_FIELD_INV_BUILTIN
+#include "./secp256k1/src/secp256k1.c"
+*/
+import "C"
+
+import (
+ "bytes"
+ "errors"
+ "github.com/ethereum/go-ethereum/crypto/randentropy"
+ "unsafe"
+)
+
+//#define USE_FIELD_5X64
+
+/*
+ Todo:
+ > Centralize key management in module
+ > add pubkey/private key struct
+ > Dont let keys leave module; address keys as ints
+
+ > 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
+ > use slow key derivation function for wallet encryption key (2 seconds)
+*/
+
+func init() {
+ C.secp256k1_start() //takes 10ms to 100ms
+}
+
+func Stop() {
+ C.secp256k1_stop()
+}
+
+/*
+int secp256k1_ecdsa_pubkey_create(
+ unsigned char *pubkey, int *pubkeylen,
+ const unsigned char *seckey, int compressed);
+*/
+
+/** Compute the public key for a secret key.
+ * In: compressed: whether the computed public key should be compressed
+ * seckey: pointer to a 32-byte private key.
+ * Out: pubkey: pointer to a 33-byte (if compressed) or 65-byte (if uncompressed)
+ * area to store the public key.
+ * pubkeylen: pointer to int that will be updated to contains the pubkey's
+ * length.
+ * Returns: 1: secret was valid, public key stores
+ * 0: secret was invalid, try again.
+ */
+
+//pubkey, seckey
+
+func GenerateKeyPair() ([]byte, []byte) {
+
+ pubkey_len := C.int(65)
+ const seckey_len = 32
+
+ var pubkey []byte = make([]byte, pubkey_len)
+ var seckey []byte = randentropy.GetEntropyMixed(seckey_len)
+
+ var pubkey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&pubkey[0]))
+ var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0]))
+
+ ret := C.secp256k1_ecdsa_pubkey_create(
+ pubkey_ptr, &pubkey_len,
+ seckey_ptr, 0)
+
+ if ret != C.int(1) {
+ return GenerateKeyPair() //invalid secret, try again
+ }
+ return pubkey, seckey
+}
+
+func GeneratePubKey(seckey []byte) ([]byte, error) {
+ pubkey_len := C.int(65)
+ const seckey_len = 32
+
+ var pubkey []byte = make([]byte, pubkey_len)
+
+ var pubkey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&pubkey[0]))
+ var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0]))
+
+ ret := C.secp256k1_ecdsa_pubkey_create(
+ pubkey_ptr, &pubkey_len,
+ seckey_ptr, 0)
+
+ if ret != C.int(1) {
+ return nil, errors.New("Unable to generate pubkey from seckey")
+ }
+
+ return pubkey, nil
+}
+
+/*
+* Create a compact ECDSA signature (64 byte + recovery id).
+* Returns: 1: signature created
+* 0: nonce invalid, try another one
+* In: msg: the message being signed
+* msglen: the length of the message being signed
+* seckey: pointer to a 32-byte secret key (assumed to be valid)
+* nonce: pointer to a 32-byte nonce (generated with a cryptographic PRNG)
+* Out: sig: pointer to a 64-byte array where the signature will be placed.
+* recid: pointer to an int, which will be updated to contain the recovery id.
+ */
+
+/*
+int secp256k1_ecdsa_sign_compact(const unsigned char *msg, int msglen,
+ unsigned char *sig64,
+ const unsigned char *seckey,
+ const unsigned char *nonce,
+ int *recid);
+*/
+
+func Sign(msg []byte, seckey []byte) ([]byte, error) {
+ nonce := randentropy.GetEntropyMixed(32)
+
+ var sig []byte = make([]byte, 65)
+ var recid C.int
+
+ var msg_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&msg[0]))
+ var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0]))
+ var nonce_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&nonce[0]))
+ var sig_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&sig[0]))
+
+ if C.secp256k1_ecdsa_seckey_verify(seckey_ptr) != C.int(1) {
+ return nil, errors.New("Invalid secret key")
+ }
+
+ ret := C.secp256k1_ecdsa_sign_compact(
+ msg_ptr, C.int(len(msg)),
+ sig_ptr,
+ seckey_ptr,
+ nonce_ptr,
+ &recid)
+
+ sig[64] = byte(int(recid))
+
+ if ret != C.int(1) {
+ // nonce invalid, retry
+ return Sign(msg, seckey)
+ }
+
+ return sig, nil
+
+}
+
+/*
+* Verify an ECDSA secret key.
+* Returns: 1: secret key is valid
+* 0: secret key is invalid
+* In: seckey: pointer to a 32-byte secret key
+ */
+
+func VerifySeckeyValidity(seckey []byte) error {
+ if len(seckey) != 32 {
+ return errors.New("priv key is not 32 bytes")
+ }
+ var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0]))
+ ret := C.secp256k1_ecdsa_seckey_verify(seckey_ptr)
+ if int(ret) != 1 {
+ return errors.New("invalid seckey")
+ }
+ return nil
+}
+
+/*
+* Validate a public key.
+* Returns: 1: valid public key
+* 0: invalid public key
+ */
+
+func VerifyPubkeyValidity(pubkey []byte) error {
+ if len(pubkey) != 65 {
+ return errors.New("pub key is not 65 bytes")
+ }
+ var pubkey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&pubkey[0]))
+ ret := C.secp256k1_ecdsa_pubkey_verify(pubkey_ptr, 65)
+ if int(ret) != 1 {
+ return errors.New("invalid pubkey")
+ }
+
+ return nil
+}
+
+func VerifySignatureValidity(sig []byte) bool {
+ //64+1
+ if len(sig) != 65 {
+ return false
+ }
+ //malleability check, highest bit must be 1
+ if (sig[32] & 0x80) == 0x80 {
+ return false
+ }
+ //recovery id check
+ if sig[64] >= 4 {
+ return false
+ }
+
+ return true
+}
+
+//for compressed signatures, does not need pubkey
+func VerifySignature(msg []byte, sig []byte, pubkey1 []byte) error {
+ if msg == nil || sig == nil || pubkey1 == nil {
+ return errors.New("inputs must be non-nil")
+ }
+ if len(sig) != 65 {
+ return errors.New("invalid signature length")
+ }
+ if len(pubkey1) != 65 {
+ return errors.New("Invalid public key length")
+ }
+
+ //to enforce malleability, highest bit of S must be 0
+ //S starts at 32nd byte
+ if (sig[32] & 0x80) == 0x80 { //highest bit must be 1
+ return errors.New("Signature not malleable")
+ }
+
+ if sig[64] >= 4 {
+ return errors.New("Recover byte invalid")
+ }
+
+ // if pubkey recovered, signature valid
+ pubkey2, err := RecoverPubkey(msg, sig)
+ if err != nil {
+ return err
+ }
+ if len(pubkey2) != 65 {
+ return errors.New("Invalid recovered public key length")
+ }
+ if !bytes.Equal(pubkey1, pubkey2) {
+ return errors.New("Public key does not match recovered public key")
+ }
+
+ return nil
+}
+
+/*
+int secp256k1_ecdsa_recover_compact(const unsigned char *msg, int msglen,
+ const unsigned char *sig64,
+ unsigned char *pubkey, int *pubkeylen,
+ int compressed, int recid);
+*/
+
+/*
+ * Recover an ECDSA public key from a compact signature.
+ * Returns: 1: public key succesfully recovered (which guarantees a correct signature).
+ * 0: otherwise.
+ * In: msg: the message assumed to be signed
+ * msglen: the length of the message
+ * compressed: whether to recover a compressed or uncompressed pubkey
+ * recid: the recovery id (as returned by ecdsa_sign_compact)
+ * Out: pubkey: pointer to a 33 or 65 byte array to put the pubkey.
+ * pubkeylen: pointer to an int that will contain the pubkey length.
+ */
+
+//recovers the public key from the signature
+//recovery of pubkey means correct signature
+func RecoverPubkey(msg []byte, sig []byte) ([]byte, error) {
+ if len(sig) != 65 {
+ return nil, errors.New("Invalid signature length")
+ }
+
+ var pubkey []byte = make([]byte, 65)
+
+ var msg_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&msg[0]))
+ var sig_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&sig[0]))
+ var pubkey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&pubkey[0]))
+
+ var pubkeylen C.int
+
+ ret := C.secp256k1_ecdsa_recover_compact(
+ msg_ptr, C.int(len(msg)),
+ sig_ptr,
+ pubkey_ptr, &pubkeylen,
+ C.int(0), C.int(sig[64]),
+ )
+
+ if ret == C.int(0) {
+ return nil, errors.New("Failed to recover public key")
+ } else if pubkeylen != C.int(65) {
+ return nil, errors.New("Impossible Error: Invalid recovered public key length")
+ } else {
+ return pubkey, nil
+ }
+ return nil, errors.New("Impossible Error: func RecoverPubkey has reached an unreachable state")
+}
diff --git a/crypto/secp256k1/secp256_test.go b/crypto/secp256k1/secp256_test.go
new file mode 100644
index 000000000..5e657cd72
--- /dev/null
+++ b/crypto/secp256k1/secp256_test.go
@@ -0,0 +1,229 @@
+package secp256k1
+
+import (
+ "bytes"
+ "fmt"
+ "github.com/ethereum/go-ethereum/crypto/randentropy"
+ "log"
+ "testing"
+)
+
+const TESTS = 10000 // how many tests
+const SigSize = 65 //64+1
+
+func Test_Secp256_00(t *testing.T) {
+
+ var nonce []byte = randentropy.GetEntropyMixed(32) //going to get bitcoins stolen!
+
+ if len(nonce) != 32 {
+ t.Fatal()
+ }
+
+}
+
+//tests for Malleability
+//highest bit of S must be 0; 32nd byte
+func CompactSigTest(sig []byte) {
+
+ var b int = int(sig[32])
+ if b < 0 {
+ log.Panic()
+ }
+ if ((b >> 7) == 1) != ((b & 0x80) == 0x80) {
+ log.Panic("b= %v b2= %v \n", b, b>>7)
+ }
+ if (b & 0x80) == 0x80 {
+ log.Panic("b= %v b2= %v \n", b, b&0x80)
+ }
+}
+
+//test pubkey/private generation
+func Test_Secp256_01(t *testing.T) {
+ pubkey, seckey := GenerateKeyPair()
+ if err := VerifySeckeyValidity(seckey); err != nil {
+ t.Fatal()
+ }
+ if err := VerifyPubkeyValidity(pubkey); err != nil {
+ t.Fatal()
+ }
+}
+
+//test size of messages
+func Test_Secp256_02s(t *testing.T) {
+ pubkey, seckey := GenerateKeyPair()
+ msg := randentropy.GetEntropyMixed(32)
+ sig, _ := Sign(msg, seckey)
+ CompactSigTest(sig)
+ if sig == nil {
+ t.Fatal("Signature nil")
+ }
+ if len(pubkey) != 65 {
+ t.Fail()
+ }
+ if len(seckey) != 32 {
+ t.Fail()
+ }
+ if len(sig) != 64+1 {
+ t.Fail()
+ }
+ if int(sig[64]) > 4 {
+ t.Fail()
+ } //should be 0 to 4
+}
+
+//test signing message
+func Test_Secp256_02(t *testing.T) {
+ pubkey1, seckey := GenerateKeyPair()
+ msg := randentropy.GetEntropyMixed(32)
+ sig, _ := Sign(msg, seckey)
+ if sig == nil {
+ t.Fatal("Signature nil")
+ }
+
+ pubkey2, _ := RecoverPubkey(msg, sig)
+ if pubkey2 == nil {
+ t.Fatal("Recovered pubkey invalid")
+ }
+ if bytes.Equal(pubkey1, pubkey2) == false {
+ t.Fatal("Recovered pubkey does not match")
+ }
+
+ err := VerifySignature(msg, sig, pubkey1)
+ if err != nil {
+ t.Fatal("Signature invalid")
+ }
+}
+
+//test pubkey recovery
+func Test_Secp256_02a(t *testing.T) {
+ pubkey1, seckey1 := GenerateKeyPair()
+ msg := randentropy.GetEntropyMixed(32)
+ sig, _ := Sign(msg, seckey1)
+
+ if sig == nil {
+ t.Fatal("Signature nil")
+ }
+ err := VerifySignature(msg, sig, pubkey1)
+ if err != nil {
+ t.Fatal("Signature invalid")
+ }
+
+ pubkey2, _ := RecoverPubkey(msg, sig)
+ if len(pubkey1) != len(pubkey2) {
+ t.Fatal()
+ }
+ for i, _ := range pubkey1 {
+ if pubkey1[i] != pubkey2[i] {
+ t.Fatal()
+ }
+ }
+ if bytes.Equal(pubkey1, pubkey2) == false {
+ t.Fatal()
+ }
+}
+
+//test random messages for the same pub/private key
+func Test_Secp256_03(t *testing.T) {
+ _, seckey := GenerateKeyPair()
+ for i := 0; i < TESTS; i++ {
+ msg := randentropy.GetEntropyMixed(32)
+ sig, _ := Sign(msg, seckey)
+ CompactSigTest(sig)
+
+ sig[len(sig)-1] %= 4
+ pubkey2, _ := RecoverPubkey(msg, sig)
+ if pubkey2 == nil {
+ t.Fail()
+ }
+ }
+}
+
+//test random messages for different pub/private keys
+func Test_Secp256_04(t *testing.T) {
+ for i := 0; i < TESTS; i++ {
+ pubkey1, seckey := GenerateKeyPair()
+ msg := randentropy.GetEntropyMixed(32)
+ sig, _ := Sign(msg, seckey)
+ CompactSigTest(sig)
+
+ if sig[len(sig)-1] >= 4 {
+ t.Fail()
+ }
+ pubkey2, _ := RecoverPubkey(msg, sig)
+ if pubkey2 == nil {
+ t.Fail()
+ }
+ if bytes.Equal(pubkey1, pubkey2) == false {
+ t.Fail()
+ }
+ }
+}
+
+//test random signatures against fixed messages; should fail
+
+//crashes:
+// -SIPA look at this
+
+func randSig() []byte {
+ sig := randentropy.GetEntropyMixed(65)
+ sig[32] &= 0x70
+ sig[64] %= 4
+ return sig
+}
+
+func Test_Secp256_06a_alt0(t *testing.T) {
+ pubkey1, seckey := GenerateKeyPair()
+ msg := randentropy.GetEntropyMixed(32)
+ sig, _ := Sign(msg, seckey)
+
+ if sig == nil {
+ t.Fail()
+ }
+ if len(sig) != 65 {
+ t.Fail()
+ }
+ for i := 0; i < TESTS; i++ {
+ sig = randSig()
+ pubkey2, _ := RecoverPubkey(msg, sig)
+
+ if bytes.Equal(pubkey1, pubkey2) == true {
+ t.Fail()
+ }
+
+ if pubkey2 != nil && VerifySignature(msg, sig, pubkey2) != nil {
+ t.Fail()
+ }
+
+ if VerifySignature(msg, sig, pubkey1) == nil {
+ t.Fail()
+ }
+ }
+}
+
+//test random messages against valid signature: should fail
+
+func Test_Secp256_06b(t *testing.T) {
+ pubkey1, seckey := GenerateKeyPair()
+ msg := randentropy.GetEntropyMixed(32)
+ sig, _ := Sign(msg, seckey)
+
+ fail_count := 0
+ for i := 0; i < TESTS; i++ {
+ msg = randentropy.GetEntropyMixed(32)
+ pubkey2, _ := RecoverPubkey(msg, sig)
+ if bytes.Equal(pubkey1, pubkey2) == true {
+ t.Fail()
+ }
+
+ if pubkey2 != nil && VerifySignature(msg, sig, pubkey2) != nil {
+ t.Fail()
+ }
+
+ if VerifySignature(msg, sig, pubkey1) == nil {
+ t.Fail()
+ }
+ }
+ if fail_count != 0 {
+ fmt.Printf("ERROR: Accepted signature for %v of %v random messages\n", fail_count, TESTS)
+ }
+}
diff --git a/crypto/secp256k1/secp256k1/COPYING b/crypto/secp256k1/secp256k1/COPYING
new file mode 100644
index 000000000..4522a5990
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/COPYING
@@ -0,0 +1,19 @@
+Copyright (c) 2013 Pieter Wuille
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/crypto/secp256k1/secp256k1/Makefile b/crypto/secp256k1/secp256k1/Makefile
new file mode 100644
index 000000000..21628f308
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/Makefile
@@ -0,0 +1,55 @@
+$(shell CC=$(CC) YASM=$(YASM) ./configure)
+include config.mk
+
+FILES := src/*.h src/impl/*.h
+
+JAVA_FILES := src/java/org_bitcoin_NativeSecp256k1.h src/java/org_bitcoin_NativeSecp256k1.c
+
+OBJS :=
+
+ifeq ($(USE_ASM), 1)
+ OBJS := $(OBJS) obj/field_5x$(HAVE_LIMB)_asm.o
+endif
+STD="gnu99"
+
+default: tests libsecp256k1.a libsecp256k1.so
+
+clean:
+ rm -rf obj/*.o bench tests *.a *.so config.mk
+
+obj/field_5x52_asm.o: src/field_5x52_asm.asm
+ $(YASM) -f elf64 -o obj/field_5x52_asm.o src/field_5x52_asm.asm
+
+obj/field_5x64_asm.o: src/field_5x64_asm.asm
+ $(YASM) -f elf64 -o obj/field_5x64_asm.o src/field_5x64_asm.asm
+
+obj/secp256k1.o: $(FILES) src/secp256k1.c include/secp256k1.h
+ $(CC) -fPIC -std=$(STD) $(CFLAGS) $(CFLAGS_EXTRA) -DNDEBUG -$(OPTLEVEL) src/secp256k1.c -c -o obj/secp256k1.o
+
+bench: $(FILES) src/bench.c $(OBJS)
+ $(CC) -fPIC -std=$(STD) $(CFLAGS) $(CFLAGS_EXTRA) $(CFLAGS_TEST_EXTRA) -DNDEBUG -$(OPTLEVEL) src/bench.c $(OBJS) $(LDFLAGS_EXTRA) $(LDFLAGS_TEST_EXTRA) -o bench
+
+tests: $(FILES) src/tests.c $(OBJS)
+ $(CC) -std=$(STD) $(CFLAGS) $(CFLAGS_EXTRA) $(CFLAGS_TEST_EXTRA) -DVERIFY -fstack-protector-all -$(OPTLEVEL) -ggdb3 src/tests.c $(OBJS) $(LDFLAGS_EXTRA) $(LDFLAGS_TEST_EXTRA) -o tests
+
+tests_fuzzer: $(FILES) src/tests_fuzzer.c obj/secp256k1.o $(OBJS)
+ $(CC) -std=$(STD) $(CFLAGS) $(CFLAGS_EXTRA) $(CFLAGS_TEST_EXTRA) -DVERIFY -fstack-protector-all -$(OPTLEVEL) -ggdb3 src/tests_fuzzer.c $(OBJS) obj/secp256k1.o $(LDFLAGS_EXTRA) $(LDFLAGS_TEST_EXTRA) -o tests_fuzzer
+
+coverage: $(FILES) src/tests.c $(OBJS)
+ rm -rf tests.gcno tests.gcda tests_cov
+ $(CC) -std=$(STD) $(CFLAGS) $(CFLAGS_EXTRA) $(CFLAGS_TEST_EXTRA) -DVERIFY --coverage -$(OPTLEVEL) -g src/tests.c $(OBJS) $(LDFLAGS_EXTRA) $(LDFLAGS_TEST_EXTRA) -o tests_cov
+ rm -rf lcov
+ mkdir -p lcov
+ cd lcov; lcov --directory ../ --zerocounters
+ cd lcov; ../tests_cov
+ cd lcov; lcov --directory ../ --capture --output-file secp256k1.info
+ cd lcov; genhtml -o . secp256k1.info
+
+libsecp256k1.a: obj/secp256k1.o $(OBJS)
+ $(AR) -rs $@ $(OBJS) obj/secp256k1.o
+
+libsecp256k1.so: obj/secp256k1.o $(OBJS)
+ $(CC) -std=$(STD) $(LDFLAGS_EXTRA) $(OBJS) obj/secp256k1.o -shared -o libsecp256k1.so
+
+libjavasecp256k1.so: $(OBJS) obj/secp256k1.o $(JAVA_FILES)
+ $(CC) -fPIC -std=$(STD) $(CFLAGS) $(CFLAGS_EXTRA) -DNDEBUG -$(OPTLEVEL) -I. src/java/org_bitcoin_NativeSecp256k1.c $(LDFLAGS_EXTRA) $(OBJS) obj/secp256k1.o -shared -o libjavasecp256k1.so
diff --git a/crypto/secp256k1/secp256k1/TODO b/crypto/secp256k1/secp256k1/TODO
new file mode 100644
index 000000000..a300e1c5e
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/TODO
@@ -0,0 +1,3 @@
+* Unit tests for fieldelem/groupelem, including ones intended to
+ trigger fieldelem's boundary cases.
+* Complete constant-time operations for signing/keygen
diff --git a/crypto/secp256k1/secp256k1/config.mk b/crypto/secp256k1/secp256k1/config.mk
new file mode 100644
index 000000000..3386b7bcb
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/config.mk
@@ -0,0 +1,9 @@
+CC=cc
+YASM=yasm
+CFLAGS_EXTRA=-DUSE_FIELD_5X52 -DUSE_FIELD_5X52_ASM -DUSE_NUM_GMP -DUSE_FIELD_INV_NUM
+CFLAGS_TEST_EXTRA=-DENABLE_OPENSSL_TESTS
+LDFLAGS_EXTRA=-lgmp
+LDFLAGS_TEST_EXTRA=-lcrypto
+USE_ASM=1
+HAVE_LIMB=52
+OPTLEVEL=O2
diff --git a/crypto/secp256k1/secp256k1/configure b/crypto/secp256k1/secp256k1/configure
new file mode 100755
index 000000000..cb69239b7
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/configure
@@ -0,0 +1,175 @@
+#!/bin/sh
+
+if test -f config.mk; then
+ exit 0
+fi
+
+if test -z "$CC"; then
+ CC=cc
+fi
+
+if test -z "$YASM"; then
+ YASM=yasm
+fi
+
+# test yasm
+$YASM -f elf64 -o /tmp/secp256k1-$$.o - <<EOF
+ BITS 64
+ GLOBAL testyasm
+ ALIGN 32
+testyasm:
+ xor r9,r9
+EOF
+if [ "$?" = 0 ]; then
+ $CC $CFLAGS -std=c99 -x c -c - -o /tmp/secp256k1-$$-2.o 2>/dev/null <<EOF
+void __attribute__ ((sysv_abi)) testyasm(void);
+int main() {
+ testyasm();
+ return 0;
+}
+EOF
+ $CC $CFLAGS -std=c99 /tmp/secp256k1-$$-2.o /tmp/secp256k1-$$.o -o /dev/null 2>/dev/null
+ if [ "$?" = 0 ]; then
+ HAVE_YASM=1
+ fi
+ rm -rf /tmp/secp256k1-$$-2.o /tmp/secp256k1-$$.o
+fi
+
+# test openssl
+HAVE_OPENSSL=0
+$CC $CFLAGS -std=c99 -x c - -o /dev/null -lcrypto 2>/dev/null <<EOF
+#include <openssl/bn.h>
+int main() {
+ BN_CTX *ctx = BN_CTX_new();
+ BN_CTX_free(ctx);
+ return 0;
+}
+EOF
+if [ "$?" = 0 ]; then
+ HAVE_OPENSSL=1
+fi
+
+# test openssl/EC
+HAVE_OPENSSL_EC=0
+if [ "$HAVE_OPENSSL" = "1" ]; then
+$CC $CFLAGS -std=c99 -x c - -o /dev/null -lcrypto 2>/dev/null <<EOF
+#include <openssl/ec.h>
+#include <openssl/ecdsa.h>
+#include <openssl/obj_mac.h>
+int main() {
+ EC_KEY *eckey = EC_KEY_new_by_curve_name(NID_secp256k1);
+ ECDSA_sign(0, NULL, 0, NULL, NULL, eckey);
+ ECDSA_verify(0, NULL, 0, NULL, 0, eckey);
+ EC_KEY_free(eckey);
+ return 0;
+}
+EOF
+if [ "$?" = 0 ]; then
+ HAVE_OPENSSL_EC=1
+fi
+fi
+
+# test gmp
+HAVE_GMP=0
+$CC $CFLAGS -std=c99 -x c - -o /dev/null -lgmp 2>/dev/null <<EOF
+#include <gmp.h>
+int main() {
+ mpz_t n;
+ mpz_init(n);
+ mpz_clear(n);
+ return 0;
+}
+EOF
+if [ "$?" = 0 ]; then
+ HAVE_GMP=1
+fi
+
+# test __int128
+HAVE_INT128=0
+$CC $CFLAGS -std=c99 -x c - -o /dev/null 2>/dev/null <<EOF
+#include <stdint.h>
+int main() {
+ __int128 x = 0;
+ return 0;
+}
+EOF
+if [ "$?" = 0 ]; then
+ HAVE_INT128=1
+fi
+
+#default limb size
+HAVE_LIMB=52
+
+for arg in "$@"; do
+ case "$arg" in
+ --no-yasm)
+ HAVE_YASM=0
+ ;;
+ --no-gmp)
+ HAVE_GMP=0
+ ;;
+ --no-openssl)
+ HAVE_OPENSSL=0
+ ;;
+ --use-5x64)
+ HAVE_LIMB=64
+ ;;
+ esac
+done
+
+LINK_OPENSSL=0
+LINK_GMP=0
+USE_ASM=0
+
+# select field implementation
+if [ "$HAVE_YASM" = "1" ]; then
+ CFLAGS_FIELD="-DUSE_FIELD_5X$HAVE_LIMB -DUSE_FIELD_5X${HAVE_LIMB}_ASM"
+ USE_ASM=1
+elif [ "$HAVE_INT128" = "1" ]; then
+ CFLAGS_FIELD="-DUSE_FIELD_5X$HAVE_LIMB -DUSE_FIELD_5X${HAVE_LIMB}_INT128"
+elif [ "$HAVE_GMP" = "1" ]; then
+ CFLAGS_FIELD="-DUSE_FIELD_GMP"
+ LINK_GMP=1
+else
+ CFLAGS_FIELD="-DUSE_FIELD_10X26"
+fi
+
+# select num implementation
+if [ "$HAVE_GMP" = "1" ]; then
+ CFLAGS_NUM="-DUSE_NUM_GMP -DUSE_FIELD_INV_NUM"
+ LINK_GMP=1
+elif [ "$HAVE_OPENSSL" = "1" ]; then
+ CFLAGS_NUM="-DUSE_NUM_OPENSSL -DUSE_FIELD_INV_BUILTIN"
+ LINK_OPENSSL=1
+else
+ echo "No usable num implementation found" >&2
+ exit 1
+fi
+
+CFLAGS_EXTRA="$CFLAGS_FIELD $CFLAGS_NUM"
+LDFLAGS_EXTRA=""
+if [ "$LINK_GMP" = "1" ]; then
+ LDFLAGS_EXTRA="-lgmp"
+fi
+if [ "$LINK_OPENSSL" = "1" ]; then
+ LDFLAGS_EXTRA="-lcrypto"
+else
+ if [ "$HAVE_OPENSSL_EC" = "1" ]; then
+ LDFLAGS_TEST_EXTRA="-lcrypto"
+ fi
+fi
+
+CFLAGS_TEST_EXTRA=""
+if [ "$HAVE_OPENSSL_EC" = "1" ]; then
+ CFLAGS_TEST_EXTRA="-DENABLE_OPENSSL_TESTS"
+fi
+
+echo "CC=$CC" > config.mk
+echo "YASM=$YASM" >>config.mk
+echo "CFLAGS_EXTRA=$CFLAGS_EXTRA" >> config.mk
+echo "CFLAGS_TEST_EXTRA=$CFLAGS_TEST_EXTRA" >> config.mk
+echo "LDFLAGS_EXTRA=$LDFLAGS_EXTRA" >> config.mk
+echo "LDFLAGS_TEST_EXTRA=$LDFLAGS_TEST_EXTRA" >> config.mk
+echo "USE_ASM=$USE_ASM" >>config.mk
+echo "HAVE_LIMB=$HAVE_LIMB" >>config.mk
+echo "OPTLEVEL=O2" >>config.mk
diff --git a/crypto/secp256k1/secp256k1/include/secp256k1.h b/crypto/secp256k1/secp256k1/include/secp256k1.h
new file mode 100644
index 000000000..fd6d6b1f4
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/include/secp256k1.h
@@ -0,0 +1,121 @@
+#ifndef _SECP256K1_
+#define _SECP256K1_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Initialize the library. This may take some time (10-100 ms).
+ * You need to call this before calling any other function.
+ * It cannot run in parallel with any other functions, but once
+ * secp256k1_start() returns, all other functions are thread-safe.
+ */
+void secp256k1_start(void);
+
+/** Free all memory associated with this library. After this, no
+ * functions can be called anymore, except secp256k1_start()
+ */
+void secp256k1_stop(void);
+
+/** Verify an ECDSA signature.
+ * Returns: 1: correct signature
+ * 0: incorrect signature
+ * -1: invalid public key
+ * -2: invalid signature
+ */
+int secp256k1_ecdsa_verify(const unsigned char *msg, int msglen,
+ const unsigned char *sig, int siglen,
+ const unsigned char *pubkey, int pubkeylen);
+
+/** Create an ECDSA signature.
+ * Returns: 1: signature created
+ * 0: nonce invalid, try another one
+ * In: msg: the message being signed
+ * msglen: the length of the message being signed
+ * seckey: pointer to a 32-byte secret key (assumed to be valid)
+ * nonce: pointer to a 32-byte nonce (generated with a cryptographic PRNG)
+ * Out: sig: pointer to a 72-byte array where the signature will be placed.
+ * siglen: pointer to an int, which will be updated to the signature length (<=72).
+ */
+int secp256k1_ecdsa_sign(const unsigned char *msg, int msglen,
+ unsigned char *sig, int *siglen,
+ const unsigned char *seckey,
+ const unsigned char *nonce);
+
+/** Create a compact ECDSA signature (64 byte + recovery id).
+ * Returns: 1: signature created
+ * 0: nonce invalid, try another one
+ * In: msg: the message being signed
+ * msglen: the length of the message being signed
+ * seckey: pointer to a 32-byte secret key (assumed to be valid)
+ * nonce: pointer to a 32-byte nonce (generated with a cryptographic PRNG)
+ * Out: sig: pointer to a 64-byte array where the signature will be placed.
+ * recid: pointer to an int, which will be updated to contain the recovery id.
+ */
+int secp256k1_ecdsa_sign_compact(const unsigned char *msg, int msglen,
+ unsigned char *sig64,
+ const unsigned char *seckey,
+ const unsigned char *nonce,
+ int *recid);
+
+/** Recover an ECDSA public key from a compact signature.
+ * Returns: 1: public key succesfully recovered (which guarantees a correct signature).
+ * 0: otherwise.
+ * In: msg: the message assumed to be signed
+ * msglen: the length of the message
+ * sig64: signature as 64 byte array
+ * compressed: whether to recover a compressed or uncompressed pubkey
+ * recid: the recovery id (as returned by ecdsa_sign_compact)
+ * Out: pubkey: pointer to a 33 or 65 byte array to put the pubkey.
+ * pubkeylen: pointer to an int that will contain the pubkey length.
+ */
+
+int secp256k1_ecdsa_recover_compact(const unsigned char *msg, int msglen,
+ const unsigned char *sig64,
+ unsigned char *pubkey, int *pubkeylen,
+ int compressed, int recid);
+
+/** Verify an ECDSA secret key.
+ * Returns: 1: secret key is valid
+ * 0: secret key is invalid
+ * In: seckey: pointer to a 32-byte secret key
+ */
+int secp256k1_ecdsa_seckey_verify(const unsigned char *seckey);
+
+/** Just validate a public key.
+ * Returns: 1: valid public key
+ * 0: invalid public key
+ */
+int secp256k1_ecdsa_pubkey_verify(const unsigned char *pubkey, int pubkeylen);
+
+/** Compute the public key for a secret key.
+ * In: compressed: whether the computed public key should be compressed
+ * seckey: pointer to a 32-byte private key.
+ * Out: pubkey: pointer to a 33-byte (if compressed) or 65-byte (if uncompressed)
+ * area to store the public key.
+ * pubkeylen: pointer to int that will be updated to contains the pubkey's
+ * length.
+ * Returns: 1: secret was valid, public key stores
+ * 0: secret was invalid, try again.
+ */
+int secp256k1_ecdsa_pubkey_create(unsigned char *pubkey, int *pubkeylen, const unsigned char *seckey, int compressed);
+
+int secp256k1_ecdsa_pubkey_decompress(unsigned char *pubkey, int *pubkeylen);
+
+int secp256k1_ecdsa_privkey_export(const unsigned char *seckey,
+ unsigned char *privkey, int *privkeylen,
+ int compressed);
+
+int secp256k1_ecdsa_privkey_import(unsigned char *seckey,
+ const unsigned char *privkey, int privkeylen);
+
+int secp256k1_ecdsa_privkey_tweak_add(unsigned char *seckey, const unsigned char *tweak);
+int secp256k1_ecdsa_pubkey_tweak_add(unsigned char *pubkey, int pubkeylen, const unsigned char *tweak);
+int secp256k1_ecdsa_privkey_tweak_mul(unsigned char *seckey, const unsigned char *tweak);
+int secp256k1_ecdsa_pubkey_tweak_mul(unsigned char *pubkey, int pubkeylen, const unsigned char *tweak);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/crypto/secp256k1/secp256k1/src/bench.c b/crypto/secp256k1/secp256k1/src/bench.c
new file mode 100644
index 000000000..eeb71343f
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/src/bench.c
@@ -0,0 +1,64 @@
+// Copyright (c) 2013 Pieter Wuille
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <stdio.h>
+
+#include "impl/num.h"
+#include "impl/field.h"
+#include "impl/group.h"
+#include "impl/ecmult.h"
+#include "impl/ecdsa.h"
+#include "impl/util.h"
+
+void random_num_order(secp256k1_num_t *num) {
+ do {
+ unsigned char b32[32];
+ secp256k1_rand256(b32);
+ secp256k1_num_set_bin(num, b32, 32);
+ if (secp256k1_num_is_zero(num))
+ continue;
+ if (secp256k1_num_cmp(num, &secp256k1_ge_consts->order) >= 0)
+ continue;
+ break;
+ } while(1);
+}
+
+int main() {
+ secp256k1_fe_start();
+ secp256k1_ge_start();
+ secp256k1_ecmult_start();
+
+ secp256k1_fe_t x;
+ const secp256k1_num_t *order = &secp256k1_ge_consts->order;
+ secp256k1_num_t r, s, m;
+ secp256k1_num_init(&r);
+ secp256k1_num_init(&s);
+ secp256k1_num_init(&m);
+ secp256k1_ecdsa_sig_t sig;
+ secp256k1_ecdsa_sig_init(&sig);
+ secp256k1_fe_set_hex(&x, "a357ae915c4a65281309edf20504740f0eb3343990216b4f81063cb65f2f7e0f", 64);
+ int cnt = 0;
+ int good = 0;
+ for (int i=0; i<1000000; i++) {
+ random_num_order(&r);
+ random_num_order(&s);
+ random_num_order(&m);
+ secp256k1_ecdsa_sig_set_rs(&sig, &r, &s);
+ secp256k1_ge_t pubkey; secp256k1_ge_set_xo(&pubkey, &x, 1);
+ if (secp256k1_ge_is_valid(&pubkey)) {
+ cnt++;
+ good += secp256k1_ecdsa_sig_verify(&sig, &pubkey, &m);
+ }
+ }
+ printf("%i/%i\n", good, cnt);
+ secp256k1_num_free(&r);
+ secp256k1_num_free(&s);
+ secp256k1_num_free(&m);
+ secp256k1_ecdsa_sig_free(&sig);
+
+ secp256k1_ecmult_stop();
+ secp256k1_ge_stop();
+ secp256k1_fe_stop();
+ return 0;
+}
diff --git a/crypto/secp256k1/secp256k1/src/ecdsa.h b/crypto/secp256k1/secp256k1/src/ecdsa.h
new file mode 100644
index 000000000..d9faaa3e8
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/src/ecdsa.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2013 Pieter Wuille
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef _SECP256K1_ECDSA_
+#define _SECP256K1_ECDSA_
+
+#include "num.h"
+
+typedef struct {
+ secp256k1_num_t r, s;
+} secp256k1_ecdsa_sig_t;
+
+void static secp256k1_ecdsa_sig_init(secp256k1_ecdsa_sig_t *r);
+void static secp256k1_ecdsa_sig_free(secp256k1_ecdsa_sig_t *r);
+
+int static secp256k1_ecdsa_pubkey_parse(secp256k1_ge_t *elem, const unsigned char *pub, int size);
+void static secp256k1_ecdsa_pubkey_serialize(secp256k1_ge_t *elem, unsigned char *pub, int *size, int compressed);
+int static secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned char *sig, int size);
+int static secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const secp256k1_ecdsa_sig_t *a);
+int static secp256k1_ecdsa_sig_verify(const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_num_t *message);
+int static secp256k1_ecdsa_sig_sign(secp256k1_ecdsa_sig_t *sig, const secp256k1_num_t *seckey, const secp256k1_num_t *message, const secp256k1_num_t *nonce, int *recid);
+int static secp256k1_ecdsa_sig_recover(const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_num_t *message, int recid);
+void static secp256k1_ecdsa_sig_set_rs(secp256k1_ecdsa_sig_t *sig, const secp256k1_num_t *r, const secp256k1_num_t *s);
+int static secp256k1_ecdsa_privkey_parse(secp256k1_num_t *key, const unsigned char *privkey, int privkeylen);
+int static secp256k1_ecdsa_privkey_serialize(unsigned char *privkey, int *privkeylen, const secp256k1_num_t *key, int compressed);
+
+#endif
diff --git a/crypto/secp256k1/secp256k1/src/ecmult.h b/crypto/secp256k1/secp256k1/src/ecmult.h
new file mode 100644
index 000000000..856bd284f
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/src/ecmult.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2013 Pieter Wuille
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef _SECP256K1_ECMULT_
+#define _SECP256K1_ECMULT_
+
+#include "num.h"
+#include "group.h"
+
+static void secp256k1_ecmult_start(void);
+static void secp256k1_ecmult_stop(void);
+
+/** Multiply with the generator: R = a*G */
+static void secp256k1_ecmult_gen(secp256k1_gej_t *r, const secp256k1_num_t *a);
+/** Double multiply: R = na*A + ng*G */
+static void secp256k1_ecmult(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_num_t *na, const secp256k1_num_t *ng);
+
+#endif
diff --git a/crypto/secp256k1/secp256k1/src/field.h b/crypto/secp256k1/secp256k1/src/field.h
new file mode 100644
index 000000000..4e0f26179
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/src/field.h
@@ -0,0 +1,101 @@
+// Copyright (c) 2013 Pieter Wuille
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef _SECP256K1_FIELD_
+#define _SECP256K1_FIELD_
+
+/** Field element module.
+ *
+ * Field elements can be represented in several ways, but code accessing
+ * it (and implementations) need to take certain properaties into account:
+ * - Each field element can be normalized or not.
+ * - Each field element has a magnitude, which represents how far away
+ * its representation is away from normalization. Normalized elements
+ * always have a magnitude of 1, but a magnitude of 1 doesn't imply
+ * normality.
+ */
+
+#if defined(USE_FIELD_GMP)
+#include "field_gmp.h"
+#elif defined(USE_FIELD_10X26)
+#include "field_10x26.h"
+#elif defined(USE_FIELD_5X52)
+#include "field_5x52.h"
+#elif defined(USE_FIELD_5X64)
+#include "field_5x64.h"
+#else
+#error "Please select field implementation"
+#endif
+
+typedef struct {
+ secp256k1_num_t p;
+} secp256k1_fe_consts_t;
+
+static const secp256k1_fe_consts_t *secp256k1_fe_consts = NULL;
+
+/** Initialize field element precomputation data. */
+void static secp256k1_fe_start(void);
+
+/** Unload field element precomputation data. */
+void static secp256k1_fe_stop(void);
+
+/** Normalize a field element. */
+void static secp256k1_fe_normalize(secp256k1_fe_t *r);
+
+/** Set a field element equal to a small integer. Resulting field element is normalized. */
+void static secp256k1_fe_set_int(secp256k1_fe_t *r, int a);
+
+/** Verify whether a field element is zero. Requires the input to be normalized. */
+int static secp256k1_fe_is_zero(const secp256k1_fe_t *a);
+
+/** Check the "oddness" of a field element. Requires the input to be normalized. */
+int static secp256k1_fe_is_odd(const secp256k1_fe_t *a);
+
+/** Compare two field elements. Requires both inputs to be normalized */
+int static secp256k1_fe_equal(const secp256k1_fe_t *a, const secp256k1_fe_t *b);
+
+/** Set a field element equal to 32-byte big endian value. Resulting field element is normalized. */
+void static secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a);
+
+/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
+void static secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a);
+
+/** Set a field element equal to the additive inverse of another. Takes a maximum magnitude of the input
+ * as an argument. The magnitude of the output is one higher. */
+void static secp256k1_fe_negate(secp256k1_fe_t *r, const secp256k1_fe_t *a, int m);
+
+/** Multiplies the passed field element with a small integer constant. Multiplies the magnitude by that
+ * small integer. */
+void static secp256k1_fe_mul_int(secp256k1_fe_t *r, int a);
+
+/** Adds a field element to another. The result has the sum of the inputs' magnitudes as magnitude. */
+void static secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a);
+
+/** Sets a field element to be the product of two others. Requires the inputs' magnitudes to be at most 8.
+ * The output magnitude is 1 (but not guaranteed to be normalized). */
+void static secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t *b);
+
+/** Sets a field element to be the square of another. Requires the input's magnitude to be at most 8.
+ * The output magnitude is 1 (but not guaranteed to be normalized). */
+void static secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a);
+
+/** Sets a field element to be the (modular) square root of another. Requires the inputs' magnitude to
+ * be at most 8. The output magnitude is 1 (but not guaranteed to be normalized). */
+void static secp256k1_fe_sqrt(secp256k1_fe_t *r, const secp256k1_fe_t *a);
+
+/** Sets a field element to be the (modular) inverse of another. Requires the input's magnitude to be
+ * at most 8. The output magnitude is 1 (but not guaranteed to be normalized). */
+void static secp256k1_fe_inv(secp256k1_fe_t *r, const secp256k1_fe_t *a);
+
+/** Potentially faster version of secp256k1_fe_inv, without constant-time guarantee. */
+void static secp256k1_fe_inv_var(secp256k1_fe_t *r, const secp256k1_fe_t *a);
+
+
+/** Convert a field element to a hexadecimal string. */
+void static secp256k1_fe_get_hex(char *r, int *rlen, const secp256k1_fe_t *a);
+
+/** Convert a hexadecimal string to a field element. */
+void static secp256k1_fe_set_hex(secp256k1_fe_t *r, const char *a, int alen);
+
+#endif
diff --git a/crypto/secp256k1/secp256k1/src/field_10x26.h b/crypto/secp256k1/secp256k1/src/field_10x26.h
new file mode 100644
index 000000000..d544139e8
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/src/field_10x26.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2013 Pieter Wuille
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef _SECP256K1_FIELD_REPR_
+#define _SECP256K1_FIELD_REPR_
+
+#include <stdint.h>
+
+typedef struct {
+ // X = sum(i=0..9, elem[i]*2^26) mod n
+ uint32_t n[10];
+#ifdef VERIFY
+ int magnitude;
+ int normalized;
+#endif
+} secp256k1_fe_t;
+
+#endif
diff --git a/crypto/secp256k1/secp256k1/src/field_5x52.h b/crypto/secp256k1/secp256k1/src/field_5x52.h
new file mode 100644
index 000000000..9d5de2cc4
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/src/field_5x52.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2013 Pieter Wuille
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef _SECP256K1_FIELD_REPR_
+#define _SECP256K1_FIELD_REPR_
+
+#include <stdint.h>
+
+typedef struct {
+ // X = sum(i=0..4, elem[i]*2^52) mod n
+ uint64_t n[5];
+#ifdef VERIFY
+ int magnitude;
+ int normalized;
+#endif
+} secp256k1_fe_t;
+
+#endif
diff --git a/crypto/secp256k1/secp256k1/src/field_5x52_asm.asm b/crypto/secp256k1/secp256k1/src/field_5x52_asm.asm
new file mode 100644
index 000000000..9237b3687
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/src/field_5x52_asm.asm
@@ -0,0 +1,463 @@
+ ;; Added by Diederik Huys, March 2013
+ ;;
+ ;; Provided public procedures:
+ ;; secp256k1_fe_mul_inner
+ ;; secp256k1_fe_sqr_inner
+ ;;
+ ;; Needed tools: YASM (http://yasm.tortall.net)
+ ;;
+ ;;
+
+ BITS 64
+
+ ;; Procedure ExSetMult
+ ;; Register Layout:
+ ;; INPUT: rdi = a->n
+ ;; rsi = b->n
+ ;; rdx = r->a
+ ;;
+ ;; INTERNAL: rdx:rax = multiplication accumulator
+ ;; r9:r8 = c
+ ;; r10-r13 = t0-t3
+ ;; r14 = b.n[0] / t4
+ ;; r15 = b.n[1] / t5
+ ;; rbx = b.n[2] / t6
+ ;; rcx = b.n[3] / t7
+ ;; rbp = Constant 0FFFFFFFFFFFFFh / t8
+ ;; rsi = b.n / b.n[4] / t9
+
+ GLOBAL secp256k1_fe_mul_inner
+ ALIGN 32
+secp256k1_fe_mul_inner:
+ push rbp
+ push rbx
+ push r12
+ push r13
+ push r14
+ push r15
+ push rdx
+ mov r14,[rsi+8*0] ; preload b.n[0]. This will be the case until
+ ; b.n[0] is no longer needed, then we reassign
+ ; r14 to t4
+ ;; c=a.n[0] * b.n[0]
+ mov rax,[rdi+0*8] ; load a.n[0]
+ mov rbp,0FFFFFFFFFFFFFh
+ mul r14 ; rdx:rax=a.n[0]*b.n[0]
+ mov r15,[rsi+1*8]
+ mov r10,rbp ; load modulus into target register for t0
+ mov r8,rax
+ and r10,rax ; only need lower qword of c
+ shrd r8,rdx,52
+ xor r9,r9 ; c < 2^64, so we ditch the HO part
+
+ ;; c+=a.n[0] * b.n[1] + a.n[1] * b.n[0]
+ mov rax,[rdi+0*8]
+ mul r15
+ add r8,rax
+ adc r9,rdx
+
+ mov rax,[rdi+1*8]
+ mul r14
+ mov r11,rbp
+ mov rbx,[rsi+2*8]
+ add r8,rax
+ adc r9,rdx
+ and r11,r8
+ shrd r8,r9,52
+ xor r9,r9
+
+ ;; c+=a.n[0 1 2] * b.n[2 1 0]
+ mov rax,[rdi+0*8]
+ mul rbx
+ add r8,rax
+ adc r9,rdx
+
+ mov rax,[rdi+1*8]
+ mul r15
+ add r8,rax
+ adc r9,rdx
+
+ mov rax,[rdi+2*8]
+ mul r14
+ mov r12,rbp
+ mov rcx,[rsi+3*8]
+ add r8,rax
+ adc r9,rdx
+ and r12,r8
+ shrd r8,r9,52
+ xor r9,r9
+
+ ;; c+=a.n[0 1 2 3] * b.n[3 2 1 0]
+ mov rax,[rdi+0*8]
+ mul rcx
+ add r8,rax
+ adc r9,rdx
+
+ mov rax,[rdi+1*8]
+ mul rbx
+ add r8,rax
+ adc r9,rdx
+
+ mov rax,[rdi+2*8]
+ mul r15
+ add r8,rax
+ adc r9,rdx
+
+ mov rax,[rdi+3*8]
+ mul r14
+ mov r13,rbp
+ mov rsi,[rsi+4*8] ; load b.n[4] and destroy pointer
+ add r8,rax
+ adc r9,rdx
+ and r13,r8
+
+ shrd r8,r9,52
+ xor r9,r9
+
+
+ ;; c+=a.n[0 1 2 3 4] * b.n[4 3 2 1 0]
+ mov rax,[rdi+0*8]
+ mul rsi
+ add r8,rax
+ adc r9,rdx
+
+ mov rax,[rdi+1*8]
+ mul rcx
+ add r8,rax
+ adc r9,rdx
+
+ mov rax,[rdi+2*8]
+ mul rbx
+ add r8,rax
+ adc r9,rdx
+
+ mov rax,[rdi+3*8]
+ mul r15
+ add r8,rax
+ adc r9,rdx
+
+ mov rax,[rdi+4*8]
+ mul r14
+ mov r14,rbp ; load modulus into t4 and destroy a.n[0]
+ add r8,rax
+ adc r9,rdx
+ and r14,r8
+ shrd r8,r9,52
+ xor r9,r9
+
+ ;; c+=a.n[1 2 3 4] * b.n[4 3 2 1]
+ mov rax,[rdi+1*8]
+ mul rsi
+ add r8,rax
+ adc r9,rdx
+
+ mov rax,[rdi+2*8]
+ mul rcx
+ add r8,rax
+ adc r9,rdx
+
+ mov rax,[rdi+3*8]
+ mul rbx
+ add r8,rax
+ adc r9,rdx
+
+ mov rax,[rdi+4*8]
+ mul r15
+ mov r15,rbp
+ add r8,rax
+ adc r9,rdx
+
+ and r15,r8
+ shrd r8,r9,52
+ xor r9,r9
+
+ ;; c+=a.n[2 3 4] * b.n[4 3 2]
+ mov rax,[rdi+2*8]
+ mul rsi
+ add r8,rax
+ adc r9,rdx
+
+ mov rax,[rdi+3*8]
+ mul rcx
+ add r8,rax
+ adc r9,rdx
+
+ mov rax,[rdi+4*8]
+ mul rbx
+ mov rbx,rbp
+ add r8,rax
+ adc r9,rdx
+
+ and rbx,r8
+ shrd r8,r9,52
+ xor r9,r9
+
+ ;; c+=a.n[3 4] * b.n[4 3]
+ mov rax,[rdi+3*8]
+ mul rsi
+ add r8,rax
+ adc r9,rdx
+
+ mov rax,[rdi+4*8]
+ mul rcx
+ mov rcx,rbp
+ add r8,rax
+ adc r9,rdx
+ and rcx,r8
+ shrd r8,r9,52
+ xor r9,r9
+
+ ;; c+=a.n[4] * b.n[4]
+ mov rax,[rdi+4*8]
+ mul rsi
+ ;; mov rbp,rbp ; modulus already there!
+ add r8,rax
+ adc r9,rdx
+ and rbp,r8
+ shrd r8,r9,52
+ xor r9,r9
+
+ mov rsi,r8 ; load c into t9 and destroy b.n[4]
+
+ ;; *******************************************************
+common_exit_norm:
+ mov rdi,01000003D10h ; load constant
+
+ mov rax,r15 ; get t5
+ mul rdi
+ add rax,r10 ; +t0
+ adc rdx,0
+ mov r10,0FFFFFFFFFFFFFh ; modulus. Sadly, we ran out of registers!
+ mov r8,rax ; +c
+ and r10,rax
+ shrd r8,rdx,52
+ xor r9,r9
+
+ mov rax,rbx ; get t6
+ mul rdi
+ add rax,r11 ; +t1
+ adc rdx,0
+ mov r11,0FFFFFFFFFFFFFh ; modulus
+ add r8,rax ; +c
+ adc r9,rdx
+ and r11,r8
+ shrd r8,r9,52
+ xor r9,r9
+
+ mov rax,rcx ; get t7
+ mul rdi
+ add rax,r12 ; +t2
+ adc rdx,0
+ pop rbx ; retrieve pointer to this.n
+ mov r12,0FFFFFFFFFFFFFh ; modulus
+ add r8,rax ; +c
+ adc r9,rdx
+ and r12,r8
+ mov [rbx+2*8],r12 ; mov into this.n[2]
+ shrd r8,r9,52
+ xor r9,r9
+
+ mov rax,rbp ; get t8
+ mul rdi
+ add rax,r13 ; +t3
+ adc rdx,0
+ mov r13,0FFFFFFFFFFFFFh ; modulus
+ add r8,rax ; +c
+ adc r9,rdx
+ and r13,r8
+ mov [rbx+3*8],r13 ; -> this.n[3]
+ shrd r8,r9,52
+ xor r9,r9
+
+ mov rax,rsi ; get t9
+ mul rdi
+ add rax,r14 ; +t4
+ adc rdx,0
+ mov r14,0FFFFFFFFFFFFh ; !!!
+ add r8,rax ; +c
+ adc r9,rdx
+ and r14,r8
+ mov [rbx+4*8],r14 ; -> this.n[4]
+ shrd r8,r9,48 ; !!!
+ xor r9,r9
+
+ mov rax,01000003D1h
+ mul r8
+ add rax,r10
+ adc rdx,0
+ mov r10,0FFFFFFFFFFFFFh ; modulus
+ mov r8,rax
+ and rax,r10
+ shrd r8,rdx,52
+ mov [rbx+0*8],rax ; -> this.n[0]
+ add r8,r11
+ mov [rbx+1*8],r8 ; -> this.n[1]
+
+ pop r15
+ pop r14
+ pop r13
+ pop r12
+ pop rbx
+ pop rbp
+ ret
+
+
+ ;; PROC ExSetSquare
+ ;; Register Layout:
+ ;; INPUT: rdi = a.n
+ ;; rsi = this.a
+ ;; INTERNAL: rdx:rax = multiplication accumulator
+ ;; r9:r8 = c
+ ;; r10-r13 = t0-t3
+ ;; r14 = a.n[0] / t4
+ ;; r15 = a.n[1] / t5
+ ;; rbx = a.n[2] / t6
+ ;; rcx = a.n[3] / t7
+ ;; rbp = 0FFFFFFFFFFFFFh / t8
+ ;; rsi = a.n[4] / t9
+ GLOBAL secp256k1_fe_sqr_inner
+ ALIGN 32
+secp256k1_fe_sqr_inner:
+ push rbp
+ push rbx
+ push r12
+ push r13
+ push r14
+ push r15
+ push rsi
+ mov rbp,0FFFFFFFFFFFFFh
+
+ ;; c=a.n[0] * a.n[0]
+ mov r14,[rdi+0*8] ; r14=a.n[0]
+ mov r10,rbp ; modulus
+ mov rax,r14
+ mul rax
+ mov r15,[rdi+1*8] ; a.n[1]
+ add r14,r14 ; r14=2*a.n[0]
+ mov r8,rax
+ and r10,rax ; only need lower qword
+ shrd r8,rdx,52
+ xor r9,r9
+
+ ;; c+=2*a.n[0] * a.n[1]
+ mov rax,r14 ; r14=2*a.n[0]
+ mul r15
+ mov rbx,[rdi+2*8] ; rbx=a.n[2]
+ mov r11,rbp ; modulus
+ add r8,rax
+ adc r9,rdx
+ and r11,r8
+ shrd r8,r9,52
+ xor r9,r9
+
+ ;; c+=2*a.n[0]*a.n[2]+a.n[1]*a.n[1]
+ mov rax,r14
+ mul rbx
+ add r8,rax
+ adc r9,rdx
+
+ mov rax,r15
+ mov r12,rbp ; modulus
+ mul rax
+ mov rcx,[rdi+3*8] ; rcx=a.n[3]
+ add r15,r15 ; r15=a.n[1]*2
+ add r8,rax
+ adc r9,rdx
+ and r12,r8 ; only need lower dword
+ shrd r8,r9,52
+ xor r9,r9
+
+ ;; c+=2*a.n[0]*a.n[3]+2*a.n[1]*a.n[2]
+ mov rax,r14
+ mul rcx
+ add r8,rax
+ adc r9,rdx
+
+ mov rax,r15 ; rax=2*a.n[1]
+ mov r13,rbp ; modulus
+ mul rbx
+ mov rsi,[rdi+4*8] ; rsi=a.n[4]
+ add r8,rax
+ adc r9,rdx
+ and r13,r8
+ shrd r8,r9,52
+ xor r9,r9
+
+ ;; c+=2*a.n[0]*a.n[4]+2*a.n[1]*a.n[3]+a.n[2]*a.n[2]
+ mov rax,r14 ; last time we need 2*a.n[0]
+ mul rsi
+ add r8,rax
+ adc r9,rdx
+
+ mov rax,r15
+ mul rcx
+ mov r14,rbp ; modulus
+ add r8,rax
+ adc r9,rdx
+
+ mov rax,rbx
+ mul rax
+ add rbx,rbx ; rcx=2*a.n[2]
+ add r8,rax
+ adc r9,rdx
+ and r14,r8
+ shrd r8,r9,52
+ xor r9,r9
+
+ ;; c+=2*a.n[1]*a.n[4]+2*a.n[2]*a.n[3]
+ mov rax,r15 ; last time we need 2*a.n[1]
+ mul rsi
+ add r8,rax
+ adc r9,rdx
+
+ mov rax,rbx
+ mul rcx
+ mov r15,rbp ; modulus
+ add r8,rax
+ adc r9,rdx
+ and r15,r8
+ shrd r8,r9,52
+ xor r9,r9
+
+ ;; c+=2*a.n[2]*a.n[4]+a.n[3]*a.n[3]
+ mov rax,rbx ; last time we need 2*a.n[2]
+ mul rsi
+ add r8,rax
+ adc r9,rdx
+
+ mov rax,rcx ; a.n[3]
+ mul rax
+ mov rbx,rbp ; modulus
+ add r8,rax
+ adc r9,rdx
+ and rbx,r8 ; only need lower dword
+ lea rax,[2*rcx]
+ shrd r8,r9,52
+ xor r9,r9
+
+ ;; c+=2*a.n[3]*a.n[4]
+ mul rsi
+ mov rcx,rbp ; modulus
+ add r8,rax
+ adc r9,rdx
+ and rcx,r8 ; only need lower dword
+ shrd r8,r9,52
+ xor r9,r9
+
+ ;; c+=a.n[4]*a.n[4]
+ mov rax,rsi
+ mul rax
+ ;; mov rbp,rbp ; modulus is already there!
+ add r8,rax
+ adc r9,rdx
+ and rbp,r8
+ shrd r8,r9,52
+ xor r9,r9
+
+ mov rsi,r8
+
+ ;; *******************************************************
+ jmp common_exit_norm
+ end
+
+
diff --git a/crypto/secp256k1/secp256k1/src/field_5x64.h b/crypto/secp256k1/secp256k1/src/field_5x64.h
new file mode 100644
index 000000000..f3d47f547
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/src/field_5x64.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2013 Pieter Wuille
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef _SECP256K1_FIELD_REPR_
+#define _SECP256K1_FIELD_REPR_
+
+#include <stdint.h>
+
+typedef struct {
+ // X = sum(i=0..4, elem[i]*2^64) mod n
+ uint64_t n[5];
+#ifdef VERIFY
+ int reduced; // n[4] == 0
+ int normalized; // reduced and X < 2^256 - 0x100003D1
+#endif
+} secp256k1_fe_t;
+
+#endif
diff --git a/crypto/secp256k1/secp256k1/src/field_5x64_asm.asm b/crypto/secp256k1/secp256k1/src/field_5x64_asm.asm
new file mode 100644
index 000000000..d449185c7
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/src/field_5x64_asm.asm
@@ -0,0 +1,332 @@
+ ;; Added by Diederik Huys, March 2013
+ ;;
+ ;; Provided public procedures:
+ ;; secp256k1_fe_mul_inner
+ ;; secp256k1_fe_sqr_inner
+ ;;
+ ;; Needed tools: YASM (http://yasm.tortall.net)
+ ;;
+ ;;
+
+ BITS 64
+
+COMP_LIMB EQU 000000001000003D1h
+
+ ;; Procedure ExSetMult
+ ;; Register Layout:
+ ;; INPUT: rdi = a->n
+ ;; rsi = b->n
+ ;; rdx = r->a
+ ;;
+ ;; INTERNAL: rdx:rax = multiplication accumulator
+ ;; r8-r10 = c0-c2
+ ;; r11-r15 = b.n[0]-b.n[4] / r3 - r7
+ ;; rbx = r0
+ ;; rcx = r1
+ ;; rbp = r2
+ ;;
+ GLOBAL secp256k1_fe_mul_inner
+ ALIGN 32
+secp256k1_fe_mul_inner:
+ push rbp
+ push rbx
+ push r12
+ push r13
+ push r14
+ push r15
+ push rdx
+
+ mov r11,[rsi+8*0] ; preload b.n[0]
+
+ ;; step 1: mul_c2
+ mov rax,[rdi+0*8] ; load a.n[0]
+ mul r11 ; rdx:rax=a.n[0]*b.n[0]
+ mov r12,[rsi+1*8] ; preload b.n[1]
+ mov rbx,rax ; retire LO qword (r[0])
+ mov r8,rdx ; save overflow
+ xor r9,r9 ; overflow HO qwords
+ xor r10,r10
+
+ ;; c+=a.n[0] * b.n[1] + a.n[1] * b.n[0]
+ mov rax,[rdi+0*8]
+ mul r12
+ mov r13,[rsi+2*8] ; preload b.n[2]
+ add r8,rax ; still the same :-)
+ adc r9,rdx ;
+ adc r10,0 ; mmm...
+
+ mov rax,[rdi+1*8]
+ mul r11
+ add r8,rax
+ adc r9,rdx
+ adc r10,0
+ mov rcx,r8 ; retire r[1]
+ xor r8,r8
+
+ ;; c+=a.n[0 1 2] * b.n[2 1 0]
+ mov rax,[rdi+0*8]
+ mul r13
+ mov r14,[rsi+3*8] ; preload b.n[3]
+ add r9,rax
+ adc r10,rdx
+ adc r8,0
+
+ mov rax,[rdi+1*8]
+ mul r12
+ add r9,rax
+ adc r10,rdx
+ adc r8,0
+
+ mov rax,[rdi+2*8]
+ mul r11
+ add r9,rax
+ adc r10,rdx
+ adc r8,0
+ mov rbp,r9 ; retire r[2]
+ xor r9,r9
+
+ ;; c+=a.n[0 1 2 3] * b.n[3 2 1 0]
+ mov rax,[rdi+0*8]
+ mul r14
+ add r10,rax
+ adc r8,rdx
+ adc r9,0
+
+ mov rax,[rdi+1*8]
+ mul r13
+ add r10,rax
+ adc r8,rdx
+ adc r9,0
+
+ mov rax,[rdi+2*8]
+ mul r12
+ add r10,rax
+ adc r8,rdx
+ adc r9,0
+
+ mov rax,[rdi+3*8]
+ mul r11
+ add r10,rax
+ adc r8,rdx
+ adc r9,0
+ mov r11,r10 ; retire r[3]
+ xor r10,r10
+
+ ;; c+=a.n[1 2 3] * b.n[3 2 1]
+ mov rax,[rdi+1*8]
+ mul r14
+ add r8,rax
+ adc r9,rdx
+ adc r10,0
+
+ mov rax,[rdi+2*8]
+ mul r13
+ add r8,rax
+ adc r9,rdx
+ adc r10,0
+
+ mov rax,[rdi+3*8]
+ mul r12
+ add r8,rax
+ adc r9,rdx
+ adc r10,0
+ mov r12,r8 ; retire r[4]
+ xor r8,r8
+
+ ;; c+=a.n[2 3] * b.n[3 2]
+ mov rax,[rdi+2*8]
+ mul r14
+ add r9,rax ; still the same :-)
+ adc r10,rdx ;
+ adc r8,0 ; mmm...
+
+ mov rax,[rdi+3*8]
+ mul r13
+ add r9,rax
+ adc r10,rdx
+ adc r8,0
+ mov r13,r9 ; retire r[5]
+ xor r9,r9
+
+ ;; c+=a.n[3] * b.n[3]
+ mov rax,[rdi+3*8]
+ mul r14
+ add r10,rax
+ adc r8,rdx
+
+ mov r14,r10
+ mov r15,r8
+
+
+ ;; *******************************************************
+common_exit_norm:
+ mov rdi,COMP_LIMB
+ mov rax,r12
+ mul rdi
+ add rax,rbx
+ adc rcx,rdx
+ pop rbx
+ mov [rbx],rax
+
+ mov rax,r13 ; get r5
+ mul rdi
+ add rax,rcx ; +r1
+ adc rbp,rdx
+ mov [rbx+1*8],rax
+
+ mov rax,r14 ; get r6
+ mul rdi
+ add rax,rbp ; +r2
+ adc r11,rdx
+ mov [rbx+2*8],rax
+
+ mov rax,r15 ; get r7
+ mul rdi
+ add rax,r11 ; +r3
+ adc rdx,0
+ mov [rbx+3*8],rax
+ mov [rbx+4*8],rdx
+
+ pop r15
+ pop r14
+ pop r13
+ pop r12
+ pop rbx
+ pop rbp
+ ret
+
+
+ ;; PROC ExSetSquare
+ ;; Register Layout:
+ ;; INPUT: rdi = a.n
+ ;; rsi = this.a
+ ;; INTERNAL: rdx:rax = multiplication accumulator
+ ;; r8-r10 = c
+ ;; r11-r15 = a.n[0]-a.n[4] / r3-r7
+ ;; rbx = r0
+ ;; rcx = r1
+ ;; rbp = r2
+ GLOBAL secp256k1_fe_sqr_inner
+
+ ALIGN 32
+secp256k1_fe_sqr_inner:
+ push rbp
+ push rbx
+ push r12
+ push r13
+ push r14
+ push r15
+ push rsi
+
+ mov r11,[rdi+8*0] ; preload a.n[0]
+
+ ;; step 1: mul_c2
+ mov rax,r11 ; load a.n[0]
+ mul rax ; rdx:rax=a.n[0]²
+ mov r12,[rdi+1*8] ; preload a.n[1]
+ mov rbx,rax ; retire LO qword (r[0])
+ mov r8,rdx ; save overflow
+ xor r9,r9 ; overflow HO qwords
+ xor r10,r10
+
+ ;; c+=2*a.n[0] * a.n[1]
+ mov rax,r11 ; load a.n[0]
+ mul r12 ; rdx:rax=a.n[0] * a.n[1]
+ mov r13,[rdi+2*8] ; preload a.n[2]
+ add rax,rax ; rdx:rax*=2
+ adc rdx,rdx
+ adc r10,0
+ add r8,rax ; still the same :-)
+ adc r9,rdx
+ adc r10,0 ; mmm...
+
+ mov rcx,r8 ; retire r[1]
+ xor r8,r8
+
+ ;; c+=2*a.n[0]*a.n[2]+a.n[1]*a.n[1]
+ mov rax,r11 ; load a.n[0]
+ mul r13 ; * a.n[2]
+ mov r14,[rdi+3*8] ; preload a.n[3]
+ add rax,rax ; rdx:rax*=2
+ adc rdx,rdx
+ adc r8,0
+ add r9,rax
+ adc r10,rdx
+ adc r8,0
+
+ mov rax,r12
+ mul rax
+ add r9,rax
+ adc r10,rdx
+ adc r8,0
+
+
+ mov rbp,r9
+ xor r9,r9
+
+ ;; c+=2*a.n[0]*a.n[3]+2*a.n[1]*a.n[2]
+ mov rax,r11 ; load a.n[0]
+ mul r14 ; * a.n[3]
+ add rax,rax ; rdx:rax*=2
+ adc rdx,rdx
+ adc r9,0
+ add r10,rax
+ adc r8,rdx
+ adc r9,0
+
+ mov rax,r12 ; load a.n[1]
+ mul r13 ; * a.n[2]
+ add rax,rax
+ adc rdx,rdx
+ adc r9,0
+ add r10,rax
+ adc r8,rdx
+ adc r9,0
+
+ mov r11,r10
+ xor r10,r10
+
+ ;; c+=2*a.n[1]*a.n[3]+a.n[2]*a.n[2]
+ mov rax,r12 ; load a.n[1]
+ mul r14 ; * a.n[3]
+ add rax,rax ; rdx:rax*=2
+ adc rdx,rdx
+ adc r10,0
+ add r8,rax
+ adc r9,rdx
+ adc r10,0
+
+ mov rax,r13
+ mul rax
+ add r8,rax
+ adc r9,rdx
+ adc r10,0
+
+ mov r12,r8
+ xor r8,r8
+ ;; c+=2*a.n[2]*a.n[3]
+ mov rax,r13 ; load a.n[2]
+ mul r14 ; * a.n[3]
+ add rax,rax ; rdx:rax*=2
+ adc rdx,rdx
+ adc r8,0
+ add r9,rax
+ adc r10,rdx
+ adc r8,0
+
+ mov r13,r9
+ xor r9,r9
+
+ ;; c+=a.n[3]²
+ mov rax,r14
+ mul rax
+ add r10,rax
+ adc r8,rdx
+
+ mov r14,r10
+ mov r15,r8
+
+ jmp common_exit_norm
+ end
+
+
diff --git a/crypto/secp256k1/secp256k1/src/field_gmp.h b/crypto/secp256k1/secp256k1/src/field_gmp.h
new file mode 100644
index 000000000..d51dea0af
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/src/field_gmp.h
@@ -0,0 +1,16 @@
+// Copyright (c) 2013 Pieter Wuille
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef _SECP256K1_FIELD_REPR_
+#define _SECP256K1_FIELD_REPR_
+
+#include <gmp.h>
+
+#define FIELD_LIMBS ((256 + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS)
+
+typedef struct {
+ mp_limb_t n[FIELD_LIMBS+1];
+} secp256k1_fe_t;
+
+#endif
diff --git a/crypto/secp256k1/secp256k1/src/group.h b/crypto/secp256k1/secp256k1/src/group.h
new file mode 100644
index 000000000..ae291c6ca
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/src/group.h
@@ -0,0 +1,108 @@
+// Copyright (c) 2013 Pieter Wuille
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef _SECP256K1_GROUP_
+#define _SECP256K1_GROUP_
+
+#include "num.h"
+#include "field.h"
+
+/** A group element of the secp256k1 curve, in affine coordinates. */
+typedef struct {
+ secp256k1_fe_t x;
+ secp256k1_fe_t y;
+ int infinity; // whether this represents the point at infinity
+} secp256k1_ge_t;
+
+/** A group element of the secp256k1 curve, in jacobian coordinates. */
+typedef struct {
+ secp256k1_fe_t x; // actual X: x/z^2
+ secp256k1_fe_t y; // actual Y: y/z^3
+ secp256k1_fe_t z;
+ int infinity; // whether this represents the point at infinity
+} secp256k1_gej_t;
+
+/** Global constants related to the group */
+typedef struct {
+ secp256k1_num_t order; // the order of the curve (= order of its generator)
+ secp256k1_num_t half_order; // half the order of the curve (= order of its generator)
+ secp256k1_ge_t g; // the generator point
+
+ // constants related to secp256k1's efficiently computable endomorphism
+ secp256k1_fe_t beta;
+ secp256k1_num_t lambda, a1b2, b1, a2;
+} secp256k1_ge_consts_t;
+
+static const secp256k1_ge_consts_t *secp256k1_ge_consts = NULL;
+
+/** Initialize the group module. */
+void static secp256k1_ge_start(void);
+
+/** De-initialize the group module. */
+void static secp256k1_ge_stop(void);
+
+/** Set a group element equal to the point at infinity */
+void static secp256k1_ge_set_infinity(secp256k1_ge_t *r);
+
+/** Set a group element equal to the point with given X and Y coordinates */
+void static secp256k1_ge_set_xy(secp256k1_ge_t *r, const secp256k1_fe_t *x, const secp256k1_fe_t *y);
+
+/** Set a group element (jacobian) equal to the point with given X coordinate, and given oddness for Y.
+ The result is not guaranteed to be valid. */
+void static secp256k1_ge_set_xo(secp256k1_ge_t *r, const secp256k1_fe_t *x, int odd);
+
+/** Check whether a group element is the point at infinity. */
+int static secp256k1_ge_is_infinity(const secp256k1_ge_t *a);
+
+/** Check whether a group element is valid (i.e., on the curve). */
+int static secp256k1_ge_is_valid(const secp256k1_ge_t *a);
+
+void static secp256k1_ge_neg(secp256k1_ge_t *r, const secp256k1_ge_t *a);
+
+/** Get a hex representation of a point. *rlen will be overwritten with the real length. */
+void static secp256k1_ge_get_hex(char *r, int *rlen, const secp256k1_ge_t *a);
+
+/** Set a group element equal to another which is given in jacobian coordinates */
+void static secp256k1_ge_set_gej(secp256k1_ge_t *r, secp256k1_gej_t *a);
+
+
+/** Set a group element (jacobian) equal to the point at infinity. */
+void static secp256k1_gej_set_infinity(secp256k1_gej_t *r);
+
+/** Set a group element (jacobian) equal to the point with given X and Y coordinates. */
+void static secp256k1_gej_set_xy(secp256k1_gej_t *r, const secp256k1_fe_t *x, const secp256k1_fe_t *y);
+
+/** Set a group element (jacobian) equal to another which is given in affine coordinates. */
+void static secp256k1_gej_set_ge(secp256k1_gej_t *r, const secp256k1_ge_t *a);
+
+/** Get the X coordinate of a group element (jacobian). */
+void static secp256k1_gej_get_x(secp256k1_fe_t *r, const secp256k1_gej_t *a);
+
+/** Set r equal to the inverse of a (i.e., mirrored around the X axis) */
+void static secp256k1_gej_neg(secp256k1_gej_t *r, const secp256k1_gej_t *a);
+
+/** Check whether a group element is the point at infinity. */
+int static secp256k1_gej_is_infinity(const secp256k1_gej_t *a);
+
+/** Set r equal to the double of a. */
+void static secp256k1_gej_double(secp256k1_gej_t *r, const secp256k1_gej_t *a);
+
+/** Set r equal to the sum of a and b. */
+void static secp256k1_gej_add(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_gej_t *b);
+
+/** Set r equal to the sum of a and b (with b given in jacobian coordinates). This is more efficient
+ than secp256k1_gej_add. */
+void static secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_ge_t *b);
+
+/** Get a hex representation of a point. *rlen will be overwritten with the real length. */
+void static secp256k1_gej_get_hex(char *r, int *rlen, const secp256k1_gej_t *a);
+
+/** Set r to be equal to lambda times a, where lambda is chosen in a way such that this is very fast. */
+void static secp256k1_gej_mul_lambda(secp256k1_gej_t *r, const secp256k1_gej_t *a);
+
+/** Find r1 and r2 such that r1+r2*lambda = a, and r1 and r2 are maximum 128 bits long (given that a is
+ not more than 256 bits). */
+void static secp256k1_gej_split_exp(secp256k1_num_t *r1, secp256k1_num_t *r2, const secp256k1_num_t *a);
+
+#endif
diff --git a/crypto/secp256k1/secp256k1/src/impl/ecdsa.h b/crypto/secp256k1/secp256k1/src/impl/ecdsa.h
new file mode 100644
index 000000000..dd26cfd11
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/src/impl/ecdsa.h
@@ -0,0 +1,309 @@
+// Copyright (c) 2013 Pieter Wuille
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef _SECP256K1_ECDSA_IMPL_H_
+#define _SECP256K1_ECDSA_IMPL_H_
+
+#include "../num.h"
+#include "../field.h"
+#include "../group.h"
+#include "../ecmult.h"
+#include "../ecdsa.h"
+
+void static secp256k1_ecdsa_sig_init(secp256k1_ecdsa_sig_t *r) {
+ secp256k1_num_init(&r->r);
+ secp256k1_num_init(&r->s);
+}
+
+void static secp256k1_ecdsa_sig_free(secp256k1_ecdsa_sig_t *r) {
+ secp256k1_num_free(&r->r);
+ secp256k1_num_free(&r->s);
+}
+
+int static secp256k1_ecdsa_pubkey_parse(secp256k1_ge_t *elem, const unsigned char *pub, int size) {
+ if (size == 33 && (pub[0] == 0x02 || pub[0] == 0x03)) {
+ secp256k1_fe_t x;
+ secp256k1_fe_set_b32(&x, pub+1);
+ secp256k1_ge_set_xo(elem, &x, pub[0] == 0x03);
+ } else if (size == 65 && (pub[0] == 0x04 || pub[0] == 0x06 || pub[0] == 0x07)) {
+ secp256k1_fe_t x, y;
+ secp256k1_fe_set_b32(&x, pub+1);
+ secp256k1_fe_set_b32(&y, pub+33);
+ secp256k1_ge_set_xy(elem, &x, &y);
+ if ((pub[0] == 0x06 || pub[0] == 0x07) && secp256k1_fe_is_odd(&y) != (pub[0] == 0x07))
+ return 0;
+ } else {
+ return 0;
+ }
+ return secp256k1_ge_is_valid(elem);
+}
+
+int static secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned char *sig, int size) {
+ if (sig[0] != 0x30) return 0;
+ int lenr = sig[3];
+ if (5+lenr >= size) return 0;
+ int lens = sig[lenr+5];
+ if (sig[1] != lenr+lens+4) return 0;
+ if (lenr+lens+6 > size) return 0;
+ if (sig[2] != 0x02) return 0;
+ if (lenr == 0) return 0;
+ if (sig[lenr+4] != 0x02) return 0;
+ if (lens == 0) return 0;
+ secp256k1_num_set_bin(&r->r, sig+4, lenr);
+ secp256k1_num_set_bin(&r->s, sig+6+lenr, lens);
+ return 1;
+}
+
+int static secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const secp256k1_ecdsa_sig_t *a) {
+ int lenR = (secp256k1_num_bits(&a->r) + 7)/8;
+ if (lenR == 0 || secp256k1_num_get_bit(&a->r, lenR*8-1))
+ lenR++;
+ int lenS = (secp256k1_num_bits(&a->s) + 7)/8;
+ if (lenS == 0 || secp256k1_num_get_bit(&a->s, lenS*8-1))
+ lenS++;
+ if (*size < 6+lenS+lenR)
+ return 0;
+ *size = 6 + lenS + lenR;
+ sig[0] = 0x30;
+ sig[1] = 4 + lenS + lenR;
+ sig[2] = 0x02;
+ sig[3] = lenR;
+ secp256k1_num_get_bin(sig+4, lenR, &a->r);
+ sig[4+lenR] = 0x02;
+ sig[5+lenR] = lenS;
+ secp256k1_num_get_bin(sig+lenR+6, lenS, &a->s);
+ return 1;
+}
+
+int static secp256k1_ecdsa_sig_recompute(secp256k1_num_t *r2, const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_num_t *message) {
+ const secp256k1_ge_consts_t *c = secp256k1_ge_consts;
+
+ if (secp256k1_num_is_neg(&sig->r) || secp256k1_num_is_neg(&sig->s))
+ return 0;
+ if (secp256k1_num_is_zero(&sig->r) || secp256k1_num_is_zero(&sig->s))
+ return 0;
+ if (secp256k1_num_cmp(&sig->r, &c->order) >= 0 || secp256k1_num_cmp(&sig->s, &c->order) >= 0)
+ return 0;
+
+ int ret = 0;
+ secp256k1_num_t sn, u1, u2;
+ secp256k1_num_init(&sn);
+ secp256k1_num_init(&u1);
+ secp256k1_num_init(&u2);
+ secp256k1_num_mod_inverse(&sn, &sig->s, &c->order);
+ secp256k1_num_mod_mul(&u1, &sn, message, &c->order);
+ secp256k1_num_mod_mul(&u2, &sn, &sig->r, &c->order);
+ secp256k1_gej_t pubkeyj; secp256k1_gej_set_ge(&pubkeyj, pubkey);
+ secp256k1_gej_t pr; secp256k1_ecmult(&pr, &pubkeyj, &u2, &u1);
+ if (!secp256k1_gej_is_infinity(&pr)) {
+ secp256k1_fe_t xr; secp256k1_gej_get_x(&xr, &pr);
+ secp256k1_fe_normalize(&xr);
+ unsigned char xrb[32]; secp256k1_fe_get_b32(xrb, &xr);
+ secp256k1_num_set_bin(r2, xrb, 32);
+ secp256k1_num_mod(r2, &c->order);
+ ret = 1;
+ }
+ secp256k1_num_free(&sn);
+ secp256k1_num_free(&u1);
+ secp256k1_num_free(&u2);
+ return ret;
+}
+
+int static secp256k1_ecdsa_sig_recover(const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_num_t *message, int recid) {
+ const secp256k1_ge_consts_t *c = secp256k1_ge_consts;
+
+ if (secp256k1_num_is_neg(&sig->r) || secp256k1_num_is_neg(&sig->s))
+ return 0;
+ if (secp256k1_num_is_zero(&sig->r) || secp256k1_num_is_zero(&sig->s))
+ return 0;
+ if (secp256k1_num_cmp(&sig->r, &c->order) >= 0 || secp256k1_num_cmp(&sig->s, &c->order) >= 0)
+ return 0;
+
+ secp256k1_num_t rx;
+ secp256k1_num_init(&rx);
+ secp256k1_num_copy(&rx, &sig->r);
+ if (recid & 2) {
+ secp256k1_num_add(&rx, &rx, &c->order);
+ if (secp256k1_num_cmp(&rx, &secp256k1_fe_consts->p) >= 0)
+ return 0;
+ }
+ unsigned char brx[32];
+ secp256k1_num_get_bin(brx, 32, &rx);
+ secp256k1_num_free(&rx);
+ secp256k1_fe_t fx;
+ secp256k1_fe_set_b32(&fx, brx);
+ secp256k1_ge_t x;
+ secp256k1_ge_set_xo(&x, &fx, recid & 1);
+ if (!secp256k1_ge_is_valid(&x))
+ return 0;
+ secp256k1_gej_t xj;
+ secp256k1_gej_set_ge(&xj, &x);
+ secp256k1_num_t rn, u1, u2;
+ secp256k1_num_init(&rn);
+ secp256k1_num_init(&u1);
+ secp256k1_num_init(&u2);
+ secp256k1_num_mod_inverse(&rn, &sig->r, &c->order);
+ secp256k1_num_mod_mul(&u1, &rn, message, &c->order);
+ secp256k1_num_sub(&u1, &c->order, &u1);
+ secp256k1_num_mod_mul(&u2, &rn, &sig->s, &c->order);
+ secp256k1_gej_t qj;
+ secp256k1_ecmult(&qj, &xj, &u2, &u1);
+ if (secp256k1_gej_is_infinity(&qj))
+ return 0;
+ secp256k1_ge_set_gej(pubkey, &qj);
+ secp256k1_num_free(&rn);
+ secp256k1_num_free(&u1);
+ secp256k1_num_free(&u2);
+ return 1;
+}
+
+int static secp256k1_ecdsa_sig_verify(const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_num_t *message) {
+ secp256k1_num_t r2;
+ secp256k1_num_init(&r2);
+ int ret = 0;
+ ret = secp256k1_ecdsa_sig_recompute(&r2, sig, pubkey, message) && secp256k1_num_cmp(&sig->r, &r2) == 0;
+ secp256k1_num_free(&r2);
+ return ret;
+}
+
+int static secp256k1_ecdsa_sig_sign(secp256k1_ecdsa_sig_t *sig, const secp256k1_num_t *seckey, const secp256k1_num_t *message, const secp256k1_num_t *nonce, int *recid) {
+ const secp256k1_ge_consts_t *c = secp256k1_ge_consts;
+
+ secp256k1_gej_t rp;
+ secp256k1_ecmult_gen(&rp, nonce);
+ secp256k1_ge_t r;
+ secp256k1_ge_set_gej(&r, &rp);
+ unsigned char b[32];
+ secp256k1_fe_normalize(&r.x);
+ secp256k1_fe_normalize(&r.y);
+ secp256k1_fe_get_b32(b, &r.x);
+ secp256k1_num_set_bin(&sig->r, b, 32);
+ if (recid)
+ *recid = (secp256k1_num_cmp(&sig->r, &c->order) >= 0 ? 2 : 0) | (secp256k1_fe_is_odd(&r.y) ? 1 : 0);
+ secp256k1_num_mod(&sig->r, &c->order);
+ secp256k1_num_t n;
+ secp256k1_num_init(&n);
+ secp256k1_num_mod_mul(&n, &sig->r, seckey, &c->order);
+ secp256k1_num_add(&n, &n, message);
+ secp256k1_num_mod(&n, &c->order);
+ secp256k1_num_mod_inverse(&sig->s, nonce, &c->order);
+ secp256k1_num_mod_mul(&sig->s, &sig->s, &n, &c->order);
+ secp256k1_num_free(&n);
+ if (secp256k1_num_is_zero(&sig->s))
+ return 0;
+ if (secp256k1_num_cmp(&sig->s, &c->half_order) > 0) {
+ secp256k1_num_sub(&sig->s, &c->order, &sig->s);
+ if (recid)
+ *recid ^= 1;
+ }
+ return 1;
+}
+
+void static secp256k1_ecdsa_sig_set_rs(secp256k1_ecdsa_sig_t *sig, const secp256k1_num_t *r, const secp256k1_num_t *s) {
+ secp256k1_num_copy(&sig->r, r);
+ secp256k1_num_copy(&sig->s, s);
+}
+
+void static secp256k1_ecdsa_pubkey_serialize(secp256k1_ge_t *elem, unsigned char *pub, int *size, int compressed) {
+ secp256k1_fe_normalize(&elem->x);
+ secp256k1_fe_normalize(&elem->y);
+ secp256k1_fe_get_b32(&pub[1], &elem->x);
+ if (compressed) {
+ *size = 33;
+ pub[0] = 0x02 | (secp256k1_fe_is_odd(&elem->y) ? 0x01 : 0x00);
+ } else {
+ *size = 65;
+ pub[0] = 0x04;
+ secp256k1_fe_get_b32(&pub[33], &elem->y);
+ }
+}
+
+int static secp256k1_ecdsa_privkey_parse(secp256k1_num_t *key, const unsigned char *privkey, int privkeylen) {
+ const unsigned char *end = privkey + privkeylen;
+ // sequence header
+ if (end < privkey+1 || *privkey != 0x30)
+ return 0;
+ privkey++;
+ // sequence length constructor
+ int lenb = 0;
+ if (end < privkey+1 || !(*privkey & 0x80))
+ return 0;
+ lenb = *privkey & ~0x80; privkey++;
+ if (lenb < 1 || lenb > 2)
+ return 0;
+ if (end < privkey+lenb)
+ return 0;
+ // sequence length
+ int len = 0;
+ len = privkey[lenb-1] | (lenb > 1 ? privkey[lenb-2] << 8 : 0);
+ privkey += lenb;
+ if (end < privkey+len)
+ return 0;
+ // sequence element 0: version number (=1)
+ if (end < privkey+3 || privkey[0] != 0x02 || privkey[1] != 0x01 || privkey[2] != 0x01)
+ return 0;
+ privkey += 3;
+ // sequence element 1: octet string, up to 32 bytes
+ if (end < privkey+2 || privkey[0] != 0x04 || privkey[1] > 0x20 || end < privkey+2+privkey[1])
+ return 0;
+ secp256k1_num_set_bin(key, privkey+2, privkey[1]);
+ return 1;
+}
+
+int static secp256k1_ecdsa_privkey_serialize(unsigned char *privkey, int *privkeylen, const secp256k1_num_t *key, int compressed) {
+ secp256k1_gej_t rp;
+ secp256k1_ecmult_gen(&rp, key);
+ secp256k1_ge_t r;
+ secp256k1_ge_set_gej(&r, &rp);
+ if (compressed) {
+ static const unsigned char begin[] = {
+ 0x30,0x81,0xD3,0x02,0x01,0x01,0x04,0x20
+ };
+ static const unsigned char middle[] = {
+ 0xA0,0x81,0x85,0x30,0x81,0x82,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48,
+ 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04,
+ 0x21,0x02,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87,
+ 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8,
+ 0x17,0x98,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E,
+ 0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x24,0x03,0x22,0x00
+ };
+ unsigned char *ptr = privkey;
+ memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin);
+ secp256k1_num_get_bin(ptr, 32, key); ptr += 32;
+ memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle);
+ int pubkeylen = 0;
+ secp256k1_ecdsa_pubkey_serialize(&r, ptr, &pubkeylen, 1); ptr += pubkeylen;
+ *privkeylen = ptr - privkey;
+ } else {
+ static const unsigned char begin[] = {
+ 0x30,0x82,0x01,0x13,0x02,0x01,0x01,0x04,0x20
+ };
+ static const unsigned char middle[] = {
+ 0xA0,0x81,0xA5,0x30,0x81,0xA2,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48,
+ 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04,
+ 0x41,0x04,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87,
+ 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8,
+ 0x17,0x98,0x48,0x3A,0xDA,0x77,0x26,0xA3,0xC4,0x65,0x5D,0xA4,0xFB,0xFC,0x0E,0x11,
+ 0x08,0xA8,0xFD,0x17,0xB4,0x48,0xA6,0x85,0x54,0x19,0x9C,0x47,0xD0,0x8F,0xFB,0x10,
+ 0xD4,0xB8,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E,
+ 0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x44,0x03,0x42,0x00
+ };
+ unsigned char *ptr = privkey;
+ memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin);
+ secp256k1_num_get_bin(ptr, 32, key); ptr += 32;
+ memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle);
+ int pubkeylen = 0;
+ secp256k1_ecdsa_pubkey_serialize(&r, ptr, &pubkeylen, 0); ptr += pubkeylen;
+ *privkeylen = ptr - privkey;
+ }
+ return 1;
+}
+
+#endif
diff --git a/crypto/secp256k1/secp256k1/src/impl/ecmult.h b/crypto/secp256k1/secp256k1/src/impl/ecmult.h
new file mode 100644
index 000000000..6acb4c408
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/src/impl/ecmult.h
@@ -0,0 +1,238 @@
+// Copyright (c) 2013 Pieter Wuille
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef _SECP256K1_ECMULT_IMPL_H_
+#define _SECP256K1_ECMULT_IMPL_H_
+
+#include "../num.h"
+#include "../group.h"
+#include "../ecmult.h"
+
+// optimal for 128-bit and 256-bit exponents.
+#define WINDOW_A 5
+
+// larger numbers may result in slightly better performance, at the cost of
+// exponentially larger precomputed tables. WINDOW_G == 14 results in 640 KiB.
+#define WINDOW_G 14
+
+/** Fill a table 'pre' with precomputed odd multiples of a. W determines the size of the table.
+ * pre will contains the values [1*a,3*a,5*a,...,(2^(w-1)-1)*a], so it needs place for
+ * 2^(w-2) entries.
+ *
+ * There are two versions of this function:
+ * - secp256k1_ecmult_precomp_wnaf_gej, which operates on group elements in jacobian notation,
+ * fast to precompute, but slower to use in later additions.
+ * - secp256k1_ecmult_precomp_wnaf_ge, which operates on group elements in affine notations,
+ * (much) slower to precompute, but a bit faster to use in later additions.
+ * To compute a*P + b*G, we use the jacobian version for P, and the affine version for G, as
+ * G is constant, so it only needs to be done once in advance.
+ */
+void static secp256k1_ecmult_table_precomp_gej(secp256k1_gej_t *pre, const secp256k1_gej_t *a, int w) {
+ pre[0] = *a;
+ secp256k1_gej_t d; secp256k1_gej_double(&d, &pre[0]);
+ for (int i=1; i<(1 << (w-2)); i++)
+ secp256k1_gej_add(&pre[i], &d, &pre[i-1]);
+}
+
+void static secp256k1_ecmult_table_precomp_ge(secp256k1_ge_t *pre, const secp256k1_ge_t *a, int w) {
+ pre[0] = *a;
+ secp256k1_gej_t x; secp256k1_gej_set_ge(&x, a);
+ secp256k1_gej_t d; secp256k1_gej_double(&d, &x);
+ for (int i=1; i<(1 << (w-2)); i++) {
+ secp256k1_gej_add_ge(&x, &d, &pre[i-1]);
+ secp256k1_ge_set_gej(&pre[i], &x);
+ }
+}
+
+/** The number of entries a table with precomputed multiples needs to have. */
+#define ECMULT_TABLE_SIZE(w) (1 << ((w)-2))
+
+/** The following two macro retrieves a particular odd multiple from a table
+ * of precomputed multiples. */
+#define ECMULT_TABLE_GET(r,pre,n,w,neg) do { \
+ assert(((n) & 1) == 1); \
+ assert((n) >= -((1 << ((w)-1)) - 1)); \
+ assert((n) <= ((1 << ((w)-1)) - 1)); \
+ if ((n) > 0) \
+ *(r) = (pre)[((n)-1)/2]; \
+ else \
+ (neg)((r), &(pre)[(-(n)-1)/2]); \
+} while(0)
+
+#define ECMULT_TABLE_GET_GEJ(r,pre,n,w) ECMULT_TABLE_GET((r),(pre),(n),(w),secp256k1_gej_neg)
+#define ECMULT_TABLE_GET_GE(r,pre,n,w) ECMULT_TABLE_GET((r),(pre),(n),(w),secp256k1_ge_neg)
+
+typedef struct {
+ secp256k1_ge_t pre_g[ECMULT_TABLE_SIZE(WINDOW_G)]; // odd multiples of the generator
+ secp256k1_ge_t pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)]; // odd multiples of 2^128*generator
+ secp256k1_ge_t prec[64][16]; // prec[j][i] = 16^j * (i+1) * G
+ secp256k1_ge_t fin; // -(sum(prec[j][0], j=0..63))
+} secp256k1_ecmult_consts_t;
+
+static const secp256k1_ecmult_consts_t *secp256k1_ecmult_consts = NULL;
+
+static void secp256k1_ecmult_start(void) {
+ if (secp256k1_ecmult_consts != NULL)
+ return;
+
+ secp256k1_ecmult_consts_t *ret = (secp256k1_ecmult_consts_t*)malloc(sizeof(secp256k1_ecmult_consts_t));
+ secp256k1_ecmult_consts = ret;
+
+ // get the generator
+ const secp256k1_ge_t *g = &secp256k1_ge_consts->g;
+
+ // calculate 2^128*generator
+ secp256k1_gej_t g_128j; secp256k1_gej_set_ge(&g_128j, g);
+ for (int i=0; i<128; i++)
+ secp256k1_gej_double(&g_128j, &g_128j);
+ secp256k1_ge_t g_128; secp256k1_ge_set_gej(&g_128, &g_128j);
+
+ // precompute the tables with odd multiples
+ secp256k1_ecmult_table_precomp_ge(ret->pre_g, g, WINDOW_G);
+ secp256k1_ecmult_table_precomp_ge(ret->pre_g_128, &g_128, WINDOW_G);
+
+ // compute prec and fin
+ secp256k1_gej_t gg; secp256k1_gej_set_ge(&gg, g);
+ secp256k1_ge_t ad = *g;
+ secp256k1_gej_t fn; secp256k1_gej_set_infinity(&fn);
+ for (int j=0; j<64; j++) {
+ secp256k1_ge_set_gej(&ret->prec[j][0], &gg);
+ secp256k1_gej_add(&fn, &fn, &gg);
+ for (int i=1; i<16; i++) {
+ secp256k1_gej_add_ge(&gg, &gg, &ad);
+ secp256k1_ge_set_gej(&ret->prec[j][i], &gg);
+ }
+ ad = ret->prec[j][15];
+ }
+ secp256k1_ge_set_gej(&ret->fin, &fn);
+ secp256k1_ge_neg(&ret->fin, &ret->fin);
+}
+
+static void secp256k1_ecmult_stop(void) {
+ if (secp256k1_ecmult_consts == NULL)
+ return;
+
+ secp256k1_ecmult_consts_t *c = (secp256k1_ecmult_consts_t*)secp256k1_ecmult_consts;
+ free(c);
+ secp256k1_ecmult_consts = NULL;
+}
+
+/** Convert a number to WNAF notation. The number becomes represented by sum(2^i * wnaf[i], i=0..bits),
+ * with the following guarantees:
+ * - each wnaf[i] is either 0, or an odd integer between -(1<<(w-1) - 1) and (1<<(w-1) - 1)
+ * - two non-zero entries in wnaf are separated by at least w-1 zeroes.
+ * - the index of the highest non-zero entry in wnaf (=return value-1) is at most bits, where
+ * bits is the number of bits necessary to represent the absolute value of the input.
+ */
+static int secp256k1_ecmult_wnaf(int *wnaf, const secp256k1_num_t *a, int w) {
+ int ret = 0;
+ int zeroes = 0;
+ secp256k1_num_t x;
+ secp256k1_num_init(&x);
+ secp256k1_num_copy(&x, a);
+ int sign = 1;
+ if (secp256k1_num_is_neg(&x)) {
+ sign = -1;
+ secp256k1_num_negate(&x);
+ }
+ while (!secp256k1_num_is_zero(&x)) {
+ while (!secp256k1_num_is_odd(&x)) {
+ zeroes++;
+ secp256k1_num_shift(&x, 1);
+ }
+ int word = secp256k1_num_shift(&x, w);
+ while (zeroes) {
+ wnaf[ret++] = 0;
+ zeroes--;
+ }
+ if (word & (1 << (w-1))) {
+ secp256k1_num_inc(&x);
+ wnaf[ret++] = sign * (word - (1 << w));
+ } else {
+ wnaf[ret++] = sign * word;
+ }
+ zeroes = w-1;
+ }
+ secp256k1_num_free(&x);
+ return ret;
+}
+
+void static secp256k1_ecmult_gen(secp256k1_gej_t *r, const secp256k1_num_t *gn) {
+ secp256k1_num_t n;
+ secp256k1_num_init(&n);
+ secp256k1_num_copy(&n, gn);
+ const secp256k1_ecmult_consts_t *c = secp256k1_ecmult_consts;
+ secp256k1_gej_set_ge(r, &c->prec[0][secp256k1_num_shift(&n, 4)]);
+ for (int j=1; j<64; j++)
+ secp256k1_gej_add_ge(r, r, &c->prec[j][secp256k1_num_shift(&n, 4)]);
+ secp256k1_num_free(&n);
+ secp256k1_gej_add_ge(r, r, &c->fin);
+}
+
+void static secp256k1_ecmult(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_num_t *na, const secp256k1_num_t *ng) {
+ const secp256k1_ecmult_consts_t *c = secp256k1_ecmult_consts;
+
+ secp256k1_num_t na_1, na_lam;
+ secp256k1_num_t ng_1, ng_128;
+ secp256k1_num_init(&na_1);
+ secp256k1_num_init(&na_lam);
+ secp256k1_num_init(&ng_1);
+ secp256k1_num_init(&ng_128);
+
+ // split na into na_1 and na_lam (where na = na_1 + na_lam*lambda, and na_1 and na_lam are ~128 bit)
+ secp256k1_gej_split_exp(&na_1, &na_lam, na);
+ // split ng into ng_1 and ng_128 (where gn = gn_1 + gn_128*2^128, and gn_1 and gn_128 are ~128 bit)
+ secp256k1_num_split(&ng_1, &ng_128, ng, 128);
+
+ // build wnaf representation for na_1, na_lam, ng_1, ng_128
+ int wnaf_na_1[129]; int bits_na_1 = secp256k1_ecmult_wnaf(wnaf_na_1, &na_1, WINDOW_A);
+ int wnaf_na_lam[129]; int bits_na_lam = secp256k1_ecmult_wnaf(wnaf_na_lam, &na_lam, WINDOW_A);
+ int wnaf_ng_1[129]; int bits_ng_1 = secp256k1_ecmult_wnaf(wnaf_ng_1, &ng_1, WINDOW_G);
+ int wnaf_ng_128[129]; int bits_ng_128 = secp256k1_ecmult_wnaf(wnaf_ng_128, &ng_128, WINDOW_G);
+
+ // calculate a_lam = a*lambda
+ secp256k1_gej_t a_lam; secp256k1_gej_mul_lambda(&a_lam, a);
+
+ // calculate odd multiples of a and a_lam
+ secp256k1_gej_t pre_a_1[ECMULT_TABLE_SIZE(WINDOW_A)], pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)];
+ secp256k1_ecmult_table_precomp_gej(pre_a_1, a, WINDOW_A);
+ secp256k1_ecmult_table_precomp_gej(pre_a_lam, &a_lam, WINDOW_A);
+
+ int bits = bits_na_1;
+ if (bits_na_lam > bits) bits = bits_na_lam;
+ if (bits_ng_1 > bits) bits = bits_ng_1;
+ if (bits_ng_128 > bits) bits = bits_ng_128;
+
+ secp256k1_gej_set_infinity(r);
+ secp256k1_gej_t tmpj;
+ secp256k1_ge_t tmpa;
+
+ for (int i=bits-1; i>=0; i--) {
+ secp256k1_gej_double(r, r);
+ int n;
+ if (i < bits_na_1 && (n = wnaf_na_1[i])) {
+ ECMULT_TABLE_GET_GEJ(&tmpj, pre_a_1, n, WINDOW_A);
+ secp256k1_gej_add(r, r, &tmpj);
+ }
+ if (i < bits_na_lam && (n = wnaf_na_lam[i])) {
+ ECMULT_TABLE_GET_GEJ(&tmpj, pre_a_lam, n, WINDOW_A);
+ secp256k1_gej_add(r, r, &tmpj);
+ }
+ if (i < bits_ng_1 && (n = wnaf_ng_1[i])) {
+ ECMULT_TABLE_GET_GE(&tmpa, c->pre_g, n, WINDOW_G);
+ secp256k1_gej_add_ge(r, r, &tmpa);
+ }
+ if (i < bits_ng_128 && (n = wnaf_ng_128[i])) {
+ ECMULT_TABLE_GET_GE(&tmpa, c->pre_g_128, n, WINDOW_G);
+ secp256k1_gej_add_ge(r, r, &tmpa);
+ }
+ }
+
+ secp256k1_num_free(&na_1);
+ secp256k1_num_free(&na_lam);
+ secp256k1_num_free(&ng_1);
+ secp256k1_num_free(&ng_128);
+}
+
+#endif
diff --git a/crypto/secp256k1/secp256k1/src/impl/field.h b/crypto/secp256k1/secp256k1/src/impl/field.h
new file mode 100644
index 000000000..edb2acadc
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/src/impl/field.h
@@ -0,0 +1,175 @@
+// Copyright (c) 2013 Pieter Wuille
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef _SECP256K1_FIELD_IMPL_H_
+#define _SECP256K1_FIELD_IMPL_H_
+
+#if defined(USE_FIELD_GMP)
+#include "field_gmp.h"
+#elif defined(USE_FIELD_10X26)
+#include "field_10x26.h"
+#elif defined(USE_FIELD_5X52)
+#include "field_5x52.h"
+#elif defined(USE_FIELD_5X64)
+#include "field_5x64.h"
+#else
+#error "Please select field implementation"
+#endif
+
+void static secp256k1_fe_get_hex(char *r, int *rlen, const secp256k1_fe_t *a) {
+ if (*rlen < 65) {
+ *rlen = 65;
+ return;
+ }
+ *rlen = 65;
+ unsigned char tmp[32];
+ secp256k1_fe_t b = *a;
+ secp256k1_fe_normalize(&b);
+ secp256k1_fe_get_b32(tmp, &b);
+ for (int i=0; i<32; i++) {
+ static const char *c = "0123456789ABCDEF";
+ r[2*i] = c[(tmp[i] >> 4) & 0xF];
+ r[2*i+1] = c[(tmp[i]) & 0xF];
+ }
+ r[64] = 0x00;
+}
+
+void static secp256k1_fe_set_hex(secp256k1_fe_t *r, const char *a, int alen) {
+ unsigned char tmp[32] = {};
+ static const int cvt[256] = {0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
+ 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
+ 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
+ 0, 1, 2, 3, 4, 5, 6,7,8,9,0,0,0,0,0,0,
+ 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,
+ 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
+ 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,
+ 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
+ 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
+ 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
+ 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
+ 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
+ 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
+ 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
+ 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
+ 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0};
+ for (int i=0; i<32; i++) {
+ if (alen > i*2)
+ tmp[32 - alen/2 + i] = (cvt[(unsigned char)a[2*i]] << 4) + cvt[(unsigned char)a[2*i+1]];
+ }
+ secp256k1_fe_set_b32(r, tmp);
+}
+
+void static secp256k1_fe_sqrt(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
+ // calculate a^p, with p={15,780,1022,1023}
+ secp256k1_fe_t a2; secp256k1_fe_sqr(&a2, a);
+ secp256k1_fe_t a3; secp256k1_fe_mul(&a3, &a2, a);
+ secp256k1_fe_t a6; secp256k1_fe_sqr(&a6, &a3);
+ secp256k1_fe_t a12; secp256k1_fe_sqr(&a12, &a6);
+ secp256k1_fe_t a15; secp256k1_fe_mul(&a15, &a12, &a3);
+ secp256k1_fe_t a30; secp256k1_fe_sqr(&a30, &a15);
+ secp256k1_fe_t a60; secp256k1_fe_sqr(&a60, &a30);
+ secp256k1_fe_t a120; secp256k1_fe_sqr(&a120, &a60);
+ secp256k1_fe_t a240; secp256k1_fe_sqr(&a240, &a120);
+ secp256k1_fe_t a255; secp256k1_fe_mul(&a255, &a240, &a15);
+ secp256k1_fe_t a510; secp256k1_fe_sqr(&a510, &a255);
+ secp256k1_fe_t a750; secp256k1_fe_mul(&a750, &a510, &a240);
+ secp256k1_fe_t a780; secp256k1_fe_mul(&a780, &a750, &a30);
+ secp256k1_fe_t a1020; secp256k1_fe_sqr(&a1020, &a510);
+ secp256k1_fe_t a1022; secp256k1_fe_mul(&a1022, &a1020, &a2);
+ secp256k1_fe_t a1023; secp256k1_fe_mul(&a1023, &a1022, a);
+ secp256k1_fe_t x = a15;
+ for (int i=0; i<21; i++) {
+ for (int j=0; j<10; j++) secp256k1_fe_sqr(&x, &x);
+ secp256k1_fe_mul(&x, &x, &a1023);
+ }
+ for (int j=0; j<10; j++) secp256k1_fe_sqr(&x, &x);
+ secp256k1_fe_mul(&x, &x, &a1022);
+ for (int i=0; i<2; i++) {
+ for (int j=0; j<10; j++) secp256k1_fe_sqr(&x, &x);
+ secp256k1_fe_mul(&x, &x, &a1023);
+ }
+ for (int j=0; j<10; j++) secp256k1_fe_sqr(&x, &x);
+ secp256k1_fe_mul(r, &x, &a780);
+}
+
+void static secp256k1_fe_inv(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
+ // calculate a^p, with p={45,63,1019,1023}
+ secp256k1_fe_t a2; secp256k1_fe_sqr(&a2, a);
+ secp256k1_fe_t a3; secp256k1_fe_mul(&a3, &a2, a);
+ secp256k1_fe_t a4; secp256k1_fe_sqr(&a4, &a2);
+ secp256k1_fe_t a5; secp256k1_fe_mul(&a5, &a4, a);
+ secp256k1_fe_t a10; secp256k1_fe_sqr(&a10, &a5);
+ secp256k1_fe_t a11; secp256k1_fe_mul(&a11, &a10, a);
+ secp256k1_fe_t a21; secp256k1_fe_mul(&a21, &a11, &a10);
+ secp256k1_fe_t a42; secp256k1_fe_sqr(&a42, &a21);
+ secp256k1_fe_t a45; secp256k1_fe_mul(&a45, &a42, &a3);
+ secp256k1_fe_t a63; secp256k1_fe_mul(&a63, &a42, &a21);
+ secp256k1_fe_t a126; secp256k1_fe_sqr(&a126, &a63);
+ secp256k1_fe_t a252; secp256k1_fe_sqr(&a252, &a126);
+ secp256k1_fe_t a504; secp256k1_fe_sqr(&a504, &a252);
+ secp256k1_fe_t a1008; secp256k1_fe_sqr(&a1008, &a504);
+ secp256k1_fe_t a1019; secp256k1_fe_mul(&a1019, &a1008, &a11);
+ secp256k1_fe_t a1023; secp256k1_fe_mul(&a1023, &a1019, &a4);
+ secp256k1_fe_t x = a63;
+ for (int i=0; i<21; i++) {
+ for (int j=0; j<10; j++) secp256k1_fe_sqr(&x, &x);
+ secp256k1_fe_mul(&x, &x, &a1023);
+ }
+ for (int j=0; j<10; j++) secp256k1_fe_sqr(&x, &x);
+ secp256k1_fe_mul(&x, &x, &a1019);
+ for (int i=0; i<2; i++) {
+ for (int j=0; j<10; j++) secp256k1_fe_sqr(&x, &x);
+ secp256k1_fe_mul(&x, &x, &a1023);
+ }
+ for (int j=0; j<10; j++) secp256k1_fe_sqr(&x, &x);
+ secp256k1_fe_mul(r, &x, &a45);
+}
+
+void static secp256k1_fe_inv_var(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
+#if defined(USE_FIELD_INV_BUILTIN)
+ secp256k1_fe_inv(r, a);
+#elif defined(USE_FIELD_INV_NUM)
+ unsigned char b[32];
+ secp256k1_fe_t c = *a;
+ secp256k1_fe_normalize(&c);
+ secp256k1_fe_get_b32(b, &c);
+ secp256k1_num_t n;
+ secp256k1_num_init(&n);
+ secp256k1_num_set_bin(&n, b, 32);
+ secp256k1_num_mod_inverse(&n, &n, &secp256k1_fe_consts->p);
+ secp256k1_num_get_bin(b, 32, &n);
+ secp256k1_num_free(&n);
+ secp256k1_fe_set_b32(r, b);
+#else
+#error "Please select field inverse implementation"
+#endif
+}
+
+void static secp256k1_fe_start(void) {
+ static const unsigned char secp256k1_fe_consts_p[] = {
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F
+ };
+ if (secp256k1_fe_consts == NULL) {
+ secp256k1_fe_inner_start();
+ secp256k1_fe_consts_t *ret = (secp256k1_fe_consts_t*)malloc(sizeof(secp256k1_fe_consts_t));
+ secp256k1_num_init(&ret->p);
+ secp256k1_num_set_bin(&ret->p, secp256k1_fe_consts_p, sizeof(secp256k1_fe_consts_p));
+ secp256k1_fe_consts = ret;
+ }
+}
+
+void static secp256k1_fe_stop(void) {
+ if (secp256k1_fe_consts != NULL) {
+ secp256k1_fe_consts_t *c = (secp256k1_fe_consts_t*)secp256k1_fe_consts;
+ secp256k1_num_free(&c->p);
+ free((void*)c);
+ secp256k1_fe_consts = NULL;
+ secp256k1_fe_inner_stop();
+ }
+}
+
+#endif
diff --git a/crypto/secp256k1/secp256k1/src/impl/field_10x26.h b/crypto/secp256k1/secp256k1/src/impl/field_10x26.h
new file mode 100644
index 000000000..449769254
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/src/impl/field_10x26.h
@@ -0,0 +1,487 @@
+// Copyright (c) 2013 Pieter Wuille
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef _SECP256K1_FIELD_REPR_IMPL_H_
+#define _SECP256K1_FIELD_REPR_IMPL_H_
+
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include "../num.h"
+#include "../field.h"
+
+void static secp256k1_fe_inner_start(void) {}
+void static secp256k1_fe_inner_stop(void) {}
+
+void static secp256k1_fe_normalize(secp256k1_fe_t *r) {
+// fog("normalize in: ", r);
+ uint32_t c;
+ c = r->n[0];
+ uint32_t t0 = c & 0x3FFFFFFUL;
+ c = (c >> 26) + r->n[1];
+ uint32_t t1 = c & 0x3FFFFFFUL;
+ c = (c >> 26) + r->n[2];
+ uint32_t t2 = c & 0x3FFFFFFUL;
+ c = (c >> 26) + r->n[3];
+ uint32_t t3 = c & 0x3FFFFFFUL;
+ c = (c >> 26) + r->n[4];
+ uint32_t t4 = c & 0x3FFFFFFUL;
+ c = (c >> 26) + r->n[5];
+ uint32_t t5 = c & 0x3FFFFFFUL;
+ c = (c >> 26) + r->n[6];
+ uint32_t t6 = c & 0x3FFFFFFUL;
+ c = (c >> 26) + r->n[7];
+ uint32_t t7 = c & 0x3FFFFFFUL;
+ c = (c >> 26) + r->n[8];
+ uint32_t t8 = c & 0x3FFFFFFUL;
+ c = (c >> 26) + r->n[9];
+ uint32_t t9 = c & 0x03FFFFFUL;
+ c >>= 22;
+/* r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;
+ r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9;
+ fog(" tm1: ", r);
+ fprintf(stderr, "out c= %08lx\n", (unsigned long)c);*/
+
+ // The following code will not modify the t's if c is initially 0.
+ uint32_t d = c * 0x3D1UL + t0;
+ t0 = d & 0x3FFFFFFULL;
+ d = (d >> 26) + t1 + c*0x40;
+ t1 = d & 0x3FFFFFFULL;
+ d = (d >> 26) + t2;
+ t2 = d & 0x3FFFFFFULL;
+ d = (d >> 26) + t3;
+ t3 = d & 0x3FFFFFFULL;
+ d = (d >> 26) + t4;
+ t4 = d & 0x3FFFFFFULL;
+ d = (d >> 26) + t5;
+ t5 = d & 0x3FFFFFFULL;
+ d = (d >> 26) + t6;
+ t6 = d & 0x3FFFFFFULL;
+ d = (d >> 26) + t7;
+ t7 = d & 0x3FFFFFFULL;
+ d = (d >> 26) + t8;
+ t8 = d & 0x3FFFFFFULL;
+ d = (d >> 26) + t9;
+ t9 = d & 0x03FFFFFULL;
+ assert((d >> 22) == 0);
+/* r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;
+ r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9;
+ fog(" tm2: ", r); */
+
+ // Subtract p if result >= p
+ uint64_t low = ((uint64_t)t1 << 26) | t0;
+ uint64_t mask = -(int64_t)((t9 < 0x03FFFFFUL) | (t8 < 0x3FFFFFFUL) | (t7 < 0x3FFFFFFUL) | (t6 < 0x3FFFFFFUL) | (t5 < 0x3FFFFFFUL) | (t4 < 0x3FFFFFFUL) | (t3 < 0x3FFFFFFUL) | (t2 < 0x3FFFFFFUL) | (low < 0xFFFFEFFFFFC2FULL));
+ t9 &= mask;
+ t8 &= mask;
+ t7 &= mask;
+ t6 &= mask;
+ t5 &= mask;
+ t4 &= mask;
+ t3 &= mask;
+ t2 &= mask;
+ low -= (~mask & 0xFFFFEFFFFFC2FULL);
+
+ // push internal variables back
+ r->n[0] = low & 0x3FFFFFFUL; r->n[1] = (low >> 26) & 0x3FFFFFFUL; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;
+ r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9;
+/* fog(" out: ", r);*/
+
+#ifdef VERIFY
+ r->magnitude = 1;
+ r->normalized = 1;
+#endif
+}
+
+void static inline secp256k1_fe_set_int(secp256k1_fe_t *r, int a) {
+ r->n[0] = a;
+ r->n[1] = r->n[2] = r->n[3] = r->n[4] = r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0;
+#ifdef VERIFY
+ r->magnitude = 1;
+ r->normalized = 1;
+#endif
+}
+
+// TODO: not constant time!
+int static inline secp256k1_fe_is_zero(const secp256k1_fe_t *a) {
+#ifdef VERIFY
+ assert(a->normalized);
+#endif
+ return (a->n[0] == 0 && a->n[1] == 0 && a->n[2] == 0 && a->n[3] == 0 && a->n[4] == 0 && a->n[5] == 0 && a->n[6] == 0 && a->n[7] == 0 && a->n[8] == 0 && a->n[9] == 0);
+}
+
+int static inline secp256k1_fe_is_odd(const secp256k1_fe_t *a) {
+#ifdef VERIFY
+ assert(a->normalized);
+#endif
+ return a->n[0] & 1;
+}
+
+// TODO: not constant time!
+int static inline secp256k1_fe_equal(const secp256k1_fe_t *a, const secp256k1_fe_t *b) {
+#ifdef VERIFY
+ assert(a->normalized);
+ assert(b->normalized);
+#endif
+ return (a->n[0] == b->n[0] && a->n[1] == b->n[1] && a->n[2] == b->n[2] && a->n[3] == b->n[3] && a->n[4] == b->n[4] &&
+ a->n[5] == b->n[5] && a->n[6] == b->n[6] && a->n[7] == b->n[7] && a->n[8] == b->n[8] && a->n[9] == b->n[9]);
+}
+
+void static secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) {
+ r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;
+ r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0;
+ for (int i=0; i<32; i++) {
+ for (int j=0; j<4; j++) {
+ int limb = (8*i+2*j)/26;
+ int shift = (8*i+2*j)%26;
+ r->n[limb] |= (uint32_t)((a[31-i] >> (2*j)) & 0x3) << shift;
+ }
+ }
+#ifdef VERIFY
+ r->magnitude = 1;
+ r->normalized = 1;
+#endif
+}
+
+/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
+void static secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a) {
+#ifdef VERIFY
+ assert(a->normalized);
+#endif
+ for (int i=0; i<32; i++) {
+ int c = 0;
+ for (int j=0; j<4; j++) {
+ int limb = (8*i+2*j)/26;
+ int shift = (8*i+2*j)%26;
+ c |= ((a->n[limb] >> shift) & 0x3) << (2 * j);
+ }
+ r[31-i] = c;
+ }
+}
+
+void static inline secp256k1_fe_negate(secp256k1_fe_t *r, const secp256k1_fe_t *a, int m) {
+#ifdef VERIFY
+ assert(a->magnitude <= m);
+ r->magnitude = m + 1;
+ r->normalized = 0;
+#endif
+ r->n[0] = 0x3FFFC2FUL * (m + 1) - a->n[0];
+ r->n[1] = 0x3FFFFBFUL * (m + 1) - a->n[1];
+ r->n[2] = 0x3FFFFFFUL * (m + 1) - a->n[2];
+ r->n[3] = 0x3FFFFFFUL * (m + 1) - a->n[3];
+ r->n[4] = 0x3FFFFFFUL * (m + 1) - a->n[4];
+ r->n[5] = 0x3FFFFFFUL * (m + 1) - a->n[5];
+ r->n[6] = 0x3FFFFFFUL * (m + 1) - a->n[6];
+ r->n[7] = 0x3FFFFFFUL * (m + 1) - a->n[7];
+ r->n[8] = 0x3FFFFFFUL * (m + 1) - a->n[8];
+ r->n[9] = 0x03FFFFFUL * (m + 1) - a->n[9];
+}
+
+void static inline secp256k1_fe_mul_int(secp256k1_fe_t *r, int a) {
+#ifdef VERIFY
+ r->magnitude *= a;
+ r->normalized = 0;
+#endif
+ r->n[0] *= a;
+ r->n[1] *= a;
+ r->n[2] *= a;
+ r->n[3] *= a;
+ r->n[4] *= a;
+ r->n[5] *= a;
+ r->n[6] *= a;
+ r->n[7] *= a;
+ r->n[8] *= a;
+ r->n[9] *= a;
+}
+
+void static inline secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
+#ifdef VERIFY
+ r->magnitude += a->magnitude;
+ r->normalized = 0;
+#endif
+ r->n[0] += a->n[0];
+ r->n[1] += a->n[1];
+ r->n[2] += a->n[2];
+ r->n[3] += a->n[3];
+ r->n[4] += a->n[4];
+ r->n[5] += a->n[5];
+ r->n[6] += a->n[6];
+ r->n[7] += a->n[7];
+ r->n[8] += a->n[8];
+ r->n[9] += a->n[9];
+}
+
+void static inline secp256k1_fe_mul_inner(const uint32_t *a, const uint32_t *b, uint32_t *r) {
+ uint64_t c = (uint64_t)a[0] * b[0];
+ uint32_t t0 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + (uint64_t)a[0] * b[1] +
+ (uint64_t)a[1] * b[0];
+ uint32_t t1 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + (uint64_t)a[0] * b[2] +
+ (uint64_t)a[1] * b[1] +
+ (uint64_t)a[2] * b[0];
+ uint32_t t2 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + (uint64_t)a[0] * b[3] +
+ (uint64_t)a[1] * b[2] +
+ (uint64_t)a[2] * b[1] +
+ (uint64_t)a[3] * b[0];
+ uint32_t t3 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + (uint64_t)a[0] * b[4] +
+ (uint64_t)a[1] * b[3] +
+ (uint64_t)a[2] * b[2] +
+ (uint64_t)a[3] * b[1] +
+ (uint64_t)a[4] * b[0];
+ uint32_t t4 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + (uint64_t)a[0] * b[5] +
+ (uint64_t)a[1] * b[4] +
+ (uint64_t)a[2] * b[3] +
+ (uint64_t)a[3] * b[2] +
+ (uint64_t)a[4] * b[1] +
+ (uint64_t)a[5] * b[0];
+ uint32_t t5 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + (uint64_t)a[0] * b[6] +
+ (uint64_t)a[1] * b[5] +
+ (uint64_t)a[2] * b[4] +
+ (uint64_t)a[3] * b[3] +
+ (uint64_t)a[4] * b[2] +
+ (uint64_t)a[5] * b[1] +
+ (uint64_t)a[6] * b[0];
+ uint32_t t6 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + (uint64_t)a[0] * b[7] +
+ (uint64_t)a[1] * b[6] +
+ (uint64_t)a[2] * b[5] +
+ (uint64_t)a[3] * b[4] +
+ (uint64_t)a[4] * b[3] +
+ (uint64_t)a[5] * b[2] +
+ (uint64_t)a[6] * b[1] +
+ (uint64_t)a[7] * b[0];
+ uint32_t t7 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + (uint64_t)a[0] * b[8] +
+ (uint64_t)a[1] * b[7] +
+ (uint64_t)a[2] * b[6] +
+ (uint64_t)a[3] * b[5] +
+ (uint64_t)a[4] * b[4] +
+ (uint64_t)a[5] * b[3] +
+ (uint64_t)a[6] * b[2] +
+ (uint64_t)a[7] * b[1] +
+ (uint64_t)a[8] * b[0];
+ uint32_t t8 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + (uint64_t)a[0] * b[9] +
+ (uint64_t)a[1] * b[8] +
+ (uint64_t)a[2] * b[7] +
+ (uint64_t)a[3] * b[6] +
+ (uint64_t)a[4] * b[5] +
+ (uint64_t)a[5] * b[4] +
+ (uint64_t)a[6] * b[3] +
+ (uint64_t)a[7] * b[2] +
+ (uint64_t)a[8] * b[1] +
+ (uint64_t)a[9] * b[0];
+ uint32_t t9 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + (uint64_t)a[1] * b[9] +
+ (uint64_t)a[2] * b[8] +
+ (uint64_t)a[3] * b[7] +
+ (uint64_t)a[4] * b[6] +
+ (uint64_t)a[5] * b[5] +
+ (uint64_t)a[6] * b[4] +
+ (uint64_t)a[7] * b[3] +
+ (uint64_t)a[8] * b[2] +
+ (uint64_t)a[9] * b[1];
+ uint32_t t10 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + (uint64_t)a[2] * b[9] +
+ (uint64_t)a[3] * b[8] +
+ (uint64_t)a[4] * b[7] +
+ (uint64_t)a[5] * b[6] +
+ (uint64_t)a[6] * b[5] +
+ (uint64_t)a[7] * b[4] +
+ (uint64_t)a[8] * b[3] +
+ (uint64_t)a[9] * b[2];
+ uint32_t t11 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + (uint64_t)a[3] * b[9] +
+ (uint64_t)a[4] * b[8] +
+ (uint64_t)a[5] * b[7] +
+ (uint64_t)a[6] * b[6] +
+ (uint64_t)a[7] * b[5] +
+ (uint64_t)a[8] * b[4] +
+ (uint64_t)a[9] * b[3];
+ uint32_t t12 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + (uint64_t)a[4] * b[9] +
+ (uint64_t)a[5] * b[8] +
+ (uint64_t)a[6] * b[7] +
+ (uint64_t)a[7] * b[6] +
+ (uint64_t)a[8] * b[5] +
+ (uint64_t)a[9] * b[4];
+ uint32_t t13 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + (uint64_t)a[5] * b[9] +
+ (uint64_t)a[6] * b[8] +
+ (uint64_t)a[7] * b[7] +
+ (uint64_t)a[8] * b[6] +
+ (uint64_t)a[9] * b[5];
+ uint32_t t14 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + (uint64_t)a[6] * b[9] +
+ (uint64_t)a[7] * b[8] +
+ (uint64_t)a[8] * b[7] +
+ (uint64_t)a[9] * b[6];
+ uint32_t t15 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + (uint64_t)a[7] * b[9] +
+ (uint64_t)a[8] * b[8] +
+ (uint64_t)a[9] * b[7];
+ uint32_t t16 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + (uint64_t)a[8] * b[9] +
+ (uint64_t)a[9] * b[8];
+ uint32_t t17 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + (uint64_t)a[9] * b[9];
+ uint32_t t18 = c & 0x3FFFFFFUL; c = c >> 26;
+ uint32_t t19 = c;
+
+ c = t0 + (uint64_t)t10 * 0x3D10UL;
+ t0 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + t1 + (uint64_t)t10*0x400UL + (uint64_t)t11 * 0x3D10UL;
+ t1 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + t2 + (uint64_t)t11*0x400UL + (uint64_t)t12 * 0x3D10UL;
+ t2 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + t3 + (uint64_t)t12*0x400UL + (uint64_t)t13 * 0x3D10UL;
+ r[3] = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + t4 + (uint64_t)t13*0x400UL + (uint64_t)t14 * 0x3D10UL;
+ r[4] = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + t5 + (uint64_t)t14*0x400UL + (uint64_t)t15 * 0x3D10UL;
+ r[5] = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + t6 + (uint64_t)t15*0x400UL + (uint64_t)t16 * 0x3D10UL;
+ r[6] = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + t7 + (uint64_t)t16*0x400UL + (uint64_t)t17 * 0x3D10UL;
+ r[7] = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + t8 + (uint64_t)t17*0x400UL + (uint64_t)t18 * 0x3D10UL;
+ r[8] = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + t9 + (uint64_t)t18*0x400UL + (uint64_t)t19 * 0x1000003D10ULL;
+ r[9] = c & 0x03FFFFFUL; c = c >> 22;
+ uint64_t d = t0 + c * 0x3D1UL;
+ r[0] = d & 0x3FFFFFFUL; d = d >> 26;
+ d = d + t1 + c*0x40;
+ r[1] = d & 0x3FFFFFFUL; d = d >> 26;
+ r[2] = t2 + d;
+}
+
+void static inline secp256k1_fe_sqr_inner(const uint32_t *a, uint32_t *r) {
+ uint64_t c = (uint64_t)a[0] * a[0];
+ uint32_t t0 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + (uint64_t)(a[0]*2) * a[1];
+ uint32_t t1 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + (uint64_t)(a[0]*2) * a[2] +
+ (uint64_t)a[1] * a[1];
+ uint32_t t2 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + (uint64_t)(a[0]*2) * a[3] +
+ (uint64_t)(a[1]*2) * a[2];
+ uint32_t t3 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + (uint64_t)(a[0]*2) * a[4] +
+ (uint64_t)(a[1]*2) * a[3] +
+ (uint64_t)a[2] * a[2];
+ uint32_t t4 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + (uint64_t)(a[0]*2) * a[5] +
+ (uint64_t)(a[1]*2) * a[4] +
+ (uint64_t)(a[2]*2) * a[3];
+ uint32_t t5 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + (uint64_t)(a[0]*2) * a[6] +
+ (uint64_t)(a[1]*2) * a[5] +
+ (uint64_t)(a[2]*2) * a[4] +
+ (uint64_t)a[3] * a[3];
+ uint32_t t6 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + (uint64_t)(a[0]*2) * a[7] +
+ (uint64_t)(a[1]*2) * a[6] +
+ (uint64_t)(a[2]*2) * a[5] +
+ (uint64_t)(a[3]*2) * a[4];
+ uint32_t t7 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + (uint64_t)(a[0]*2) * a[8] +
+ (uint64_t)(a[1]*2) * a[7] +
+ (uint64_t)(a[2]*2) * a[6] +
+ (uint64_t)(a[3]*2) * a[5] +
+ (uint64_t)a[4] * a[4];
+ uint32_t t8 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + (uint64_t)(a[0]*2) * a[9] +
+ (uint64_t)(a[1]*2) * a[8] +
+ (uint64_t)(a[2]*2) * a[7] +
+ (uint64_t)(a[3]*2) * a[6] +
+ (uint64_t)(a[4]*2) * a[5];
+ uint32_t t9 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + (uint64_t)(a[1]*2) * a[9] +
+ (uint64_t)(a[2]*2) * a[8] +
+ (uint64_t)(a[3]*2) * a[7] +
+ (uint64_t)(a[4]*2) * a[6] +
+ (uint64_t)a[5] * a[5];
+ uint32_t t10 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + (uint64_t)(a[2]*2) * a[9] +
+ (uint64_t)(a[3]*2) * a[8] +
+ (uint64_t)(a[4]*2) * a[7] +
+ (uint64_t)(a[5]*2) * a[6];
+ uint32_t t11 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + (uint64_t)(a[3]*2) * a[9] +
+ (uint64_t)(a[4]*2) * a[8] +
+ (uint64_t)(a[5]*2) * a[7] +
+ (uint64_t)a[6] * a[6];
+ uint32_t t12 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + (uint64_t)(a[4]*2) * a[9] +
+ (uint64_t)(a[5]*2) * a[8] +
+ (uint64_t)(a[6]*2) * a[7];
+ uint32_t t13 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + (uint64_t)(a[5]*2) * a[9] +
+ (uint64_t)(a[6]*2) * a[8] +
+ (uint64_t)a[7] * a[7];
+ uint32_t t14 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + (uint64_t)(a[6]*2) * a[9] +
+ (uint64_t)(a[7]*2) * a[8];
+ uint32_t t15 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + (uint64_t)(a[7]*2) * a[9] +
+ (uint64_t)a[8] * a[8];
+ uint32_t t16 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + (uint64_t)(a[8]*2) * a[9];
+ uint32_t t17 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + (uint64_t)a[9] * a[9];
+ uint32_t t18 = c & 0x3FFFFFFUL; c = c >> 26;
+ uint32_t t19 = c;
+
+ c = t0 + (uint64_t)t10 * 0x3D10UL;
+ t0 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + t1 + (uint64_t)t10*0x400UL + (uint64_t)t11 * 0x3D10UL;
+ t1 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + t2 + (uint64_t)t11*0x400UL + (uint64_t)t12 * 0x3D10UL;
+ t2 = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + t3 + (uint64_t)t12*0x400UL + (uint64_t)t13 * 0x3D10UL;
+ r[3] = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + t4 + (uint64_t)t13*0x400UL + (uint64_t)t14 * 0x3D10UL;
+ r[4] = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + t5 + (uint64_t)t14*0x400UL + (uint64_t)t15 * 0x3D10UL;
+ r[5] = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + t6 + (uint64_t)t15*0x400UL + (uint64_t)t16 * 0x3D10UL;
+ r[6] = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + t7 + (uint64_t)t16*0x400UL + (uint64_t)t17 * 0x3D10UL;
+ r[7] = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + t8 + (uint64_t)t17*0x400UL + (uint64_t)t18 * 0x3D10UL;
+ r[8] = c & 0x3FFFFFFUL; c = c >> 26;
+ c = c + t9 + (uint64_t)t18*0x400UL + (uint64_t)t19 * 0x1000003D10ULL;
+ r[9] = c & 0x03FFFFFUL; c = c >> 22;
+ uint64_t d = t0 + c * 0x3D1UL;
+ r[0] = d & 0x3FFFFFFUL; d = d >> 26;
+ d = d + t1 + c*0x40;
+ r[1] = d & 0x3FFFFFFUL; d = d >> 26;
+ r[2] = t2 + d;
+}
+
+
+void static secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t *b) {
+#ifdef VERIFY
+ assert(a->magnitude <= 8);
+ assert(b->magnitude <= 8);
+ r->magnitude = 1;
+ r->normalized = 0;
+#endif
+ secp256k1_fe_mul_inner(a->n, b->n, r->n);
+}
+
+void static secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
+#ifdef VERIFY
+ assert(a->magnitude <= 8);
+ r->magnitude = 1;
+ r->normalized = 0;
+#endif
+ secp256k1_fe_sqr_inner(a->n, r->n);
+}
+
+#endif
diff --git a/crypto/secp256k1/secp256k1/src/impl/field_5x52.h b/crypto/secp256k1/secp256k1/src/impl/field_5x52.h
new file mode 100644
index 000000000..5347189f1
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/src/impl/field_5x52.h
@@ -0,0 +1,196 @@
+// Copyright (c) 2013 Pieter Wuille
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef _SECP256K1_FIELD_REPR_IMPL_H_
+#define _SECP256K1_FIELD_REPR_IMPL_H_
+
+#include <assert.h>
+#include <string.h>
+#include "../num.h"
+#include "../field.h"
+
+#if defined(USE_FIELD_5X52_ASM)
+#include "field_5x52_asm.h"
+#elif defined(USE_FIELD_5X52_INT128)
+#include "field_5x52_int128.h"
+#else
+#error "Please select field_5x52 implementation"
+#endif
+
+/** Implements arithmetic modulo FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F,
+ * represented as 5 uint64_t's in base 2^52. The values are allowed to contain >52 each. In particular,
+ * each FieldElem has a 'magnitude' associated with it. Internally, a magnitude M means each element
+ * is at most M*(2^53-1), except the most significant one, which is limited to M*(2^49-1). All operations
+ * accept any input with magnitude at most M, and have different rules for propagating magnitude to their
+ * output.
+ */
+
+void static secp256k1_fe_inner_start(void) {}
+void static secp256k1_fe_inner_stop(void) {}
+
+void static secp256k1_fe_normalize(secp256k1_fe_t *r) {
+ uint64_t c;
+ c = r->n[0];
+ uint64_t t0 = c & 0xFFFFFFFFFFFFFULL;
+ c = (c >> 52) + r->n[1];
+ uint64_t t1 = c & 0xFFFFFFFFFFFFFULL;
+ c = (c >> 52) + r->n[2];
+ uint64_t t2 = c & 0xFFFFFFFFFFFFFULL;
+ c = (c >> 52) + r->n[3];
+ uint64_t t3 = c & 0xFFFFFFFFFFFFFULL;
+ c = (c >> 52) + r->n[4];
+ uint64_t t4 = c & 0x0FFFFFFFFFFFFULL;
+ c >>= 48;
+
+ // The following code will not modify the t's if c is initially 0.
+ c = c * 0x1000003D1ULL + t0;
+ t0 = c & 0xFFFFFFFFFFFFFULL;
+ c = (c >> 52) + t1;
+ t1 = c & 0xFFFFFFFFFFFFFULL;
+ c = (c >> 52) + t2;
+ t2 = c & 0xFFFFFFFFFFFFFULL;
+ c = (c >> 52) + t3;
+ t3 = c & 0xFFFFFFFFFFFFFULL;
+ c = (c >> 52) + t4;
+ t4 = c & 0x0FFFFFFFFFFFFULL;
+ assert((c >> 48) == 0);
+
+ // Subtract p if result >= p
+ uint64_t mask = -(int64_t)((t4 < 0xFFFFFFFFFFFFULL) | (t3 < 0xFFFFFFFFFFFFFULL) | (t2 < 0xFFFFFFFFFFFFFULL) | (t1 < 0xFFFFFFFFFFFFFULL) | (t0 < 0xFFFFEFFFFFC2FULL));
+ t4 &= mask;
+ t3 &= mask;
+ t2 &= mask;
+ t1 &= mask;
+ t0 -= (~mask & 0xFFFFEFFFFFC2FULL);
+
+ // push internal variables back
+ r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;
+
+#ifdef VERIFY
+ r->magnitude = 1;
+ r->normalized = 1;
+#endif
+}
+
+void static inline secp256k1_fe_set_int(secp256k1_fe_t *r, int a) {
+ r->n[0] = a;
+ r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;
+#ifdef VERIFY
+ r->magnitude = 1;
+ r->normalized = 1;
+#endif
+}
+
+// TODO: not constant time!
+int static inline secp256k1_fe_is_zero(const secp256k1_fe_t *a) {
+#ifdef VERIFY
+ assert(a->normalized);
+#endif
+ return (a->n[0] == 0 && a->n[1] == 0 && a->n[2] == 0 && a->n[3] == 0 && a->n[4] == 0);
+}
+
+int static inline secp256k1_fe_is_odd(const secp256k1_fe_t *a) {
+#ifdef VERIFY
+ assert(a->normalized);
+#endif
+ return a->n[0] & 1;
+}
+
+// TODO: not constant time!
+int static inline secp256k1_fe_equal(const secp256k1_fe_t *a, const secp256k1_fe_t *b) {
+#ifdef VERIFY
+ assert(a->normalized);
+ assert(b->normalized);
+#endif
+ return (a->n[0] == b->n[0] && a->n[1] == b->n[1] && a->n[2] == b->n[2] && a->n[3] == b->n[3] && a->n[4] == b->n[4]);
+}
+
+void static secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) {
+ r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;
+ for (int i=0; i<32; i++) {
+ for (int j=0; j<2; j++) {
+ int limb = (8*i+4*j)/52;
+ int shift = (8*i+4*j)%52;
+ r->n[limb] |= (uint64_t)((a[31-i] >> (4*j)) & 0xF) << shift;
+ }
+ }
+#ifdef VERIFY
+ r->magnitude = 1;
+ r->normalized = 1;
+#endif
+}
+
+/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
+void static secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a) {
+#ifdef VERIFY
+ assert(a->normalized);
+#endif
+ for (int i=0; i<32; i++) {
+ int c = 0;
+ for (int j=0; j<2; j++) {
+ int limb = (8*i+4*j)/52;
+ int shift = (8*i+4*j)%52;
+ c |= ((a->n[limb] >> shift) & 0xF) << (4 * j);
+ }
+ r[31-i] = c;
+ }
+}
+
+void static inline secp256k1_fe_negate(secp256k1_fe_t *r, const secp256k1_fe_t *a, int m) {
+#ifdef VERIFY
+ assert(a->magnitude <= m);
+ r->magnitude = m + 1;
+ r->normalized = 0;
+#endif
+ r->n[0] = 0xFFFFEFFFFFC2FULL * (m + 1) - a->n[0];
+ r->n[1] = 0xFFFFFFFFFFFFFULL * (m + 1) - a->n[1];
+ r->n[2] = 0xFFFFFFFFFFFFFULL * (m + 1) - a->n[2];
+ r->n[3] = 0xFFFFFFFFFFFFFULL * (m + 1) - a->n[3];
+ r->n[4] = 0x0FFFFFFFFFFFFULL * (m + 1) - a->n[4];
+}
+
+void static inline secp256k1_fe_mul_int(secp256k1_fe_t *r, int a) {
+#ifdef VERIFY
+ r->magnitude *= a;
+ r->normalized = 0;
+#endif
+ r->n[0] *= a;
+ r->n[1] *= a;
+ r->n[2] *= a;
+ r->n[3] *= a;
+ r->n[4] *= a;
+}
+
+void static inline secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
+#ifdef VERIFY
+ r->magnitude += a->magnitude;
+ r->normalized = 0;
+#endif
+ r->n[0] += a->n[0];
+ r->n[1] += a->n[1];
+ r->n[2] += a->n[2];
+ r->n[3] += a->n[3];
+ r->n[4] += a->n[4];
+}
+
+void static secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t *b) {
+#ifdef VERIFY
+ assert(a->magnitude <= 8);
+ assert(b->magnitude <= 8);
+ r->magnitude = 1;
+ r->normalized = 0;
+#endif
+ secp256k1_fe_mul_inner(a->n, b->n, r->n);
+}
+
+void static secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
+#ifdef VERIFY
+ assert(a->magnitude <= 8);
+ r->magnitude = 1;
+ r->normalized = 0;
+#endif
+ secp256k1_fe_sqr_inner(a->n, r->n);
+}
+
+#endif
diff --git a/crypto/secp256k1/secp256k1/src/impl/field_5x52_asm.h b/crypto/secp256k1/secp256k1/src/impl/field_5x52_asm.h
new file mode 100644
index 000000000..93c6ab6b5
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/src/impl/field_5x52_asm.h
@@ -0,0 +1,11 @@
+// Copyright (c) 2013 Pieter Wuille
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef _SECP256K1_FIELD_INNER5X52_IMPL_H_
+#define _SECP256K1_FIELD_INNER5X52_IMPL_H_
+
+void __attribute__ ((sysv_abi)) secp256k1_fe_mul_inner(const uint64_t *a, const uint64_t *b, uint64_t *r);
+void __attribute__ ((sysv_abi)) secp256k1_fe_sqr_inner(const uint64_t *a, uint64_t *r);
+
+#endif
diff --git a/crypto/secp256k1/secp256k1/src/impl/field_5x52_int128.h b/crypto/secp256k1/secp256k1/src/impl/field_5x52_int128.h
new file mode 100644
index 000000000..23cb13462
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/src/impl/field_5x52_int128.h
@@ -0,0 +1,105 @@
+// Copyright (c) 2013 Pieter Wuille
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef _SECP256K1_FIELD_INNER5X52_IMPL_H_
+#define _SECP256K1_FIELD_INNER5X52_IMPL_H_
+
+#include <stdint.h>
+
+void static inline secp256k1_fe_mul_inner(const uint64_t *a, const uint64_t *b, uint64_t *r) {
+ __int128 c = (__int128)a[0] * b[0];
+ uint64_t t0 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0FFFFFFFFFFFFFE0
+ c = c + (__int128)a[0] * b[1] +
+ (__int128)a[1] * b[0];
+ uint64_t t1 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 20000000000000BF
+ c = c + (__int128)a[0] * b[2] +
+ (__int128)a[1] * b[1] +
+ (__int128)a[2] * b[0];
+ uint64_t t2 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 30000000000001A0
+ c = c + (__int128)a[0] * b[3] +
+ (__int128)a[1] * b[2] +
+ (__int128)a[2] * b[1] +
+ (__int128)a[3] * b[0];
+ uint64_t t3 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 4000000000000280
+ c = c + (__int128)a[0] * b[4] +
+ (__int128)a[1] * b[3] +
+ (__int128)a[2] * b[2] +
+ (__int128)a[3] * b[1] +
+ (__int128)a[4] * b[0];
+ uint64_t t4 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 320000000000037E
+ c = c + (__int128)a[1] * b[4] +
+ (__int128)a[2] * b[3] +
+ (__int128)a[3] * b[2] +
+ (__int128)a[4] * b[1];
+ uint64_t t5 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 22000000000002BE
+ c = c + (__int128)a[2] * b[4] +
+ (__int128)a[3] * b[3] +
+ (__int128)a[4] * b[2];
+ uint64_t t6 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 12000000000001DE
+ c = c + (__int128)a[3] * b[4] +
+ (__int128)a[4] * b[3];
+ uint64_t t7 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 02000000000000FE
+ c = c + (__int128)a[4] * b[4];
+ uint64_t t8 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 001000000000001E
+ uint64_t t9 = c;
+
+ c = t0 + (__int128)t5 * 0x1000003D10ULL;
+ t0 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
+ c = c + t1 + (__int128)t6 * 0x1000003D10ULL;
+ t1 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
+ c = c + t2 + (__int128)t7 * 0x1000003D10ULL;
+ r[2] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
+ c = c + t3 + (__int128)t8 * 0x1000003D10ULL;
+ r[3] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
+ c = c + t4 + (__int128)t9 * 0x1000003D10ULL;
+ r[4] = c & 0x0FFFFFFFFFFFFULL; c = c >> 48; // c max 000001000003D110
+ c = t0 + (__int128)c * 0x1000003D1ULL;
+ r[0] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 1000008
+ r[1] = t1 + c;
+
+}
+
+void static inline secp256k1_fe_sqr_inner(const uint64_t *a, uint64_t *r) {
+ __int128 c = (__int128)a[0] * a[0];
+ uint64_t t0 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0FFFFFFFFFFFFFE0
+ c = c + (__int128)(a[0]*2) * a[1];
+ uint64_t t1 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 20000000000000BF
+ c = c + (__int128)(a[0]*2) * a[2] +
+ (__int128)a[1] * a[1];
+ uint64_t t2 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 30000000000001A0
+ c = c + (__int128)(a[0]*2) * a[3] +
+ (__int128)(a[1]*2) * a[2];
+ uint64_t t3 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 4000000000000280
+ c = c + (__int128)(a[0]*2) * a[4] +
+ (__int128)(a[1]*2) * a[3] +
+ (__int128)a[2] * a[2];
+ uint64_t t4 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 320000000000037E
+ c = c + (__int128)(a[1]*2) * a[4] +
+ (__int128)(a[2]*2) * a[3];
+ uint64_t t5 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 22000000000002BE
+ c = c + (__int128)(a[2]*2) * a[4] +
+ (__int128)a[3] * a[3];
+ uint64_t t6 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 12000000000001DE
+ c = c + (__int128)(a[3]*2) * a[4];
+ uint64_t t7 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 02000000000000FE
+ c = c + (__int128)a[4] * a[4];
+ uint64_t t8 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 001000000000001E
+ uint64_t t9 = c;
+ c = t0 + (__int128)t5 * 0x1000003D10ULL;
+ t0 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
+ c = c + t1 + (__int128)t6 * 0x1000003D10ULL;
+ t1 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
+ c = c + t2 + (__int128)t7 * 0x1000003D10ULL;
+ r[2] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
+ c = c + t3 + (__int128)t8 * 0x1000003D10ULL;
+ r[3] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
+ c = c + t4 + (__int128)t9 * 0x1000003D10ULL;
+ r[4] = c & 0x0FFFFFFFFFFFFULL; c = c >> 48; // c max 000001000003D110
+ c = t0 + (__int128)c * 0x1000003D1ULL;
+ r[0] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 1000008
+ r[1] = t1 + c;
+
+}
+
+#endif
diff --git a/crypto/secp256k1/secp256k1/src/impl/field_5x64.h b/crypto/secp256k1/secp256k1/src/impl/field_5x64.h
new file mode 100644
index 000000000..1e645cddb
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/src/impl/field_5x64.h
@@ -0,0 +1,371 @@
+// Copyright (c) 2013 Pieter Wuille
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef _SECP256K1_FIELD_REPR_IMPL_H_
+#define _SECP256K1_FIELD_REPR_IMPL_H_
+
+#include <assert.h>
+#include <string.h>
+#include "../num.h"
+#include "../field.h"
+
+#include <stdio.h>
+#include "field_5x64_asm.h"
+
+/** Implements arithmetic modulo FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F,
+ * represented as 4 uint64_t's in base 2^64, and one overflow uint64_t.
+ */
+
+#define FULL_LIMB (0xFFFFFFFFFFFFFFFFULL)
+#define LAST_LIMB (0xFFFFFFFEFFFFFC2FULL)
+#define COMP_LIMB (0x00000001000003D1ULL)
+
+void static secp256k1_fe_inner_start(void) {}
+void static secp256k1_fe_inner_stop(void) {}
+
+void static secp256k1_fe_reduce(secp256k1_fe_t *r) {
+ unsigned __int128 c = (unsigned __int128)r->n[4] * COMP_LIMB + r->n[0];
+ uint64_t n0 = c;
+ c = (c >> 64) + r->n[1];
+ uint64_t n1 = c;
+ c = (c >> 64) + r->n[2];
+ r->n[2] = c;
+ c = (c >> 64) + r->n[3];
+ r->n[3] = c;
+ c = (c >> 64) * COMP_LIMB + n0;
+ r->n[0] = c;
+ r->n[1] = n1 + (c >> 64);
+ assert(r->n[1] >= n1);
+ r->n[4] = 0;
+#ifdef VERIFY
+ r->reduced = 1;
+#endif
+}
+
+void static secp256k1_fe_normalize(secp256k1_fe_t *r) {
+ secp256k1_fe_reduce(r);
+
+ // Subtract p if result >= p
+ uint64_t mask = -(int64_t)((r->n[0] < LAST_LIMB) | (r->n[1] != ~0ULL) | (r->n[2] != ~0ULL) | (r->n[3] != ~0ULL));
+ r->n[0] -= (~mask & LAST_LIMB);
+ r->n[1] &= mask;
+ r->n[2] &= mask;
+ r->n[3] &= mask;
+ assert(r->n[4] == 0);
+
+#ifdef VERIFY
+ r->normalized = 1;
+#endif
+}
+
+void static inline secp256k1_fe_set_int(secp256k1_fe_t *r, int a) {
+ r->n[0] = a;
+ r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;
+
+#ifdef VERIFY
+ r->reduced = 1;
+ r->normalized = 1;
+#endif
+}
+
+// TODO: not constant time!
+int static inline secp256k1_fe_is_zero(const secp256k1_fe_t *a) {
+#ifdef VERIFY
+ assert(a->normalized);
+#endif
+ return (a->n[0] == 0 && a->n[1] == 0 && a->n[2] == 0 && a->n[3] == 0);
+}
+
+int static inline secp256k1_fe_is_odd(const secp256k1_fe_t *a) {
+#ifdef VERIFY
+ assert(a->normalized);
+#endif
+ return a->n[0] & 1;
+}
+
+// TODO: not constant time!
+int static inline secp256k1_fe_equal(const secp256k1_fe_t *a, const secp256k1_fe_t *b) {
+#ifdef VERIFY
+ assert(a->normalized);
+ assert(b->normalized);
+#endif
+ return (a->n[0] == b->n[0] && a->n[1] == b->n[1] && a->n[2] == b->n[2] && a->n[3] == b->n[3]);
+}
+
+void static secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) {
+ r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;
+ for (int i=0; i<32; i++) {
+ r->n[i/8] |= (uint64_t)a[31-i] << (i&7)*8;
+ }
+#ifdef VERIFY
+ r->reduced = 1;
+ r->normalized = 0;
+#endif
+}
+
+/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
+void static secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a) {
+#ifdef VERIFY
+ assert(a->normalized);
+#endif
+ for (int i=0; i<32; i++) {
+ r[31-i] = a->n[i/8] >> ((i&7)*8);
+ }
+}
+
+void static inline secp256k1_fe_negate(secp256k1_fe_t *r, const secp256k1_fe_t *ac, int m) {
+ secp256k1_fe_t a = *ac;
+ secp256k1_fe_reduce(&a);
+ unsigned __int128 c = (unsigned __int128)(~a.n[0]) + LAST_LIMB + 1;
+ r->n[0] = c;
+ c = (c >> 64) + (~a.n[1]) + FULL_LIMB;
+ r->n[1] = c;
+ c = (c >> 64) + (~a.n[2]) + FULL_LIMB;
+ r->n[2] = c;
+ c = (c >> 64) + (~a.n[3]) + FULL_LIMB;
+ r->n[3] = c;
+ r->n[4] = 0;
+#ifdef VERIFY
+ r->reduced = 1;
+ r->normalized = 0;
+#endif
+}
+
+void static inline secp256k1_fe_mul_int(secp256k1_fe_t *r, int a) {
+#ifdef VERIFY
+ r->reduced = 0;
+ r->normalized = 0;
+#endif
+ unsigned __int128 c = (unsigned __int128)r->n[0] * a;
+ r->n[0] = c;
+ c = (c >> 64) + (unsigned __int128)r->n[1] * a;
+ r->n[1] = c;
+ c = (c >> 64) + (unsigned __int128)r->n[2] * a;
+ r->n[2] = c;
+ c = (c >> 64) + (unsigned __int128)r->n[3] * a;
+ r->n[3] = c;
+ c = (c >> 64) + (unsigned __int128)r->n[4] * a;
+ r->n[4] = c;
+}
+
+void static inline secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
+#ifdef VERIFY
+ r->reduced = 0;
+ r->normalized = 0;
+#endif
+ unsigned __int128 c = (unsigned __int128)r->n[0] + a->n[0];
+ r->n[0] = c;
+ c = (unsigned __int128)r->n[1] + a->n[1] + (c >> 64);
+ r->n[1] = c;
+ c = (unsigned __int128)r->n[2] + a->n[2] + (c >> 64);
+ r->n[2] = c;
+ c = (unsigned __int128)r->n[3] + a->n[3] + (c >> 64);
+ r->n[3] = c;
+ c = (unsigned __int128)r->n[4] + a->n[4] + (c >> 64);
+ r->n[4] = c;
+ assert((c >> 64) == 0);
+}
+
+#if 0
+#define muladd_c3(a,b,c0,c1,c2) { \
+ unsigned __int128 q1 = ((unsigned __int128)(a)) * (b) + (c0); \
+ (c0) = q1; \
+ unsigned __int128 q2 = (q1 >> 64) + (c1) + (((unsigned __int128)(c2)) << 64); \
+ (c1) = q2; \
+ (c2) = q2 >> 64; \
+}
+
+#define sqradd_c3(a,c0,c1,c2) muladd_c3(a,a,c0,c1,c2)
+
+/*#define muladd_c3(a,b,c0,c1,c2) { \
+ unsigned __int128 q = (unsigned __int128)(a) * (b) + (c0); \
+ (c0) = q; \
+ (c1) += (q >> 64); \
+ (c2) += ((c1) < (q >> 64))?1:0; \
+}*/
+
+#define muladd2_c3(a,b,c0,c1,c2) { \
+ unsigned __int128 q = (unsigned __int128)(a) * (b); \
+ uint64_t t1 = (q >> 64); \
+ uint64_t t0 = q; \
+ uint64_t t2 = t1+t1; (c2) += (t2<t1)?1:0; \
+ t1 = t0+t0; t2 += (t1<t0)?1:0; \
+ (c0) += t1; t2 += ((c0)<t1)?1:0; \
+ (c1) += t2; (c2) += ((c1)<t2)?1:0; \
+}
+
+/*#define muladd2_c3(a,b,c0,c1,c2) { \
+ muladd_c3(a,b,c0,c1,c2); \
+ muladd_c3(a,b,c0,c1,c2); \
+}*/
+#else
+
+#define muladd_c3(a,b,c0,c1,c2) { \
+ register uint64_t t1, t2; \
+ asm ("mulq %3" \
+ : "=a"(t1),"=d"(t2) \
+ : "a"(a),"m"(b) \
+ : "cc"); \
+ asm ("addq %2,%0; adcq %3,%1" \
+ : "+r"(c0),"+d"(t2) \
+ : "a"(t1),"g"(0) \
+ : "cc"); \
+ asm ("addq %2,%0; adcq %3,%1" \
+ : "+r"(c1),"+r"(c2) \
+ : "d"(t2),"g"(0) \
+ : "cc"); \
+ }
+
+#define sqradd_c3(a,c0,c1,c2) { \
+ register uint64_t t1, t2; \
+ asm ("mulq %2" \
+ : "=a"(t1),"=d"(t2) \
+ : "a"(a) \
+ : "cc"); \
+ asm ("addq %2,%0; adcq %3,%1" \
+ : "+r"(c0),"+d"(t2) \
+ : "a"(t1),"g"(0) \
+ : "cc"); \
+ asm ("addq %2,%0; adcq %3,%1" \
+ : "+r"(c1),"+r"(c2) \
+ : "d"(t2),"g"(0) \
+ : "cc"); \
+ }
+
+#define muladd2_c3(a,b,c0,c1,c2) { \
+ register uint64_t t1, t2; \
+ asm ("mulq %3" \
+ : "=a"(t1),"=d"(t2) \
+ : "a"(a),"m"(b) \
+ : "cc"); \
+ asm ("addq %0,%0; adcq %2,%1" \
+ : "+d"(t2),"+r"(c2) \
+ : "g"(0) \
+ : "cc"); \
+ asm ("addq %0,%0; adcq %2,%1" \
+ : "+a"(t1),"+d"(t2) \
+ : "g"(0) \
+ : "cc"); \
+ asm ("addq %2,%0; adcq %3,%1" \
+ : "+r"(c0),"+d"(t2) \
+ : "a"(t1),"g"(0) \
+ : "cc"); \
+ asm ("addq %2,%0; adcq %3,%1" \
+ : "+r"(c1),"+r"(c2) \
+ : "d"(t2),"g"(0) \
+ : "cc"); \
+ }
+#endif
+
+#define mul_c2(a,b,c0,c1) { \
+ unsigned __int128 q = (unsigned __int128)(a) * (b); \
+ (c0) = q; \
+ (c1) = (q >> 64); \
+}
+
+void static secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *ac, const secp256k1_fe_t *bc) {
+
+ secp256k1_fe_t a = *ac, b = *bc;
+ secp256k1_fe_reduce(&a);
+ secp256k1_fe_reduce(&b);
+
+#ifdef USE_FIELD_5X64_ASM
+ secp256k1_fe_mul_inner((&a)->n,(&b)->n,r->n);
+#else
+ uint64_t c1,c2,c3;
+ c3=0;
+ mul_c2(a.n[0], b.n[0], c1, c2);
+ uint64_t r0 = c1; c1 = 0;
+ muladd_c3(a.n[0], b.n[1], c2, c3, c1);
+ muladd_c3(a.n[1], b.n[0], c2, c3, c1);
+ uint64_t r1 = c2; c2 = 0;
+ muladd_c3(a.n[2], b.n[0], c3, c1, c2);
+ muladd_c3(a.n[1], b.n[1], c3, c1, c2);
+ muladd_c3(a.n[0], b.n[2], c3, c1, c2);
+ uint64_t r2 = c3; c3 = 0;
+ muladd_c3(a.n[0], b.n[3], c1, c2, c3);
+ muladd_c3(a.n[1], b.n[2], c1, c2, c3);
+ muladd_c3(a.n[2], b.n[1], c1, c2, c3);
+ muladd_c3(a.n[3], b.n[0], c1, c2, c3);
+ uint64_t r3 = c1; c1 = 0;
+ muladd_c3(a.n[3], b.n[1], c2, c3, c1);
+ muladd_c3(a.n[2], b.n[2], c2, c3, c1);
+ muladd_c3(a.n[1], b.n[3], c2, c3, c1);
+ uint64_t r4 = c2; c2 = 0;
+ muladd_c3(a.n[2], b.n[3], c3, c1, c2);
+ muladd_c3(a.n[3], b.n[2], c3, c1, c2);
+ uint64_t r5 = c3; c3 = 0;
+ muladd_c3(a.n[3], b.n[3], c1, c2, c3);
+ uint64_t r6 = c1;
+ uint64_t r7 = c2;
+ assert(c3 == 0);
+ unsigned __int128 c = (unsigned __int128)r4 * COMP_LIMB + r0;
+ r->n[0] = c;
+ c = (unsigned __int128)r5 * COMP_LIMB + r1 + (c >> 64);
+ r->n[1] = c;
+ c = (unsigned __int128)r6 * COMP_LIMB + r2 + (c >> 64);
+ r->n[2] = c;
+ c = (unsigned __int128)r7 * COMP_LIMB + r3 + (c >> 64);
+ r->n[3] = c;
+ r->n[4] = c >> 64;
+#endif
+
+#ifdef VERIFY
+ r->normalized = 0;
+ r->reduced = 0;
+#endif
+ secp256k1_fe_reduce(r);
+}
+
+/*void static secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
+ secp256k1_fe_mul(r, a, a);
+}*/
+
+void static secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *ac) {
+ secp256k1_fe_t a = *ac;
+ secp256k1_fe_reduce(&a);
+
+#ifdef USE_FIELD_5X64_ASM
+ secp256k1_fe_sqr_inner((&a)->n,r->n);
+#else
+ uint64_t c1,c2,c3;
+ c3=0;
+ mul_c2(a.n[0], a.n[0], c1, c2);
+ uint64_t r0 = c1; c1 = 0;
+ muladd2_c3(a.n[0], a.n[1], c2, c3, c1);
+ uint64_t r1 = c2; c2 = 0;
+ muladd2_c3(a.n[2], a.n[0], c3, c1, c2);
+ sqradd_c3(a.n[1], c3, c1, c2);
+ uint64_t r2 = c3; c3 = 0;
+ muladd2_c3(a.n[0], a.n[3], c1, c2, c3);
+ muladd2_c3(a.n[1], a.n[2], c1, c2, c3);
+ uint64_t r3 = c1; c1 = 0;
+ muladd2_c3(a.n[3], a.n[1], c2, c3, c1);
+ sqradd_c3(a.n[2], c2, c3, c1);
+ uint64_t r4 = c2; c2 = 0;
+ muladd2_c3(a.n[2], a.n[3], c3, c1, c2);
+ uint64_t r5 = c3; c3 = 0;
+ sqradd_c3(a.n[3], c1, c2, c3);
+ uint64_t r6 = c1;
+ uint64_t r7 = c2;
+ assert(c3 == 0);
+ unsigned __int128 c = (unsigned __int128)r4 * COMP_LIMB + r0;
+ r->n[0] = c;
+ c = (unsigned __int128)r5 * COMP_LIMB + r1 + (c >> 64);
+ r->n[1] = c;
+ c = (unsigned __int128)r6 * COMP_LIMB + r2 + (c >> 64);
+ r->n[2] = c;
+ c = (unsigned __int128)r7 * COMP_LIMB + r3 + (c >> 64);
+ r->n[3] = c;
+ r->n[4] = c >> 64;
+#endif
+
+#ifdef VERIFY
+ r->normalized = 0;
+ r->reduced = 0;
+#endif
+ secp256k1_fe_reduce(r);
+}
+
+#endif
diff --git a/crypto/secp256k1/secp256k1/src/impl/field_5x64_asm.h b/crypto/secp256k1/secp256k1/src/impl/field_5x64_asm.h
new file mode 100644
index 000000000..93c6ab6b5
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/src/impl/field_5x64_asm.h
@@ -0,0 +1,11 @@
+// Copyright (c) 2013 Pieter Wuille
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef _SECP256K1_FIELD_INNER5X52_IMPL_H_
+#define _SECP256K1_FIELD_INNER5X52_IMPL_H_
+
+void __attribute__ ((sysv_abi)) secp256k1_fe_mul_inner(const uint64_t *a, const uint64_t *b, uint64_t *r);
+void __attribute__ ((sysv_abi)) secp256k1_fe_sqr_inner(const uint64_t *a, uint64_t *r);
+
+#endif
diff --git a/crypto/secp256k1/secp256k1/src/impl/field_gmp.h b/crypto/secp256k1/secp256k1/src/impl/field_gmp.h
new file mode 100644
index 000000000..6172ef48e
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/src/impl/field_gmp.h
@@ -0,0 +1,155 @@
+// Copyright (c) 2013 Pieter Wuille
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef _SECP256K1_FIELD_REPR_IMPL_H_
+#define _SECP256K1_FIELD_REPR_IMPL_H_
+
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include "../num.h"
+#include "../field.h"
+
+static mp_limb_t secp256k1_field_p[FIELD_LIMBS];
+static mp_limb_t secp256k1_field_pc[(33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS];
+
+void static secp256k1_fe_inner_start(void) {
+ for (int i=0; i<(33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; i++)
+ secp256k1_field_pc[i] = 0;
+ secp256k1_field_pc[0] += 0x3D1UL;
+ secp256k1_field_pc[32/GMP_NUMB_BITS] += (1UL << (32 % GMP_NUMB_BITS));
+ for (int i=0; i<FIELD_LIMBS; i++) {
+ secp256k1_field_p[i] = 0;
+ }
+ mpn_sub(secp256k1_field_p, secp256k1_field_p, FIELD_LIMBS, secp256k1_field_pc, (33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS);
+}
+
+void static secp256k1_fe_inner_stop(void) {
+}
+
+void static secp256k1_fe_normalize(secp256k1_fe_t *r) {
+ if (r->n[FIELD_LIMBS] != 0) {
+#if (GMP_NUMB_BITS >= 40)
+ mp_limb_t carry = mpn_add_1(r->n, r->n, FIELD_LIMBS, 0x1000003D1ULL * r->n[FIELD_LIMBS]);
+ mpn_add_1(r->n, r->n, FIELD_LIMBS, 0x1000003D1ULL * carry);
+#else
+ mp_limb_t carry = mpn_add_1(r->n, r->n, FIELD_LIMBS, 0x3D1UL * r->n[FIELD_LIMBS]) +
+ mpn_add_1(r->n+(32/GMP_NUMB_BITS), r->n+(32/GMP_NUMB_BITS), FIELD_LIMBS-(32/GMP_NUMB_BITS), r->n[FIELD_LIMBS] << (32 % GMP_NUMB_BITS));
+ mpn_add_1(r->n, r->n, FIELD_LIMBS, 0x3D1UL * carry);
+ mpn_add_1(r->n+(32/GMP_NUMB_BITS), r->n+(32/GMP_NUMB_BITS), FIELD_LIMBS-(32/GMP_NUMB_BITS), carry << (32%GMP_NUMB_BITS));
+#endif
+ r->n[FIELD_LIMBS] = 0;
+ }
+ if (mpn_cmp(r->n, secp256k1_field_p, FIELD_LIMBS) >= 0)
+ mpn_sub(r->n, r->n, FIELD_LIMBS, secp256k1_field_p, FIELD_LIMBS);
+}
+
+void static inline secp256k1_fe_set_int(secp256k1_fe_t *r, int a) {
+ r->n[0] = a;
+ for (int i=1; i<FIELD_LIMBS+1; i++)
+ r->n[i] = 0;
+}
+
+int static inline secp256k1_fe_is_zero(const secp256k1_fe_t *a) {
+ int ret = 1;
+ for (int i=0; i<FIELD_LIMBS+1; i++)
+ ret &= (a->n[i] == 0);
+ return ret;
+}
+
+int static inline secp256k1_fe_is_odd(const secp256k1_fe_t *a) {
+ return a->n[0] & 1;
+}
+
+int static inline secp256k1_fe_equal(const secp256k1_fe_t *a, const secp256k1_fe_t *b) {
+ int ret = 1;
+ for (int i=0; i<FIELD_LIMBS+1; i++)
+ ret &= (a->n[i] == b->n[i]);
+ return ret;
+}
+
+void static secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) {
+ for (int i=0; i<FIELD_LIMBS+1; i++)
+ r->n[i] = 0;
+ for (int i=0; i<256; i++) {
+ int limb = i/GMP_NUMB_BITS;
+ int shift = i%GMP_NUMB_BITS;
+ r->n[limb] |= (mp_limb_t)((a[31-i/8] >> (i%8)) & 0x1) << shift;
+ }
+}
+
+/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
+void static secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a) {
+ for (int i=0; i<32; i++) {
+ int c = 0;
+ for (int j=0; j<8; j++) {
+ int limb = (8*i+j)/GMP_NUMB_BITS;
+ int shift = (8*i+j)%GMP_NUMB_BITS;
+ c |= ((a->n[limb] >> shift) & 0x1) << j;
+ }
+ r[31-i] = c;
+ }
+}
+
+void static inline secp256k1_fe_negate(secp256k1_fe_t *r, const secp256k1_fe_t *a, int m) {
+ *r = *a;
+ secp256k1_fe_normalize(r);
+ for (int i=0; i<FIELD_LIMBS; i++)
+ r->n[i] = ~(r->n[i]);
+#if (GMP_NUMB_BITS >= 33)
+ mpn_sub_1(r->n, r->n, FIELD_LIMBS, 0x1000003D0ULL);
+#else
+ mpn_sub_1(r->n, r->n, FIELD_LIMBS, 0x3D0UL);
+ mpn_sub_1(r->n+(32/GMP_NUMB_BITS), r->n+(32/GMP_NUMB_BITS), FIELD_LIMBS-(32/GMP_NUMB_BITS), 0x1UL << (32%GMP_NUMB_BITS));
+#endif
+}
+
+void static inline secp256k1_fe_mul_int(secp256k1_fe_t *r, int a) {
+ mpn_mul_1(r->n, r->n, FIELD_LIMBS+1, a);
+}
+
+void static inline secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
+ mpn_add(r->n, r->n, FIELD_LIMBS+1, a->n, FIELD_LIMBS+1);
+}
+
+void static secp256k1_fe_reduce(secp256k1_fe_t *r, mp_limb_t *tmp) {
+ // <A1 A2 A3 A4> <B1 B2 B3 B4>
+ // B1 B2 B3 B4
+ // + C * A1 A2 A3 A4
+ // + A1 A2 A3 A4
+
+#if (GMP_NUMB_BITS >= 33)
+ mp_limb_t o = mpn_addmul_1(tmp, tmp+FIELD_LIMBS, FIELD_LIMBS, 0x1000003D1ULL);
+#else
+ mp_limb_t o = mpn_addmul_1(tmp, tmp+FIELD_LIMBS, FIELD_LIMBS, 0x3D1UL) +
+ mpn_addmul_1(tmp+(32/GMP_NUMB_BITS), tmp+FIELD_LIMBS, FIELD_LIMBS-(32/GMP_NUMB_BITS), 0x1UL << (32%GMP_NUMB_BITS));
+#endif
+ mp_limb_t q[1+(33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS];
+ q[(33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS] = mpn_mul_1(q, secp256k1_field_pc, (33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS, o);
+#if (GMP_NUMB_BITS <= 32)
+ mp_limb_t o2 = tmp[2*FIELD_LIMBS-(32/GMP_NUMB_BITS)] << (32%GMP_NUMB_BITS);
+ q[(33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS] += mpn_addmul_1(q, secp256k1_field_pc, (33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS, o2);
+#endif
+ r->n[FIELD_LIMBS] = mpn_add(r->n, tmp, FIELD_LIMBS, q, 1+(33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS);
+}
+
+void static secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t *b) {
+ secp256k1_fe_t ac = *a;
+ secp256k1_fe_t bc = *b;
+ secp256k1_fe_normalize(&ac);
+ secp256k1_fe_normalize(&bc);
+ mp_limb_t tmp[2*FIELD_LIMBS];
+ mpn_mul_n(tmp, ac.n, bc.n, FIELD_LIMBS);
+ secp256k1_fe_reduce(r, tmp);
+}
+
+void static secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
+ secp256k1_fe_t ac = *a;
+ secp256k1_fe_normalize(&ac);
+ mp_limb_t tmp[2*FIELD_LIMBS];
+ mpn_sqr(tmp, ac.n, FIELD_LIMBS);
+ secp256k1_fe_reduce(r, tmp);
+}
+
+#endif
diff --git a/crypto/secp256k1/secp256k1/src/impl/group.h b/crypto/secp256k1/secp256k1/src/impl/group.h
new file mode 100644
index 000000000..ce8d7b204
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/src/impl/group.h
@@ -0,0 +1,397 @@
+// Copyright (c) 2013 Pieter Wuille
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef _SECP256K1_GROUP_IMPL_H_
+#define _SECP256K1_GROUP_IMPL_H_
+
+#include <string.h>
+
+#include "../num.h"
+#include "../field.h"
+#include "../group.h"
+
+void static secp256k1_ge_set_infinity(secp256k1_ge_t *r) {
+ r->infinity = 1;
+}
+
+void static secp256k1_ge_set_xy(secp256k1_ge_t *r, const secp256k1_fe_t *x, const secp256k1_fe_t *y) {
+ r->infinity = 0;
+ r->x = *x;
+ r->y = *y;
+}
+
+int static secp256k1_ge_is_infinity(const secp256k1_ge_t *a) {
+ return a->infinity;
+}
+
+void static secp256k1_ge_neg(secp256k1_ge_t *r, const secp256k1_ge_t *a) {
+ r->infinity = a->infinity;
+ r->x = a->x;
+ r->y = a->y;
+ secp256k1_fe_normalize(&r->y);
+ secp256k1_fe_negate(&r->y, &r->y, 1);
+}
+
+void static secp256k1_ge_get_hex(char *r, int *rlen, const secp256k1_ge_t *a) {
+ char cx[65]; int lx=65;
+ char cy[65]; int ly=65;
+ secp256k1_fe_get_hex(cx, &lx, &a->x);
+ secp256k1_fe_get_hex(cy, &ly, &a->y);
+ lx = strlen(cx);
+ ly = strlen(cy);
+ int len = lx + ly + 3 + 1;
+ if (*rlen < len) {
+ *rlen = len;
+ return;
+ }
+ *rlen = len;
+ r[0] = '(';
+ memcpy(r+1, cx, lx);
+ r[1+lx] = ',';
+ memcpy(r+2+lx, cy, ly);
+ r[2+lx+ly] = ')';
+ r[3+lx+ly] = 0;
+}
+
+void static secp256k1_ge_set_gej(secp256k1_ge_t *r, secp256k1_gej_t *a) {
+ secp256k1_fe_inv_var(&a->z, &a->z);
+ secp256k1_fe_t z2; secp256k1_fe_sqr(&z2, &a->z);
+ secp256k1_fe_t z3; secp256k1_fe_mul(&z3, &a->z, &z2);
+ secp256k1_fe_mul(&a->x, &a->x, &z2);
+ secp256k1_fe_mul(&a->y, &a->y, &z3);
+ secp256k1_fe_set_int(&a->z, 1);
+ r->infinity = a->infinity;
+ r->x = a->x;
+ r->y = a->y;
+}
+
+void static secp256k1_gej_set_infinity(secp256k1_gej_t *r) {
+ r->infinity = 1;
+}
+
+void static secp256k1_gej_set_xy(secp256k1_gej_t *r, const secp256k1_fe_t *x, const secp256k1_fe_t *y) {
+ r->infinity = 0;
+ r->x = *x;
+ r->y = *y;
+ secp256k1_fe_set_int(&r->z, 1);
+}
+
+void static secp256k1_ge_set_xo(secp256k1_ge_t *r, const secp256k1_fe_t *x, int odd) {
+ r->x = *x;
+ secp256k1_fe_t x2; secp256k1_fe_sqr(&x2, x);
+ secp256k1_fe_t x3; secp256k1_fe_mul(&x3, x, &x2);
+ r->infinity = 0;
+ secp256k1_fe_t c; secp256k1_fe_set_int(&c, 7);
+ secp256k1_fe_add(&c, &x3);
+ secp256k1_fe_sqrt(&r->y, &c);
+ secp256k1_fe_normalize(&r->y);
+ if (secp256k1_fe_is_odd(&r->y) != odd)
+ secp256k1_fe_negate(&r->y, &r->y, 1);
+}
+
+void static secp256k1_gej_set_ge(secp256k1_gej_t *r, const secp256k1_ge_t *a) {
+ r->infinity = a->infinity;
+ r->x = a->x;
+ r->y = a->y;
+ secp256k1_fe_set_int(&r->z, 1);
+}
+
+void static secp256k1_gej_get_x(secp256k1_fe_t *r, const secp256k1_gej_t *a) {
+ secp256k1_fe_t zi2; secp256k1_fe_inv_var(&zi2, &a->z); secp256k1_fe_sqr(&zi2, &zi2);
+ secp256k1_fe_mul(r, &a->x, &zi2);
+}
+
+void static secp256k1_gej_neg(secp256k1_gej_t *r, const secp256k1_gej_t *a) {
+ r->infinity = a->infinity;
+ r->x = a->x;
+ r->y = a->y;
+ r->z = a->z;
+ secp256k1_fe_normalize(&r->y);
+ secp256k1_fe_negate(&r->y, &r->y, 1);
+}
+
+int static secp256k1_gej_is_infinity(const secp256k1_gej_t *a) {
+ return a->infinity;
+}
+
+int static secp256k1_gej_is_valid(const secp256k1_gej_t *a) {
+ if (a->infinity)
+ return 0;
+ // y^2 = x^3 + 7
+ // (Y/Z^3)^2 = (X/Z^2)^3 + 7
+ // Y^2 / Z^6 = X^3 / Z^6 + 7
+ // Y^2 = X^3 + 7*Z^6
+ secp256k1_fe_t y2; secp256k1_fe_sqr(&y2, &a->y);
+ secp256k1_fe_t x3; secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x);
+ secp256k1_fe_t z2; secp256k1_fe_sqr(&z2, &a->z);
+ secp256k1_fe_t z6; secp256k1_fe_sqr(&z6, &z2); secp256k1_fe_mul(&z6, &z6, &z2);
+ secp256k1_fe_mul_int(&z6, 7);
+ secp256k1_fe_add(&x3, &z6);
+ secp256k1_fe_normalize(&y2);
+ secp256k1_fe_normalize(&x3);
+ return secp256k1_fe_equal(&y2, &x3);
+}
+
+int static secp256k1_ge_is_valid(const secp256k1_ge_t *a) {
+ if (a->infinity)
+ return 0;
+ // y^2 = x^3 + 7
+ secp256k1_fe_t y2; secp256k1_fe_sqr(&y2, &a->y);
+ secp256k1_fe_t x3; secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x);
+ secp256k1_fe_t c; secp256k1_fe_set_int(&c, 7);
+ secp256k1_fe_add(&x3, &c);
+ secp256k1_fe_normalize(&y2);
+ secp256k1_fe_normalize(&x3);
+ return secp256k1_fe_equal(&y2, &x3);
+}
+
+void static secp256k1_gej_double(secp256k1_gej_t *r, const secp256k1_gej_t *a) {
+ secp256k1_fe_t t5 = a->y;
+ secp256k1_fe_normalize(&t5);
+ if (a->infinity || secp256k1_fe_is_zero(&t5)) {
+ r->infinity = 1;
+ return;
+ }
+
+ secp256k1_fe_t t1,t2,t3,t4;
+ secp256k1_fe_mul(&r->z, &t5, &a->z);
+ secp256k1_fe_mul_int(&r->z, 2); // Z' = 2*Y*Z (2)
+ secp256k1_fe_sqr(&t1, &a->x);
+ secp256k1_fe_mul_int(&t1, 3); // T1 = 3*X^2 (3)
+ secp256k1_fe_sqr(&t2, &t1); // T2 = 9*X^4 (1)
+ secp256k1_fe_sqr(&t3, &t5);
+ secp256k1_fe_mul_int(&t3, 2); // T3 = 2*Y^2 (2)
+ secp256k1_fe_sqr(&t4, &t3);
+ secp256k1_fe_mul_int(&t4, 2); // T4 = 8*Y^4 (2)
+ secp256k1_fe_mul(&t3, &a->x, &t3); // T3 = 2*X*Y^2 (1)
+ r->x = t3;
+ secp256k1_fe_mul_int(&r->x, 4); // X' = 8*X*Y^2 (4)
+ secp256k1_fe_negate(&r->x, &r->x, 4); // X' = -8*X*Y^2 (5)
+ secp256k1_fe_add(&r->x, &t2); // X' = 9*X^4 - 8*X*Y^2 (6)
+ secp256k1_fe_negate(&t2, &t2, 1); // T2 = -9*X^4 (2)
+ secp256k1_fe_mul_int(&t3, 6); // T3 = 12*X*Y^2 (6)
+ secp256k1_fe_add(&t3, &t2); // T3 = 12*X*Y^2 - 9*X^4 (8)
+ secp256k1_fe_mul(&r->y, &t1, &t3); // Y' = 36*X^3*Y^2 - 27*X^6 (1)
+ secp256k1_fe_negate(&t2, &t4, 2); // T2 = -8*Y^4 (3)
+ secp256k1_fe_add(&r->y, &t2); // Y' = 36*X^3*Y^2 - 27*X^6 - 8*Y^4 (4)
+ r->infinity = 0;
+}
+
+void static secp256k1_gej_add(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_gej_t *b) {
+ if (a->infinity) {
+ *r = *b;
+ return;
+ }
+ if (b->infinity) {
+ *r = *a;
+ return;
+ }
+ r->infinity = 0;
+ secp256k1_fe_t z22; secp256k1_fe_sqr(&z22, &b->z);
+ secp256k1_fe_t z12; secp256k1_fe_sqr(&z12, &a->z);
+ secp256k1_fe_t u1; secp256k1_fe_mul(&u1, &a->x, &z22);
+ secp256k1_fe_t u2; secp256k1_fe_mul(&u2, &b->x, &z12);
+ secp256k1_fe_t s1; secp256k1_fe_mul(&s1, &a->y, &z22); secp256k1_fe_mul(&s1, &s1, &b->z);
+ secp256k1_fe_t s2; secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &a->z);
+ secp256k1_fe_normalize(&u1);
+ secp256k1_fe_normalize(&u2);
+ if (secp256k1_fe_equal(&u1, &u2)) {
+ secp256k1_fe_normalize(&s1);
+ secp256k1_fe_normalize(&s2);
+ if (secp256k1_fe_equal(&s1, &s2)) {
+ secp256k1_gej_double(r, a);
+ } else {
+ r->infinity = 1;
+ }
+ return;
+ }
+ secp256k1_fe_t h; secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2);
+ secp256k1_fe_t i; secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2);
+ secp256k1_fe_t i2; secp256k1_fe_sqr(&i2, &i);
+ secp256k1_fe_t h2; secp256k1_fe_sqr(&h2, &h);
+ secp256k1_fe_t h3; secp256k1_fe_mul(&h3, &h, &h2);
+ secp256k1_fe_mul(&r->z, &a->z, &b->z); secp256k1_fe_mul(&r->z, &r->z, &h);
+ secp256k1_fe_t t; secp256k1_fe_mul(&t, &u1, &h2);
+ r->x = t; secp256k1_fe_mul_int(&r->x, 2); secp256k1_fe_add(&r->x, &h3); secp256k1_fe_negate(&r->x, &r->x, 3); secp256k1_fe_add(&r->x, &i2);
+ secp256k1_fe_negate(&r->y, &r->x, 5); secp256k1_fe_add(&r->y, &t); secp256k1_fe_mul(&r->y, &r->y, &i);
+ secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_negate(&h3, &h3, 1);
+ secp256k1_fe_add(&r->y, &h3);
+}
+
+void static secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_ge_t *b) {
+ if (a->infinity) {
+ r->infinity = b->infinity;
+ r->x = b->x;
+ r->y = b->y;
+ secp256k1_fe_set_int(&r->z, 1);
+ return;
+ }
+ if (b->infinity) {
+ *r = *a;
+ return;
+ }
+ r->infinity = 0;
+ secp256k1_fe_t z12; secp256k1_fe_sqr(&z12, &a->z);
+ secp256k1_fe_t u1 = a->x; secp256k1_fe_normalize(&u1);
+ secp256k1_fe_t u2; secp256k1_fe_mul(&u2, &b->x, &z12);
+ secp256k1_fe_t s1 = a->y; secp256k1_fe_normalize(&s1);
+ secp256k1_fe_t s2; secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &a->z);
+ secp256k1_fe_normalize(&u1);
+ secp256k1_fe_normalize(&u2);
+ if (secp256k1_fe_equal(&u1, &u2)) {
+ secp256k1_fe_normalize(&s1);
+ secp256k1_fe_normalize(&s2);
+ if (secp256k1_fe_equal(&s1, &s2)) {
+ secp256k1_gej_double(r, a);
+ } else {
+ r->infinity = 1;
+ }
+ return;
+ }
+ secp256k1_fe_t h; secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2);
+ secp256k1_fe_t i; secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2);
+ secp256k1_fe_t i2; secp256k1_fe_sqr(&i2, &i);
+ secp256k1_fe_t h2; secp256k1_fe_sqr(&h2, &h);
+ secp256k1_fe_t h3; secp256k1_fe_mul(&h3, &h, &h2);
+ r->z = a->z; secp256k1_fe_mul(&r->z, &r->z, &h);
+ secp256k1_fe_t t; secp256k1_fe_mul(&t, &u1, &h2);
+ r->x = t; secp256k1_fe_mul_int(&r->x, 2); secp256k1_fe_add(&r->x, &h3); secp256k1_fe_negate(&r->x, &r->x, 3); secp256k1_fe_add(&r->x, &i2);
+ secp256k1_fe_negate(&r->y, &r->x, 5); secp256k1_fe_add(&r->y, &t); secp256k1_fe_mul(&r->y, &r->y, &i);
+ secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_negate(&h3, &h3, 1);
+ secp256k1_fe_add(&r->y, &h3);
+}
+
+void static secp256k1_gej_get_hex(char *r, int *rlen, const secp256k1_gej_t *a) {
+ secp256k1_gej_t c = *a;
+ secp256k1_ge_t t; secp256k1_ge_set_gej(&t, &c);
+ secp256k1_ge_get_hex(r, rlen, &t);
+}
+
+void static secp256k1_gej_mul_lambda(secp256k1_gej_t *r, const secp256k1_gej_t *a) {
+ const secp256k1_fe_t *beta = &secp256k1_ge_consts->beta;
+ *r = *a;
+ secp256k1_fe_mul(&r->x, &r->x, beta);
+}
+
+void static secp256k1_gej_split_exp(secp256k1_num_t *r1, secp256k1_num_t *r2, const secp256k1_num_t *a) {
+ const secp256k1_ge_consts_t *c = secp256k1_ge_consts;
+ secp256k1_num_t bnc1, bnc2, bnt1, bnt2, bnn2;
+
+ secp256k1_num_init(&bnc1);
+ secp256k1_num_init(&bnc2);
+ secp256k1_num_init(&bnt1);
+ secp256k1_num_init(&bnt2);
+ secp256k1_num_init(&bnn2);
+
+ secp256k1_num_copy(&bnn2, &c->order);
+ secp256k1_num_shift(&bnn2, 1);
+
+ secp256k1_num_mul(&bnc1, a, &c->a1b2);
+ secp256k1_num_add(&bnc1, &bnc1, &bnn2);
+ secp256k1_num_div(&bnc1, &bnc1, &c->order);
+
+ secp256k1_num_mul(&bnc2, a, &c->b1);
+ secp256k1_num_add(&bnc2, &bnc2, &bnn2);
+ secp256k1_num_div(&bnc2, &bnc2, &c->order);
+
+ secp256k1_num_mul(&bnt1, &bnc1, &c->a1b2);
+ secp256k1_num_mul(&bnt2, &bnc2, &c->a2);
+ secp256k1_num_add(&bnt1, &bnt1, &bnt2);
+ secp256k1_num_sub(r1, a, &bnt1);
+ secp256k1_num_mul(&bnt1, &bnc1, &c->b1);
+ secp256k1_num_mul(&bnt2, &bnc2, &c->a1b2);
+ secp256k1_num_sub(r2, &bnt1, &bnt2);
+
+ secp256k1_num_free(&bnc1);
+ secp256k1_num_free(&bnc2);
+ secp256k1_num_free(&bnt1);
+ secp256k1_num_free(&bnt2);
+ secp256k1_num_free(&bnn2);
+}
+
+
+void static secp256k1_ge_start(void) {
+ static const unsigned char secp256k1_ge_consts_order[] = {
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,
+ 0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,
+ 0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x41
+ };
+ static const unsigned char secp256k1_ge_consts_g_x[] = {
+ 0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,
+ 0x55,0xA0,0x62,0x95,0xCE,0x87,0x0B,0x07,
+ 0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,
+ 0x59,0xF2,0x81,0x5B,0x16,0xF8,0x17,0x98
+ };
+ static const unsigned char secp256k1_ge_consts_g_y[] = {
+ 0x48,0x3A,0xDA,0x77,0x26,0xA3,0xC4,0x65,
+ 0x5D,0xA4,0xFB,0xFC,0x0E,0x11,0x08,0xA8,
+ 0xFD,0x17,0xB4,0x48,0xA6,0x85,0x54,0x19,
+ 0x9C,0x47,0xD0,0x8F,0xFB,0x10,0xD4,0xB8
+ };
+ // properties of secp256k1's efficiently computable endomorphism
+ static const unsigned char secp256k1_ge_consts_lambda[] = {
+ 0x53,0x63,0xad,0x4c,0xc0,0x5c,0x30,0xe0,
+ 0xa5,0x26,0x1c,0x02,0x88,0x12,0x64,0x5a,
+ 0x12,0x2e,0x22,0xea,0x20,0x81,0x66,0x78,
+ 0xdf,0x02,0x96,0x7c,0x1b,0x23,0xbd,0x72
+ };
+ static const unsigned char secp256k1_ge_consts_beta[] = {
+ 0x7a,0xe9,0x6a,0x2b,0x65,0x7c,0x07,0x10,
+ 0x6e,0x64,0x47,0x9e,0xac,0x34,0x34,0xe9,
+ 0x9c,0xf0,0x49,0x75,0x12,0xf5,0x89,0x95,
+ 0xc1,0x39,0x6c,0x28,0x71,0x95,0x01,0xee
+ };
+ static const unsigned char secp256k1_ge_consts_a1b2[] = {
+ 0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,
+ 0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15
+ };
+ static const unsigned char secp256k1_ge_consts_b1[] = {
+ 0xe4,0x43,0x7e,0xd6,0x01,0x0e,0x88,0x28,
+ 0x6f,0x54,0x7f,0xa9,0x0a,0xbf,0xe4,0xc3
+ };
+ static const unsigned char secp256k1_ge_consts_a2[] = {
+ 0x01,
+ 0x14,0xca,0x50,0xf7,0xa8,0xe2,0xf3,0xf6,
+ 0x57,0xc1,0x10,0x8d,0x9d,0x44,0xcf,0xd8
+ };
+ if (secp256k1_ge_consts == NULL) {
+ secp256k1_ge_consts_t *ret = (secp256k1_ge_consts_t*)malloc(sizeof(secp256k1_ge_consts_t));
+ secp256k1_num_init(&ret->order);
+ secp256k1_num_init(&ret->half_order);
+ secp256k1_num_init(&ret->lambda);
+ secp256k1_num_init(&ret->a1b2);
+ secp256k1_num_init(&ret->a2);
+ secp256k1_num_init(&ret->b1);
+ secp256k1_num_set_bin(&ret->order, secp256k1_ge_consts_order, sizeof(secp256k1_ge_consts_order));
+ secp256k1_num_set_bin(&ret->lambda, secp256k1_ge_consts_lambda, sizeof(secp256k1_ge_consts_lambda));
+ secp256k1_num_set_bin(&ret->a1b2, secp256k1_ge_consts_a1b2, sizeof(secp256k1_ge_consts_a1b2));
+ secp256k1_num_set_bin(&ret->a2, secp256k1_ge_consts_a2, sizeof(secp256k1_ge_consts_a2));
+ secp256k1_num_set_bin(&ret->b1, secp256k1_ge_consts_b1, sizeof(secp256k1_ge_consts_b1));
+ secp256k1_num_copy(&ret->half_order, &ret->order);
+ secp256k1_num_shift(&ret->half_order, 1);
+ secp256k1_fe_set_b32(&ret->beta, secp256k1_ge_consts_beta);
+ secp256k1_fe_t g_x, g_y;
+ secp256k1_fe_set_b32(&g_x, secp256k1_ge_consts_g_x);
+ secp256k1_fe_set_b32(&g_y, secp256k1_ge_consts_g_y);
+ secp256k1_ge_set_xy(&ret->g, &g_x, &g_y);
+ secp256k1_ge_consts = ret;
+ }
+}
+
+void static secp256k1_ge_stop(void) {
+ if (secp256k1_ge_consts != NULL) {
+ secp256k1_ge_consts_t *c = (secp256k1_ge_consts_t*)secp256k1_ge_consts;
+ secp256k1_num_free(&c->order);
+ secp256k1_num_free(&c->half_order);
+ secp256k1_num_free(&c->lambda);
+ secp256k1_num_free(&c->a1b2);
+ secp256k1_num_free(&c->a2);
+ secp256k1_num_free(&c->b1);
+ free((void*)c);
+ secp256k1_ge_consts = NULL;
+ }
+}
+
+#endif
diff --git a/crypto/secp256k1/secp256k1/src/impl/num.h b/crypto/secp256k1/secp256k1/src/impl/num.h
new file mode 100644
index 000000000..fc6d05c3d
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/src/impl/num.h
@@ -0,0 +1,18 @@
+// Copyright (c) 2013 Pieter Wuille
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef _SECP256K1_NUM_IMPL_H_
+#define _SECP256K1_NUM_IMPL_H_
+
+#include "../num.h"
+
+#if defined(USE_NUM_GMP)
+#include "num_gmp.h"
+#elif defined(USE_NUM_OPENSSL)
+#include "num_openssl.h"
+#else
+#error "Please select num implementation"
+#endif
+
+#endif
diff --git a/crypto/secp256k1/secp256k1/src/impl/num_gmp.h b/crypto/secp256k1/secp256k1/src/impl/num_gmp.h
new file mode 100644
index 000000000..067c15180
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/src/impl/num_gmp.h
@@ -0,0 +1,346 @@
+// Copyright (c) 2013 Pieter Wuille
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef _SECP256K1_NUM_REPR_IMPL_H_
+#define _SECP256K1_NUM_REPR_IMPL_H_
+
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <gmp.h>
+
+#include "num.h"
+
+#ifdef VERIFY
+void static secp256k1_num_sanity(const secp256k1_num_t *a) {
+ assert(a->limbs == 1 || (a->limbs > 1 && a->data[a->limbs-1] != 0));
+}
+#else
+#define secp256k1_num_sanity(a) do { } while(0)
+#endif
+
+void static secp256k1_num_init(secp256k1_num_t *r) {
+ r->neg = 0;
+ r->limbs = 1;
+ r->data[0] = 0;
+}
+
+void static secp256k1_num_free(secp256k1_num_t *r) {
+}
+
+void static secp256k1_num_copy(secp256k1_num_t *r, const secp256k1_num_t *a) {
+ *r = *a;
+}
+
+int static secp256k1_num_bits(const secp256k1_num_t *a) {
+ int ret=(a->limbs-1)*GMP_NUMB_BITS;
+ mp_limb_t x=a->data[a->limbs-1];
+ while (x) {
+ x >>= 1;
+ ret++;
+ }
+ return ret;
+}
+
+
+void static secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num_t *a) {
+ unsigned char tmp[65];
+ int len = 0;
+ if (a->limbs>1 || a->data[0] != 0) {
+ len = mpn_get_str(tmp, 256, (mp_limb_t*)a->data, a->limbs);
+ }
+ int shift = 0;
+ while (shift < len && tmp[shift] == 0) shift++;
+ assert(len-shift <= rlen);
+ memset(r, 0, rlen - len + shift);
+ if (len > shift)
+ memcpy(r + rlen - len + shift, tmp + shift, len - shift);
+}
+
+void static secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, unsigned int alen) {
+ assert(alen > 0);
+ assert(alen <= 64);
+ int len = mpn_set_str(r->data, a, alen, 256);
+ assert(len <= NUM_LIMBS*2);
+ r->limbs = len;
+ r->neg = 0;
+ while (r->limbs > 1 && r->data[r->limbs-1]==0) r->limbs--;
+}
+
+void static secp256k1_num_set_int(secp256k1_num_t *r, int a) {
+ r->limbs = 1;
+ r->neg = (a < 0);
+ r->data[0] = (a < 0) ? -a : a;
+}
+
+void static secp256k1_num_add_abs(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
+ mp_limb_t c = mpn_add(r->data, a->data, a->limbs, b->data, b->limbs);
+ r->limbs = a->limbs;
+ if (c != 0) {
+ assert(r->limbs < 2*NUM_LIMBS);
+ r->data[r->limbs++] = c;
+ }
+}
+
+void static secp256k1_num_sub_abs(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
+ mp_limb_t c = mpn_sub(r->data, a->data, a->limbs, b->data, b->limbs);
+ assert(c == 0);
+ r->limbs = a->limbs;
+ while (r->limbs > 1 && r->data[r->limbs-1]==0) r->limbs--;
+}
+
+void static secp256k1_num_mod(secp256k1_num_t *r, const secp256k1_num_t *m) {
+ secp256k1_num_sanity(r);
+ secp256k1_num_sanity(m);
+
+ if (r->limbs >= m->limbs) {
+ mp_limb_t t[2*NUM_LIMBS];
+ mpn_tdiv_qr(t, r->data, 0, r->data, r->limbs, m->data, m->limbs);
+ r->limbs = m->limbs;
+ while (r->limbs > 1 && r->data[r->limbs-1]==0) r->limbs--;
+ }
+
+ if (r->neg && (r->limbs > 1 || r->data[0] != 0)) {
+ secp256k1_num_sub_abs(r, m, r);
+ r->neg = 0;
+ }
+}
+
+void static secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *m) {
+ secp256k1_num_sanity(a);
+ secp256k1_num_sanity(m);
+
+ // mpn_gcdext computes: (G,S) = gcdext(U,V), where
+ // * G = gcd(U,V)
+ // * G = U*S + V*T
+ // * U has equal or more limbs than V, and V has no padding
+ // If we set U to be (a padded version of) a, and V = m:
+ // G = a*S + m*T
+ // G = a*S mod m
+ // Assuming G=1:
+ // S = 1/a mod m
+ assert(m->limbs <= NUM_LIMBS);
+ assert(m->data[m->limbs-1] != 0);
+ mp_limb_t g[NUM_LIMBS+1];
+ mp_limb_t u[NUM_LIMBS+1];
+ mp_limb_t v[NUM_LIMBS+1];
+ for (int i=0; i < m->limbs; i++) {
+ u[i] = (i < a->limbs) ? a->data[i] : 0;
+ v[i] = m->data[i];
+ }
+ mp_size_t sn = NUM_LIMBS+1;
+ mp_size_t gn = mpn_gcdext(g, r->data, &sn, u, m->limbs, v, m->limbs);
+ assert(gn == 1);
+ assert(g[0] == 1);
+ r->neg = a->neg ^ m->neg;
+ if (sn < 0) {
+ mpn_sub(r->data, m->data, m->limbs, r->data, -sn);
+ r->limbs = m->limbs;
+ while (r->limbs > 1 && r->data[r->limbs-1]==0) r->limbs--;
+ } else {
+ r->limbs = sn;
+ }
+}
+
+int static secp256k1_num_is_zero(const secp256k1_num_t *a) {
+ return (a->limbs == 1 && a->data[0] == 0);
+}
+
+int static secp256k1_num_is_odd(const secp256k1_num_t *a) {
+ return a->data[0] & 1;
+}
+
+int static secp256k1_num_is_neg(const secp256k1_num_t *a) {
+ return (a->limbs > 1 || a->data[0] != 0) && a->neg;
+}
+
+int static secp256k1_num_cmp(const secp256k1_num_t *a, const secp256k1_num_t *b) {
+ if (a->limbs > b->limbs) return 1;
+ if (a->limbs < b->limbs) return -1;
+ return mpn_cmp(a->data, b->data, a->limbs);
+}
+
+void static secp256k1_num_subadd(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b, int bneg) {
+ if (!(b->neg ^ bneg ^ a->neg)) { // a and b have the same sign
+ r->neg = a->neg;
+ if (a->limbs >= b->limbs) {
+ secp256k1_num_add_abs(r, a, b);
+ } else {
+ secp256k1_num_add_abs(r, b, a);
+ }
+ } else {
+ if (secp256k1_num_cmp(a, b) > 0) {
+ r->neg = a->neg;
+ secp256k1_num_sub_abs(r, a, b);
+ } else {
+ r->neg = b->neg ^ bneg;
+ secp256k1_num_sub_abs(r, b, a);
+ }
+ }
+}
+
+void static secp256k1_num_add(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
+ secp256k1_num_sanity(a);
+ secp256k1_num_sanity(b);
+ secp256k1_num_subadd(r, a, b, 0);
+}
+
+void static secp256k1_num_sub(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
+ secp256k1_num_sanity(a);
+ secp256k1_num_sanity(b);
+ secp256k1_num_subadd(r, a, b, 1);
+}
+
+void static secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
+ secp256k1_num_sanity(a);
+ secp256k1_num_sanity(b);
+
+ mp_limb_t tmp[2*NUM_LIMBS+1];
+ assert(a->limbs + b->limbs <= 2*NUM_LIMBS+1);
+ if ((a->limbs==1 && a->data[0]==0) || (b->limbs==1 && b->data[0]==0)) {
+ r->limbs = 1;
+ r->neg = 0;
+ r->data[0] = 0;
+ return;
+ }
+ if (a->limbs >= b->limbs)
+ mpn_mul(tmp, a->data, a->limbs, b->data, b->limbs);
+ else
+ mpn_mul(tmp, b->data, b->limbs, a->data, a->limbs);
+ r->limbs = a->limbs + b->limbs;
+ if (r->limbs > 1 && tmp[r->limbs - 1]==0) r->limbs--;
+ assert(r->limbs <= 2*NUM_LIMBS);
+ mpn_copyi(r->data, tmp, r->limbs);
+ r->neg = a->neg ^ b->neg;
+}
+
+void static secp256k1_num_div(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
+ secp256k1_num_sanity(a);
+ secp256k1_num_sanity(b);
+ if (b->limbs > a->limbs) {
+ r->limbs = 1;
+ r->data[0] = 0;
+ r->neg = 0;
+ return;
+ }
+
+ mp_limb_t quo[2*NUM_LIMBS+1];
+ mp_limb_t rem[2*NUM_LIMBS+1];
+ mpn_tdiv_qr(quo, rem, 0, a->data, a->limbs, b->data, b->limbs);
+ mpn_copyi(r->data, quo, a->limbs - b->limbs + 1);
+ r->limbs = a->limbs - b->limbs + 1;
+ while (r->limbs > 1 && r->data[r->limbs - 1]==0) r->limbs--;
+ r->neg = a->neg ^ b->neg;
+}
+
+void static secp256k1_num_mod_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b, const secp256k1_num_t *m) {
+ secp256k1_num_mul(r, a, b);
+ secp256k1_num_mod(r, m);
+}
+
+
+int static secp256k1_num_shift(secp256k1_num_t *r, int bits) {
+ assert(bits <= GMP_NUMB_BITS);
+ mp_limb_t ret = mpn_rshift(r->data, r->data, r->limbs, bits);
+ if (r->limbs>1 && r->data[r->limbs-1]==0) r->limbs--;
+ ret >>= (GMP_NUMB_BITS - bits);
+ return ret;
+}
+
+int static secp256k1_num_get_bit(const secp256k1_num_t *a, int pos) {
+ return (a->limbs*GMP_NUMB_BITS > pos) && ((a->data[pos/GMP_NUMB_BITS] >> (pos % GMP_NUMB_BITS)) & 1);
+}
+
+void static secp256k1_num_inc(secp256k1_num_t *r) {
+ mp_limb_t ret = mpn_add_1(r->data, r->data, r->limbs, (mp_limb_t)1);
+ if (ret) {
+ assert(r->limbs < 2*NUM_LIMBS);
+ r->data[r->limbs++] = ret;
+ }
+}
+
+void static secp256k1_num_set_hex(secp256k1_num_t *r, const char *a, int alen) {
+ static const unsigned char cvt[256] = {
+ 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
+ 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
+ 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
+ 0, 1, 2, 3, 4, 5, 6,7,8,9,0,0,0,0,0,0,
+ 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,
+ 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
+ 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,
+ 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
+ 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
+ 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
+ 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
+ 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
+ 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
+ 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
+ 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
+ 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0
+ };
+ unsigned char num[257] = {};
+ for (int i=0; i<alen; i++) {
+ num[i] = cvt[a[i]];
+ }
+ r->limbs = mpn_set_str(r->data, num, alen, 16);
+ while (r->limbs > 1 && r->data[r->limbs-1] == 0) r->limbs--;
+}
+
+void static secp256k1_num_get_hex(char *r, int rlen, const secp256k1_num_t *a) {
+ static const unsigned char cvt[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+ unsigned char *tmp = malloc(257);
+ mp_size_t len = mpn_get_str(tmp, 16, (mp_limb_t*)a->data, a->limbs);
+ assert(len <= rlen);
+ for (int i=0; i<len; i++) {
+ assert(rlen-len+i >= 0);
+ assert(rlen-len+i < rlen);
+ assert(tmp[i] >= 0);
+ assert(tmp[i] < 16);
+ r[rlen-len+i] = cvt[tmp[i]];
+ }
+ for (int i=0; i<rlen-len; i++) {
+ assert(i >= 0);
+ assert(i < rlen);
+ r[i] = cvt[0];
+ }
+ free(tmp);
+}
+
+void static secp256k1_num_split(secp256k1_num_t *rl, secp256k1_num_t *rh, const secp256k1_num_t *a, int bits) {
+ assert(bits > 0);
+ rh->neg = a->neg;
+ if (bits >= a->limbs * GMP_NUMB_BITS) {
+ *rl = *a;
+ rh->limbs = 1;
+ rh->data[0] = 0;
+ return;
+ }
+ rl->limbs = 0;
+ rl->neg = a->neg;
+ int left = bits;
+ while (left >= GMP_NUMB_BITS) {
+ rl->data[rl->limbs] = a->data[rl->limbs];
+ rl->limbs++;
+ left -= GMP_NUMB_BITS;
+ }
+ if (left == 0) {
+ mpn_copyi(rh->data, a->data + rl->limbs, a->limbs - rl->limbs);
+ rh->limbs = a->limbs - rl->limbs;
+ } else {
+ mpn_rshift(rh->data, a->data + rl->limbs, a->limbs - rl->limbs, left);
+ rh->limbs = a->limbs - rl->limbs;
+ while (rh->limbs>1 && rh->data[rh->limbs-1]==0) rh->limbs--;
+ }
+ if (left > 0) {
+ rl->data[rl->limbs] = a->data[rl->limbs] & ((((mp_limb_t)1) << left) - 1);
+ rl->limbs++;
+ }
+ while (rl->limbs>1 && rl->data[rl->limbs-1]==0) rl->limbs--;
+}
+
+void static secp256k1_num_negate(secp256k1_num_t *r) {
+ r->neg ^= 1;
+}
+
+#endif
diff --git a/crypto/secp256k1/secp256k1/src/impl/num_openssl.h b/crypto/secp256k1/secp256k1/src/impl/num_openssl.h
new file mode 100644
index 000000000..0a54689ac
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/src/impl/num_openssl.h
@@ -0,0 +1,145 @@
+// Copyright (c) 2013 Pieter Wuille
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef _SECP256K1_NUM_REPR_IMPL_H_
+#define _SECP256K1_NUM_REPR_IMPL_H_
+
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <openssl/bn.h>
+#include <openssl/crypto.h>
+
+#include "../num.h"
+
+void static secp256k1_num_init(secp256k1_num_t *r) {
+ BN_init(&r->bn);
+}
+
+void static secp256k1_num_free(secp256k1_num_t *r) {
+ BN_free(&r->bn);
+}
+
+void static secp256k1_num_copy(secp256k1_num_t *r, const secp256k1_num_t *a) {
+ BN_copy(&r->bn, &a->bn);
+}
+
+void static secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num_t *a) {
+ unsigned int size = BN_num_bytes(&a->bn);
+ assert(size <= rlen);
+ memset(r,0,rlen);
+ BN_bn2bin(&a->bn, r + rlen - size);
+}
+
+void static secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, unsigned int alen) {
+ BN_bin2bn(a, alen, &r->bn);
+}
+
+void static secp256k1_num_set_int(secp256k1_num_t *r, int a) {
+ BN_set_word(&r->bn, a < 0 ? -a : a);
+ BN_set_negative(&r->bn, a < 0);
+}
+
+void static secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *m) {
+ BN_CTX *ctx = BN_CTX_new();
+ BN_mod_inverse(&r->bn, &a->bn, &m->bn, ctx);
+ BN_CTX_free(ctx);
+}
+
+void static secp256k1_num_mod_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b, const secp256k1_num_t *m) {
+ BN_CTX *ctx = BN_CTX_new();
+ BN_mod_mul(&r->bn, &a->bn, &b->bn, &m->bn, ctx);
+ BN_CTX_free(ctx);
+}
+
+int static secp256k1_num_cmp(const secp256k1_num_t *a, const secp256k1_num_t *b) {
+ return BN_cmp(&a->bn, &b->bn);
+}
+
+void static secp256k1_num_add(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
+ BN_add(&r->bn, &a->bn, &b->bn);
+}
+
+void static secp256k1_num_sub(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
+ BN_sub(&r->bn, &a->bn, &b->bn);
+}
+
+void static secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
+ BN_CTX *ctx = BN_CTX_new();
+ BN_mul(&r->bn, &a->bn, &b->bn, ctx);
+ BN_CTX_free(ctx);
+}
+
+void static secp256k1_num_div(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
+ BN_CTX *ctx = BN_CTX_new();
+ BN_div(&r->bn, NULL, &a->bn, &b->bn, ctx);
+ BN_CTX_free(ctx);
+}
+
+void static secp256k1_num_mod(secp256k1_num_t *r, const secp256k1_num_t *m) {
+ BN_CTX *ctx = BN_CTX_new();
+ BN_nnmod(&r->bn, &r->bn, &m->bn, ctx);
+ BN_CTX_free(ctx);
+}
+
+int static secp256k1_num_bits(const secp256k1_num_t *a) {
+ return BN_num_bits(&a->bn);
+}
+
+int static secp256k1_num_shift(secp256k1_num_t *r, int bits) {
+ int ret = BN_is_zero(&r->bn) ? 0 : r->bn.d[0] & ((1 << bits) - 1);
+ BN_rshift(&r->bn, &r->bn, bits);
+ return ret;
+}
+
+int static secp256k1_num_is_zero(const secp256k1_num_t *a) {
+ return BN_is_zero(&a->bn);
+}
+
+int static secp256k1_num_is_odd(const secp256k1_num_t *a) {
+ return BN_is_odd(&a->bn);
+}
+
+int static secp256k1_num_is_neg(const secp256k1_num_t *a) {
+ return BN_is_negative(&a->bn);
+}
+
+int static secp256k1_num_get_bit(const secp256k1_num_t *a, int pos) {
+ return BN_is_bit_set(&a->bn, pos);
+}
+
+void static secp256k1_num_inc(secp256k1_num_t *r) {
+ BN_add_word(&r->bn, 1);
+}
+
+void static secp256k1_num_set_hex(secp256k1_num_t *r, const char *a, int alen) {
+ char *str = (char*)malloc(alen+1);
+ memcpy(str, a, alen);
+ str[alen] = 0;
+ BIGNUM *pbn = &r->bn;
+ BN_hex2bn(&pbn, str);
+ free(str);
+}
+
+void static secp256k1_num_get_hex(char *r, int rlen, const secp256k1_num_t *a) {
+ char *str = BN_bn2hex(&a->bn);
+ int len = strlen(str);
+ assert(rlen >= len);
+ for (int i=0; i<rlen-len; i++)
+ r[i] = '0';
+ memcpy(r+rlen-len, str, len);
+ OPENSSL_free(str);
+}
+
+void static secp256k1_num_split(secp256k1_num_t *rl, secp256k1_num_t *rh, const secp256k1_num_t *a, int bits) {
+ BN_copy(&rl->bn, &a->bn);
+ BN_rshift(&rh->bn, &a->bn, bits);
+ BN_mask_bits(&rl->bn, bits);
+}
+
+void static secp256k1_num_negate(secp256k1_num_t *r) {
+ BN_set_negative(&r->bn, !BN_is_negative(&r->bn));
+}
+
+#endif
diff --git a/crypto/secp256k1/secp256k1/src/impl/util.h b/crypto/secp256k1/secp256k1/src/impl/util.h
new file mode 100644
index 000000000..a59a00cac
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/src/impl/util.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2013 Pieter Wuille
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef _SECP256K1_UTIL_IMPL_H_
+#define _SECP256K1_UTIL_IMPL_H_
+
+#include <stdint.h>
+#include <string.h>
+
+#include "../util.h"
+
+static inline uint32_t secp256k1_rand32(void) {
+ static uint32_t Rz = 11, Rw = 11;
+ Rz = 36969 * (Rz & 0xFFFF) + (Rz >> 16);
+ Rw = 18000 * (Rw & 0xFFFF) + (Rw >> 16);
+ return (Rw << 16) + (Rw >> 16) + Rz;
+}
+
+static void secp256k1_rand256(unsigned char *b32) {
+ for (int i=0; i<8; i++) {
+ uint32_t r = secp256k1_rand32();
+ b32[i*4 + 0] = (r >> 0) & 0xFF;
+ b32[i*4 + 1] = (r >> 8) & 0xFF;
+ b32[i*4 + 2] = (r >> 16) & 0xFF;
+ b32[i*4 + 3] = (r >> 24) & 0xFF;
+ }
+}
+
+static void secp256k1_rand256_test(unsigned char *b32) {
+ int bits=0;
+ memset(b32, 0, 32);
+ while (bits < 256) {
+ uint32_t ent = secp256k1_rand32();
+ int now = 1 + ((ent % 64)*((ent >> 6) % 32)+16)/31;
+ uint32_t val = 1 & (ent >> 11);
+ while (now > 0 && bits < 256) {
+ b32[bits / 8] |= val << (bits % 8);
+ now--;
+ bits++;
+ }
+ }
+}
+
+#endif
diff --git a/crypto/secp256k1/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java b/crypto/secp256k1/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java
new file mode 100644
index 000000000..90a498eaa
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java
@@ -0,0 +1,60 @@
+package org.bitcoin;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import com.google.common.base.Preconditions;
+
+
+/**
+ * This class holds native methods to handle ECDSA verification.
+ * You can find an example library that can be used for this at
+ * https://github.com/sipa/secp256k1
+ */
+public class NativeSecp256k1 {
+ public static final boolean enabled;
+ static {
+ boolean isEnabled = true;
+ try {
+ System.loadLibrary("javasecp256k1");
+ } catch (UnsatisfiedLinkError e) {
+ isEnabled = false;
+ }
+ enabled = isEnabled;
+ }
+
+ private static ThreadLocal<ByteBuffer> nativeECDSABuffer = new ThreadLocal<ByteBuffer>();
+ /**
+ * Verifies the given secp256k1 signature in native code.
+ * Calling when enabled == false is undefined (probably library not loaded)
+ *
+ * @param data The data which was signed, must be exactly 32 bytes
+ * @param signature The signature
+ * @param pub The public key which did the signing
+ */
+ public static boolean verify(byte[] data, byte[] signature, byte[] pub) {
+ Preconditions.checkArgument(data.length == 32 && signature.length <= 520 && pub.length <= 520);
+
+ ByteBuffer byteBuff = nativeECDSABuffer.get();
+ if (byteBuff == null) {
+ byteBuff = ByteBuffer.allocateDirect(32 + 8 + 520 + 520);
+ byteBuff.order(ByteOrder.nativeOrder());
+ nativeECDSABuffer.set(byteBuff);
+ }
+ byteBuff.rewind();
+ byteBuff.put(data);
+ byteBuff.putInt(signature.length);
+ byteBuff.putInt(pub.length);
+ byteBuff.put(signature);
+ byteBuff.put(pub);
+ return secp256k1_ecdsa_verify(byteBuff) == 1;
+ }
+
+ /**
+ * @param byteBuff signature format is byte[32] data,
+ * native-endian int signatureLength, native-endian int pubkeyLength,
+ * byte[signatureLength] signature, byte[pubkeyLength] pub
+ * @returns 1 for valid signature, anything else for invalid
+ */
+ private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff);
+}
diff --git a/crypto/secp256k1/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c b/crypto/secp256k1/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c
new file mode 100644
index 000000000..ed65cccf6
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c
@@ -0,0 +1,23 @@
+#include "org_bitcoin_NativeSecp256k1.h"
+#include "include/secp256k1.h"
+
+JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify
+ (JNIEnv* env, jclass classObject, jobject byteBufferObject)
+{
+ unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
+ int sigLen = *((int*)(data + 32));
+ int pubLen = *((int*)(data + 32 + 4));
+
+ return secp256k1_ecdsa_verify(data, 32, data+32+8, sigLen, data+32+8+sigLen, pubLen);
+}
+
+static void __javasecp256k1_attach(void) __attribute__((constructor));
+static void __javasecp256k1_detach(void) __attribute__((destructor));
+
+static void __javasecp256k1_attach(void) {
+ secp256k1_start();
+}
+
+static void __javasecp256k1_detach(void) {
+ secp256k1_stop();
+}
diff --git a/crypto/secp256k1/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h b/crypto/secp256k1/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h
new file mode 100644
index 000000000..d7fb004fa
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h
@@ -0,0 +1,21 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class org_bitcoin_NativeSecp256k1 */
+
+#ifndef _Included_org_bitcoin_NativeSecp256k1
+#define _Included_org_bitcoin_NativeSecp256k1
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: org_bitcoin_NativeSecp256k1
+ * Method: secp256k1_ecdsa_verify
+ * Signature: (Ljava/nio/ByteBuffer;)I
+ */
+JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify
+ (JNIEnv *, jclass, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/crypto/secp256k1/secp256k1/src/num.h b/crypto/secp256k1/secp256k1/src/num.h
new file mode 100644
index 000000000..b2e7462bc
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/src/num.h
@@ -0,0 +1,93 @@
+// Copyright (c) 2013 Pieter Wuille
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef _SECP256K1_NUM_
+#define _SECP256K1_NUM_
+
+#if defined(USE_NUM_GMP)
+#include "num_gmp.h"
+#elif defined(USE_NUM_OPENSSL)
+#include "num_openssl.h"
+#else
+#error "Please select num implementation"
+#endif
+
+/** Initialize a number. */
+void static secp256k1_num_init(secp256k1_num_t *r);
+
+/** Free a number. */
+void static secp256k1_num_free(secp256k1_num_t *r);
+
+/** Copy a number. */
+void static secp256k1_num_copy(secp256k1_num_t *r, const secp256k1_num_t *a);
+
+/** Convert a number's absolute value to a binary big-endian string.
+ * There must be enough place. */
+void static secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num_t *a);
+
+/** Set a number to the value of a binary big-endian string. */
+void static secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, unsigned int alen);
+
+/** Set a number equal to a (signed) integer. */
+void static secp256k1_num_set_int(secp256k1_num_t *r, int a);
+
+/** Compute a modular inverse. The input must be less than the modulus. */
+void static secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *m);
+
+/** Multiply two numbers modulo another. */
+void static secp256k1_num_mod_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b, const secp256k1_num_t *m);
+
+/** Compare the absolute value of two numbers. */
+int static secp256k1_num_cmp(const secp256k1_num_t *a, const secp256k1_num_t *b);
+
+/** Add two (signed) numbers. */
+void static secp256k1_num_add(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b);
+
+/** Subtract two (signed) numbers. */
+void static secp256k1_num_sub(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b);
+
+/** Multiply two (signed) numbers. */
+void static secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b);
+
+/** Divide two (signed) numbers. */
+void static secp256k1_num_div(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b);
+
+/** Replace a number by its remainder modulo m. M's sign is ignored. The result is a number between 0 and m-1,
+ even if r was negative. */
+void static secp256k1_num_mod(secp256k1_num_t *r, const secp256k1_num_t *m);
+
+/** Calculate the number of bits in (the absolute value of) a number. */
+int static secp256k1_num_bits(const secp256k1_num_t *a);
+
+/** Right-shift the passed number by bits bits, and return those bits. */
+int static secp256k1_num_shift(secp256k1_num_t *r, int bits);
+
+/** Check whether a number is zero. */
+int static secp256k1_num_is_zero(const secp256k1_num_t *a);
+
+/** Check whether a number is odd. */
+int static secp256k1_num_is_odd(const secp256k1_num_t *a);
+
+/** Check whether a number is strictly negative. */
+int static secp256k1_num_is_neg(const secp256k1_num_t *a);
+
+/** Check whether a particular bit is set in a number. */
+int static secp256k1_num_get_bit(const secp256k1_num_t *a, int pos);
+
+/** Increase a number by 1. */
+void static secp256k1_num_inc(secp256k1_num_t *r);
+
+/** Set a number equal to the value of a hex string (unsigned). */
+void static secp256k1_num_set_hex(secp256k1_num_t *r, const char *a, int alen);
+
+/** Convert (the absolute value of) a number to a hexadecimal string. */
+void static secp256k1_num_get_hex(char *r, int rlen, const secp256k1_num_t *a);
+
+/** Split a number into a low and high part. */
+void static secp256k1_num_split(secp256k1_num_t *rl, secp256k1_num_t *rh, const secp256k1_num_t *a, int bits);
+
+/** Change a number's sign. */
+void static secp256k1_num_negate(secp256k1_num_t *r);
+
+#endif
diff --git a/crypto/secp256k1/secp256k1/src/num_gmp.h b/crypto/secp256k1/secp256k1/src/num_gmp.h
new file mode 100644
index 000000000..960df8605
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/src/num_gmp.h
@@ -0,0 +1,18 @@
+// Copyright (c) 2013 Pieter Wuille
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef _SECP256K1_NUM_REPR_
+#define _SECP256K1_NUM_REPR_
+
+#include <gmp.h>
+
+#define NUM_LIMBS ((256+GMP_NUMB_BITS-1)/GMP_NUMB_BITS)
+
+typedef struct {
+ mp_limb_t data[2*NUM_LIMBS];
+ int neg;
+ int limbs;
+} secp256k1_num_t;
+
+#endif
diff --git a/crypto/secp256k1/secp256k1/src/num_openssl.h b/crypto/secp256k1/secp256k1/src/num_openssl.h
new file mode 100644
index 000000000..7d03757f6
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/src/num_openssl.h
@@ -0,0 +1,14 @@
+// Copyright (c) 2013 Pieter Wuille
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef _SECP256K1_NUM_REPR_
+#define _SECP256K1_NUM_REPR_
+
+#include <openssl/bn.h>
+
+typedef struct {
+ BIGNUM bn;
+} secp256k1_num_t;
+
+#endif
diff --git a/crypto/secp256k1/secp256k1/src/secp256k1.c b/crypto/secp256k1/secp256k1/src/secp256k1.c
new file mode 100644
index 000000000..ed8bf2e95
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/src/secp256k1.c
@@ -0,0 +1,269 @@
+// Copyright (c) 2013 Pieter Wuille
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "impl/num.h"
+#include "impl/field.h"
+#include "impl/group.h"
+#include "impl/ecmult.h"
+#include "impl/ecdsa.h"
+
+void secp256k1_start(void) {
+ secp256k1_fe_start();
+ secp256k1_ge_start();
+ secp256k1_ecmult_start();
+}
+
+void secp256k1_stop(void) {
+ secp256k1_ecmult_stop();
+ secp256k1_ge_stop();
+ secp256k1_fe_stop();
+}
+
+int secp256k1_ecdsa_verify(const unsigned char *msg, int msglen, const unsigned char *sig, int siglen, const unsigned char *pubkey, int pubkeylen) {
+ int ret = -3;
+ secp256k1_num_t m;
+ secp256k1_num_init(&m);
+ secp256k1_ecdsa_sig_t s;
+ secp256k1_ecdsa_sig_init(&s);
+ secp256k1_ge_t q;
+ secp256k1_num_set_bin(&m, msg, msglen);
+
+ if (!secp256k1_ecdsa_pubkey_parse(&q, pubkey, pubkeylen)) {
+ ret = -1;
+ goto end;
+ }
+ if (!secp256k1_ecdsa_sig_parse(&s, sig, siglen)) {
+ ret = -2;
+ goto end;
+ }
+ if (!secp256k1_ecdsa_sig_verify(&s, &q, &m)) {
+ ret = 0;
+ goto end;
+ }
+ ret = 1;
+end:
+ secp256k1_ecdsa_sig_free(&s);
+ secp256k1_num_free(&m);
+ return ret;
+}
+
+int secp256k1_ecdsa_sign(const unsigned char *message, int messagelen, unsigned char *signature, int *signaturelen, const unsigned char *seckey, const unsigned char *nonce) {
+ secp256k1_num_t sec, non, msg;
+ secp256k1_num_init(&sec);
+ secp256k1_num_init(&non);
+ secp256k1_num_init(&msg);
+ secp256k1_num_set_bin(&sec, seckey, 32);
+ secp256k1_num_set_bin(&non, nonce, 32);
+ secp256k1_num_set_bin(&msg, message, messagelen);
+ secp256k1_ecdsa_sig_t sig;
+ secp256k1_ecdsa_sig_init(&sig);
+ int ret = secp256k1_ecdsa_sig_sign(&sig, &sec, &msg, &non, NULL);
+ if (ret) {
+ secp256k1_ecdsa_sig_serialize(signature, signaturelen, &sig);
+ }
+ secp256k1_ecdsa_sig_free(&sig);
+ secp256k1_num_free(&msg);
+ secp256k1_num_free(&non);
+ secp256k1_num_free(&sec);
+ return ret;
+}
+
+int secp256k1_ecdsa_sign_compact(const unsigned char *message, int messagelen, unsigned char *sig64, const unsigned char *seckey, const unsigned char *nonce, int *recid) {
+ secp256k1_num_t sec, non, msg;
+ secp256k1_num_init(&sec);
+ secp256k1_num_init(&non);
+ secp256k1_num_init(&msg);
+ secp256k1_num_set_bin(&sec, seckey, 32);
+ secp256k1_num_set_bin(&non, nonce, 32);
+ secp256k1_num_set_bin(&msg, message, messagelen);
+ secp256k1_ecdsa_sig_t sig;
+ secp256k1_ecdsa_sig_init(&sig);
+ int ret = secp256k1_ecdsa_sig_sign(&sig, &sec, &msg, &non, recid);
+ if (ret) {
+ secp256k1_num_get_bin(sig64, 32, &sig.r);
+ secp256k1_num_get_bin(sig64 + 32, 32, &sig.s);
+ }
+ secp256k1_ecdsa_sig_free(&sig);
+ secp256k1_num_free(&msg);
+ secp256k1_num_free(&non);
+ secp256k1_num_free(&sec);
+ return ret;
+}
+
+int secp256k1_ecdsa_recover_compact(const unsigned char *msg, int msglen, const unsigned char *sig64, unsigned char *pubkey, int *pubkeylen, int compressed, int recid) {
+ int ret = 0;
+ secp256k1_num_t m;
+ secp256k1_num_init(&m);
+ secp256k1_ecdsa_sig_t sig;
+ secp256k1_ecdsa_sig_init(&sig);
+ secp256k1_num_set_bin(&sig.r, sig64, 32);
+ secp256k1_num_set_bin(&sig.s, sig64 + 32, 32);
+ secp256k1_num_set_bin(&m, msg, msglen);
+
+ secp256k1_ge_t q;
+ if (secp256k1_ecdsa_sig_recover(&sig, &q, &m, recid)) {
+ secp256k1_ecdsa_pubkey_serialize(&q, pubkey, pubkeylen, compressed);
+ ret = 1;
+ }
+ secp256k1_ecdsa_sig_free(&sig);
+ secp256k1_num_free(&m);
+ return ret;
+}
+
+int secp256k1_ecdsa_seckey_verify(const unsigned char *seckey) {
+ secp256k1_num_t sec;
+ secp256k1_num_init(&sec);
+ secp256k1_num_set_bin(&sec, seckey, 32);
+ int ret = !secp256k1_num_is_zero(&sec) &&
+ (secp256k1_num_cmp(&sec, &secp256k1_ge_consts->order) < 0);
+ secp256k1_num_free(&sec);
+ return ret;
+}
+
+int secp256k1_ecdsa_pubkey_verify(const unsigned char *pubkey, int pubkeylen) {
+ secp256k1_ge_t q;
+ return secp256k1_ecdsa_pubkey_parse(&q, pubkey, pubkeylen);
+}
+
+int secp256k1_ecdsa_pubkey_create(unsigned char *pubkey, int *pubkeylen, const unsigned char *seckey, int compressed) {
+ secp256k1_num_t sec;
+ secp256k1_num_init(&sec);
+ secp256k1_num_set_bin(&sec, seckey, 32);
+ secp256k1_gej_t pj;
+ secp256k1_ecmult_gen(&pj, &sec);
+ secp256k1_ge_t p;
+ secp256k1_ge_set_gej(&p, &pj);
+ secp256k1_ecdsa_pubkey_serialize(&p, pubkey, pubkeylen, compressed);
+ return 1;
+}
+
+int secp256k1_ecdsa_pubkey_decompress(unsigned char *pubkey, int *pubkeylen) {
+ secp256k1_ge_t p;
+ if (!secp256k1_ecdsa_pubkey_parse(&p, pubkey, *pubkeylen))
+ return 0;
+ secp256k1_ecdsa_pubkey_serialize(&p, pubkey, pubkeylen, 0);
+ return 1;
+}
+
+int secp256k1_ecdsa_privkey_tweak_add(unsigned char *seckey, const unsigned char *tweak) {
+ int ret = 1;
+ secp256k1_num_t term;
+ secp256k1_num_init(&term);
+ secp256k1_num_set_bin(&term, tweak, 32);
+ if (secp256k1_num_cmp(&term, &secp256k1_ge_consts->order) >= 0)
+ ret = 0;
+ secp256k1_num_t sec;
+ secp256k1_num_init(&sec);
+ if (ret) {
+ secp256k1_num_set_bin(&sec, seckey, 32);
+ secp256k1_num_add(&sec, &sec, &term);
+ secp256k1_num_mod(&sec, &secp256k1_ge_consts->order);
+ if (secp256k1_num_is_zero(&sec))
+ ret = 0;
+ }
+ if (ret)
+ secp256k1_num_get_bin(seckey, 32, &sec);
+ secp256k1_num_free(&sec);
+ secp256k1_num_free(&term);
+ return ret;
+}
+
+int secp256k1_ecdsa_pubkey_tweak_add(unsigned char *pubkey, int pubkeylen, const unsigned char *tweak) {
+ int ret = 1;
+ secp256k1_num_t term;
+ secp256k1_num_init(&term);
+ secp256k1_num_set_bin(&term, tweak, 32);
+ if (secp256k1_num_cmp(&term, &secp256k1_ge_consts->order) >= 0)
+ ret = 0;
+ secp256k1_ge_t p;
+ if (ret) {
+ if (!secp256k1_ecdsa_pubkey_parse(&p, pubkey, pubkeylen))
+ ret = 0;
+ }
+ if (ret) {
+ secp256k1_gej_t pt;
+ secp256k1_ecmult_gen(&pt, &term);
+ secp256k1_gej_add_ge(&pt, &pt, &p);
+ if (secp256k1_gej_is_infinity(&pt))
+ ret = 0;
+ secp256k1_ge_set_gej(&p, &pt);
+ int oldlen = pubkeylen;
+ secp256k1_ecdsa_pubkey_serialize(&p, pubkey, &pubkeylen, oldlen <= 33);
+ assert(pubkeylen == oldlen);
+ }
+ secp256k1_num_free(&term);
+ return ret;
+}
+
+int secp256k1_ecdsa_privkey_tweak_mul(unsigned char *seckey, const unsigned char *tweak) {
+ int ret = 1;
+ secp256k1_num_t factor;
+ secp256k1_num_init(&factor);
+ secp256k1_num_set_bin(&factor, tweak, 32);
+ if (secp256k1_num_is_zero(&factor))
+ ret = 0;
+ if (secp256k1_num_cmp(&factor, &secp256k1_ge_consts->order) >= 0)
+ ret = 0;
+ secp256k1_num_t sec;
+ secp256k1_num_init(&sec);
+ if (ret) {
+ secp256k1_num_set_bin(&sec, seckey, 32);
+ secp256k1_num_mod_mul(&sec, &sec, &factor, &secp256k1_ge_consts->order);
+ }
+ if (ret)
+ secp256k1_num_get_bin(seckey, 32, &sec);
+ secp256k1_num_free(&sec);
+ secp256k1_num_free(&factor);
+ return ret;
+}
+
+int secp256k1_ecdsa_pubkey_tweak_mul(unsigned char *pubkey, int pubkeylen, const unsigned char *tweak) {
+ int ret = 1;
+ secp256k1_num_t factor;
+ secp256k1_num_init(&factor);
+ secp256k1_num_set_bin(&factor, tweak, 32);
+ if (secp256k1_num_is_zero(&factor))
+ ret = 0;
+ if (secp256k1_num_cmp(&factor, &secp256k1_ge_consts->order) >= 0)
+ ret = 0;
+ secp256k1_ge_t p;
+ if (ret) {
+ if (!secp256k1_ecdsa_pubkey_parse(&p, pubkey, pubkeylen))
+ ret = 0;
+ }
+ if (ret) {
+ secp256k1_num_t zero;
+ secp256k1_num_init(&zero);
+ secp256k1_num_set_int(&zero, 0);
+ secp256k1_gej_t pt;
+ secp256k1_gej_set_ge(&pt, &p);
+ secp256k1_ecmult(&pt, &pt, &factor, &zero);
+ secp256k1_num_free(&zero);
+ secp256k1_ge_set_gej(&p, &pt);
+ int oldlen = pubkeylen;
+ secp256k1_ecdsa_pubkey_serialize(&p, pubkey, &pubkeylen, oldlen <= 33);
+ assert(pubkeylen == oldlen);
+ }
+ secp256k1_num_free(&factor);
+ return ret;
+}
+
+int secp256k1_ecdsa_privkey_export(const unsigned char *seckey, unsigned char *privkey, int *privkeylen, int compressed) {
+ secp256k1_num_t key;
+ secp256k1_num_init(&key);
+ secp256k1_num_set_bin(&key, seckey, 32);
+ int ret = secp256k1_ecdsa_privkey_serialize(privkey, privkeylen, &key, compressed);
+ secp256k1_num_free(&key);
+ return ret;
+}
+
+int secp256k1_ecdsa_privkey_import(unsigned char *seckey, const unsigned char *privkey, int privkeylen) {
+ secp256k1_num_t key;
+ secp256k1_num_init(&key);
+ int ret = secp256k1_ecdsa_privkey_parse(&key, privkey, privkeylen);
+ if (ret)
+ secp256k1_num_get_bin(seckey, 32, &key);
+ secp256k1_num_free(&key);
+ return ret;
+}
diff --git a/crypto/secp256k1/secp256k1/src/tests.c b/crypto/secp256k1/secp256k1/src/tests.c
new file mode 100644
index 000000000..af7bbaad0
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/src/tests.c
@@ -0,0 +1,465 @@
+// Copyright (c) 2013 Pieter Wuille
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <assert.h>
+
+#include "impl/num.h"
+#include "impl/field.h"
+#include "impl/group.h"
+#include "impl/ecmult.h"
+#include "impl/ecdsa.h"
+#include "impl/util.h"
+
+#ifdef ENABLE_OPENSSL_TESTS
+#include "openssl/bn.h"
+#include "openssl/ec.h"
+#include "openssl/ecdsa.h"
+#include "openssl/obj_mac.h"
+#endif
+
+static int count = 100;
+
+/***** NUM TESTS *****/
+
+void random_num_negate(secp256k1_num_t *num) {
+ if (secp256k1_rand32() & 1)
+ secp256k1_num_negate(num);
+}
+
+void random_num_order_test(secp256k1_num_t *num) {
+ do {
+ unsigned char b32[32];
+ secp256k1_rand256_test(b32);
+ secp256k1_num_set_bin(num, b32, 32);
+ if (secp256k1_num_is_zero(num))
+ continue;
+ if (secp256k1_num_cmp(num, &secp256k1_ge_consts->order) >= 0)
+ continue;
+ break;
+ } while(1);
+}
+
+void random_num_order(secp256k1_num_t *num) {
+ do {
+ unsigned char b32[32];
+ secp256k1_rand256(b32);
+ secp256k1_num_set_bin(num, b32, 32);
+ if (secp256k1_num_is_zero(num))
+ continue;
+ if (secp256k1_num_cmp(num, &secp256k1_ge_consts->order) >= 0)
+ continue;
+ break;
+ } while(1);
+}
+
+void test_num_copy_inc_cmp() {
+ secp256k1_num_t n1,n2;
+ secp256k1_num_init(&n1);
+ secp256k1_num_init(&n2);
+ random_num_order(&n1);
+ secp256k1_num_copy(&n2, &n1);
+ assert(secp256k1_num_cmp(&n1, &n2) == 0);
+ assert(secp256k1_num_cmp(&n2, &n1) == 0);
+ secp256k1_num_inc(&n2);
+ assert(secp256k1_num_cmp(&n1, &n2) != 0);
+ assert(secp256k1_num_cmp(&n2, &n1) != 0);
+ secp256k1_num_free(&n1);
+ secp256k1_num_free(&n2);
+}
+
+
+void test_num_get_set_hex() {
+ secp256k1_num_t n1,n2;
+ secp256k1_num_init(&n1);
+ secp256k1_num_init(&n2);
+ random_num_order_test(&n1);
+ char c[64];
+ secp256k1_num_get_hex(c, 64, &n1);
+ secp256k1_num_set_hex(&n2, c, 64);
+ assert(secp256k1_num_cmp(&n1, &n2) == 0);
+ for (int i=0; i<64; i++) {
+ // check whether the lower 4 bits correspond to the last hex character
+ int low1 = secp256k1_num_shift(&n1, 4);
+ int lowh = c[63];
+ int low2 = (lowh>>6)*9+(lowh-'0')&15;
+ assert(low1 == low2);
+ // shift bits off the hex representation, and compare
+ memmove(c+1, c, 63);
+ c[0] = '0';
+ secp256k1_num_set_hex(&n2, c, 64);
+ assert(secp256k1_num_cmp(&n1, &n2) == 0);
+ }
+ secp256k1_num_free(&n2);
+ secp256k1_num_free(&n1);
+}
+
+void test_num_get_set_bin() {
+ secp256k1_num_t n1,n2;
+ secp256k1_num_init(&n1);
+ secp256k1_num_init(&n2);
+ random_num_order_test(&n1);
+ unsigned char c[32];
+ secp256k1_num_get_bin(c, 32, &n1);
+ secp256k1_num_set_bin(&n2, c, 32);
+ assert(secp256k1_num_cmp(&n1, &n2) == 0);
+ for (int i=0; i<32; i++) {
+ // check whether the lower 8 bits correspond to the last byte
+ int low1 = secp256k1_num_shift(&n1, 8);
+ int low2 = c[31];
+ assert(low1 == low2);
+ // shift bits off the byte representation, and compare
+ memmove(c+1, c, 31);
+ c[0] = 0;
+ secp256k1_num_set_bin(&n2, c, 32);
+ assert(secp256k1_num_cmp(&n1, &n2) == 0);
+ }
+ secp256k1_num_free(&n2);
+ secp256k1_num_free(&n1);
+}
+
+void run_num_int() {
+ secp256k1_num_t n1;
+ secp256k1_num_init(&n1);
+ for (int i=-255; i<256; i++) {
+ unsigned char c1[3] = {};
+ c1[2] = abs(i);
+ unsigned char c2[3] = {0x11,0x22,0x33};
+ secp256k1_num_set_int(&n1, i);
+ secp256k1_num_get_bin(c2, 3, &n1);
+ assert(memcmp(c1, c2, 3) == 0);
+ }
+ secp256k1_num_free(&n1);
+}
+
+void test_num_negate() {
+ secp256k1_num_t n1;
+ secp256k1_num_t n2;
+ secp256k1_num_init(&n1);
+ secp256k1_num_init(&n2);
+ random_num_order_test(&n1); // n1 = R
+ random_num_negate(&n1);
+ secp256k1_num_copy(&n2, &n1); // n2 = R
+ secp256k1_num_sub(&n1, &n2, &n1); // n1 = n2-n1 = 0
+ assert(secp256k1_num_is_zero(&n1));
+ secp256k1_num_copy(&n1, &n2); // n1 = R
+ secp256k1_num_negate(&n1); // n1 = -R
+ assert(!secp256k1_num_is_zero(&n1));
+ secp256k1_num_add(&n1, &n2, &n1); // n1 = n2+n1 = 0
+ assert(secp256k1_num_is_zero(&n1));
+ secp256k1_num_copy(&n1, &n2); // n1 = R
+ secp256k1_num_negate(&n1); // n1 = -R
+ assert(secp256k1_num_is_neg(&n1) != secp256k1_num_is_neg(&n2));
+ secp256k1_num_negate(&n1); // n1 = R
+ assert(secp256k1_num_cmp(&n1, &n2) == 0);
+ assert(secp256k1_num_is_neg(&n1) == secp256k1_num_is_neg(&n2));
+ secp256k1_num_free(&n2);
+ secp256k1_num_free(&n1);
+}
+
+void test_num_add_sub() {
+ secp256k1_num_t n1;
+ secp256k1_num_t n2;
+ secp256k1_num_init(&n1);
+ secp256k1_num_init(&n2);
+ random_num_order_test(&n1); // n1 = R1
+ random_num_negate(&n1);
+ random_num_order_test(&n2); // n2 = R2
+ random_num_negate(&n2);
+ secp256k1_num_t n1p2, n2p1, n1m2, n2m1;
+ secp256k1_num_init(&n1p2);
+ secp256k1_num_init(&n2p1);
+ secp256k1_num_init(&n1m2);
+ secp256k1_num_init(&n2m1);
+ secp256k1_num_add(&n1p2, &n1, &n2); // n1p2 = R1 + R2
+ secp256k1_num_add(&n2p1, &n2, &n1); // n2p1 = R2 + R1
+ secp256k1_num_sub(&n1m2, &n1, &n2); // n1m2 = R1 - R2
+ secp256k1_num_sub(&n2m1, &n2, &n1); // n2m1 = R2 - R1
+ assert(secp256k1_num_cmp(&n1p2, &n2p1) == 0);
+ assert(secp256k1_num_cmp(&n1p2, &n1m2) != 0);
+ secp256k1_num_negate(&n2m1); // n2m1 = -R2 + R1
+ assert(secp256k1_num_cmp(&n2m1, &n1m2) == 0);
+ assert(secp256k1_num_cmp(&n2m1, &n1) != 0);
+ secp256k1_num_add(&n2m1, &n2m1, &n2); // n2m1 = -R2 + R1 + R2 = R1
+ assert(secp256k1_num_cmp(&n2m1, &n1) == 0);
+ assert(secp256k1_num_cmp(&n2p1, &n1) != 0);
+ secp256k1_num_sub(&n2p1, &n2p1, &n2); // n2p1 = R2 + R1 - R2 = R1
+ assert(secp256k1_num_cmp(&n2p1, &n1) == 0);
+ secp256k1_num_free(&n2m1);
+ secp256k1_num_free(&n1m2);
+ secp256k1_num_free(&n2p1);
+ secp256k1_num_free(&n1p2);
+ secp256k1_num_free(&n2);
+ secp256k1_num_free(&n1);
+}
+
+void run_num_smalltests() {
+ for (int i=0; i<100*count; i++) {
+ test_num_copy_inc_cmp();
+ test_num_get_set_hex();
+ test_num_get_set_bin();
+ test_num_negate();
+ test_num_add_sub();
+ }
+ run_num_int();
+}
+
+void run_ecmult_chain() {
+ // random starting point A (on the curve)
+ secp256k1_fe_t ax; secp256k1_fe_set_hex(&ax, "8b30bbe9ae2a990696b22f670709dff3727fd8bc04d3362c6c7bf458e2846004", 64);
+ secp256k1_fe_t ay; secp256k1_fe_set_hex(&ay, "a357ae915c4a65281309edf20504740f0eb3343990216b4f81063cb65f2f7e0f", 64);
+ secp256k1_gej_t a; secp256k1_gej_set_xy(&a, &ax, &ay);
+ // two random initial factors xn and gn
+ secp256k1_num_t xn;
+ secp256k1_num_init(&xn);
+ secp256k1_num_set_hex(&xn, "84cc5452f7fde1edb4d38a8ce9b1b84ccef31f146e569be9705d357a42985407", 64);
+ secp256k1_num_t gn;
+ secp256k1_num_init(&gn);
+ secp256k1_num_set_hex(&gn, "a1e58d22553dcd42b23980625d4c57a96e9323d42b3152e5ca2c3990edc7c9de", 64);
+ // two small multipliers to be applied to xn and gn in every iteration:
+ secp256k1_num_t xf;
+ secp256k1_num_init(&xf);
+ secp256k1_num_set_hex(&xf, "1337", 4);
+ secp256k1_num_t gf;
+ secp256k1_num_init(&gf);
+ secp256k1_num_set_hex(&gf, "7113", 4);
+ // accumulators with the resulting coefficients to A and G
+ secp256k1_num_t ae;
+ secp256k1_num_init(&ae);
+ secp256k1_num_set_int(&ae, 1);
+ secp256k1_num_t ge;
+ secp256k1_num_init(&ge);
+ secp256k1_num_set_int(&ge, 0);
+ // the point being computed
+ secp256k1_gej_t x = a;
+ const secp256k1_num_t *order = &secp256k1_ge_consts->order;
+ for (int i=0; i<200*count; i++) {
+ // in each iteration, compute X = xn*X + gn*G;
+ secp256k1_ecmult(&x, &x, &xn, &gn);
+ // also compute ae and ge: the actual accumulated factors for A and G
+ // if X was (ae*A+ge*G), xn*X + gn*G results in (xn*ae*A + (xn*ge+gn)*G)
+ secp256k1_num_mod_mul(&ae, &ae, &xn, order);
+ secp256k1_num_mod_mul(&ge, &ge, &xn, order);
+ secp256k1_num_add(&ge, &ge, &gn);
+ secp256k1_num_mod(&ge, order);
+ // modify xn and gn
+ secp256k1_num_mod_mul(&xn, &xn, &xf, order);
+ secp256k1_num_mod_mul(&gn, &gn, &gf, order);
+
+ // verify
+ if (i == 19999) {
+ char res[132]; int resl = 132;
+ secp256k1_gej_get_hex(res, &resl, &x);
+ assert(strcmp(res, "(D6E96687F9B10D092A6F35439D86CEBEA4535D0D409F53586440BD74B933E830,B95CBCA2C77DA786539BE8FD53354D2D3B4F566AE658045407ED6015EE1B2A88)") == 0);
+ }
+ }
+ // redo the computation, but directly with the resulting ae and ge coefficients:
+ secp256k1_gej_t x2; secp256k1_ecmult(&x2, &a, &ae, &ge);
+ char res[132]; int resl = 132;
+ char res2[132]; int resl2 = 132;
+ secp256k1_gej_get_hex(res, &resl, &x);
+ secp256k1_gej_get_hex(res2, &resl2, &x2);
+ assert(strcmp(res, res2) == 0);
+ assert(strlen(res) == 131);
+ secp256k1_num_free(&xn);
+ secp256k1_num_free(&gn);
+ secp256k1_num_free(&xf);
+ secp256k1_num_free(&gf);
+ secp256k1_num_free(&ae);
+ secp256k1_num_free(&ge);
+}
+
+void test_point_times_order(const secp256k1_gej_t *point) {
+ // either the point is not on the curve, or multiplying it by the order results in O
+ if (!secp256k1_gej_is_valid(point))
+ return;
+
+ const secp256k1_num_t *order = &secp256k1_ge_consts->order;
+ secp256k1_num_t zero;
+ secp256k1_num_init(&zero);
+ secp256k1_num_set_int(&zero, 0);
+ secp256k1_gej_t res;
+ secp256k1_ecmult(&res, point, order, order); // calc res = order * point + order * G;
+ assert(secp256k1_gej_is_infinity(&res));
+ secp256k1_num_free(&zero);
+}
+
+void run_point_times_order() {
+ secp256k1_fe_t x; secp256k1_fe_set_hex(&x, "02", 2);
+ for (int i=0; i<500; i++) {
+ secp256k1_ge_t p; secp256k1_ge_set_xo(&p, &x, 1);
+ secp256k1_gej_t j; secp256k1_gej_set_ge(&j, &p);
+ test_point_times_order(&j);
+ secp256k1_fe_sqr(&x, &x);
+ }
+ char c[65]; int cl=65;
+ secp256k1_fe_get_hex(c, &cl, &x);
+ assert(strcmp(c, "7603CB59B0EF6C63FE6084792A0C378CDB3233A80F8A9A09A877DEAD31B38C45") == 0);
+}
+
+void test_wnaf(const secp256k1_num_t *number, int w) {
+ secp256k1_num_t x, two, t;
+ secp256k1_num_init(&x);
+ secp256k1_num_init(&two);
+ secp256k1_num_init(&t);
+ secp256k1_num_set_int(&x, 0);
+ secp256k1_num_set_int(&two, 2);
+ int wnaf[257];
+ int bits = secp256k1_ecmult_wnaf(wnaf, number, w);
+ int zeroes = -1;
+ for (int i=bits-1; i>=0; i--) {
+ secp256k1_num_mul(&x, &x, &two);
+ int v = wnaf[i];
+ if (v) {
+ assert(zeroes == -1 || zeroes >= w-1); // check that distance between non-zero elements is at least w-1
+ zeroes=0;
+ assert((v & 1) == 1); // check non-zero elements are odd
+ assert(v <= (1 << (w-1)) - 1); // check range below
+ assert(v >= -(1 << (w-1)) - 1); // check range above
+ } else {
+ assert(zeroes != -1); // check that no unnecessary zero padding exists
+ zeroes++;
+ }
+ secp256k1_num_set_int(&t, v);
+ secp256k1_num_add(&x, &x, &t);
+ }
+ assert(secp256k1_num_cmp(&x, number) == 0); // check that wnaf represents number
+ secp256k1_num_free(&x);
+ secp256k1_num_free(&two);
+ secp256k1_num_free(&t);
+}
+
+void run_wnaf() {
+ secp256k1_num_t n;
+ secp256k1_num_init(&n);
+ for (int i=0; i<count; i++) {
+ random_num_order(&n);
+ if (i % 1)
+ secp256k1_num_negate(&n);
+ test_wnaf(&n, 4+(i%10));
+ }
+ secp256k1_num_free(&n);
+}
+
+void random_sign(secp256k1_ecdsa_sig_t *sig, const secp256k1_num_t *key, const secp256k1_num_t *msg, int *recid) {
+ secp256k1_num_t nonce;
+ secp256k1_num_init(&nonce);
+ do {
+ random_num_order_test(&nonce);
+ } while(!secp256k1_ecdsa_sig_sign(sig, key, msg, &nonce, recid));
+ secp256k1_num_free(&nonce);
+}
+
+void test_ecdsa_sign_verify() {
+ const secp256k1_ge_consts_t *c = secp256k1_ge_consts;
+ secp256k1_num_t msg, key;
+ secp256k1_num_init(&msg);
+ random_num_order_test(&msg);
+ secp256k1_num_init(&key);
+ random_num_order_test(&key);
+ secp256k1_gej_t pubj; secp256k1_ecmult_gen(&pubj, &key);
+ secp256k1_ge_t pub; secp256k1_ge_set_gej(&pub, &pubj);
+ secp256k1_ecdsa_sig_t sig;
+ secp256k1_ecdsa_sig_init(&sig);
+ random_sign(&sig, &key, &msg, NULL);
+ assert(secp256k1_ecdsa_sig_verify(&sig, &pub, &msg));
+ secp256k1_num_inc(&msg);
+ assert(!secp256k1_ecdsa_sig_verify(&sig, &pub, &msg));
+ secp256k1_ecdsa_sig_free(&sig);
+ secp256k1_num_free(&msg);
+ secp256k1_num_free(&key);
+}
+
+void run_ecdsa_sign_verify() {
+ for (int i=0; i<10*count; i++) {
+ test_ecdsa_sign_verify();
+ }
+}
+
+#ifdef ENABLE_OPENSSL_TESTS
+EC_KEY *get_openssl_key(const secp256k1_num_t *key) {
+ unsigned char privkey[300];
+ int privkeylen;
+ int compr = secp256k1_rand32() & 1;
+ const unsigned char* pbegin = privkey;
+ EC_KEY *ec_key = EC_KEY_new_by_curve_name(NID_secp256k1);
+ assert(secp256k1_ecdsa_privkey_serialize(privkey, &privkeylen, key, compr));
+ assert(d2i_ECPrivateKey(&ec_key, &pbegin, privkeylen));
+ assert(EC_KEY_check_key(ec_key));
+ return ec_key;
+}
+
+void test_ecdsa_openssl() {
+ const secp256k1_ge_consts_t *c = secp256k1_ge_consts;
+ secp256k1_num_t key, msg;
+ secp256k1_num_init(&msg);
+ unsigned char message[32];
+ secp256k1_rand256_test(message);
+ secp256k1_num_set_bin(&msg, message, 32);
+ secp256k1_num_init(&key);
+ random_num_order_test(&key);
+ secp256k1_gej_t qj;
+ secp256k1_ecmult_gen(&qj, &key);
+ secp256k1_ge_t q;
+ secp256k1_ge_set_gej(&q, &qj);
+ EC_KEY *ec_key = get_openssl_key(&key);
+ assert(ec_key);
+ unsigned char signature[80];
+ int sigsize = 80;
+ assert(ECDSA_sign(0, message, sizeof(message), signature, &sigsize, ec_key));
+ secp256k1_ecdsa_sig_t sig;
+ secp256k1_ecdsa_sig_init(&sig);
+ assert(secp256k1_ecdsa_sig_parse(&sig, signature, sigsize));
+ assert(secp256k1_ecdsa_sig_verify(&sig, &q, &msg));
+ secp256k1_num_inc(&sig.r);
+ assert(!secp256k1_ecdsa_sig_verify(&sig, &q, &msg));
+
+ random_sign(&sig, &key, &msg, NULL);
+ sigsize = 80;
+ assert(secp256k1_ecdsa_sig_serialize(signature, &sigsize, &sig));
+ assert(ECDSA_verify(0, message, sizeof(message), signature, sigsize, ec_key) == 1);
+
+ secp256k1_ecdsa_sig_free(&sig);
+ EC_KEY_free(ec_key);
+ secp256k1_num_free(&key);
+ secp256k1_num_free(&msg);
+}
+
+void run_ecdsa_openssl() {
+ for (int i=0; i<10*count; i++) {
+ test_ecdsa_openssl();
+ }
+}
+#endif
+
+int main(int argc, char **argv) {
+ if (argc > 1)
+ count = strtol(argv[1], NULL, 0)*47;
+
+ printf("test count = %i\n", count);
+
+ // initialize
+ secp256k1_fe_start();
+ secp256k1_ge_start();
+ secp256k1_ecmult_start();
+
+ // num tests
+ run_num_smalltests();
+
+ // ecmult tests
+ run_wnaf();
+ run_point_times_order();
+ run_ecmult_chain();
+
+ // ecdsa tests
+ run_ecdsa_sign_verify();
+#ifdef ENABLE_OPENSSL_TESTS
+ run_ecdsa_openssl();
+#endif
+
+ // shutdown
+ secp256k1_ecmult_stop();
+ secp256k1_ge_stop();
+ secp256k1_fe_stop();
+ return 0;
+}
diff --git a/crypto/secp256k1/secp256k1/src/util.h b/crypto/secp256k1/secp256k1/src/util.h
new file mode 100644
index 000000000..357c7e06b
--- /dev/null
+++ b/crypto/secp256k1/secp256k1/src/util.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2013 Pieter Wuille
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef _SECP256K1_UTIL_H_
+#define _SECP256K1_UTIL_H_
+
+/** Generate a pseudorandom 32-bit number. */
+static uint32_t secp256k1_rand32(void);
+
+/** Generate a pseudorandom 32-byte array. */
+static void secp256k1_rand256(unsigned char *b32);
+
+/** Generate a pseudorandom 32-byte array with long sequences of zero and one bits. */
+static void secp256k1_rand256_test(unsigned char *b32);
+
+#include "impl/util.h"
+
+#endif
diff --git a/crypto/sha3/keccakf.go b/crypto/sha3/keccakf.go
new file mode 100644
index 000000000..3baf13ba3
--- /dev/null
+++ b/crypto/sha3/keccakf.go
@@ -0,0 +1,171 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sha3
+
+// This file implements the core Keccak permutation function necessary for computing SHA3.
+// This is implemented in a separate file to allow for replacement by an optimized implementation.
+// Nothing in this package is exported.
+// For the detailed specification, refer to the Keccak web site (http://keccak.noekeon.org/).
+
+// rc stores the round constants for use in the ι step.
+var rc = [...]uint64{
+ 0x0000000000000001,
+ 0x0000000000008082,
+ 0x800000000000808A,
+ 0x8000000080008000,
+ 0x000000000000808B,
+ 0x0000000080000001,
+ 0x8000000080008081,
+ 0x8000000000008009,
+ 0x000000000000008A,
+ 0x0000000000000088,
+ 0x0000000080008009,
+ 0x000000008000000A,
+ 0x000000008000808B,
+ 0x800000000000008B,
+ 0x8000000000008089,
+ 0x8000000000008003,
+ 0x8000000000008002,
+ 0x8000000000000080,
+ 0x000000000000800A,
+ 0x800000008000000A,
+ 0x8000000080008081,
+ 0x8000000000008080,
+ 0x0000000080000001,
+ 0x8000000080008008,
+}
+
+// ro_xx represent the rotation offsets for use in the χ step.
+// Defining them as const instead of in an array allows the compiler to insert constant shifts.
+const (
+ ro_00 = 0
+ ro_01 = 36
+ ro_02 = 3
+ ro_03 = 41
+ ro_04 = 18
+ ro_05 = 1
+ ro_06 = 44
+ ro_07 = 10
+ ro_08 = 45
+ ro_09 = 2
+ ro_10 = 62
+ ro_11 = 6
+ ro_12 = 43
+ ro_13 = 15
+ ro_14 = 61
+ ro_15 = 28
+ ro_16 = 55
+ ro_17 = 25
+ ro_18 = 21
+ ro_19 = 56
+ ro_20 = 27
+ ro_21 = 20
+ ro_22 = 39
+ ro_23 = 8
+ ro_24 = 14
+)
+
+// keccakF computes the complete Keccak-f function consisting of 24 rounds with a different
+// constant (rc) in each round. This implementation fully unrolls the round function to avoid
+// inner loops, as well as pre-calculating shift offsets.
+func (d *digest) keccakF() {
+ for _, roundConstant := range rc {
+ // θ step
+ d.c[0] = d.a[0] ^ d.a[5] ^ d.a[10] ^ d.a[15] ^ d.a[20]
+ d.c[1] = d.a[1] ^ d.a[6] ^ d.a[11] ^ d.a[16] ^ d.a[21]
+ d.c[2] = d.a[2] ^ d.a[7] ^ d.a[12] ^ d.a[17] ^ d.a[22]
+ d.c[3] = d.a[3] ^ d.a[8] ^ d.a[13] ^ d.a[18] ^ d.a[23]
+ d.c[4] = d.a[4] ^ d.a[9] ^ d.a[14] ^ d.a[19] ^ d.a[24]
+
+ d.d[0] = d.c[4] ^ (d.c[1]<<1 ^ d.c[1]>>63)
+ d.d[1] = d.c[0] ^ (d.c[2]<<1 ^ d.c[2]>>63)
+ d.d[2] = d.c[1] ^ (d.c[3]<<1 ^ d.c[3]>>63)
+ d.d[3] = d.c[2] ^ (d.c[4]<<1 ^ d.c[4]>>63)
+ d.d[4] = d.c[3] ^ (d.c[0]<<1 ^ d.c[0]>>63)
+
+ d.a[0] ^= d.d[0]
+ d.a[1] ^= d.d[1]
+ d.a[2] ^= d.d[2]
+ d.a[3] ^= d.d[3]
+ d.a[4] ^= d.d[4]
+ d.a[5] ^= d.d[0]
+ d.a[6] ^= d.d[1]
+ d.a[7] ^= d.d[2]
+ d.a[8] ^= d.d[3]
+ d.a[9] ^= d.d[4]
+ d.a[10] ^= d.d[0]
+ d.a[11] ^= d.d[1]
+ d.a[12] ^= d.d[2]
+ d.a[13] ^= d.d[3]
+ d.a[14] ^= d.d[4]
+ d.a[15] ^= d.d[0]
+ d.a[16] ^= d.d[1]
+ d.a[17] ^= d.d[2]
+ d.a[18] ^= d.d[3]
+ d.a[19] ^= d.d[4]
+ d.a[20] ^= d.d[0]
+ d.a[21] ^= d.d[1]
+ d.a[22] ^= d.d[2]
+ d.a[23] ^= d.d[3]
+ d.a[24] ^= d.d[4]
+
+ // ρ and π steps
+ d.b[0] = d.a[0]
+ d.b[1] = d.a[6]<<ro_06 ^ d.a[6]>>(64-ro_06)
+ d.b[2] = d.a[12]<<ro_12 ^ d.a[12]>>(64-ro_12)
+ d.b[3] = d.a[18]<<ro_18 ^ d.a[18]>>(64-ro_18)
+ d.b[4] = d.a[24]<<ro_24 ^ d.a[24]>>(64-ro_24)
+ d.b[5] = d.a[3]<<ro_15 ^ d.a[3]>>(64-ro_15)
+ d.b[6] = d.a[9]<<ro_21 ^ d.a[9]>>(64-ro_21)
+ d.b[7] = d.a[10]<<ro_02 ^ d.a[10]>>(64-ro_02)
+ d.b[8] = d.a[16]<<ro_08 ^ d.a[16]>>(64-ro_08)
+ d.b[9] = d.a[22]<<ro_14 ^ d.a[22]>>(64-ro_14)
+ d.b[10] = d.a[1]<<ro_05 ^ d.a[1]>>(64-ro_05)
+ d.b[11] = d.a[7]<<ro_11 ^ d.a[7]>>(64-ro_11)
+ d.b[12] = d.a[13]<<ro_17 ^ d.a[13]>>(64-ro_17)
+ d.b[13] = d.a[19]<<ro_23 ^ d.a[19]>>(64-ro_23)
+ d.b[14] = d.a[20]<<ro_04 ^ d.a[20]>>(64-ro_04)
+ d.b[15] = d.a[4]<<ro_20 ^ d.a[4]>>(64-ro_20)
+ d.b[16] = d.a[5]<<ro_01 ^ d.a[5]>>(64-ro_01)
+ d.b[17] = d.a[11]<<ro_07 ^ d.a[11]>>(64-ro_07)
+ d.b[18] = d.a[17]<<ro_13 ^ d.a[17]>>(64-ro_13)
+ d.b[19] = d.a[23]<<ro_19 ^ d.a[23]>>(64-ro_19)
+ d.b[20] = d.a[2]<<ro_10 ^ d.a[2]>>(64-ro_10)
+ d.b[21] = d.a[8]<<ro_16 ^ d.a[8]>>(64-ro_16)
+ d.b[22] = d.a[14]<<ro_22 ^ d.a[14]>>(64-ro_22)
+ d.b[23] = d.a[15]<<ro_03 ^ d.a[15]>>(64-ro_03)
+ d.b[24] = d.a[21]<<ro_09 ^ d.a[21]>>(64-ro_09)
+
+ // χ step
+ d.a[0] = d.b[0] ^ (^d.b[1] & d.b[2])
+ d.a[1] = d.b[1] ^ (^d.b[2] & d.b[3])
+ d.a[2] = d.b[2] ^ (^d.b[3] & d.b[4])
+ d.a[3] = d.b[3] ^ (^d.b[4] & d.b[0])
+ d.a[4] = d.b[4] ^ (^d.b[0] & d.b[1])
+ d.a[5] = d.b[5] ^ (^d.b[6] & d.b[7])
+ d.a[6] = d.b[6] ^ (^d.b[7] & d.b[8])
+ d.a[7] = d.b[7] ^ (^d.b[8] & d.b[9])
+ d.a[8] = d.b[8] ^ (^d.b[9] & d.b[5])
+ d.a[9] = d.b[9] ^ (^d.b[5] & d.b[6])
+ d.a[10] = d.b[10] ^ (^d.b[11] & d.b[12])
+ d.a[11] = d.b[11] ^ (^d.b[12] & d.b[13])
+ d.a[12] = d.b[12] ^ (^d.b[13] & d.b[14])
+ d.a[13] = d.b[13] ^ (^d.b[14] & d.b[10])
+ d.a[14] = d.b[14] ^ (^d.b[10] & d.b[11])
+ d.a[15] = d.b[15] ^ (^d.b[16] & d.b[17])
+ d.a[16] = d.b[16] ^ (^d.b[17] & d.b[18])
+ d.a[17] = d.b[17] ^ (^d.b[18] & d.b[19])
+ d.a[18] = d.b[18] ^ (^d.b[19] & d.b[15])
+ d.a[19] = d.b[19] ^ (^d.b[15] & d.b[16])
+ d.a[20] = d.b[20] ^ (^d.b[21] & d.b[22])
+ d.a[21] = d.b[21] ^ (^d.b[22] & d.b[23])
+ d.a[22] = d.b[22] ^ (^d.b[23] & d.b[24])
+ d.a[23] = d.b[23] ^ (^d.b[24] & d.b[20])
+ d.a[24] = d.b[24] ^ (^d.b[20] & d.b[21])
+
+ // ι step
+ d.a[0] ^= roundConstant
+ }
+}
diff --git a/crypto/sha3/sha3.go b/crypto/sha3/sha3.go
new file mode 100644
index 000000000..22df0ef11
--- /dev/null
+++ b/crypto/sha3/sha3.go
@@ -0,0 +1,216 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package sha3 implements the SHA3 hash algorithm (formerly called Keccak) chosen by NIST in 2012.
+// This file provides a SHA3 implementation which implements the standard hash.Hash interface.
+// Writing input data, including padding, and reading output data are computed in this file.
+// Note that the current implementation can compute the hash of an integral number of bytes only.
+// This is a consequence of the hash interface in which a buffer of bytes is passed in.
+// The internals of the Keccak-f function are computed in keccakf.go.
+// For the detailed specification, refer to the Keccak web site (http://keccak.noekeon.org/).
+package sha3
+
+import (
+ "encoding/binary"
+ "hash"
+)
+
+// laneSize is the size in bytes of each "lane" of the internal state of SHA3 (5 * 5 * 8).
+// Note that changing this size would requires using a type other than uint64 to store each lane.
+const laneSize = 8
+
+// sliceSize represents the dimensions of the internal state, a square matrix of
+// sliceSize ** 2 lanes. This is the size of both the "rows" and "columns" dimensions in the
+// terminology of the SHA3 specification.
+const sliceSize = 5
+
+// numLanes represents the total number of lanes in the state.
+const numLanes = sliceSize * sliceSize
+
+// stateSize is the size in bytes of the internal state of SHA3 (5 * 5 * WSize).
+const stateSize = laneSize * numLanes
+
+// digest represents the partial evaluation of a checksum.
+// Note that capacity, and not outputSize, is the critical security parameter, as SHA3 can output
+// an arbitrary number of bytes for any given capacity. The Keccak proposal recommends that
+// capacity = 2*outputSize to ensure that finding a collision of size outputSize requires
+// O(2^{outputSize/2}) computations (the birthday lower bound). Future standards may modify the
+// capacity/outputSize ratio to allow for more output with lower cryptographic security.
+type digest struct {
+ a [numLanes]uint64 // main state of the hash
+ b [numLanes]uint64 // intermediate states
+ c [sliceSize]uint64 // intermediate states
+ d [sliceSize]uint64 // intermediate states
+ outputSize int // desired output size in bytes
+ capacity int // number of bytes to leave untouched during squeeze/absorb
+ absorbed int // number of bytes absorbed thus far
+}
+
+// minInt returns the lesser of two integer arguments, to simplify the absorption routine.
+func minInt(v1, v2 int) int {
+ if v1 <= v2 {
+ return v1
+ }
+ return v2
+}
+
+// rate returns the number of bytes of the internal state which can be absorbed or squeezed
+// in between calls to the permutation function.
+func (d *digest) rate() int {
+ return stateSize - d.capacity
+}
+
+// Reset clears the internal state by zeroing bytes in the state buffer.
+// This can be skipped for a newly-created hash state; the default zero-allocated state is correct.
+func (d *digest) Reset() {
+ d.absorbed = 0
+ for i := range d.a {
+ d.a[i] = 0
+ }
+}
+
+// BlockSize, required by the hash.Hash interface, does not have a standard intepretation
+// for a sponge-based construction like SHA3. We return the data rate: the number of bytes which
+// can be absorbed per invocation of the permutation function. For Merkle-Damgård based hashes
+// (ie SHA1, SHA2, MD5) the output size of the internal compression function is returned.
+// We consider this to be roughly equivalent because it represents the number of bytes of output
+// produced per cryptographic operation.
+func (d *digest) BlockSize() int { return d.rate() }
+
+// Size returns the output size of the hash function in bytes.
+func (d *digest) Size() int {
+ return d.outputSize
+}
+
+// unalignedAbsorb is a helper function for Write, which absorbs data that isn't aligned with an
+// 8-byte lane. This requires shifting the individual bytes into position in a uint64.
+func (d *digest) unalignedAbsorb(p []byte) {
+ var t uint64
+ for i := len(p) - 1; i >= 0; i-- {
+ t <<= 8
+ t |= uint64(p[i])
+ }
+ offset := (d.absorbed) % d.rate()
+ t <<= 8 * uint(offset%laneSize)
+ d.a[offset/laneSize] ^= t
+ d.absorbed += len(p)
+}
+
+// Write "absorbs" bytes into the state of the SHA3 hash, updating as needed when the sponge
+// "fills up" with rate() bytes. Since lanes are stored internally as type uint64, this requires
+// converting the incoming bytes into uint64s using a little endian interpretation. This
+// implementation is optimized for large, aligned writes of multiples of 8 bytes (laneSize).
+// Non-aligned or uneven numbers of bytes require shifting and are slower.
+func (d *digest) Write(p []byte) (int, error) {
+ // An initial offset is needed if the we aren't absorbing to the first lane initially.
+ offset := d.absorbed % d.rate()
+ toWrite := len(p)
+
+ // The first lane may need to absorb unaligned and/or incomplete data.
+ if (offset%laneSize != 0 || len(p) < 8) && len(p) > 0 {
+ toAbsorb := minInt(laneSize-(offset%laneSize), len(p))
+ d.unalignedAbsorb(p[:toAbsorb])
+ p = p[toAbsorb:]
+ offset = (d.absorbed) % d.rate()
+
+ // For every rate() bytes absorbed, the state must be permuted via the F Function.
+ if (d.absorbed)%d.rate() == 0 {
+ d.keccakF()
+ }
+ }
+
+ // This loop should absorb the bulk of the data into full, aligned lanes.
+ // It will call the update function as necessary.
+ for len(p) > 7 {
+ firstLane := offset / laneSize
+ lastLane := minInt(d.rate()/laneSize, firstLane+len(p)/laneSize)
+
+ // This inner loop absorbs input bytes into the state in groups of 8, converted to uint64s.
+ for lane := firstLane; lane < lastLane; lane++ {
+ d.a[lane] ^= binary.LittleEndian.Uint64(p[:laneSize])
+ p = p[laneSize:]
+ }
+ d.absorbed += (lastLane - firstLane) * laneSize
+ // For every rate() bytes absorbed, the state must be permuted via the F Function.
+ if (d.absorbed)%d.rate() == 0 {
+ d.keccakF()
+ }
+
+ offset = 0
+ }
+
+ // If there are insufficient bytes to fill the final lane, an unaligned absorption.
+ // This should always start at a correct lane boundary though, or else it would be caught
+ // by the uneven opening lane case above.
+ if len(p) > 0 {
+ d.unalignedAbsorb(p)
+ }
+
+ return toWrite, nil
+}
+
+// pad computes the SHA3 padding scheme based on the number of bytes absorbed.
+// The padding is a 1 bit, followed by an arbitrary number of 0s and then a final 1 bit, such that
+// the input bits plus padding bits are a multiple of rate(). Adding the padding simply requires
+// xoring an opening and closing bit into the appropriate lanes.
+func (d *digest) pad() {
+ offset := d.absorbed % d.rate()
+ // The opening pad bit must be shifted into position based on the number of bytes absorbed
+ padOpenLane := offset / laneSize
+ d.a[padOpenLane] ^= 0x0000000000000001 << uint(8*(offset%laneSize))
+ // The closing padding bit is always in the last position
+ padCloseLane := (d.rate() / laneSize) - 1
+ d.a[padCloseLane] ^= 0x8000000000000000
+}
+
+// finalize prepares the hash to output data by padding and one final permutation of the state.
+func (d *digest) finalize() {
+ d.pad()
+ d.keccakF()
+}
+
+// squeeze outputs an arbitrary number of bytes from the hash state.
+// Squeezing can require multiple calls to the F function (one per rate() bytes squeezed),
+// although this is not the case for standard SHA3 parameters. This implementation only supports
+// squeezing a single time, subsequent squeezes may lose alignment. Future implementations
+// may wish to support multiple squeeze calls, for example to support use as a PRNG.
+func (d *digest) squeeze(in []byte, toSqueeze int) []byte {
+ // Because we read in blocks of laneSize, we need enough room to read
+ // an integral number of lanes
+ needed := toSqueeze + (laneSize-toSqueeze%laneSize)%laneSize
+ if cap(in)-len(in) < needed {
+ newIn := make([]byte, len(in), len(in)+needed)
+ copy(newIn, in)
+ in = newIn
+ }
+ out := in[len(in) : len(in)+needed]
+
+ for len(out) > 0 {
+ for i := 0; i < d.rate() && len(out) > 0; i += laneSize {
+ binary.LittleEndian.PutUint64(out[:], d.a[i/laneSize])
+ out = out[laneSize:]
+ }
+ if len(out) > 0 {
+ d.keccakF()
+ }
+ }
+ return in[:len(in)+toSqueeze] // Re-slice in case we wrote extra data.
+}
+
+// Sum applies padding to the hash state and then squeezes out the desired nubmer of output bytes.
+func (d *digest) Sum(in []byte) []byte {
+ // Make a copy of the original hash so that caller can keep writing and summing.
+ dup := *d
+ dup.finalize()
+ return dup.squeeze(in, dup.outputSize)
+}
+
+// The NewKeccakX constructors enable initializing a hash in any of the four recommend sizes
+// from the Keccak specification, all of which set capacity=2*outputSize. Note that the final
+// NIST standard for SHA3 may specify different input/output lengths.
+// The output size is indicated in bits but converted into bytes internally.
+func NewKeccak224() hash.Hash { return &digest{outputSize: 224 / 8, capacity: 2 * 224 / 8} }
+func NewKeccak256() hash.Hash { return &digest{outputSize: 256 / 8, capacity: 2 * 256 / 8} }
+func NewKeccak384() hash.Hash { return &digest{outputSize: 384 / 8, capacity: 2 * 384 / 8} }
+func NewKeccak512() hash.Hash { return &digest{outputSize: 512 / 8, capacity: 2 * 512 / 8} }