github.com/onflow/flow-go/crypto@v0.24.8/sign.go (about) 1 // Package crypto ... 2 package crypto 3 4 import ( 5 "crypto/elliptic" 6 "fmt" 7 8 "github.com/btcsuite/btcd/btcec/v2" 9 10 "github.com/onflow/flow-go/crypto/hash" 11 ) 12 13 // revive:disable:var-naming 14 15 // revive:enable 16 17 // SigningAlgorithm is an identifier for a signing algorithm 18 // (and parameters if applicable) 19 type SigningAlgorithm int 20 21 const ( 22 // Supported signing algorithms 23 UnknownSigningAlgorithm SigningAlgorithm = iota 24 // BLSBLS12381 is BLS on BLS 12-381 curve 25 BLSBLS12381 26 // ECDSAP256 is ECDSA on NIST P-256 curve 27 ECDSAP256 28 // ECDSASecp256k1 is ECDSA on secp256k1 curve 29 ECDSASecp256k1 30 ) 31 32 // String returns the string representation of this signing algorithm. 33 func (f SigningAlgorithm) String() string { 34 return [...]string{"UNKNOWN", "BLS_BLS12381", "ECDSA_P256", "ECDSA_secp256k1"}[f] 35 } 36 37 // Signature is a generic type, regardless of the signature scheme 38 type Signature []byte 39 40 // Signer interface 41 type signer interface { 42 // generatePrivateKey generates a private key 43 generatePrivateKey([]byte) (PrivateKey, error) 44 // decodePrivateKey loads a private key from a byte array 45 decodePrivateKey([]byte) (PrivateKey, error) 46 // decodePublicKey loads a public key from a byte array 47 decodePublicKey([]byte) (PublicKey, error) 48 // decodePublicKeyCompressed loads a public key from a byte array representing a point in compressed form 49 decodePublicKeyCompressed([]byte) (PublicKey, error) 50 } 51 52 // newNonRelicSigner returns a signer that does not depend on Relic library. 53 func newNonRelicSigner(algo SigningAlgorithm) (signer, error) { 54 switch algo { 55 case ECDSAP256: 56 return p256Instance, nil 57 case ECDSASecp256k1: 58 return secp256k1Instance, nil 59 default: 60 return nil, invalidInputsErrorf("the signature scheme %s is not supported", algo) 61 } 62 } 63 64 // Initialize the context of all algos not requiring Relic 65 func initNonRelic() { 66 // P-256 67 p256Instance = &(ecdsaAlgo{ 68 curve: elliptic.P256(), 69 algo: ECDSAP256, 70 }) 71 72 // secp256k1 73 secp256k1Instance = &(ecdsaAlgo{ 74 curve: btcec.S256(), 75 algo: ECDSASecp256k1, 76 }) 77 } 78 79 // Signature format Check for non-relic algos (ECDSA) 80 func signatureFormatCheckNonRelic(algo SigningAlgorithm, s Signature) (bool, error) { 81 switch algo { 82 case ECDSAP256: 83 return p256Instance.signatureFormatCheck(s), nil 84 case ECDSASecp256k1: 85 return secp256k1Instance.signatureFormatCheck(s), nil 86 default: 87 return false, invalidInputsErrorf( 88 "the signature scheme %s is not supported", 89 algo) 90 } 91 } 92 93 // SignatureFormatCheck verifies the format of a serialized signature, 94 // regardless of messages or public keys. 95 // 96 // This function is only defined for ECDSA algos for now. 97 // 98 // If SignatureFormatCheck returns false then the input is not a valid 99 // signature and will fail a verification against any message and public key. 100 func SignatureFormatCheck(algo SigningAlgorithm, s Signature) (bool, error) { 101 // For now, signatureFormatCheckNonRelic is only defined for non-Relic algos. 102 return signatureFormatCheckNonRelic(algo, s) 103 } 104 105 // GeneratePrivateKey generates a private key of the algorithm using the entropy of the given seed. 106 // 107 // The seed minimum length is 32 bytes and it should have enough entropy. 108 // It is recommended to use a secure crypto RNG to generate the seed. 109 // 110 // The function returns: 111 // - (false, invalidInputsErrors) if the signing algorithm is not supported or 112 // if the seed length is not valid (less than 32 bytes or larger than 256 bytes) 113 // - (false, error) if an unexpected error occurs 114 // - (sk, nil) if key generation was successful 115 func GeneratePrivateKey(algo SigningAlgorithm, seed []byte) (PrivateKey, error) { 116 signer, err := newSigner(algo) 117 if err != nil { 118 return nil, fmt.Errorf("key generation failed: %w", err) 119 } 120 return signer.generatePrivateKey(seed) 121 } 122 123 // DecodePrivateKey decodes an array of bytes into a private key of the given algorithm 124 // 125 // The function returns: 126 // - (nil, invalidInputsErrors) if the signing algorithm is not supported 127 // - (nil, invalidInputsErrors) if the input does not serialize a valid private key: 128 // - ECDSA: bytes(x) where bytes() is the big-endian encoding padded to the curve order. 129 // - BLS: bytes(x) where bytes() is the big-endian encoding padded to the order of BLS12-381. 130 // for all algorithms supported, input is big-endian encoding 131 // of a the private scalar less than the curve order and left-padded to 32 bytes 132 // - (nil, error) if an unexpected error occurs 133 // - (sk, nil) otherwise 134 func DecodePrivateKey(algo SigningAlgorithm, data []byte) (PrivateKey, error) { 135 signer, err := newSigner(algo) 136 if err != nil { 137 return nil, fmt.Errorf("decode private key failed: %w", err) 138 } 139 return signer.decodePrivateKey(data) 140 } 141 142 // DecodePublicKey decodes an array of bytes into a public key of the given algorithm 143 // 144 // The function returns: 145 // - (nil, invalidInputsErrors) if the signing algorithm is not supported 146 // - (nil, invalidInputsErrors) if the input does not serialize a valid public key: 147 // - ECDSA: bytes(x)||bytes(y) where bytes() is the big-endian encoding padded to the field size. 148 // - BLS: compressed serialization of a G2 point following https://www.ietf.org/archive/id/draft-irtf-cfrg-pairing-friendly-curves-08.html#name-zcash-serialization-format- 149 // - (nil, error) if an unexpected error occurs 150 // - (sk, nil) otherwise 151 func DecodePublicKey(algo SigningAlgorithm, data []byte) (PublicKey, error) { 152 signer, err := newSigner(algo) 153 if err != nil { 154 return nil, fmt.Errorf("decode public key failed: %w", err) 155 } 156 return signer.decodePublicKey(data) 157 } 158 159 // DecodePublicKeyCompressed decodes an array of bytes given in a compressed representation into a public key of the given algorithm 160 // Only ECDSA is supported (BLS uses the compressed serialzation by default). 161 // 162 // The function returns: 163 // - (nil, invalidInputsErrors) if the signing algorithm is not supported (is not ECDSA) 164 // - (nil, invalidInputsErrors) if the input does not serialize a valid public key: 165 // - ECDSA: sign_byte||bytes(x) according to X9.62 section 4.3.6. 166 // - (nil, error) if an unexpected error occurs 167 // - (sk, nil) otherwise 168 func DecodePublicKeyCompressed(algo SigningAlgorithm, data []byte) (PublicKey, error) { 169 signer, err := newSigner(algo) 170 if err != nil { 171 return nil, fmt.Errorf("decode public key failed: %w", err) 172 } 173 return signer.decodePublicKeyCompressed(data) 174 } 175 176 // Signature type tools 177 178 // Bytes returns a byte array of the signature data 179 func (s Signature) Bytes() []byte { 180 return s[:] 181 } 182 183 // String returns a String representation of the signature data 184 func (s Signature) String() string { 185 return fmt.Sprintf("%#x", s.Bytes()) 186 } 187 188 // Key Pair 189 190 // PrivateKey is an unspecified signature scheme private key 191 type PrivateKey interface { 192 // Algorithm returns the signing algorithm related to the private key. 193 Algorithm() SigningAlgorithm 194 // Size return the key size in bytes. 195 Size() int 196 // String return a hex representation of the key 197 String() string 198 // Sign generates a signature using the provided hasher. 199 Sign([]byte, hash.Hasher) (Signature, error) 200 // PublicKey returns the public key. 201 PublicKey() PublicKey 202 // Encode returns a bytes representation of the private key 203 Encode() []byte 204 // Equals returns true if the given PrivateKeys are equal. Keys are considered unequal if their algorithms are 205 // unequal or if their encoded representations are unequal. If the encoding of either key fails, they are considered 206 // unequal as well. 207 Equals(PrivateKey) bool 208 } 209 210 // PublicKey is an unspecified signature scheme public key. 211 type PublicKey interface { 212 // Algorithm returns the signing algorithm related to the public key. 213 Algorithm() SigningAlgorithm 214 // Size() return the key size in bytes. 215 Size() int 216 // String return a hex representation of the key 217 String() string 218 // Verify verifies a signature of an input message using the provided hasher. 219 Verify(Signature, []byte, hash.Hasher) (bool, error) 220 // Encode returns a bytes representation of the public key. 221 Encode() []byte 222 // EncodeCompressed returns a compressed byte representation of the public key. 223 // The compressed serialization concept is generic to elliptic curves, 224 // but we refer to individual curve parameters for details of the compressed format 225 EncodeCompressed() []byte 226 // Equals returns true if the given PublicKeys are equal. Keys are considered unequal if their algorithms are 227 // unequal or if their encoded representations are unequal. If the encoding of either key fails, they are considered 228 // unequal as well. 229 Equals(PublicKey) bool 230 }