mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-18 19:00:46 +00:00
crypto,crypto/secp256k1: Support custom nonce counter for specialized signing
This commit is contained in:
parent
54f72c796f
commit
9fff572442
6 changed files with 59 additions and 8 deletions
|
|
@ -87,7 +87,8 @@ SECP256K1_API int secp256k1_ecdsa_sign_recoverable(
|
|||
const unsigned char *msghash32,
|
||||
const unsigned char *seckey,
|
||||
secp256k1_nonce_function noncefp,
|
||||
const void *ndata
|
||||
const void *ndata,
|
||||
const unsigned int initialcount
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Recover an ECDSA public key from a signature.
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ static int secp256k1_ecdsa_sig_recover(const secp256k1_scalar *sigr, const secp2
|
|||
return !secp256k1_gej_is_infinity(&qj);
|
||||
}
|
||||
|
||||
int secp256k1_ecdsa_sign_recoverable(const secp256k1_context* ctx, secp256k1_ecdsa_recoverable_signature *signature, const unsigned char *msghash32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) {
|
||||
int secp256k1_ecdsa_sign_recoverable(const secp256k1_context* ctx, secp256k1_ecdsa_recoverable_signature *signature, const unsigned char *msghash32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata, const unsigned int initialcount) {
|
||||
secp256k1_scalar r, s;
|
||||
int ret, recid;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
|
|
@ -129,7 +129,7 @@ int secp256k1_ecdsa_sign_recoverable(const secp256k1_context* ctx, secp256k1_ecd
|
|||
ARG_CHECK(signature != NULL);
|
||||
ARG_CHECK(seckey != NULL);
|
||||
|
||||
ret = secp256k1_ecdsa_sign_inner(ctx, &r, &s, &recid, msghash32, seckey, noncefp, noncedata);
|
||||
ret = secp256k1_ecdsa_sign_inner(ctx, &r, &s, &recid, msghash32, seckey, noncefp, noncedata, initialcount);
|
||||
secp256k1_ecdsa_recoverable_signature_save(signature, &r, &s, recid);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -507,12 +507,12 @@ static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *m
|
|||
const secp256k1_nonce_function secp256k1_nonce_function_rfc6979 = nonce_function_rfc6979;
|
||||
const secp256k1_nonce_function secp256k1_nonce_function_default = nonce_function_rfc6979;
|
||||
|
||||
static int secp256k1_ecdsa_sign_inner(const secp256k1_context* ctx, secp256k1_scalar* r, secp256k1_scalar* s, int* recid, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) {
|
||||
static int secp256k1_ecdsa_sign_inner(const secp256k1_context* ctx, secp256k1_scalar* r, secp256k1_scalar* s, int* recid, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata, const unsigned int initialcount) {
|
||||
secp256k1_scalar sec, non, msg;
|
||||
int ret = 0;
|
||||
int is_sec_valid;
|
||||
unsigned char nonce32[32];
|
||||
unsigned int count = 0;
|
||||
unsigned int count = initialcount;
|
||||
/* Default initialization here is important so we won't pass uninit values to the cmov in the end */
|
||||
*r = secp256k1_scalar_zero;
|
||||
*s = secp256k1_scalar_zero;
|
||||
|
|
@ -572,7 +572,7 @@ int secp256k1_ecdsa_sign(const secp256k1_context* ctx, secp256k1_ecdsa_signature
|
|||
ARG_CHECK(signature != NULL);
|
||||
ARG_CHECK(seckey != NULL);
|
||||
|
||||
ret = secp256k1_ecdsa_sign_inner(ctx, &r, &s, NULL, msghash32, seckey, noncefp, noncedata);
|
||||
ret = secp256k1_ecdsa_sign_inner(ctx, &r, &s, NULL, msghash32, seckey, noncefp, noncedata, 0);
|
||||
secp256k1_ecdsa_signature_save(signature, &r, &s);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,6 +60,14 @@ var (
|
|||
// directly by an attacker. It is usually preferable to use a cryptographic
|
||||
// hash function on any input before handing it to this function.
|
||||
func Sign(msg []byte, seckey []byte) ([]byte, error) {
|
||||
return SignUnsafe(msg, seckey, 0)
|
||||
}
|
||||
|
||||
// SignUnsafe signs a hash with a custom starting counter for nonce derivation.
|
||||
// WARNING: This function is unsafe and should only be used for specialized cases
|
||||
// like finding low-R signatures or canonical signatures. Improper use can lead
|
||||
// to private key exposure. Use Sign for standard signing operations.
|
||||
func SignUnsafe(msg []byte, seckey []byte, counter uint) ([]byte, error) {
|
||||
if len(msg) != 32 {
|
||||
return nil, ErrInvalidMsgLen
|
||||
}
|
||||
|
|
@ -76,7 +84,7 @@ func Sign(msg []byte, seckey []byte) ([]byte, error) {
|
|||
noncefunc = C.secp256k1_nonce_function_rfc6979
|
||||
sigstruct C.secp256k1_ecdsa_recoverable_signature
|
||||
)
|
||||
if C.secp256k1_ecdsa_sign_recoverable(context, &sigstruct, msgdata, seckeydata, noncefunc, nil) == 0 {
|
||||
if C.secp256k1_ecdsa_sign_recoverable(context, &sigstruct, msgdata, seckeydata, noncefunc, nil, (C.uint)(counter)) == 0 {
|
||||
return nil, ErrSignFailed
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -130,6 +130,40 @@ func TestSignDeterministic(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestSignUnsafe(t *testing.T) {
|
||||
pubkey1, seckey := generateKeyPair()
|
||||
msg := make([]byte, 32)
|
||||
|
||||
sig1, err := Sign(msg, seckey)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sig2, err := SignUnsafe(msg, seckey, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(sig1, sig2) {
|
||||
t.Fatal("signatures not equal")
|
||||
}
|
||||
|
||||
sig3, err := SignUnsafe(msg, seckey, 1000)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if bytes.Equal(sig1, sig3) {
|
||||
t.Fatal("signatures with different count param equal")
|
||||
}
|
||||
|
||||
pubkey2, err := RecoverPubkey(msg, sig3)
|
||||
if err != nil {
|
||||
t.Errorf("recover error: %s", err)
|
||||
}
|
||||
if !bytes.Equal(pubkey1, pubkey2) {
|
||||
t.Errorf("pubkey mismatch: want: %x have: %x", pubkey1, pubkey2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRandomMessagesWithSameKey(t *testing.T) {
|
||||
pubkey, seckey := generateKeyPair()
|
||||
keys := func() ([]byte, []byte) {
|
||||
|
|
|
|||
|
|
@ -51,12 +51,20 @@ func SigToPub(hash, sig []byte) (*ecdsa.PublicKey, error) {
|
|||
//
|
||||
// The produced signature is in the [R || S || V] format where V is 0 or 1.
|
||||
func Sign(digestHash []byte, prv *ecdsa.PrivateKey) (sig []byte, err error) {
|
||||
return SignUnsafe(digestHash, prv, 0)
|
||||
}
|
||||
|
||||
// SignUnsafe signs a hash with a custom starting counter for nonce derivation.
|
||||
// WARNING: This function is unsafe and should only be used for specialized cases
|
||||
// like finding low-R signatures or canonical signatures. Improper use can lead
|
||||
// to private key exposure. Use Sign for standard signing operations.
|
||||
func SignUnsafe(digestHash []byte, prv *ecdsa.PrivateKey, counter uint) (sig []byte, err error) {
|
||||
if len(digestHash) != DigestLength {
|
||||
return nil, fmt.Errorf("hash is required to be exactly %d bytes (%d)", DigestLength, len(digestHash))
|
||||
}
|
||||
seckey := math.PaddedBigBytes(prv.D, prv.Params().BitSize/8)
|
||||
defer zeroBytes(seckey)
|
||||
return secp256k1.Sign(digestHash, seckey)
|
||||
return secp256k1.SignUnsafe(digestHash, seckey, counter)
|
||||
}
|
||||
|
||||
// VerifySignature checks that the given public key created signature over digest.
|
||||
|
|
|
|||
Loading…
Reference in a new issue