// RawTxInSignatureAlt returns the serialized ECDSA signature for the input idx of // the given transaction, with hashType appended to it. func RawTxInSignatureAlt(tx *wire.MsgTx, idx int, subScript []byte, hashType SigHashType, key chainec.PrivateKey, sigType sigTypes) ([]byte, error) { parsedScript, err := parseScript(subScript) if err != nil { return nil, fmt.Errorf("cannot parse output script: %v", err) } hash, err := calcSignatureHash(parsedScript, hashType, tx, idx, nil) if err != nil { return nil, err } var sig chainec.Signature switch sigType { case edwards: r, s, err := chainec.Edwards.Sign(key, hash) if err != nil { return nil, fmt.Errorf("cannot sign tx input: %s", err) } sig = chainec.Edwards.NewSignature(r, s) case secSchnorr: r, s, err := chainec.SecSchnorr.Sign(key, hash) if err != nil { return nil, fmt.Errorf("cannot sign tx input: %s", err) } sig = chainec.SecSchnorr.NewSignature(r, s) default: return nil, fmt.Errorf("unknown alt sig type %v", sigType) } return append(sig.Serialize(), byte(hashType)), nil }
// Exists returns true if an existing entry of 'sig' over 'sigHash' for public // key 'pubKey' is found within the SigCache. Otherwise, false is returned. // // 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 chainec.Signature, pubKey chainec.PublicKey) bool { info := sigInfo{sigHash, string(sig.Serialize()), string(pubKey.SerializeCompressed())} s.RLock() _, ok := s.validSigs[info] s.RUnlock() return ok }
// Exists returns true if an existing entry of 'sig' over 'sigHash' for public // key 'pubKey' is found within the SigCache. Otherwise, false is returned. // // 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 chainec.Signature, pubKey chainec.PublicKey) bool { s.RLock() defer s.RUnlock() if entry, ok := s.validSigs[sigHash]; ok { pkEqual := bytes.Equal(entry.pubKey.SerializeCompressed(), pubKey.SerializeCompressed()) sigEqual := bytes.Equal(entry.sig.Serialize(), sig.Serialize()) return pkEqual && sigEqual } return false }
// Add adds an entry for a signature over 'sigHash' under public key 'pubKey' // to the signature cache. In the event that the SigCache is 'full', an // existing entry it randomly chosen to be evicted in order to make space for // the new entry. // // 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 chainec.Signature, pubKey chainec.PublicKey) { s.Lock() defer s.Unlock() if s.maxEntries <= 0 { return } // If adding this new entry will put us over the max number of allowed // entries, then evict an entry. if uint(len(s.validSigs)+1) > s.maxEntries { // Generate a cryptographically random hash. randHashBytes := make([]byte, chainhash.HashSize) _, err := rand.Read(randHashBytes) if err != nil { // Failure to read a random hash results in the proposed // entry not being added to the cache since we are // unable to evict any existing entries. return } // Try to find the first entry that is greater than the random // hash. Use the first entry (which is already pseudo random due // to Go's range statement over maps) as a fall back if none of // the hashes in the rejected transactions pool are larger than // the random hash. var foundEntry sigInfo for sigEntry := range s.validSigs { if foundEntry.sig == "" { foundEntry = sigEntry } if bytes.Compare(sigEntry.sigHash.Bytes(), randHashBytes) > 0 { foundEntry = sigEntry break } } delete(s.validSigs, foundEntry) } info := sigInfo{sigHash, string(sig.Serialize()), string(pubKey.SerializeCompressed())} s.validSigs[info] = struct{}{} }