github.com/hashgraph/hedera-sdk-go/v2@v2.48.0/ecdsa_public_key.go (about) 1 package hedera 2 3 /*- 4 * 5 * Hedera Go SDK 6 * 7 * Copyright (C) 2020 - 2024 Hedera Hashgraph, LLC 8 * 9 * Licensed under the Apache License, Version 2.0 (the "License"); 10 * you may not use this file except in compliance with the License. 11 * You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 * 21 */ 22 23 import ( 24 "bytes" 25 "crypto/ecdsa" 26 "crypto/elliptic" 27 "encoding/asn1" 28 "encoding/hex" 29 "math/big" 30 "strings" 31 32 "github.com/btcsuite/btcd/btcec/v2" 33 "github.com/ethereum/go-ethereum/crypto" 34 "github.com/hashgraph/hedera-protobufs-go/services" 35 "github.com/pkg/errors" 36 ) 37 38 type _ECDSAPublicKey struct { 39 *ecdsa.PublicKey 40 } 41 42 const _LegacyECDSAPubKeyPrefix = "302d300706052b8104000a032200" 43 44 func _ECDSAPublicKeyFromBytes(byt []byte) (*_ECDSAPublicKey, error) { 45 length := len(byt) 46 switch length { 47 case 33: 48 return _ECDSAPublicKeyFromBytesRaw(byt) 49 case 47: 50 return _LegacyECDSAPublicKeyFromBytesDer(byt) 51 case 56: 52 return _ECDSAPublicKeyFromBytesDer(byt) 53 default: 54 return &_ECDSAPublicKey{}, _NewErrBadKeyf("invalid compressed ECDSA public key length: %v bytes", len(byt)) 55 } 56 } 57 58 func _ECDSAPublicKeyFromBytesRaw(byt []byte) (*_ECDSAPublicKey, error) { 59 if byt == nil { 60 return &_ECDSAPublicKey{}, errByteArrayNull 61 } 62 if len(byt) != 33 { 63 return &_ECDSAPublicKey{}, _NewErrBadKeyf("invalid public key length: %v bytes", len(byt)) 64 } 65 66 key, err := crypto.DecompressPubkey(byt) 67 if err != nil { 68 return &_ECDSAPublicKey{}, err 69 } 70 71 return &_ECDSAPublicKey{ 72 key, 73 }, nil 74 } 75 76 func _LegacyECDSAPublicKeyFromBytesDer(byt []byte) (*_ECDSAPublicKey, error) { 77 if byt == nil { 78 return &_ECDSAPublicKey{}, errByteArrayNull 79 } 80 81 given := hex.EncodeToString(byt) 82 result := strings.ReplaceAll(given, _LegacyECDSAPubKeyPrefix, "") 83 decoded, err := hex.DecodeString(result) 84 if err != nil { 85 return &_ECDSAPublicKey{}, err 86 } 87 88 if len(decoded) != 33 { 89 return &_ECDSAPublicKey{}, _NewErrBadKeyf("invalid public key length: %v bytes", len(byt)) 90 } 91 92 key, err := crypto.DecompressPubkey(decoded) 93 if err != nil { 94 return &_ECDSAPublicKey{}, err 95 } 96 97 return &_ECDSAPublicKey{ 98 key, 99 }, nil 100 } 101 func _ECDSAPublicKeyFromBytesDer(byt []byte) (*_ECDSAPublicKey, error) { 102 if byt == nil { 103 return &_ECDSAPublicKey{}, errByteArrayNull 104 } 105 106 type AlgorithmIdentifier struct { 107 Algorithm asn1.ObjectIdentifier 108 Parameters asn1.ObjectIdentifier 109 } 110 111 type PublicKeyInfo struct { 112 AlgorithmIdentifier AlgorithmIdentifier 113 PublicKey asn1.BitString 114 } 115 116 key := &PublicKeyInfo{} 117 _, err := asn1.Unmarshal(byt, key) 118 if err != nil { 119 return nil, err 120 } 121 122 // Check if the parsed key uses ECDSA public key algorithm 123 ecdsaPublicKeyAlgorithmOID := asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1} 124 if !key.AlgorithmIdentifier.Algorithm.Equal(ecdsaPublicKeyAlgorithmOID) { 125 return nil, errors.New("public key is not an ECDSA public key") 126 } 127 128 // Check if the parsed key uses secp256k1 curve 129 secp256k1OID := asn1.ObjectIdentifier{1, 3, 132, 0, 10} 130 if !key.AlgorithmIdentifier.Parameters.Equal(secp256k1OID) { 131 return nil, errors.New("public key is not a secp256k1 public key") 132 } 133 134 // Check if the public key is compressed and decompress it if necessary 135 var pubKeyBytes []byte 136 if key.PublicKey.Bytes[0] == 0x02 || key.PublicKey.Bytes[0] == 0x03 { 137 // Decompress the public key 138 pubKey, err := btcec.ParsePubKey(key.PublicKey.Bytes) 139 if err != nil { 140 return nil, err 141 } 142 pubKeyBytes = pubKey.SerializeUncompressed() 143 } else { 144 pubKeyBytes = key.PublicKey.Bytes 145 } 146 147 if len(pubKeyBytes) != 65 { 148 return nil, errors.New("invalid public key length") 149 } 150 151 x := new(big.Int).SetBytes(pubKeyBytes[1:33]) 152 y := new(big.Int).SetBytes(pubKeyBytes[33:]) 153 154 pubKey := &ecdsa.PublicKey{ 155 Curve: btcec.S256(), 156 X: x, 157 Y: y, 158 } 159 160 // Validate the public key 161 if !pubKey.Curve.IsOnCurve(pubKey.X, pubKey.Y) { 162 return nil, errors.New("public key is not on the curve") 163 } 164 165 return &_ECDSAPublicKey{ 166 PublicKey: pubKey, 167 }, nil 168 } 169 170 func _ECDSAPublicKeyFromString(s string) (*_ECDSAPublicKey, error) { 171 byt, err := hex.DecodeString(s) 172 if err != nil { 173 return &_ECDSAPublicKey{}, err 174 } 175 176 return _ECDSAPublicKeyFromBytes(byt) 177 } 178 179 func (pk _ECDSAPublicKey) _BytesRaw() []byte { 180 return crypto.CompressPubkey(pk.PublicKey) 181 } 182 183 func (pk _ECDSAPublicKey) _BytesDer() []byte { 184 // Marshal the public key 185 publicKeyBytes := pk._BytesRaw() 186 187 // Define the public key structure 188 publicKeyInfo := struct { 189 Algorithm struct { 190 Algorithm asn1.ObjectIdentifier 191 Parameters asn1.ObjectIdentifier 192 } 193 PublicKey asn1.BitString 194 }{ 195 Algorithm: struct { 196 Algorithm asn1.ObjectIdentifier 197 Parameters asn1.ObjectIdentifier 198 }{ 199 Algorithm: asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1}, // id-ecPublicKey 200 Parameters: asn1.ObjectIdentifier{1, 3, 132, 0, 10}, // secp256k1 201 }, 202 PublicKey: asn1.BitString{ 203 Bytes: publicKeyBytes, 204 BitLength: 8 * len(publicKeyBytes), 205 }, 206 } 207 208 // Marshal the public key info into DER format 209 derBytes, err := asn1.Marshal(publicKeyInfo) 210 if err != nil { 211 return nil 212 } 213 214 return derBytes 215 } 216 217 func (pk _ECDSAPublicKey) String() string { 218 return pk._StringRaw() 219 } 220 func (pk _ECDSAPublicKey) _StringRaw() string { 221 return hex.EncodeToString(pk._BytesRaw()) 222 } 223 func (pk _ECDSAPublicKey) _StringDer() string { 224 return hex.EncodeToString(pk._BytesDer()) 225 } 226 227 func (pk _ECDSAPublicKey) _ToProtoKey() *services.Key { 228 b := crypto.CompressPubkey(pk.PublicKey) 229 return &services.Key{Key: &services.Key_ECDSASecp256K1{ECDSASecp256K1: b}} 230 } 231 232 func (pk _ECDSAPublicKey) _ToSignaturePairProtobuf(signature []byte) *services.SignaturePair { 233 return &services.SignaturePair{ 234 PubKeyPrefix: pk._BytesRaw(), 235 Signature: &services.SignaturePair_ECDSASecp256K1{ 236 ECDSASecp256K1: signature, 237 }, 238 } 239 } 240 241 func (pk _ECDSAPublicKey) _Verify(message []byte, signature []byte) bool { 242 return crypto.VerifySignature(pk._BytesRaw(), message, signature) 243 } 244 245 func (pk _ECDSAPublicKey) _VerifyTransaction(tx Transaction) bool { 246 if tx.signedTransactions._Length() == 0 { 247 return false 248 } 249 250 _, _ = tx._BuildAllTransactions() 251 252 for _, value := range tx.signedTransactions.slice { 253 tx := value.(*services.SignedTransaction) 254 found := false 255 for _, sigPair := range tx.SigMap.GetSigPair() { 256 if bytes.Equal(sigPair.GetPubKeyPrefix(), pk._BytesRaw()) { 257 found = true 258 if !pk._Verify(tx.BodyBytes, sigPair.GetECDSASecp256K1()) { 259 return false 260 } 261 } 262 } 263 264 if !found { 265 return false 266 } 267 } 268 269 return true 270 } 271 272 func (pk _ECDSAPublicKey) _ToFullKey() []byte { 273 return elliptic.Marshal(crypto.S256(), pk.X, pk.Y) 274 } 275 276 func (pk _ECDSAPublicKey) _ToEthereumAddress() string { 277 temp := pk._ToFullKey()[1:] 278 hash := crypto.Keccak256(temp) 279 return hex.EncodeToString(hash[12:]) 280 }