-
Notifications
You must be signed in to change notification settings - Fork 14
/
hashcache.go
93 lines (77 loc) · 2.98 KB
/
hashcache.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
package zecutil
import (
"bytes"
"encoding/binary"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
)
const (
prevoutsHashPersonalization = "ZcashPrevoutHash"
sequenceHashPersonalization = "ZcashSequencHash"
outputsHashPersonalization = "ZcashOutputsHash"
)
// NewTxSigHashes computes, and returns the cached sighashes of the given
// transaction.
func NewTxSigHashes(tx *MsgTx) (h *txscript.TxSigHashes, err error) {
h = &txscript.TxSigHashes{}
if h.HashPrevOuts, err = calcHashPrevOuts(tx); err != nil {
return
}
if h.HashSequence, err = calcHashSequence(tx); err != nil {
return
}
if h.HashOutputs, err = calcHashOutputs(tx); err != nil {
return
}
return
}
// calcHashPrevOuts calculates a single hash of all the previous outputs
// (txid:index) referenced within the passed transaction. This calculated hash
// can be re-used when validating all inputs spending segwit outputs, with a
// signature hash type of SigHashAll. This allows validation to re-use previous
// hashing computation, reducing the complexity of validating SigHashAll inputs
// from O(N^2) to O(N).
func calcHashPrevOuts(tx *MsgTx) (chainhash.Hash, error) {
var b bytes.Buffer
for _, in := range tx.TxIn {
// First write out the 32-byte transaction ID one of whose
// outputs are being referenced by this input.
b.Write(in.PreviousOutPoint.Hash[:])
// Next, we'll encode the index of the referenced output as a
// little endian integer.
var buf [4]byte
binary.LittleEndian.PutUint32(buf[:], in.PreviousOutPoint.Index)
b.Write(buf[:])
}
return blake2bHash(b.Bytes(), []byte(prevoutsHashPersonalization))
}
// calcHashSequence computes an aggregated hash of each of the sequence numbers
// within the inputs of the passed transaction. This single hash can be re-used
// when validating all inputs spending segwit outputs, which include signatures
// using the SigHashAll sighash type. This allows validation to re-use previous
// hashing computation, reducing the complexity of validating SigHashAll inputs
// from O(N^2) to O(N).
func calcHashSequence(tx *MsgTx) (chainhash.Hash, error) {
var b bytes.Buffer
for _, in := range tx.TxIn {
var buf [4]byte
binary.LittleEndian.PutUint32(buf[:], in.Sequence)
b.Write(buf[:])
}
return blake2bHash(b.Bytes(), []byte(sequenceHashPersonalization))
}
// calcHashOutputs computes a hash digest of all outputs created by the
// transaction encoded using the wire format. This single hash can be re-used
// when validating all inputs spending witness programs, which include
// signatures using the SigHashAll sighash type. This allows computation to be
// cached, reducing the total hashing complexity from O(N^2) to O(N).
func calcHashOutputs(tx *MsgTx) (_ chainhash.Hash, err error) {
var b bytes.Buffer
for _, out := range tx.TxOut {
if err = wire.WriteTxOut(&b, 0, 0, out); err != nil {
return chainhash.Hash{}, err
}
}
return blake2bHash(b.Bytes(), []byte(outputsHashPersonalization))
}