mirror of
https://github.com/btcsuite/btcd.git
synced 2024-11-19 01:40:07 +01:00
txscript: update SigCache to cache both ECDSA and Schnorr signatures
In this commit, we make the sigCache slightly more general in order to be able to cache both ECDSA and Schnorr signatures. The cache is now based off of byte slices (the values) rather than the direct objects. We rely on the fact that the sighash for ecdsa and the schnorr types are distinct, so we can keep using the same top-level sighash key. In the future with Go type params, we can use a type param here instead as they all have an `IsEqual` method.
This commit is contained in:
parent
e781b66e2f
commit
1cd509d9a5
@ -1954,9 +1954,9 @@ func opcodeCheckSig(op *opcode, data []byte, vm *Engine) error {
|
||||
var sigHash chainhash.Hash
|
||||
copy(sigHash[:], hash)
|
||||
|
||||
valid = vm.sigCache.Exists(sigHash, signature, pubKey)
|
||||
valid = vm.sigCache.Exists(sigHash, sigBytes, pkBytes)
|
||||
if !valid && signature.Verify(hash, pubKey) {
|
||||
vm.sigCache.Add(sigHash, signature, pubKey)
|
||||
vm.sigCache.Add(sigHash, sigBytes, pkBytes)
|
||||
valid = true
|
||||
}
|
||||
} else {
|
||||
@ -2202,9 +2202,9 @@ func opcodeCheckMultiSig(op *opcode, data []byte, vm *Engine) error {
|
||||
var sigHash chainhash.Hash
|
||||
copy(sigHash[:], hash)
|
||||
|
||||
valid = vm.sigCache.Exists(sigHash, parsedSig, parsedPubKey)
|
||||
valid = vm.sigCache.Exists(sigHash, signature, pubKey)
|
||||
if !valid && parsedSig.Verify(hash, parsedPubKey) {
|
||||
vm.sigCache.Add(sigHash, parsedSig, parsedPubKey)
|
||||
vm.sigCache.Add(sigHash, signature, pubKey)
|
||||
valid = true
|
||||
}
|
||||
} else {
|
||||
|
@ -5,10 +5,9 @@
|
||||
package txscript
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"sync"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
"github.com/btcsuite/btcd/btcec/v2/ecdsa"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
)
|
||||
|
||||
@ -19,20 +18,23 @@ import (
|
||||
// match. In the occasion that two sigHashes collide, the newer sigHash will
|
||||
// simply overwrite the existing entry.
|
||||
type sigCacheEntry struct {
|
||||
sig *ecdsa.Signature
|
||||
pubKey *btcec.PublicKey
|
||||
sig []byte
|
||||
pubKey []byte
|
||||
}
|
||||
|
||||
// SigCache implements an ECDSA signature verification cache with a randomized
|
||||
// entry eviction policy. Only valid signatures will be added to the cache. The
|
||||
// benefits of SigCache are two fold. Firstly, usage of SigCache mitigates a DoS
|
||||
// attack wherein an attack causes a victim's client to hang due to worst-case
|
||||
// behavior triggered while processing attacker crafted invalid transactions. A
|
||||
// detailed description of the mitigated DoS attack can be found here:
|
||||
// SigCache implements an Schnorr+ECDSA signature verification cache with a
|
||||
// randomized entry eviction policy. Only valid signatures will be added to the
|
||||
// cache. The benefits of SigCache are two fold. Firstly, usage of SigCache
|
||||
// mitigates a DoS attack wherein an attack causes a victim's client to hang
|
||||
// due to worst-case behavior triggered while processing attacker crafted
|
||||
// invalid transactions. A detailed description of the mitigated DoS attack can
|
||||
// be found here:
|
||||
// https://bitslog.wordpress.com/2013/01/23/fixed-bitcoin-vulnerability-explanation-why-the-signature-cache-is-a-dos-protection/.
|
||||
// Secondly, usage of the SigCache introduces a signature verification
|
||||
// optimization which speeds up the validation of transactions within a block,
|
||||
// if they've already been seen and verified within the mempool.
|
||||
//
|
||||
// TODO(roasbeef): use type params here after Go 1.18
|
||||
type SigCache struct {
|
||||
sync.RWMutex
|
||||
validSigs map[chainhash.Hash]sigCacheEntry
|
||||
@ -56,12 +58,12 @@ func NewSigCache(maxEntries uint) *SigCache {
|
||||
//
|
||||
// NOTE: This function is safe for concurrent access. Readers won't be blocked
|
||||
// unless there exists a writer, adding an entry to the SigCache.
|
||||
func (s *SigCache) Exists(sigHash chainhash.Hash, sig *ecdsa.Signature, pubKey *btcec.PublicKey) bool {
|
||||
func (s *SigCache) Exists(sigHash chainhash.Hash, sig []byte, pubKey []byte) bool {
|
||||
s.RLock()
|
||||
entry, ok := s.validSigs[sigHash]
|
||||
s.RUnlock()
|
||||
|
||||
return ok && entry.pubKey.IsEqual(pubKey) && entry.sig.IsEqual(sig)
|
||||
return ok && bytes.Equal(entry.pubKey, pubKey) && bytes.Equal(entry.sig, sig)
|
||||
}
|
||||
|
||||
// Add adds an entry for a signature over 'sigHash' under public key 'pubKey'
|
||||
@ -71,7 +73,7 @@ func (s *SigCache) Exists(sigHash chainhash.Hash, sig *ecdsa.Signature, pubKey *
|
||||
//
|
||||
// NOTE: This function is safe for concurrent access. Writers will block
|
||||
// simultaneous readers until function execution has concluded.
|
||||
func (s *SigCache) Add(sigHash chainhash.Hash, sig *ecdsa.Signature, pubKey *btcec.PublicKey) {
|
||||
func (s *SigCache) Add(sigHash chainhash.Hash, sig []byte, pubKey []byte) {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user