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