github.com/Synthesix/Sia@v1.3.3-0.20180413141344-f863baeed3ca/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/Synthesix/Sia/crypto" 14 "github.com/Synthesix/Sia/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 := encoder(&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) (hash crypto.Hash) { 184 cf := t.TransactionSignatures[i].CoveredFields 185 h := crypto.NewHash() 186 if cf.WholeTransaction { 187 t.marshalSiaNoSignatures(h) 188 h.Write(t.TransactionSignatures[i].ParentID[:]) 189 encoding.WriteUint64(h, t.TransactionSignatures[i].PublicKeyIndex) 190 encoding.WriteUint64(h, uint64(t.TransactionSignatures[i].Timelock)) 191 } else { 192 for _, input := range cf.SiacoinInputs { 193 t.SiacoinInputs[input].MarshalSia(h) 194 } 195 for _, output := range cf.SiacoinOutputs { 196 t.SiacoinOutputs[output].MarshalSia(h) 197 } 198 for _, contract := range cf.FileContracts { 199 t.FileContracts[contract].MarshalSia(h) 200 } 201 for _, revision := range cf.FileContractRevisions { 202 t.FileContractRevisions[revision].MarshalSia(h) 203 } 204 for _, storageProof := range cf.StorageProofs { 205 t.StorageProofs[storageProof].MarshalSia(h) 206 } 207 for _, siafundInput := range cf.SiafundInputs { 208 t.SiafundInputs[siafundInput].MarshalSia(h) 209 } 210 for _, siafundOutput := range cf.SiafundOutputs { 211 t.SiafundOutputs[siafundOutput].MarshalSia(h) 212 } 213 for _, minerFee := range cf.MinerFees { 214 t.MinerFees[minerFee].MarshalSia(h) 215 } 216 for _, arbData := range cf.ArbitraryData { 217 encoding.WritePrefix(h, t.ArbitraryData[arbData]) 218 } 219 } 220 221 for _, sig := range cf.TransactionSignatures { 222 t.TransactionSignatures[sig].MarshalSia(h) 223 } 224 225 h.Sum(hash[:0]) 226 return 227 } 228 229 // sortedUnique checks that 'elems' is sorted, contains no repeats, and that no 230 // element is larger than or equal to 'max'. 231 func sortedUnique(elems []uint64, max int) bool { 232 if len(elems) == 0 { 233 return true 234 } 235 236 biggest := elems[0] 237 for _, elem := range elems[1:] { 238 if elem <= biggest { 239 return false 240 } 241 biggest = elem 242 } 243 if biggest >= uint64(max) { 244 return false 245 } 246 return true 247 } 248 249 // validCoveredFields makes sure that all covered fields objects in the 250 // signatures follow the rules. This means that if 'WholeTransaction' is set to 251 // true, all fields except for 'Signatures' must be empty. All fields must be 252 // sorted numerically, and there can be no repeats. 253 func (t Transaction) validCoveredFields() error { 254 for _, sig := range t.TransactionSignatures { 255 // convenience variables 256 cf := sig.CoveredFields 257 fieldMaxs := []struct { 258 field []uint64 259 max int 260 }{ 261 {cf.SiacoinInputs, len(t.SiacoinInputs)}, 262 {cf.SiacoinOutputs, len(t.SiacoinOutputs)}, 263 {cf.FileContracts, len(t.FileContracts)}, 264 {cf.FileContractRevisions, len(t.FileContractRevisions)}, 265 {cf.StorageProofs, len(t.StorageProofs)}, 266 {cf.SiafundInputs, len(t.SiafundInputs)}, 267 {cf.SiafundOutputs, len(t.SiafundOutputs)}, 268 {cf.MinerFees, len(t.MinerFees)}, 269 {cf.ArbitraryData, len(t.ArbitraryData)}, 270 {cf.TransactionSignatures, len(t.TransactionSignatures)}, 271 } 272 273 // Check that all fields are empty if 'WholeTransaction' is set, except 274 // for the Signatures field which isn't affected. 275 if cf.WholeTransaction { 276 // 'WholeTransaction' does not check signatures. 277 for _, fieldMax := range fieldMaxs[:len(fieldMaxs)-1] { 278 if len(fieldMax.field) != 0 { 279 return ErrWholeTransactionViolation 280 } 281 } 282 } 283 284 // Check that all fields are sorted, and without repeat values, and 285 // that all elements point to objects that exists within the 286 // transaction. If there are repeats, it means a transaction is trying 287 // to sign the same object twice. This is unncecessary, and opens up a 288 // DoS vector where the transaction asks the verifier to verify many GB 289 // of data. 290 for _, fieldMax := range fieldMaxs { 291 if !sortedUnique(fieldMax.field, fieldMax.max) { 292 return ErrSortedUniqueViolation 293 } 294 } 295 } 296 297 return nil 298 } 299 300 // validSignatures checks the validaty of all signatures in a transaction. 301 func (t *Transaction) validSignatures(currentHeight BlockHeight) error { 302 // Check that all covered fields objects follow the rules. 303 err := t.validCoveredFields() 304 if err != nil { 305 return err 306 } 307 308 // Create the inputSignatures object for each input. 309 sigMap := make(map[crypto.Hash]*inputSignatures) 310 for i, input := range t.SiacoinInputs { 311 id := crypto.Hash(input.ParentID) 312 _, exists := sigMap[id] 313 if exists { 314 return ErrDoubleSpend 315 } 316 317 sigMap[id] = &inputSignatures{ 318 remainingSignatures: input.UnlockConditions.SignaturesRequired, 319 possibleKeys: input.UnlockConditions.PublicKeys, 320 usedKeys: make(map[uint64]struct{}), 321 index: i, 322 } 323 } 324 for i, revision := range t.FileContractRevisions { 325 id := crypto.Hash(revision.ParentID) 326 _, exists := sigMap[id] 327 if exists { 328 return ErrDoubleSpend 329 } 330 331 sigMap[id] = &inputSignatures{ 332 remainingSignatures: revision.UnlockConditions.SignaturesRequired, 333 possibleKeys: revision.UnlockConditions.PublicKeys, 334 usedKeys: make(map[uint64]struct{}), 335 index: i, 336 } 337 } 338 for i, input := range t.SiafundInputs { 339 id := crypto.Hash(input.ParentID) 340 _, exists := sigMap[id] 341 if exists { 342 return ErrDoubleSpend 343 } 344 345 sigMap[id] = &inputSignatures{ 346 remainingSignatures: input.UnlockConditions.SignaturesRequired, 347 possibleKeys: input.UnlockConditions.PublicKeys, 348 usedKeys: make(map[uint64]struct{}), 349 index: i, 350 } 351 } 352 353 // Check all of the signatures for validity. 354 for i, sig := range t.TransactionSignatures { 355 // Check that sig corresponds to an entry in sigMap. 356 inSig, exists := sigMap[crypto.Hash(sig.ParentID)] 357 if !exists || inSig.remainingSignatures == 0 { 358 return ErrFrivolousSignature 359 } 360 // Check that sig's key hasn't already been used. 361 _, exists = inSig.usedKeys[sig.PublicKeyIndex] 362 if exists { 363 return ErrPublicKeyOveruse 364 } 365 // Check that the public key index refers to an existing public key. 366 if sig.PublicKeyIndex >= uint64(len(inSig.possibleKeys)) { 367 return ErrInvalidPubKeyIndex 368 } 369 // Check that the timelock has expired. 370 if sig.Timelock > currentHeight { 371 return ErrPrematureSignature 372 } 373 374 // Check that the signature verifies. Multiple signature schemes are 375 // supported. 376 publicKey := inSig.possibleKeys[sig.PublicKeyIndex] 377 switch publicKey.Algorithm { 378 case SignatureEntropy: 379 // Entropy cannot ever be used to sign a transaction. 380 return ErrEntropyKey 381 382 case SignatureEd25519: 383 // Decode the public key and signature. 384 var edPK crypto.PublicKey 385 err := encoding.Unmarshal([]byte(publicKey.Key), &edPK) 386 if err != nil { 387 return err 388 } 389 var edSig [crypto.SignatureSize]byte 390 err = encoding.Unmarshal([]byte(sig.Signature), &edSig) 391 if err != nil { 392 return err 393 } 394 cryptoSig := crypto.Signature(edSig) 395 396 sigHash := t.SigHash(i) 397 err = crypto.VerifyHash(sigHash, edPK, cryptoSig) 398 if err != nil { 399 return err 400 } 401 402 default: 403 // If the identifier is not recognized, assume that the signature 404 // is valid. This allows more signature types to be added via soft 405 // forking. 406 } 407 408 inSig.usedKeys[sig.PublicKeyIndex] = struct{}{} 409 inSig.remainingSignatures-- 410 } 411 412 // Check that all inputs have been sufficiently signed. 413 for _, reqSigs := range sigMap { 414 if reqSigs.remainingSignatures != 0 { 415 return ErrMissingSignatures 416 } 417 } 418 419 return nil 420 }