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