code.vegaprotocol.io/vega@v0.79.0/libs/crypto/signature/signature.go (about) 1 // Copyright (C) 2023 Gobalsky Labs Limited 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 package crypto 17 18 import ( 19 "errors" 20 "fmt" 21 22 wcrypto "code.vegaprotocol.io/vega/wallet/crypto" 23 24 "github.com/ethereum/go-ethereum/common" 25 ecrypto "github.com/ethereum/go-ethereum/crypto" 26 ) 27 28 var ( 29 ErrAddressesDoesNotMatch = func(expected, recovered common.Address) error { 30 return fmt.Errorf("addresses does not match, expected(%s) recovered(%s)", expected.Hex(), recovered.Hex()) 31 } 32 ErrInvalidSignature = errors.New("invalid signature") 33 ErrEthInvalidSignature = errors.New("invalid ethereum signature") 34 ) 35 36 func VerifyEthereumSignature(message, signature []byte, hexAddress string) error { 37 address := common.HexToAddress(hexAddress) 38 hash := ecrypto.Keccak256(message) 39 40 if len(signature) <= ecrypto.RecoveryIDOffset { 41 return ErrEthInvalidSignature 42 } 43 44 // see reference in multisig control signature verification for more details 45 if signature[ecrypto.RecoveryIDOffset] == 27 || signature[ecrypto.RecoveryIDOffset] == 28 { 46 signature[ecrypto.RecoveryIDOffset] -= 27 47 } 48 49 // get the pubkey from the signature 50 pubkey, err := ecrypto.SigToPub(hash, signature) 51 if err != nil { 52 return err 53 } 54 55 // verify the signature 56 signatureNoID := signature[:len(signature)-1] 57 if !ecrypto.VerifySignature(ecrypto.CompressPubkey(pubkey), hash, signatureNoID) { 58 return ErrEthInvalidSignature 59 } 60 61 // ensure the signer is the expected ethereum wallet 62 signerAddress := ecrypto.PubkeyToAddress(*pubkey) 63 if address != signerAddress { 64 return ErrAddressesDoesNotMatch(address, signerAddress) 65 } 66 67 return nil 68 } 69 70 func RecoverEthereumAddress(message, signature []byte) (common.Address, error) { 71 hash := ecrypto.Keccak256(message) 72 73 if len(signature) <= ecrypto.RecoveryIDOffset { 74 return common.Address{}, ErrEthInvalidSignature 75 } 76 77 // see reference in multisig control signature verification for more details 78 if signature[ecrypto.RecoveryIDOffset] == 27 || signature[ecrypto.RecoveryIDOffset] == 28 { 79 signature[ecrypto.RecoveryIDOffset] -= 27 80 } 81 82 // get the pubkey from the signature 83 pubkey, err := ecrypto.SigToPub(hash, signature) 84 if err != nil { 85 return common.Address{}, err 86 } 87 88 // verify the signature 89 signatureNoID := signature[:len(signature)-1] 90 if !ecrypto.VerifySignature(ecrypto.CompressPubkey(pubkey), hash, signatureNoID) { 91 return common.Address{}, ErrEthInvalidSignature 92 } 93 94 return ecrypto.PubkeyToAddress(*pubkey), nil 95 } 96 97 func VerifyVegaSignature(message, signature, pubkey []byte) error { 98 alg := wcrypto.NewEd25519() 99 ok, err := alg.Verify(pubkey, message, signature) 100 if err != nil { 101 return err 102 } 103 104 if !ok { 105 return ErrInvalidSignature 106 } 107 108 return nil 109 }