github.com/koko1123/flow-go-1@v0.29.6/fvm/crypto/crypto.go (about) 1 package crypto 2 3 import ( 4 "encoding/hex" 5 "fmt" 6 7 "github.com/onflow/cadence/runtime" 8 9 "github.com/koko1123/flow-go-1/fvm/errors" 10 "github.com/koko1123/flow-go-1/model/flow" 11 msig "github.com/koko1123/flow-go-1/module/signature" 12 "github.com/onflow/flow-go/crypto" 13 "github.com/onflow/flow-go/crypto/hash" 14 ) 15 16 func HashWithTag(hashAlgo hash.HashingAlgorithm, tag string, data []byte) ([]byte, error) { 17 var hasher hash.Hasher 18 19 switch hashAlgo { 20 case hash.SHA2_256, hash.SHA3_256, hash.SHA2_384, hash.SHA3_384, hash.Keccak_256: 21 var err error 22 if hasher, err = NewPrefixedHashing(hashAlgo, tag); err != nil { 23 return nil, errors.NewValueErrorf(err.Error(), "verification failed") 24 } 25 case hash.KMAC128: 26 hasher = msig.NewBLSHasher(tag) 27 default: 28 err := errors.NewValueErrorf(fmt.Sprint(hashAlgo), "hashing algorithm type not found") 29 return nil, fmt.Errorf("hashing failed: %w", err) 30 } 31 32 return hasher.ComputeHash(data), nil 33 } 34 35 // RuntimeToCryptoSigningAlgorithm converts a runtime signature algorithm to a crypto signature algorithm. 36 func RuntimeToCryptoSigningAlgorithm(s runtime.SignatureAlgorithm) crypto.SigningAlgorithm { 37 switch s { 38 case runtime.SignatureAlgorithmECDSA_P256: 39 return crypto.ECDSAP256 40 case runtime.SignatureAlgorithmECDSA_secp256k1: 41 return crypto.ECDSASecp256k1 42 case runtime.SignatureAlgorithmBLS_BLS12_381: 43 return crypto.BLSBLS12381 44 default: 45 return crypto.UnknownSigningAlgorithm 46 } 47 } 48 49 // CryptoToRuntimeSigningAlgorithm converts a crypto signature algorithm to a runtime signature algorithm. 50 func CryptoToRuntimeSigningAlgorithm(s crypto.SigningAlgorithm) runtime.SignatureAlgorithm { 51 switch s { 52 case crypto.ECDSAP256: 53 return runtime.SignatureAlgorithmECDSA_P256 54 case crypto.ECDSASecp256k1: 55 return runtime.SignatureAlgorithmECDSA_secp256k1 56 case crypto.BLSBLS12381: 57 return runtime.SignatureAlgorithmBLS_BLS12_381 58 default: 59 return runtime.SignatureAlgorithmUnknown 60 } 61 } 62 63 // RuntimeToCryptoHashingAlgorithm converts a runtime hash algorithm to a crypto hashing algorithm. 64 func RuntimeToCryptoHashingAlgorithm(s runtime.HashAlgorithm) hash.HashingAlgorithm { 65 switch s { 66 case runtime.HashAlgorithmSHA2_256: 67 return hash.SHA2_256 68 case runtime.HashAlgorithmSHA3_256: 69 return hash.SHA3_256 70 case runtime.HashAlgorithmSHA2_384: 71 return hash.SHA2_384 72 case runtime.HashAlgorithmSHA3_384: 73 return hash.SHA3_384 74 case runtime.HashAlgorithmKMAC128_BLS_BLS12_381: 75 return hash.KMAC128 76 case runtime.HashAlgorithmKECCAK_256: 77 return hash.Keccak_256 78 default: 79 return hash.UnknownHashingAlgorithm 80 } 81 } 82 83 // CryptoToRuntimeHashingAlgorithm converts a crypto hashing algorithm to a runtime hash algorithm. 84 func CryptoToRuntimeHashingAlgorithm(h hash.HashingAlgorithm) runtime.HashAlgorithm { 85 switch h { 86 case hash.SHA2_256: 87 return runtime.HashAlgorithmSHA2_256 88 case hash.SHA3_256: 89 return runtime.HashAlgorithmSHA3_256 90 case hash.SHA2_384: 91 return runtime.HashAlgorithmSHA2_384 92 case hash.SHA3_384: 93 return runtime.HashAlgorithmSHA3_384 94 case hash.KMAC128: 95 return runtime.HashAlgorithmKMAC128_BLS_BLS12_381 96 case hash.Keccak_256: 97 return runtime.HashAlgorithmKECCAK_256 98 default: 99 return runtime.HashAlgorithmUnknown 100 } 101 } 102 103 // ValidatePublicKey returns : 104 // - nil if key is valid and no exception occurred. 105 // - crypto.invalidInputsError if key is invalid and no exception occurred. 106 // - panics if an exception occurred. 107 func ValidatePublicKey(signAlgo runtime.SignatureAlgorithm, pk []byte) error { 108 sigAlgo := RuntimeToCryptoSigningAlgorithm(signAlgo) 109 110 _, err := crypto.DecodePublicKey(sigAlgo, pk) 111 112 if err != nil { 113 if crypto.IsInvalidInputsError(err) { 114 return err 115 } 116 panic(fmt.Errorf("validate public key failed with unexpected error %w", err)) 117 } 118 return nil 119 } 120 121 // VerifySignatureFromRuntime performs signature verification using raw values provided 122 // by the Cadence runtime. 123 // 124 // The signature/hash function combinations accepted are: 125 // - ECDSA (on both curves P-256 and secp256k1) with any of SHA2-256/SHA3-256/Keccak256. 126 // - BLS (on BLS12-381 curve) with the specific KMAC128 for BLS. 127 // 128 // The tag is applied to the message depending on the hash function used. 129 // 130 // The function errors: 131 // - NewValueErrorf for any user error 132 // - panic for any other unexpected error 133 func VerifySignatureFromRuntime( 134 signature []byte, 135 tag string, 136 message []byte, 137 rawPublicKey []byte, 138 signatureAlgorithm runtime.SignatureAlgorithm, 139 hashAlgorithm runtime.HashAlgorithm, 140 ) (bool, error) { 141 142 sigAlgo := RuntimeToCryptoSigningAlgorithm(signatureAlgorithm) 143 if sigAlgo == crypto.UnknownSigningAlgorithm { 144 return false, errors.NewValueErrorf(fmt.Sprintf("%d", signatureAlgorithm), "signature algorithm type not found") 145 } 146 147 hashAlgo := RuntimeToCryptoHashingAlgorithm(hashAlgorithm) 148 if hashAlgo == hash.UnknownHashingAlgorithm { 149 return false, errors.NewValueErrorf(fmt.Sprintf("%d", hashAlgorithm), "hashing algorithm type not found") 150 } 151 152 // check ECDSA compatibilites 153 if sigAlgo == crypto.ECDSAP256 || sigAlgo == crypto.ECDSASecp256k1 { 154 // hashing compatibility 155 if hashAlgo != hash.SHA2_256 && hashAlgo != hash.SHA3_256 && hashAlgo != hash.Keccak_256 { 156 return false, errors.NewValueErrorf(sigAlgo.String(), "cannot use hashing algorithm type %s with signature signature algorithm type %s", 157 hashAlgo, sigAlgo) 158 } 159 // tag constraints are checked when initializing a prefix-hasher 160 161 // check BLS compatibilites 162 } else if sigAlgo == crypto.BLSBLS12381 && hashAlgo != hash.KMAC128 { 163 // hashing compatibility 164 return false, errors.NewValueErrorf(sigAlgo.String(), "cannot use hashing algorithm type %s with signature signature algorithm type %s", 165 hashAlgo, sigAlgo) 166 // there are no tag constraints 167 } 168 169 // decode the public key 170 publicKey, err := crypto.DecodePublicKey(sigAlgo, rawPublicKey) 171 if err != nil { 172 return false, errors.NewValueErrorf(hex.EncodeToString(rawPublicKey), "cannot decode public key: %w", err) 173 } 174 175 // create a hasher 176 var hasher hash.Hasher 177 switch hashAlgo { 178 case hash.SHA2_256, hash.SHA3_256, hash.Keccak_256: 179 var err error 180 if hasher, err = NewPrefixedHashing(hashAlgo, tag); err != nil { 181 return false, errors.NewValueErrorf(err.Error(), "runtime verification failed") 182 } 183 case hash.KMAC128: 184 hasher = msig.NewBLSHasher(tag) 185 default: 186 return false, errors.NewValueErrorf(fmt.Sprint(hashAlgo), "hashing algorithm type not found") 187 } 188 189 valid, err := publicKey.Verify(signature, message, hasher) 190 if err != nil { 191 // All inputs are guaranteed to be valid at this stage. 192 // The check for crypto.InvalidInputs is only a sanity check 193 if crypto.IsInvalidInputsError(err) { 194 return false, err 195 } 196 panic(fmt.Errorf("verify runtime signature failed with unexpected error %w", err)) 197 } 198 199 return valid, nil 200 } 201 202 // VerifySignatureFromRuntime performs signature verification using raw values provided 203 // by the Cadence runtime. 204 // 205 // The signature/hash function combinations accepted are: 206 // - ECDSA (on both curves P-256 and secp256k1) with any of SHA2-256/SHA3-256. 207 // 208 // The tag is applied to the message as a constant length prefix. 209 // 210 // The function errors: 211 // - NewValueErrorf for any user error 212 // - panic for any other unexpected error 213 func VerifySignatureFromTransaction( 214 signature []byte, 215 message []byte, 216 pk crypto.PublicKey, 217 hashAlgo hash.HashingAlgorithm, 218 ) (bool, error) { 219 220 // check ECDSA compatibilites 221 if pk.Algorithm() != crypto.ECDSAP256 && pk.Algorithm() != crypto.ECDSASecp256k1 { 222 // TODO: check if we should panic 223 // This case only happens in production if there is a bug 224 return false, errors.NewUnknownFailure(fmt.Errorf( 225 pk.Algorithm().String(), "is not supported in transactions")) 226 } 227 // hashing compatibility 228 if hashAlgo != hash.SHA2_256 && hashAlgo != hash.SHA3_256 { 229 // TODO: check if we should panic 230 // This case only happens in production if there is a bug 231 return false, errors.NewUnknownFailure(fmt.Errorf( 232 hashAlgo.String(), "is not supported in transactions")) 233 } 234 235 hasher, err := NewPrefixedHashing(hashAlgo, flow.TransactionTagString) 236 if err != nil { 237 return false, errors.NewValueErrorf(err.Error(), "transaction verification failed") 238 } 239 240 valid, err := pk.Verify(signature, message, hasher) 241 if err != nil { 242 // All inputs are guaranteed to be valid at this stage. 243 // The check for crypto.InvalidInputs is only a sanity check 244 if crypto.IsInvalidInputsError(err) { 245 return false, err 246 } 247 // unexpected error in normal operations 248 panic(fmt.Errorf("verify transaction signature failed with unexpected error %w", err)) 249 } 250 251 return valid, nil 252 } 253 254 // VerifyPOP verifies a proof of possession (PoP) for the receiver public key; currently only works for BLS 255 func VerifyPOP(pk *runtime.PublicKey, s crypto.Signature) (bool, error) { 256 257 key, err := crypto.DecodePublicKey(crypto.BLSBLS12381, pk.PublicKey) 258 if err != nil { 259 // at this stage, the runtime public key is valid and there are no possible user value errors 260 panic(fmt.Errorf("verify PoP failed: runtime BLS public key should be valid %x", pk.PublicKey)) 261 } 262 263 valid, err := crypto.BLSVerifyPOP(key, s) 264 if err != nil { 265 // no user errors possible at this stage 266 panic(fmt.Errorf("verify PoP failed with unexpected error %w", err)) 267 } 268 return valid, nil 269 } 270 271 // AggregateSignatures aggregate multiple signatures into one; currently only works for BLS 272 func AggregateSignatures(sigs [][]byte) (crypto.Signature, error) { 273 s := make([]crypto.Signature, 0, len(sigs)) 274 for _, sig := range sigs { 275 s = append(s, sig) 276 } 277 278 aggregatedSignature, err := crypto.AggregateBLSSignatures(s) 279 if err != nil { 280 // check for a user error 281 if crypto.IsInvalidInputsError(err) { 282 return nil, err 283 } 284 panic(fmt.Errorf("aggregate BLS signatures failed with unexpected error %w", err)) 285 } 286 return aggregatedSignature, nil 287 } 288 289 // AggregatePublicKeys aggregate multiple public keys into one; currently only works for BLS 290 func AggregatePublicKeys(keys []*runtime.PublicKey) (*runtime.PublicKey, error) { 291 pks := make([]crypto.PublicKey, 0, len(keys)) 292 for _, key := range keys { 293 // TODO: avoid validating the public keys again since Cadence makes sure runtime keys have been validated. 294 // This requires exporting an unsafe function in the crypto package. 295 pk, err := crypto.DecodePublicKey(crypto.BLSBLS12381, key.PublicKey) 296 if err != nil { 297 // at this stage, the runtime public key is valid and there are no possible user value errors 298 panic(fmt.Errorf("aggregate BLS public keys failed: runtime public key should be valid %x", key.PublicKey)) 299 } 300 pks = append(pks, pk) 301 } 302 303 pk, err := crypto.AggregateBLSPublicKeys(pks) 304 if err != nil { 305 // check for a user error 306 if crypto.IsInvalidInputsError(err) { 307 return nil, err 308 } 309 panic(fmt.Errorf("aggregate BLS public keys failed with unexpected error %w", err)) 310 } 311 312 return &runtime.PublicKey{ 313 PublicKey: pk.Encode(), 314 SignAlgo: CryptoToRuntimeSigningAlgorithm(crypto.BLSBLS12381), 315 }, nil 316 }