未验证 提交 e85b68ef 编写于 作者: F Felix Lange 提交者: GitHub

crypto: add DecompressPubkey, VerifySignature (#15615)

We need those operations for p2p/enr.

Also upgrade github.com/btcsuite/btcd/btcec to the latest version
and improve BenchmarkSha3. The benchmark printed extra output 
that confused tools like benchstat and ignored N.
上级 6e613cf3
...@@ -20,12 +20,10 @@ import ( ...@@ -20,12 +20,10 @@ import (
"bytes" "bytes"
"crypto/ecdsa" "crypto/ecdsa"
"encoding/hex" "encoding/hex"
"fmt"
"io/ioutil" "io/ioutil"
"math/big" "math/big"
"os" "os"
"testing" "testing"
"time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
) )
...@@ -44,13 +42,9 @@ func TestKeccak256Hash(t *testing.T) { ...@@ -44,13 +42,9 @@ func TestKeccak256Hash(t *testing.T) {
func BenchmarkSha3(b *testing.B) { func BenchmarkSha3(b *testing.B) {
a := []byte("hello world") a := []byte("hello world")
amount := 1000000 for i := 0; i < b.N; i++ {
start := time.Now()
for i := 0; i < amount; i++ {
Keccak256(a) Keccak256(a)
} }
fmt.Println(amount, ":", time.Since(start))
} }
func TestSign(t *testing.T) { func TestSign(t *testing.T) {
......
...@@ -46,6 +46,55 @@ static int secp256k1_ecdsa_recover_pubkey( ...@@ -46,6 +46,55 @@ static int secp256k1_ecdsa_recover_pubkey(
return secp256k1_ec_pubkey_serialize(ctx, pubkey_out, &outputlen, &pubkey, SECP256K1_EC_UNCOMPRESSED); return secp256k1_ec_pubkey_serialize(ctx, pubkey_out, &outputlen, &pubkey, SECP256K1_EC_UNCOMPRESSED);
} }
// secp256k1_ecdsa_verify_enc verifies an encoded compact signature.
//
// Returns: 1: signature is valid
// 0: signature is invalid
// Args: ctx: pointer to a context object (cannot be NULL)
// In: sigdata: pointer to a 64-byte signature (cannot be NULL)
// msgdata: pointer to a 32-byte message (cannot be NULL)
// pubkeydata: pointer to public key data (cannot be NULL)
// pubkeylen: length of pubkeydata
static int secp256k1_ecdsa_verify_enc(
const secp256k1_context* ctx,
const unsigned char *sigdata,
const unsigned char *msgdata,
const unsigned char *pubkeydata,
size_t pubkeylen
) {
secp256k1_ecdsa_signature sig;
secp256k1_pubkey pubkey;
if (!secp256k1_ecdsa_signature_parse_compact(ctx, &sig, sigdata)) {
return 0;
}
if (!secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeydata, pubkeylen)) {
return 0;
}
return secp256k1_ecdsa_verify(ctx, &sig, msgdata, &pubkey);
}
// secp256k1_decompress_pubkey decompresses a public key.
//
// Returns: 1: public key is valid
// 0: public key is invalid
// Args: ctx: pointer to a context object (cannot be NULL)
// Out: pubkey_out: the serialized 65-byte public key (cannot be NULL)
// In: pubkeydata: pointer to 33 bytes of compressed public key data (cannot be NULL)
static int secp256k1_decompress_pubkey(
const secp256k1_context* ctx,
unsigned char *pubkey_out,
const unsigned char *pubkeydata
) {
secp256k1_pubkey pubkey;
if (!secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeydata, 33)) {
return 0;
}
size_t outputlen = 65;
return secp256k1_ec_pubkey_serialize(ctx, pubkey_out, &outputlen, &pubkey, SECP256K1_EC_UNCOMPRESSED);
}
// secp256k1_pubkey_scalar_mul multiplies a point by a scalar in constant time. // secp256k1_pubkey_scalar_mul multiplies a point by a scalar in constant time.
// //
// Returns: 1: multiplication was successful // Returns: 1: multiplication was successful
......
...@@ -38,6 +38,7 @@ import "C" ...@@ -38,6 +38,7 @@ import "C"
import ( import (
"errors" "errors"
"math/big"
"unsafe" "unsafe"
) )
...@@ -55,6 +56,7 @@ var ( ...@@ -55,6 +56,7 @@ var (
ErrInvalidSignatureLen = errors.New("invalid signature length") ErrInvalidSignatureLen = errors.New("invalid signature length")
ErrInvalidRecoveryID = errors.New("invalid signature recovery id") ErrInvalidRecoveryID = errors.New("invalid signature recovery id")
ErrInvalidKey = errors.New("invalid private key") ErrInvalidKey = errors.New("invalid private key")
ErrInvalidPubkey = errors.New("invalid public key")
ErrSignFailed = errors.New("signing failed") ErrSignFailed = errors.New("signing failed")
ErrRecoverFailed = errors.New("recovery failed") ErrRecoverFailed = errors.New("recovery failed")
) )
...@@ -119,6 +121,33 @@ func RecoverPubkey(msg []byte, sig []byte) ([]byte, error) { ...@@ -119,6 +121,33 @@ func RecoverPubkey(msg []byte, sig []byte) ([]byte, error) {
return pubkey, nil return pubkey, nil
} }
// VerifySignature checks that the given pubkey created signature over message.
// The signature should be in [R || S] format.
func VerifySignature(pubkey, msg, signature []byte) bool {
if len(msg) != 32 || len(signature) != 64 || len(pubkey) == 0 {
return false
}
sigdata := (*C.uchar)(unsafe.Pointer(&signature[0]))
msgdata := (*C.uchar)(unsafe.Pointer(&msg[0]))
keydata := (*C.uchar)(unsafe.Pointer(&pubkey[0]))
return C.secp256k1_ecdsa_verify_enc(context, sigdata, msgdata, keydata, C.size_t(len(pubkey))) != 0
}
// DecompressPubkey parses a public key in the 33-byte compressed format.
// It returns non-nil coordinates if the public key is valid.
func DecompressPubkey(pubkey []byte) (X, Y *big.Int) {
if len(pubkey) != 33 {
return nil, nil
}
buf := make([]byte, 65)
bufdata := (*C.uchar)(unsafe.Pointer(&buf[0]))
pubkeydata := (*C.uchar)(unsafe.Pointer(&pubkey[0]))
if C.secp256k1_decompress_pubkey(context, bufdata, pubkeydata) == 0 {
return nil, nil
}
return new(big.Int).SetBytes(buf[1:33]), new(big.Int).SetBytes(buf[33:])
}
func checkSignature(sig []byte) error { func checkSignature(sig []byte) error {
if len(sig) != 65 { if len(sig) != 65 {
return ErrInvalidSignatureLen return ErrInvalidSignatureLen
......
...@@ -27,10 +27,12 @@ import ( ...@@ -27,10 +27,12 @@ import (
"github.com/ethereum/go-ethereum/crypto/secp256k1" "github.com/ethereum/go-ethereum/crypto/secp256k1"
) )
// Ecrecover returns the uncompressed public key that created the given signature.
func Ecrecover(hash, sig []byte) ([]byte, error) { func Ecrecover(hash, sig []byte) ([]byte, error) {
return secp256k1.RecoverPubkey(hash, sig) return secp256k1.RecoverPubkey(hash, sig)
} }
// SigToPub returns the public key that created the given signature.
func SigToPub(hash, sig []byte) (*ecdsa.PublicKey, error) { func SigToPub(hash, sig []byte) (*ecdsa.PublicKey, error) {
s, err := Ecrecover(hash, sig) s, err := Ecrecover(hash, sig)
if err != nil { if err != nil {
...@@ -58,6 +60,22 @@ func Sign(hash []byte, prv *ecdsa.PrivateKey) (sig []byte, err error) { ...@@ -58,6 +60,22 @@ func Sign(hash []byte, prv *ecdsa.PrivateKey) (sig []byte, err error) {
return secp256k1.Sign(hash, seckey) return secp256k1.Sign(hash, seckey)
} }
// VerifySignature checks that the given public key created signature over hash.
// The public key should be in compressed (33 bytes) or uncompressed (65 bytes) format.
// The signature should have the 64 byte [R || S] format.
func VerifySignature(pubkey, hash, signature []byte) bool {
return secp256k1.VerifySignature(pubkey, hash, signature)
}
// DecompressPubkey parses a public key in the 33-byte compressed format.
func DecompressPubkey(pubkey []byte) (*ecdsa.PublicKey, error) {
x, y := secp256k1.DecompressPubkey(pubkey)
if x == nil {
return nil, fmt.Errorf("invalid public key")
}
return &ecdsa.PublicKey{X: x, Y: y, Curve: S256()}, nil
}
// S256 returns an instance of the secp256k1 curve. // S256 returns an instance of the secp256k1 curve.
func S256() elliptic.Curve { func S256() elliptic.Curve {
return secp256k1.S256() return secp256k1.S256()
......
...@@ -21,11 +21,14 @@ package crypto ...@@ -21,11 +21,14 @@ package crypto
import ( import (
"crypto/ecdsa" "crypto/ecdsa"
"crypto/elliptic" "crypto/elliptic"
"errors"
"fmt" "fmt"
"math/big"
"github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/btcec"
) )
// Ecrecover returns the uncompressed public key that created the given signature.
func Ecrecover(hash, sig []byte) ([]byte, error) { func Ecrecover(hash, sig []byte) ([]byte, error) {
pub, err := SigToPub(hash, sig) pub, err := SigToPub(hash, sig)
if err != nil { if err != nil {
...@@ -35,6 +38,7 @@ func Ecrecover(hash, sig []byte) ([]byte, error) { ...@@ -35,6 +38,7 @@ func Ecrecover(hash, sig []byte) ([]byte, error) {
return bytes, err return bytes, err
} }
// SigToPub returns the public key that created the given signature.
func SigToPub(hash, sig []byte) (*ecdsa.PublicKey, error) { func SigToPub(hash, sig []byte) (*ecdsa.PublicKey, error) {
// Convert to btcec input format with 'recovery id' v at the beginning. // Convert to btcec input format with 'recovery id' v at the beginning.
btcsig := make([]byte, 65) btcsig := make([]byte, 65)
...@@ -71,6 +75,33 @@ func Sign(hash []byte, prv *ecdsa.PrivateKey) ([]byte, error) { ...@@ -71,6 +75,33 @@ func Sign(hash []byte, prv *ecdsa.PrivateKey) ([]byte, error) {
return sig, nil return sig, nil
} }
// VerifySignature checks that the given public key created signature over hash.
// The public key should be in compressed (33 bytes) or uncompressed (65 bytes) format.
// The signature should have the 64 byte [R || S] format.
func VerifySignature(pubkey, hash, signature []byte) bool {
if len(signature) != 64 {
return false
}
sig := &btcec.Signature{R: new(big.Int).SetBytes(signature[:32]), S: new(big.Int).SetBytes(signature[32:])}
key, err := btcec.ParsePubKey(pubkey, btcec.S256())
if err != nil {
return false
}
return sig.Verify(hash, key)
}
// DecompressPubkey parses a public key in the 33-byte compressed format.
func DecompressPubkey(pubkey []byte) (*ecdsa.PublicKey, error) {
if len(pubkey) != 33 {
return nil, errors.New("invalid compressed public key length")
}
key, err := btcec.ParsePubKey(pubkey, btcec.S256())
if err != nil {
return nil, err
}
return key.ToECDSA(), nil
}
// S256 returns an instance of the secp256k1 curve. // S256 returns an instance of the secp256k1 curve.
func S256() elliptic.Curve { func S256() elliptic.Curve {
return btcec.S256() return btcec.S256()
......
...@@ -18,19 +18,95 @@ package crypto ...@@ -18,19 +18,95 @@ package crypto
import ( import (
"bytes" "bytes"
"encoding/hex"
"testing" "testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
)
var (
testmsg = hexutil.MustDecode("0xce0677bb30baa8cf067c88db9811f4333d131bf8bcf12fe7065d211dce971008")
testsig = hexutil.MustDecode("0x90f27b8b488db00b00606796d2987f6a5f59ae62ea05effe84fef5b8b0e549984a691139ad57a3f0b906637673aa2f63d1f55cb1a69199d4009eea23ceaddc9301")
testpubkey = hexutil.MustDecode("0x04e32df42865e97135acfb65f3bae71bdc86f4d49150ad6a440b6f15878109880a0a2b2667f7e725ceea70c673093bf67663e0312623c8e091b13cf2c0f11ef652")
testpubkeyc = hexutil.MustDecode("0x02e32df42865e97135acfb65f3bae71bdc86f4d49150ad6a440b6f15878109880a")
) )
func TestRecoverSanity(t *testing.T) { func TestEcrecover(t *testing.T) {
msg, _ := hex.DecodeString("ce0677bb30baa8cf067c88db9811f4333d131bf8bcf12fe7065d211dce971008") pubkey, err := Ecrecover(testmsg, testsig)
sig, _ := hex.DecodeString("90f27b8b488db00b00606796d2987f6a5f59ae62ea05effe84fef5b8b0e549984a691139ad57a3f0b906637673aa2f63d1f55cb1a69199d4009eea23ceaddc9301")
pubkey1, _ := hex.DecodeString("04e32df42865e97135acfb65f3bae71bdc86f4d49150ad6a440b6f15878109880a0a2b2667f7e725ceea70c673093bf67663e0312623c8e091b13cf2c0f11ef652")
pubkey2, err := Ecrecover(msg, sig)
if err != nil { if err != nil {
t.Fatalf("recover error: %s", err) t.Fatalf("recover error: %s", err)
} }
if !bytes.Equal(pubkey1, pubkey2) { if !bytes.Equal(pubkey, testpubkey) {
t.Errorf("pubkey mismatch: want: %x have: %x", pubkey1, pubkey2) t.Errorf("pubkey mismatch: want: %x have: %x", testpubkey, pubkey)
}
}
func TestVerifySignature(t *testing.T) {
sig := testsig[:len(testsig)-1] // remove recovery id
if !VerifySignature(testpubkey, testmsg, sig) {
t.Errorf("can't verify signature with uncompressed key")
}
if !VerifySignature(testpubkeyc, testmsg, sig) {
t.Errorf("can't verify signature with compressed key")
}
if VerifySignature(nil, testmsg, sig) {
t.Errorf("signature valid with no key")
}
if VerifySignature(testpubkey, nil, sig) {
t.Errorf("signature valid with no message")
}
if VerifySignature(testpubkey, testmsg, nil) {
t.Errorf("nil signature valid")
}
if VerifySignature(testpubkey, testmsg, append(common.CopyBytes(sig), 1, 2, 3)) {
t.Errorf("signature valid with extra bytes at the end")
}
if VerifySignature(testpubkey, testmsg, sig[:len(sig)-2]) {
t.Errorf("signature valid even though it's incomplete")
}
}
func TestDecompressPubkey(t *testing.T) {
key, err := DecompressPubkey(testpubkeyc)
if err != nil {
t.Fatal(err)
}
if uncompressed := FromECDSAPub(key); !bytes.Equal(uncompressed, testpubkey) {
t.Errorf("wrong public key result: got %x, want %x", uncompressed, testpubkey)
}
if _, err := DecompressPubkey(nil); err == nil {
t.Errorf("no error for nil pubkey")
}
if _, err := DecompressPubkey(testpubkeyc[:5]); err == nil {
t.Errorf("no error for incomplete pubkey")
}
if _, err := DecompressPubkey(append(common.CopyBytes(testpubkeyc), 1, 2, 3)); err == nil {
t.Errorf("no error for pubkey with extra bytes at the end")
}
}
func BenchmarkEcrecoverSignature(b *testing.B) {
for i := 0; i < b.N; i++ {
if _, err := Ecrecover(testmsg, testsig); err != nil {
b.Fatal("ecrecover error", err)
}
}
}
func BenchmarkVerifySignature(b *testing.B) {
sig := testsig[:len(testsig)-1] // remove recovery id
for i := 0; i < b.N; i++ {
if !VerifySignature(testpubkey, testmsg, sig) {
b.Fatal("verify error")
}
}
}
func BenchmarkDecompressPubkey(b *testing.B) {
for i := 0; i < b.N; i++ {
if _, err := DecompressPubkey(testpubkeyc); err != nil {
b.Fatal(err)
}
} }
} }
btcec btcec
===== =====
[![Build Status](https://travis-ci.org/btcsuite/btcd.png?branch=master)] [![Build Status](https://travis-ci.org/btcsuite/btcd.png?branch=master)](https://travis-ci.org/btcsuite/btcec)
(https://travis-ci.org/btcsuite/btcec) [![ISC License] [![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
(http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org) [![GoDoc](https://godoc.org/github.com/btcsuite/btcd/btcec?status.png)](http://godoc.org/github.com/btcsuite/btcd/btcec)
[![GoDoc](https://godoc.org/github.com/btcsuite/btcd/btcec?status.png)]
(http://godoc.org/github.com/btcsuite/btcd/btcec)
Package btcec implements elliptic curve cryptography needed for working with Package btcec implements elliptic curve cryptography needed for working with
Bitcoin (secp256k1 only for now). It is designed so that it may be used with the Bitcoin (secp256k1 only for now). It is designed so that it may be used with the
...@@ -27,23 +25,19 @@ $ go get -u github.com/btcsuite/btcd/btcec ...@@ -27,23 +25,19 @@ $ go get -u github.com/btcsuite/btcd/btcec
## Examples ## Examples
* [Sign Message] * [Sign Message](http://godoc.org/github.com/btcsuite/btcd/btcec#example-package--SignMessage)
(http://godoc.org/github.com/btcsuite/btcd/btcec#example-package--SignMessage)
Demonstrates signing a message with a secp256k1 private key that is first Demonstrates signing a message with a secp256k1 private key that is first
parsed form raw bytes and serializing the generated signature. parsed form raw bytes and serializing the generated signature.
* [Verify Signature] * [Verify Signature](http://godoc.org/github.com/btcsuite/btcd/btcec#example-package--VerifySignature)
(http://godoc.org/github.com/btcsuite/btcd/btcec#example-package--VerifySignature)
Demonstrates verifying a secp256k1 signature against a public key that is Demonstrates verifying a secp256k1 signature against a public key that is
first parsed from raw bytes. The signature is also parsed from raw bytes. first parsed from raw bytes. The signature is also parsed from raw bytes.
* [Encryption] * [Encryption](http://godoc.org/github.com/btcsuite/btcd/btcec#example-package--EncryptMessage)
(http://godoc.org/github.com/btcsuite/btcd/btcec#example-package--EncryptMessage)
Demonstrates encrypting a message for a public key that is first parsed from Demonstrates encrypting a message for a public key that is first parsed from
raw bytes, then decrypting it using the corresponding private key. raw bytes, then decrypting it using the corresponding private key.
* [Decryption] * [Decryption](http://godoc.org/github.com/btcsuite/btcd/btcec#example-package--DecryptMessage)
(http://godoc.org/github.com/btcsuite/btcd/btcec#example-package--DecryptMessage)
Demonstrates decrypting a message using a private key that is first parsed Demonstrates decrypting a message using a private key that is first parsed
from raw bytes. from raw bytes.
......
...@@ -36,8 +36,9 @@ var ( ...@@ -36,8 +36,9 @@ var (
// interface from crypto/elliptic. // interface from crypto/elliptic.
type KoblitzCurve struct { type KoblitzCurve struct {
*elliptic.CurveParams *elliptic.CurveParams
q *big.Int q *big.Int
H int // cofactor of the curve. H int // cofactor of the curve.
halfOrder *big.Int // half the order N
// byteSize is simply the bit size / 8 and is provided for convenience // byteSize is simply the bit size / 8 and is provided for convenience
// since it is calculated repeatedly. // since it is calculated repeatedly.
...@@ -747,9 +748,9 @@ func NAF(k []byte) ([]byte, []byte) { ...@@ -747,9 +748,9 @@ func NAF(k []byte) ([]byte, []byte) {
} }
if carry { if carry {
retPos[0] = 1 retPos[0] = 1
return retPos, retNeg
} }
return retPos[1:], retNeg[1:]
return retPos, retNeg
} }
// ScalarMult returns k*(Bx, By) where k is a big endian integer. // ScalarMult returns k*(Bx, By) where k is a big endian integer.
...@@ -912,9 +913,10 @@ func initS256() { ...@@ -912,9 +913,10 @@ func initS256() {
secp256k1.Gx = fromHex("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798") secp256k1.Gx = fromHex("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798")
secp256k1.Gy = fromHex("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8") secp256k1.Gy = fromHex("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8")
secp256k1.BitSize = 256 secp256k1.BitSize = 256
secp256k1.H = 1
secp256k1.q = new(big.Int).Div(new(big.Int).Add(secp256k1.P, secp256k1.q = new(big.Int).Div(new(big.Int).Add(secp256k1.P,
big.NewInt(1)), big.NewInt(4)) big.NewInt(1)), big.NewInt(4))
secp256k1.H = 1
secp256k1.halfOrder = new(big.Int).Rsh(secp256k1.N, 1)
// Provided for convenience since this gets computed repeatedly. // Provided for convenience since this gets computed repeatedly.
secp256k1.byteSize = secp256k1.BitSize / 8 secp256k1.byteSize = secp256k1.BitSize / 8
......
...@@ -100,10 +100,6 @@ const ( ...@@ -100,10 +100,6 @@ const (
// fieldPrimeWordOne is word one of the secp256k1 prime in the // fieldPrimeWordOne is word one of the secp256k1 prime in the
// internal field representation. It is used during negation. // internal field representation. It is used during negation.
fieldPrimeWordOne = 0x3ffffbf fieldPrimeWordOne = 0x3ffffbf
// primeLowBits is the lower 2*fieldBase bits of the secp256k1 prime in
// its standard normalized form. It is used during modular reduction.
primeLowBits = 0xffffefffffc2f
) )
// fieldVal implements optimized fixed-precision arithmetic over the // fieldVal implements optimized fixed-precision arithmetic over the
...@@ -250,39 +246,15 @@ func (f *fieldVal) SetHex(hexString string) *fieldVal { ...@@ -250,39 +246,15 @@ func (f *fieldVal) SetHex(hexString string) *fieldVal {
// performs fast modular reduction over the secp256k1 prime by making use of the // performs fast modular reduction over the secp256k1 prime by making use of the
// special form of the prime. // special form of the prime.
func (f *fieldVal) Normalize() *fieldVal { func (f *fieldVal) Normalize() *fieldVal {
// The field representation leaves 6 bits of overflow in each // The field representation leaves 6 bits of overflow in each word so
// word so intermediate calculations can be performed without needing // intermediate calculations can be performed without needing to
// to propagate the carry to each higher word during the calculations. // propagate the carry to each higher word during the calculations. In
// In order to normalize, first we need to "compact" the full 256-bit // order to normalize, we need to "compact" the full 256-bit value to
// value to the right and treat the additional 64 leftmost bits as // the right while propagating any carries through to the high order
// the magnitude. // word.
m := f.n[0] //
t0 := m & fieldBaseMask // Since this field is doing arithmetic modulo the secp256k1 prime, we
m = (m >> fieldBase) + f.n[1] // also need to perform modular reduction over the prime.
t1 := m & fieldBaseMask
m = (m >> fieldBase) + f.n[2]
t2 := m & fieldBaseMask
m = (m >> fieldBase) + f.n[3]
t3 := m & fieldBaseMask
m = (m >> fieldBase) + f.n[4]
t4 := m & fieldBaseMask
m = (m >> fieldBase) + f.n[5]
t5 := m & fieldBaseMask
m = (m >> fieldBase) + f.n[6]
t6 := m & fieldBaseMask
m = (m >> fieldBase) + f.n[7]
t7 := m & fieldBaseMask
m = (m >> fieldBase) + f.n[8]
t8 := m & fieldBaseMask
m = (m >> fieldBase) + f.n[9]
t9 := m & fieldMSBMask
m = m >> fieldMSBBits
// At this point, if the magnitude is greater than 0, the overall value
// is greater than the max possible 256-bit value. In particular, it is
// "how many times larger" than the max value it is. Since this field
// is doing arithmetic modulo the secp256k1 prime, we need to perform
// modular reduction over the prime.
// //
// Per [HAC] section 14.3.4: Reduction method of moduli of special form, // Per [HAC] section 14.3.4: Reduction method of moduli of special form,
// when the modulus is of the special form m = b^t - c, highly efficient // when the modulus is of the special form m = b^t - c, highly efficient
...@@ -298,98 +270,87 @@ func (f *fieldVal) Normalize() *fieldVal { ...@@ -298,98 +270,87 @@ func (f *fieldVal) Normalize() *fieldVal {
// //
// The algorithm presented in the referenced section typically repeats // The algorithm presented in the referenced section typically repeats
// until the quotient is zero. However, due to our field representation // until the quotient is zero. However, due to our field representation
// we already know at least how many times we would need to repeat as // we already know to within one reduction how many times we would need
// it's the value currently in m. Thus we can simply multiply the // to repeat as it's the uppermost bits of the high order word. Thus we
// magnitude by the field representation of the prime and do a single // can simply multiply the magnitude by the field representation of the
// iteration. Notice that nothing will be changed when the magnitude is // prime and do a single iteration. After this step there might be an
// zero, so we could skip this in that case, however always running // additional carry to bit 256 (bit 22 of the high order word).
// regardless allows it to run in constant time. t9 := f.n[9]
r := t0 + m*977 m := t9 >> fieldMSBBits
t0 = r & fieldBaseMask t9 = t9 & fieldMSBMask
r = (r >> fieldBase) + t1 + m*64 t0 := f.n[0] + m*977
t1 = r & fieldBaseMask t1 := (t0 >> fieldBase) + f.n[1] + (m << 6)
r = (r >> fieldBase) + t2 t0 = t0 & fieldBaseMask
t2 = r & fieldBaseMask t2 := (t1 >> fieldBase) + f.n[2]
r = (r >> fieldBase) + t3 t1 = t1 & fieldBaseMask
t3 = r & fieldBaseMask t3 := (t2 >> fieldBase) + f.n[3]
r = (r >> fieldBase) + t4 t2 = t2 & fieldBaseMask
t4 = r & fieldBaseMask t4 := (t3 >> fieldBase) + f.n[4]
r = (r >> fieldBase) + t5 t3 = t3 & fieldBaseMask
t5 = r & fieldBaseMask t5 := (t4 >> fieldBase) + f.n[5]
r = (r >> fieldBase) + t6 t4 = t4 & fieldBaseMask
t6 = r & fieldBaseMask t6 := (t5 >> fieldBase) + f.n[6]
r = (r >> fieldBase) + t7 t5 = t5 & fieldBaseMask
t7 = r & fieldBaseMask t7 := (t6 >> fieldBase) + f.n[7]
r = (r >> fieldBase) + t8 t6 = t6 & fieldBaseMask
t8 = r & fieldBaseMask t8 := (t7 >> fieldBase) + f.n[8]
r = (r >> fieldBase) + t9 t7 = t7 & fieldBaseMask
t9 = r & fieldMSBMask t9 = (t8 >> fieldBase) + t9
t8 = t8 & fieldBaseMask
// At this point, the result will be in the range 0 <= result <=
// prime + (2^64 - c). Therefore, one more subtraction of the prime // At this point, the magnitude is guaranteed to be one, however, the
// might be needed if the current result is greater than or equal to the // value could still be greater than the prime if there was either a
// prime. The following does the final reduction in constant time. // carry through to bit 256 (bit 22 of the higher order word) or the
// Note that the if/else here intentionally does the bitwise OR with // value is greater than or equal to the field characteristic. The
// zero even though it won't change the value to ensure constant time // following determines if either or these conditions are true and does
// between the branches. // the final reduction in constant time.
var mask int32 //
lowBits := uint64(t1)<<fieldBase | uint64(t0) // Note that the if/else statements here intentionally do the bitwise
if lowBits < primeLowBits { // operators even when it won't change the value to ensure constant time
mask |= -1 // between the branches. Also note that 'm' will be zero when neither
} else { // of the aforementioned conditions are true and the value will not be
mask |= 0 // changed when 'm' is zero.
} m = 1
if t2 < fieldBaseMask { if t9 == fieldMSBMask {
mask |= -1 m &= 1
} else {
mask |= 0
}
if t3 < fieldBaseMask {
mask |= -1
} else {
mask |= 0
}
if t4 < fieldBaseMask {
mask |= -1
} else {
mask |= 0
}
if t5 < fieldBaseMask {
mask |= -1
} else {
mask |= 0
}
if t6 < fieldBaseMask {
mask |= -1
} else { } else {
mask |= 0 m &= 0
} }
if t7 < fieldBaseMask { if t2&t3&t4&t5&t6&t7&t8 == fieldBaseMask {
mask |= -1 m &= 1
} else { } else {
mask |= 0 m &= 0
} }
if t8 < fieldBaseMask { if ((t0+977)>>fieldBase + t1 + 64) > fieldBaseMask {
mask |= -1 m &= 1
} else { } else {
mask |= 0 m &= 0
} }
if t9 < fieldMSBMask { if t9>>fieldMSBBits != 0 {
mask |= -1 m |= 1
} else { } else {
mask |= 0 m |= 0
} }
lowBits -= ^uint64(mask) & primeLowBits t0 = t0 + m*977
t0 = uint32(lowBits & fieldBaseMask) t1 = (t0 >> fieldBase) + t1 + (m << 6)
t1 = uint32((lowBits >> fieldBase) & fieldBaseMask) t0 = t0 & fieldBaseMask
t2 = t2 & uint32(mask) t2 = (t1 >> fieldBase) + t2
t3 = t3 & uint32(mask) t1 = t1 & fieldBaseMask
t4 = t4 & uint32(mask) t3 = (t2 >> fieldBase) + t3
t5 = t5 & uint32(mask) t2 = t2 & fieldBaseMask
t6 = t6 & uint32(mask) t4 = (t3 >> fieldBase) + t4
t7 = t7 & uint32(mask) t3 = t3 & fieldBaseMask
t8 = t8 & uint32(mask) t5 = (t4 >> fieldBase) + t5
t9 = t9 & uint32(mask) t4 = t4 & fieldBaseMask
t6 = (t5 >> fieldBase) + t6
t5 = t5 & fieldBaseMask
t7 = (t6 >> fieldBase) + t7
t6 = t6 & fieldBaseMask
t8 = (t7 >> fieldBase) + t8
t7 = t7 & fieldBaseMask
t9 = (t8 >> fieldBase) + t9
t8 = t8 & fieldBaseMask
t9 = t9 & fieldMSBMask // Remove potential multiple of 2^256.
// Finally, set the normalized and reduced words. // Finally, set the normalized and reduced words.
f.n[0] = t0 f.n[0] = t0
......
// Copyright 2015 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
// This file is ignored during the regular build due to the following build tag.
// It is called by go generate and used to automatically generate pre-computed
// tables used to accelerate operations.
// +build ignore
package main
import (
"bytes"
"compress/zlib"
"encoding/base64"
"fmt"
"log"
"os"
"github.com/btcsuite/btcd/btcec"
)
func main() {
fi, err := os.Create("secp256k1.go")
if err != nil {
log.Fatal(err)
}
defer fi.Close()
// Compress the serialized byte points.
serialized := btcec.S256().SerializedBytePoints()
var compressed bytes.Buffer
w := zlib.NewWriter(&compressed)
if _, err := w.Write(serialized); err != nil {
fmt.Println(err)
os.Exit(1)
}
w.Close()
// Encode the compressed byte points with base64.
encoded := make([]byte, base64.StdEncoding.EncodedLen(compressed.Len()))
base64.StdEncoding.Encode(encoded, compressed.Bytes())
fmt.Fprintln(fi, "// Copyright (c) 2015 The btcsuite developers")
fmt.Fprintln(fi, "// Use of this source code is governed by an ISC")
fmt.Fprintln(fi, "// license that can be found in the LICENSE file.")
fmt.Fprintln(fi)
fmt.Fprintln(fi, "package btcec")
fmt.Fprintln(fi)
fmt.Fprintln(fi, "// Auto-generated file (see genprecomps.go)")
fmt.Fprintln(fi, "// DO NOT EDIT")
fmt.Fprintln(fi)
fmt.Fprintf(fi, "var secp256k1BytePoints = %q\n", string(encoded))
a1, b1, a2, b2 := btcec.S256().EndomorphismVectors()
fmt.Println("The following values are the computed linearly " +
"independent vectors needed to make use of the secp256k1 " +
"endomorphism:")
fmt.Printf("a1: %x\n", a1)
fmt.Printf("b1: %x\n", b1)
fmt.Printf("a2: %x\n", a2)
fmt.Printf("b2: %x\n", b2)
}
...@@ -54,6 +54,15 @@ const ( ...@@ -54,6 +54,15 @@ const (
pubkeyHybrid byte = 0x6 // y_bit + x coord + y coord pubkeyHybrid byte = 0x6 // y_bit + x coord + y coord
) )
// IsCompressedPubKey returns true the the passed serialized public key has
// been encoded in compressed format, and false otherwise.
func IsCompressedPubKey(pubKey []byte) bool {
// The public key is only compressed if it is the correct length and
// the format (first byte) is one of the compressed pubkey values.
return len(pubKey) == PubKeyBytesLenCompressed &&
(pubKey[0]&^byte(0x1) == pubkeyCompressed)
}
// ParsePubKey parses a public key for a koblitz curve from a bytestring into a // ParsePubKey parses a public key for a koblitz curve from a bytestring into a
// ecdsa.Publickey, verifying that it is valid. It supports compressed, // ecdsa.Publickey, verifying that it is valid. It supports compressed,
// uncompressed and hybrid signature formats. // uncompressed and hybrid signature formats.
......
因为 它太大了无法显示 source diff 。你可以改为 查看blob
...@@ -29,10 +29,6 @@ type Signature struct { ...@@ -29,10 +29,6 @@ type Signature struct {
} }
var ( var (
// Curve order and halforder, used to tame ECDSA malleability (see BIP-0062)
order = new(big.Int).Set(S256().N)
halforder = new(big.Int).Rsh(order, 1)
// Used in RFC6979 implementation when testing the nonce for correctness // Used in RFC6979 implementation when testing the nonce for correctness
one = big.NewInt(1) one = big.NewInt(1)
...@@ -51,8 +47,8 @@ var ( ...@@ -51,8 +47,8 @@ var (
func (sig *Signature) Serialize() []byte { func (sig *Signature) Serialize() []byte {
// low 'S' malleability breaker // low 'S' malleability breaker
sigS := sig.S sigS := sig.S
if sigS.Cmp(halforder) == 1 { if sigS.Cmp(S256().halfOrder) == 1 {
sigS = new(big.Int).Sub(order, sigS) sigS = new(big.Int).Sub(S256().N, sigS)
} }
// Ensure the encoded bytes for the r and s values are canonical and // Ensure the encoded bytes for the r and s values are canonical and
// thus suitable for DER encoding. // thus suitable for DER encoding.
...@@ -62,7 +58,7 @@ func (sig *Signature) Serialize() []byte { ...@@ -62,7 +58,7 @@ func (sig *Signature) Serialize() []byte {
// total length of returned signature is 1 byte for each magic and // total length of returned signature is 1 byte for each magic and
// length (6 total), plus lengths of r and s // length (6 total), plus lengths of r and s
length := 6 + len(rb) + len(sb) length := 6 + len(rb) + len(sb)
b := make([]byte, length, length) b := make([]byte, length)
b[0] = 0x30 b[0] = 0x30
b[1] = byte(length - 2) b[1] = byte(length - 2)
...@@ -420,7 +416,8 @@ func RecoverCompact(curve *KoblitzCurve, signature, ...@@ -420,7 +416,8 @@ func RecoverCompact(curve *KoblitzCurve, signature,
func signRFC6979(privateKey *PrivateKey, hash []byte) (*Signature, error) { func signRFC6979(privateKey *PrivateKey, hash []byte) (*Signature, error) {
privkey := privateKey.ToECDSA() privkey := privateKey.ToECDSA()
N := order N := S256().N
halfOrder := S256().halfOrder
k := nonceRFC6979(privkey.D, hash) k := nonceRFC6979(privkey.D, hash)
inv := new(big.Int).ModInverse(k, N) inv := new(big.Int).ModInverse(k, N)
r, _ := privkey.Curve.ScalarBaseMult(k.Bytes()) r, _ := privkey.Curve.ScalarBaseMult(k.Bytes())
...@@ -438,7 +435,7 @@ func signRFC6979(privateKey *PrivateKey, hash []byte) (*Signature, error) { ...@@ -438,7 +435,7 @@ func signRFC6979(privateKey *PrivateKey, hash []byte) (*Signature, error) {
s.Mul(s, inv) s.Mul(s, inv)
s.Mod(s, N) s.Mod(s, N)
if s.Cmp(halforder) == 1 { if s.Cmp(halfOrder) == 1 {
s.Sub(N, s) s.Sub(N, s)
} }
if s.Sign() == 0 { if s.Sign() == 0 {
......
...@@ -51,10 +51,10 @@ ...@@ -51,10 +51,10 @@
"revisionTime": "2017-02-10T01:56:32Z" "revisionTime": "2017-02-10T01:56:32Z"
}, },
{ {
"checksumSHA1": "fIpm6Vr5a8kgr22gWkQx7vKUTyU=", "checksumSHA1": "gZQ6HheWahvZzIc3phBnOwoWHjE=",
"path": "github.com/btcsuite/btcd/btcec", "path": "github.com/btcsuite/btcd/btcec",
"revision": "d06c0bb181529331be8f8d9350288c420d9e60e4", "revision": "2e60448ffcc6bf78332d1fe590260095f554dd78",
"revisionTime": "2017-02-01T21:25:25Z" "revisionTime": "2017-11-28T15:02:46Z"
}, },
{ {
"checksumSHA1": "cDMtzKmdTx4CcIpP4broa+16X9g=", "checksumSHA1": "cDMtzKmdTx4CcIpP4broa+16X9g=",
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册