mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-07 21:44:27 +00:00
add SignUnsafe with RFC6979 counter support
This commit is contained in:
parent
de3d0c69dd
commit
fac8fc3c6c
2 changed files with 94 additions and 0 deletions
|
|
@ -59,6 +59,24 @@ func Sign(digestHash []byte, prv *ecdsa.PrivateKey) (sig []byte, err error) {
|
||||||
return secp256k1.Sign(digestHash, seckey)
|
return secp256k1.Sign(digestHash, seckey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SignUnsafe calculates an ECDSA signature, using the given RFC6979 counter as the
|
||||||
|
// starting point for nonce generation.
|
||||||
|
//
|
||||||
|
// This function is susceptible to chosen plaintext attacks that can leak
|
||||||
|
// information about the private key that is used for signing. Callers must
|
||||||
|
// be aware that the given digest cannot be chosen by an adversary. Common
|
||||||
|
// solution is to hash any input before calculating the signature.
|
||||||
|
//
|
||||||
|
// The produced signature is in the [R || S || V] format where V is 0 or 1.
|
||||||
|
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.SignUnsafe(digestHash, seckey, counter)
|
||||||
|
}
|
||||||
|
|
||||||
// VerifySignature checks that the given public key created signature over digest.
|
// VerifySignature checks that the given public key created signature over digest.
|
||||||
// The public key should be in compressed (33 bytes) or uncompressed (65 bytes) format.
|
// The public key should be in compressed (33 bytes) or uncompressed (65 bytes) format.
|
||||||
// The signature should have the 64 byte [R || S] format.
|
// The signature should have the 64 byte [R || S] format.
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,82 @@ func Sign(hash []byte, prv *ecdsa.PrivateKey) ([]byte, error) {
|
||||||
return sig, nil
|
return sig, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SignUnsafe calculates an ECDSA signature, using the given RFC6979 counter as the
|
||||||
|
// starting point for nonce generation.
|
||||||
|
//
|
||||||
|
// This function is susceptible to chosen plaintext attacks that can leak
|
||||||
|
// information about the private key that is used for signing. Callers must
|
||||||
|
// be aware that the given hash cannot be chosen by an adversary. Common
|
||||||
|
// solution is to hash any input before calculating the signature.
|
||||||
|
//
|
||||||
|
// The produced signature is in the [R || S || V] format where V is 0 or 1.
|
||||||
|
func SignUnsafe(hash []byte, prv *ecdsa.PrivateKey, counter uint) ([]byte, error) {
|
||||||
|
if counter > uint(^uint32(0)) {
|
||||||
|
return nil, errors.New("invalid counter")
|
||||||
|
}
|
||||||
|
if counter == 0 {
|
||||||
|
return Sign(hash, prv)
|
||||||
|
}
|
||||||
|
if len(hash) != DigestLength {
|
||||||
|
return nil, fmt.Errorf("hash is required to be exactly %d bytes (%d)", DigestLength, len(hash))
|
||||||
|
}
|
||||||
|
if prv.Curve != S256() {
|
||||||
|
return nil, errors.New("private key curve is not secp256k1")
|
||||||
|
}
|
||||||
|
// ecdsa.PrivateKey -> secp256k1.PrivateKey
|
||||||
|
var priv secp256k1.PrivateKey
|
||||||
|
if overflow := priv.Key.SetByteSlice(prv.D.Bytes()); overflow || priv.Key.IsZero() {
|
||||||
|
return nil, errors.New("invalid private key")
|
||||||
|
}
|
||||||
|
defer priv.Zero()
|
||||||
|
|
||||||
|
// RFC6979/BIP62 deterministic signing with the ability to choose the initial
|
||||||
|
// RFC6979 extra-iterations counter.
|
||||||
|
privKeyScalar := &priv.Key
|
||||||
|
var privKeyBytes [32]byte
|
||||||
|
privKeyScalar.PutBytes(&privKeyBytes)
|
||||||
|
defer zeroBytes(privKeyBytes[:])
|
||||||
|
|
||||||
|
for iteration := uint32(counter); ; iteration++ {
|
||||||
|
k := secp256k1.NonceRFC6979(privKeyBytes[:], hash, nil, nil, iteration)
|
||||||
|
|
||||||
|
var kG secp256k1.JacobianPoint
|
||||||
|
secp256k1.ScalarBaseMultNonConst(k, &kG)
|
||||||
|
kG.ToAffine()
|
||||||
|
|
||||||
|
var xBuf [32]byte
|
||||||
|
kG.X.PutBytes(&xBuf)
|
||||||
|
var r secp256k1.ModNScalar
|
||||||
|
overflow := r.SetBytes(&xBuf)
|
||||||
|
zeroBytes(xBuf[:])
|
||||||
|
if r.IsZero() {
|
||||||
|
k.Zero()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
pubKeyRecoveryCode := byte(overflow<<1) | byte(kG.Y.IsOddBit())
|
||||||
|
|
||||||
|
var e secp256k1.ModNScalar
|
||||||
|
e.SetByteSlice(hash)
|
||||||
|
|
||||||
|
kInv := new(secp256k1.ModNScalar).InverseValNonConst(k)
|
||||||
|
k.Zero()
|
||||||
|
s := new(secp256k1.ModNScalar).Mul2(privKeyScalar, &r).Add(&e).Mul(kInv)
|
||||||
|
if s.IsZero() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if s.IsOverHalfOrder() {
|
||||||
|
s.Negate()
|
||||||
|
pubKeyRecoveryCode ^= 0x01
|
||||||
|
}
|
||||||
|
|
||||||
|
sig := make([]byte, SignatureLength)
|
||||||
|
r.PutBytesUnchecked(sig[:32])
|
||||||
|
s.PutBytesUnchecked(sig[32:64])
|
||||||
|
sig[RecoveryIDOffset] = pubKeyRecoveryCode
|
||||||
|
return sig, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// VerifySignature checks that the given public key created signature over hash.
|
// 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 public key should be in compressed (33 bytes) or uncompressed (65 bytes) format.
|
||||||
// The signature should have the 64 byte [R || S] format.
|
// The signature should have the 64 byte [R || S] format.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue