gitlab.com/jokerrs1/Sia@v1.3.2/types/signatures.go (about) 1 package types 2 3 // signatures.go contains all of the types and functions related to creating 4 // and verifying transaction signatures. There are a lot of rules surrounding 5 // the correct use of signatures. Signatures can cover part or all of a 6 // transaction, can be multiple different algorithms, and must satify a field 7 // called 'UnlockConditions'. 8 9 import ( 10 "bytes" 11 "errors" 12 13 "github.com/NebulousLabs/Sia/crypto" 14 "github.com/NebulousLabs/Sia/encoding" 15 ) 16 17 var ( 18 ErrEntropyKey = errors.New("transaction tries to sign an entproy public key") 19 ErrFrivolousSignature = errors.New("transaction contains a frivolous signature") 20 ErrInvalidPubKeyIndex = errors.New("transaction contains a signature that points to a nonexistent public key") 21 ErrInvalidUnlockHashChecksum = errors.New("provided unlock hash has an invalid checksum") 22 ErrMissingSignatures = errors.New("transaction has inputs with missing signatures") 23 ErrPrematureSignature = errors.New("timelock on signature has not expired") 24 ErrPublicKeyOveruse = errors.New("public key was used multiple times while signing transaction") 25 ErrSortedUniqueViolation = errors.New("sorted unique violation") 26 ErrUnlockHashWrongLen = errors.New("marshalled unlock hash is the wrong length") 27 ErrWholeTransactionViolation = errors.New("covered fields violation") 28 29 // FullCoveredFields is a covered fileds object where the 30 // 'WholeTransaction' field has been set to true. The primary purpose of 31 // this variable is syntactic sugar. 32 FullCoveredFields = CoveredFields{WholeTransaction: true} 33 34 // These Specifiers enumerate the types of signatures that are recognized 35 // by this implementation. If a signature's type is unrecognized, the 36 // signature is treated as valid. Signatures using the special "entropy" 37 // type are always treated as invalid; see Consensus.md for more details. 38 SignatureEd25519 = Specifier{'e', 'd', '2', '5', '5', '1', '9'} 39 SignatureEntropy = Specifier{'e', 'n', 't', 'r', 'o', 'p', 'y'} 40 ) 41 42 type ( 43 // CoveredFields indicates which fields in a transaction have been covered by 44 // the signature. (Note that the signature does not sign the fields 45 // themselves, but rather their combined hash; see SigHash.) Each slice 46 // corresponds to a slice in the Transaction type, indicating which indices of 47 // the slice have been signed. The indices must be valid, i.e. within the 48 // bounds of the slice. In addition, they must be sorted and unique. 49 // 50 // As a convenience, a signature of the entire transaction can be indicated by 51 // the 'WholeTransaction' field. If 'WholeTransaction' == true, all other 52 // fields must be empty (except for the Signatures field, since a signature 53 // cannot sign itself). 54 CoveredFields struct { 55 WholeTransaction bool `json:"wholetransaction"` 56 SiacoinInputs []uint64 `json:"siacoininputs"` 57 SiacoinOutputs []uint64 `json:"siacoinoutputs"` 58 FileContracts []uint64 `json:"filecontracts"` 59 FileContractRevisions []uint64 `json:"filecontractrevisions"` 60 StorageProofs []uint64 `json:"storageproofs"` 61 SiafundInputs []uint64 `json:"siafundinputs"` 62 SiafundOutputs []uint64 `json:"siafundoutputs"` 63 MinerFees []uint64 `json:"minerfees"` 64 ArbitraryData []uint64 `json:"arbitrarydata"` 65 TransactionSignatures []uint64 `json:"transactionsignatures"` 66 } 67 68 // A SiaPublicKey is a public key prefixed by a Specifier. The Specifier 69 // indicates the algorithm used for signing and verification. Unrecognized 70 // algorithms will always verify, which allows new algorithms to be added to 71 // the protocol via a soft-fork. 72 SiaPublicKey struct { 73 Algorithm Specifier `json:"algorithm"` 74 Key []byte `json:"key"` 75 } 76 77 // A TransactionSignature is a signature that is included in the transaction. 78 // The signature should correspond to a public key in one of the 79 // UnlockConditions of the transaction. This key is specified first by 80 // 'ParentID', which specifies the UnlockConditions, and then 81 // 'PublicKeyIndex', which indicates the key in the UnlockConditions. There 82 // are three types that use UnlockConditions: SiacoinInputs, SiafundInputs, 83 // and FileContractTerminations. Each of these types also references a 84 // ParentID, and this is the hash that 'ParentID' must match. The 'Timelock' 85 // prevents the signature from being used until a certain height. 86 // 'CoveredFields' indicates which parts of the transaction are being signed; 87 // see CoveredFields. 88 TransactionSignature struct { 89 ParentID crypto.Hash `json:"parentid"` 90 PublicKeyIndex uint64 `json:"publickeyindex"` 91 Timelock BlockHeight `json:"timelock"` 92 CoveredFields CoveredFields `json:"coveredfields"` 93 Signature []byte `json:"signature"` 94 } 95 96 // UnlockConditions are a set of conditions which must be met to execute 97 // certain actions, such as spending a SiacoinOutput or terminating a 98 // FileContract. 99 // 100 // The simplest requirement is that the block containing the UnlockConditions 101 // must have a height >= 'Timelock'. 102 // 103 // 'PublicKeys' specifies the set of keys that can be used to satisfy the 104 // UnlockConditions; of these, at least 'SignaturesRequired' unique keys must sign 105 // the transaction. The keys that do not need to use the same cryptographic 106 // algorithm. 107 // 108 // If 'SignaturesRequired' == 0, the UnlockConditions are effectively "anyone can 109 // unlock." If 'SignaturesRequired' > len('PublicKeys'), then the UnlockConditions 110 // cannot be fulfilled under any circumstances. 111 UnlockConditions struct { 112 Timelock BlockHeight `json:"timelock"` 113 PublicKeys []SiaPublicKey `json:"publickeys"` 114 SignaturesRequired uint64 `json:"signaturesrequired"` 115 } 116 117 // Each input has a list of public keys and a required number of signatures. 118 // inputSignatures keeps track of which public keys have been used and how many 119 // more signatures are needed. 120 inputSignatures struct { 121 remainingSignatures uint64 122 possibleKeys []SiaPublicKey 123 usedKeys map[uint64]struct{} 124 index int 125 } 126 ) 127 128 // Ed25519PublicKey returns pk as a SiaPublicKey, denoting its algorithm as 129 // Ed25519. 130 func Ed25519PublicKey(pk crypto.PublicKey) SiaPublicKey { 131 return SiaPublicKey{ 132 Algorithm: SignatureEd25519, 133 Key: pk[:], 134 } 135 } 136 137 // UnlockHash calculates the root hash of a Merkle tree of the 138 // UnlockConditions object. The leaves of this tree are formed by taking the 139 // hash of the timelock, the hash of the public keys (one leaf each), and the 140 // hash of the number of signatures. The keys are put in the middle because 141 // Timelock and SignaturesRequired are both low entropy fields; they can be 142 // protected by having random public keys next to them. 143 func (uc UnlockConditions) UnlockHash() UnlockHash { 144 var buf bytes.Buffer 145 e := encoder(&buf) 146 tree := crypto.NewTree() 147 e.WriteUint64(uint64(uc.Timelock)) 148 tree.Push(buf.Bytes()) 149 buf.Reset() 150 for _, key := range uc.PublicKeys { 151 key.MarshalSia(e) 152 tree.Push(buf.Bytes()) 153 buf.Reset() 154 } 155 e.WriteUint64(uc.SignaturesRequired) 156 tree.Push(buf.Bytes()) 157 return UnlockHash(tree.Root()) 158 } 159 160 // SigHash returns the hash of the fields in a transaction covered by a given 161 // signature. See CoveredFields for more details. 162 func (t Transaction) SigHash(i int) (hash crypto.Hash) { 163 cf := t.TransactionSignatures[i].CoveredFields 164 h := crypto.NewHash() 165 if cf.WholeTransaction { 166 t.marshalSiaNoSignatures(h) 167 h.Write(t.TransactionSignatures[i].ParentID[:]) 168 encoding.WriteUint64(h, t.TransactionSignatures[i].PublicKeyIndex) 169 encoding.WriteUint64(h, uint64(t.TransactionSignatures[i].Timelock)) 170 } else { 171 for _, input := range cf.SiacoinInputs { 172 t.SiacoinInputs[input].MarshalSia(h) 173 } 174 for _, output := range cf.SiacoinOutputs { 175 t.SiacoinOutputs[output].MarshalSia(h) 176 } 177 for _, contract := range cf.FileContracts { 178 t.FileContracts[contract].MarshalSia(h) 179 } 180 for _, revision := range cf.FileContractRevisions { 181 t.FileContractRevisions[revision].MarshalSia(h) 182 } 183 for _, storageProof := range cf.StorageProofs { 184 t.StorageProofs[storageProof].MarshalSia(h) 185 } 186 for _, siafundInput := range cf.SiafundInputs { 187 t.SiafundInputs[siafundInput].MarshalSia(h) 188 } 189 for _, siafundOutput := range cf.SiafundOutputs { 190 t.SiafundOutputs[siafundOutput].MarshalSia(h) 191 } 192 for _, minerFee := range cf.MinerFees { 193 t.MinerFees[minerFee].MarshalSia(h) 194 } 195 for _, arbData := range cf.ArbitraryData { 196 encoding.WritePrefix(h, t.ArbitraryData[arbData]) 197 } 198 } 199 200 for _, sig := range cf.TransactionSignatures { 201 t.TransactionSignatures[sig].MarshalSia(h) 202 } 203 204 h.Sum(hash[:0]) 205 return 206 } 207 208 // sortedUnique checks that 'elems' is sorted, contains no repeats, and that no 209 // element is larger than or equal to 'max'. 210 func sortedUnique(elems []uint64, max int) bool { 211 if len(elems) == 0 { 212 return true 213 } 214 215 biggest := elems[0] 216 for _, elem := range elems[1:] { 217 if elem <= biggest { 218 return false 219 } 220 biggest = elem 221 } 222 if biggest >= uint64(max) { 223 return false 224 } 225 return true 226 } 227 228 // validCoveredFields makes sure that all covered fields objects in the 229 // signatures follow the rules. This means that if 'WholeTransaction' is set to 230 // true, all fields except for 'Signatures' must be empty. All fields must be 231 // sorted numerically, and there can be no repeats. 232 func (t Transaction) validCoveredFields() error { 233 for _, sig := range t.TransactionSignatures { 234 // convenience variables 235 cf := sig.CoveredFields 236 fieldMaxs := []struct { 237 field []uint64 238 max int 239 }{ 240 {cf.SiacoinInputs, len(t.SiacoinInputs)}, 241 {cf.SiacoinOutputs, len(t.SiacoinOutputs)}, 242 {cf.FileContracts, len(t.FileContracts)}, 243 {cf.FileContractRevisions, len(t.FileContractRevisions)}, 244 {cf.StorageProofs, len(t.StorageProofs)}, 245 {cf.SiafundInputs, len(t.SiafundInputs)}, 246 {cf.SiafundOutputs, len(t.SiafundOutputs)}, 247 {cf.MinerFees, len(t.MinerFees)}, 248 {cf.ArbitraryData, len(t.ArbitraryData)}, 249 {cf.TransactionSignatures, len(t.TransactionSignatures)}, 250 } 251 252 // Check that all fields are empty if 'WholeTransaction' is set, except 253 // for the Signatures field which isn't affected. 254 if cf.WholeTransaction { 255 // 'WholeTransaction' does not check signatures. 256 for _, fieldMax := range fieldMaxs[:len(fieldMaxs)-1] { 257 if len(fieldMax.field) != 0 { 258 return ErrWholeTransactionViolation 259 } 260 } 261 } 262 263 // Check that all fields are sorted, and without repeat values, and 264 // that all elements point to objects that exists within the 265 // transaction. If there are repeats, it means a transaction is trying 266 // to sign the same object twice. This is unncecessary, and opens up a 267 // DoS vector where the transaction asks the verifier to verify many GB 268 // of data. 269 for _, fieldMax := range fieldMaxs { 270 if !sortedUnique(fieldMax.field, fieldMax.max) { 271 return ErrSortedUniqueViolation 272 } 273 } 274 } 275 276 return nil 277 } 278 279 // validSignatures checks the validaty of all signatures in a transaction. 280 func (t *Transaction) validSignatures(currentHeight BlockHeight) error { 281 // Check that all covered fields objects follow the rules. 282 err := t.validCoveredFields() 283 if err != nil { 284 return err 285 } 286 287 // Create the inputSignatures object for each input. 288 sigMap := make(map[crypto.Hash]*inputSignatures) 289 for i, input := range t.SiacoinInputs { 290 id := crypto.Hash(input.ParentID) 291 _, exists := sigMap[id] 292 if exists { 293 return ErrDoubleSpend 294 } 295 296 sigMap[id] = &inputSignatures{ 297 remainingSignatures: input.UnlockConditions.SignaturesRequired, 298 possibleKeys: input.UnlockConditions.PublicKeys, 299 usedKeys: make(map[uint64]struct{}), 300 index: i, 301 } 302 } 303 for i, revision := range t.FileContractRevisions { 304 id := crypto.Hash(revision.ParentID) 305 _, exists := sigMap[id] 306 if exists { 307 return ErrDoubleSpend 308 } 309 310 sigMap[id] = &inputSignatures{ 311 remainingSignatures: revision.UnlockConditions.SignaturesRequired, 312 possibleKeys: revision.UnlockConditions.PublicKeys, 313 usedKeys: make(map[uint64]struct{}), 314 index: i, 315 } 316 } 317 for i, input := range t.SiafundInputs { 318 id := crypto.Hash(input.ParentID) 319 _, exists := sigMap[id] 320 if exists { 321 return ErrDoubleSpend 322 } 323 324 sigMap[id] = &inputSignatures{ 325 remainingSignatures: input.UnlockConditions.SignaturesRequired, 326 possibleKeys: input.UnlockConditions.PublicKeys, 327 usedKeys: make(map[uint64]struct{}), 328 index: i, 329 } 330 } 331 332 // Check all of the signatures for validity. 333 for i, sig := range t.TransactionSignatures { 334 // Check that sig corresponds to an entry in sigMap. 335 inSig, exists := sigMap[crypto.Hash(sig.ParentID)] 336 if !exists || inSig.remainingSignatures == 0 { 337 return ErrFrivolousSignature 338 } 339 // Check that sig's key hasn't already been used. 340 _, exists = inSig.usedKeys[sig.PublicKeyIndex] 341 if exists { 342 return ErrPublicKeyOveruse 343 } 344 // Check that the public key index refers to an existing public key. 345 if sig.PublicKeyIndex >= uint64(len(inSig.possibleKeys)) { 346 return ErrInvalidPubKeyIndex 347 } 348 // Check that the timelock has expired. 349 if sig.Timelock > currentHeight { 350 return ErrPrematureSignature 351 } 352 353 // Check that the signature verifies. Multiple signature schemes are 354 // supported. 355 publicKey := inSig.possibleKeys[sig.PublicKeyIndex] 356 switch publicKey.Algorithm { 357 case SignatureEntropy: 358 // Entropy cannot ever be used to sign a transaction. 359 return ErrEntropyKey 360 361 case SignatureEd25519: 362 // Decode the public key and signature. 363 var edPK crypto.PublicKey 364 err := encoding.Unmarshal([]byte(publicKey.Key), &edPK) 365 if err != nil { 366 return err 367 } 368 var edSig [crypto.SignatureSize]byte 369 err = encoding.Unmarshal([]byte(sig.Signature), &edSig) 370 if err != nil { 371 return err 372 } 373 cryptoSig := crypto.Signature(edSig) 374 375 sigHash := t.SigHash(i) 376 err = crypto.VerifyHash(sigHash, edPK, cryptoSig) 377 if err != nil { 378 return err 379 } 380 381 default: 382 // If the identifier is not recognized, assume that the signature 383 // is valid. This allows more signature types to be added via soft 384 // forking. 385 } 386 387 inSig.usedKeys[sig.PublicKeyIndex] = struct{}{} 388 inSig.remainingSignatures-- 389 } 390 391 // Check that all inputs have been sufficiently signed. 392 for _, reqSigs := range sigMap { 393 if reqSigs.remainingSignatures != 0 { 394 return ErrMissingSignatures 395 } 396 } 397 398 return nil 399 }