github.com/koko1123/flow-go-1@v0.29.6/network/p2p/keyutils/keyTranslator.go (about) 1 package keyutils 2 3 import ( 4 goecdsa "crypto/ecdsa" 5 "crypto/elliptic" 6 "crypto/x509" 7 "fmt" 8 "math/big" 9 10 lcrypto "github.com/libp2p/go-libp2p/core/crypto" 11 lcrypto_pb "github.com/libp2p/go-libp2p/core/crypto/pb" 12 "github.com/libp2p/go-libp2p/core/peer" 13 14 "github.com/onflow/flow-go/crypto" 15 fcrypto "github.com/onflow/flow-go/crypto" 16 ) 17 18 // This module is meant to help libp2p <-> flow public key conversions 19 // Flow's Network Public Keys and LibP2P's public keys are a marshalling standard away from each other and inter-convertible. 20 // Libp2p supports keys as ECDSA public Keys on either the NIST P-256 curve or the "Bitcoin" secp256k1 curve, see https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md#peer-ids 21 // libp2p represents the P-256 keys as ASN1-DER and the secp256k1 keys as X9.62 encodings in compressed format 22 // 23 // While Flow's key types supports both secp256k1 and P-256 keys (under crypto/ecdsa), note that Flow's networking keys are always P-256 keys. 24 // Flow represents both the P-256 keys and the secp256k1 keys in uncompressed representation, but their byte serializations (Encode) do not include the X9.62 compression bit 25 // Flow also makes a X9.62 compressed format (with compression bit) accessible (EncodeCompressed) 26 27 // assigns a big.Int input to a Go ecdsa private key 28 func setPrKey(c elliptic.Curve, k *big.Int) *goecdsa.PrivateKey { 29 priv := new(goecdsa.PrivateKey) 30 priv.PublicKey.Curve = c 31 priv.D = k 32 priv.PublicKey.X, priv.PublicKey.Y = c.ScalarBaseMult(k.Bytes()) 33 return priv 34 } 35 36 // assigns two big.Int inputs to a Go ecdsa public key 37 func setPubKey(c elliptic.Curve, x *big.Int, y *big.Int) *goecdsa.PublicKey { 38 pub := new(goecdsa.PublicKey) 39 pub.Curve = c 40 pub.X = x 41 pub.Y = y 42 return pub 43 } 44 45 // Both Flow and LibP2P define a crypto package with their own abstraction of Keys 46 // These utility functions convert a Flow crypto key to a LibP2P key (Flow --> LibP2P) 47 48 // PeerIDFromFlowPublicKey converts a Flow public key to a LibP2P peer ID. 49 func PeerIDFromFlowPublicKey(networkPubKey fcrypto.PublicKey) (pid peer.ID, err error) { 50 pk, err := LibP2PPublicKeyFromFlow(networkPubKey) 51 if err != nil { 52 err = fmt.Errorf("failed to convert Flow key to LibP2P key: %w", err) 53 return 54 } 55 56 pid, err = peer.IDFromPublicKey(pk) 57 if err != nil { 58 err = fmt.Errorf("failed to convert LibP2P key to peer ID: %w", err) 59 return 60 } 61 62 return 63 } 64 65 // LibP2PPrivKeyFromFlow converts a Flow private key to a LibP2P Private key 66 func LibP2PPrivKeyFromFlow(fpk fcrypto.PrivateKey) (lcrypto.PrivKey, error) { 67 // get the signature algorithm 68 keyType, err := keyType(fpk.Algorithm()) 69 if err != nil { 70 return nil, err 71 } 72 73 // based on the signature algorithm, get the appropriate libp2p unmarshaller 74 um, ok := lcrypto.PrivKeyUnmarshallers[keyType] 75 if !ok { 76 return nil, lcrypto.ErrBadKeyType 77 } 78 79 // get the raw dump of the flow key 80 bytes := fpk.Encode() 81 82 // in the case of NIST curves, the raw bytes need to be converted to x509 bytes 83 // to accommodate libp2p unmarshaller 84 if keyType == lcrypto_pb.KeyType_ECDSA { 85 var k big.Int 86 k.SetBytes(bytes) 87 goKey := setPrKey(elliptic.P256(), &k) 88 bytes, err = x509.MarshalECPrivateKey(goKey) 89 if err != nil { 90 return nil, lcrypto.ErrBadKeyType 91 } 92 } 93 return um(bytes) 94 } 95 96 // LibP2PPublicKeyFromFlow converts a Flow public key to a LibP2P public key 97 func LibP2PPublicKeyFromFlow(fpk fcrypto.PublicKey) (lcrypto.PubKey, error) { 98 keyType, err := keyType(fpk.Algorithm()) 99 if err != nil { 100 return nil, err 101 } 102 um, ok := lcrypto.PubKeyUnmarshallers[keyType] 103 if !ok { 104 return nil, lcrypto.ErrBadKeyType 105 } 106 107 tempBytes := fpk.Encode() 108 109 // at this point, keytype is either KeyType_ECDSA or KeyType_Secp256k1 110 // and can't hold another value 111 var bytes []byte 112 if keyType == lcrypto_pb.KeyType_ECDSA { 113 var x, y big.Int 114 x.SetBytes(tempBytes[:len(tempBytes)/2]) 115 y.SetBytes(tempBytes[len(tempBytes)/2:]) 116 goKey := setPubKey(elliptic.P256(), &x, &y) 117 bytes, err = x509.MarshalPKIXPublicKey(goKey) 118 if err != nil { 119 return nil, lcrypto.ErrBadKeyType 120 } 121 } else if keyType == lcrypto_pb.KeyType_Secp256k1 { 122 bytes = make([]byte, crypto.PubKeyLenECDSASecp256k1+1) // libp2p requires an extra byte 123 bytes[0] = 4 // signals uncompressed form as specified in section 4.3.6/7 of ANSI X9.62. 124 copy(bytes[1:], tempBytes) 125 } 126 127 return um(bytes) 128 } 129 130 // This converts some libp2p PubKeys to a flow PublicKey 131 // - the supported key types are ECDSA P-256 and ECDSA Secp256k1 public keys, 132 // - libp2p also supports RSA and Ed25519 keys, which Flow doesn't, their conversion will return an error. 133 func FlowPublicKeyFromLibP2P(lpk lcrypto.PubKey) (fcrypto.PublicKey, error) { 134 135 switch ktype := lpk.Type(); ktype { 136 case lcrypto_pb.KeyType_ECDSA: 137 pubB, err := lpk.Raw() 138 if err != nil { 139 return nil, lcrypto.ErrBadKeyType 140 } 141 key, err := x509.ParsePKIXPublicKey(pubB) 142 if err != nil { 143 // impossible to decode from ASN1.DER 144 return nil, lcrypto.ErrBadKeyType 145 } 146 cryptoKey, ok := key.(*goecdsa.PublicKey) 147 if !ok { 148 // not recognized as crypto.P-256 149 return nil, lcrypto.ErrNotECDSAPubKey 150 } 151 // ferrying through DecodePublicKey to get the curve checks 152 pk_uncompressed := elliptic.Marshal(cryptoKey, cryptoKey.X, cryptoKey.Y) 153 // the first bit is the compression bit of X9.62 154 pubKey, err := crypto.DecodePublicKey(crypto.ECDSAP256, pk_uncompressed[1:]) 155 if err != nil { 156 return nil, lcrypto.ErrNotECDSAPubKey 157 } 158 return pubKey, nil 159 case lcrypto_pb.KeyType_Secp256k1: 160 // libp2p uses the compressed representation, flow the uncompressed one 161 lpk_secp256k1, ok := lpk.(*lcrypto.Secp256k1PublicKey) 162 if !ok { 163 return nil, lcrypto.ErrBadKeyType 164 } 165 secpBytes, err := lpk_secp256k1.Raw() 166 if err != nil { // this never errors 167 return nil, lcrypto.ErrBadKeyType 168 } 169 pk, err := crypto.DecodePublicKeyCompressed(crypto.ECDSASecp256k1, secpBytes) 170 if err != nil { 171 return nil, lcrypto.ErrNotECDSAPubKey 172 } 173 return pk, nil 174 default: 175 return nil, lcrypto.ErrBadKeyType 176 } 177 178 } 179 180 // keyType translates Flow signing algorithm constants to the corresponding LibP2P constants 181 func keyType(sa fcrypto.SigningAlgorithm) (lcrypto_pb.KeyType, error) { 182 switch sa { 183 case fcrypto.ECDSAP256: 184 return lcrypto_pb.KeyType_ECDSA, nil 185 case fcrypto.ECDSASecp256k1: 186 return lcrypto_pb.KeyType_Secp256k1, nil 187 default: 188 return -1, lcrypto.ErrBadKeyType 189 } 190 }