Skip to content

Commit

Permalink
Merge pull request #6 from berachain/ethpub
Browse files Browse the repository at this point in the history
ethpub
  • Loading branch information
itsdevbear authored Feb 23, 2023
2 parents 367abc3 + 4f5848e commit 79bc906
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 5 deletions.
81 changes: 76 additions & 5 deletions core/types/transaction_signing.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,9 @@ type Signer interface {
// Sender returns the sender address of the transaction.
Sender(tx *Transaction) (common.Address, error)

// PubKey returns the public key of the sender.
PubKey(tx *Transaction) ([]byte, error)

// SignatureValues returns the raw R, S, V values corresponding to the
// given signature.
SignatureValues(tx *Transaction, sig []byte) (r, s, v *big.Int, err error)
Expand Down Expand Up @@ -195,6 +198,20 @@ func (s londonSigner) Sender(tx *Transaction) (common.Address, error) {
return recoverPlain(s.Hash(tx), R, S, V, true)
}

func (s londonSigner) PubKey(tx *Transaction) ([]byte, error) {
if tx.Type() != DynamicFeeTxType {
return s.eip2930Signer.PubKey(tx)
}
V, R, S := tx.RawSignatureValues()
// DynamicFee txs are defined to use 0 and 1 as their recovery
// id, add 27 to become equivalent to unprotected Homestead signatures.
V = new(big.Int).Add(V, big.NewInt(27))
if tx.ChainId().Cmp(s.chainId) != 0 {
return nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, tx.ChainId(), s.chainId)
}
return recoverPub(s.Hash(tx), R, S, V, true)
}

func (s londonSigner) Equal(s2 Signer) bool {
x, ok := s2.(londonSigner)
return ok && x.chainId.Cmp(s.chainId) == 0
Expand Down Expand Up @@ -275,6 +292,28 @@ func (s eip2930Signer) Sender(tx *Transaction) (common.Address, error) {
return recoverPlain(s.Hash(tx), R, S, V, true)
}

func (s eip2930Signer) PubKey(tx *Transaction) ([]byte, error) {
V, R, S := tx.RawSignatureValues()
switch tx.Type() {
case LegacyTxType:
if !tx.Protected() {
return HomesteadSigner{}.PubKey(tx)
}
V = new(big.Int).Sub(V, s.chainIdMul)
V.Sub(V, big8)
case AccessListTxType:
// AL txs are defined to use 0 and 1 as their recovery
// id, add 27 to become equivalent to unprotected Homestead signatures.
V = new(big.Int).Add(V, big.NewInt(27))
default:
return nil, ErrTxTypeNotSupported
}
if tx.ChainId().Cmp(s.chainId) != 0 {
return nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, tx.ChainId(), s.chainId)
}
return recoverPub(s.Hash(tx), R, S, V, true)
}

func (s eip2930Signer) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) {
switch txdata := tx.inner.(type) {
case *LegacyTx:
Expand Down Expand Up @@ -372,6 +411,22 @@ func (s EIP155Signer) Sender(tx *Transaction) (common.Address, error) {
return recoverPlain(s.Hash(tx), R, S, V, true)
}

func (s EIP155Signer) PubKey(tx *Transaction) ([]byte, error) {
if tx.Type() != LegacyTxType {
return nil, ErrTxTypeNotSupported
}
if !tx.Protected() {
return HomesteadSigner{}.PubKey(tx)
}
if tx.ChainId().Cmp(s.chainId) != 0 {
return nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, tx.ChainId(), s.chainId)
}
V, R, S := tx.RawSignatureValues()
V = new(big.Int).Sub(V, s.chainIdMul)
V.Sub(V, big8)
return recoverPub(s.Hash(tx), R, S, V, true)
}

// SignatureValues returns signature values. This signature
// needs to be in the [R || S || V] format where V is 0 or 1.
func (s EIP155Signer) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) {
Expand Down Expand Up @@ -448,6 +503,14 @@ func (fs FrontierSigner) Sender(tx *Transaction) (common.Address, error) {
return recoverPlain(fs.Hash(tx), r, s, v, false)
}

func (fs FrontierSigner) PubKey(tx *Transaction) ([]byte, error) {
if tx.Type() != LegacyTxType {
return nil, ErrTxTypeNotSupported
}
v, r, s := tx.RawSignatureValues()
return recoverPub(fs.Hash(tx), r, s, v, false)
}

// SignatureValues returns signature values. This signature
// needs to be in the [R || S || V] format where V is 0 or 1.
func (fs FrontierSigner) SignatureValues(tx *Transaction, sig []byte) (r, s, v *big.Int, err error) {
Expand Down Expand Up @@ -481,13 +544,13 @@ func decodeSignature(sig []byte) (r, s, v *big.Int) {
return r, s, v
}

func recoverPlain(sighash common.Hash, R, S, Vb *big.Int, homestead bool) (common.Address, error) {
func recoverPub(sighash common.Hash, R, S, Vb *big.Int, homestead bool) ([]byte, error) {
if Vb.BitLen() > 8 {
return common.Address{}, ErrInvalidSig
return nil, ErrInvalidSig
}
V := byte(Vb.Uint64() - 27)
if !crypto.ValidateSignatureValues(V, R, S, homestead) {
return common.Address{}, ErrInvalidSig
return nil, ErrInvalidSig
}
// encode the signature in uncompressed format
r, s := R.Bytes(), S.Bytes()
Expand All @@ -498,10 +561,18 @@ func recoverPlain(sighash common.Hash, R, S, Vb *big.Int, homestead bool) (commo
// recover the public key from the signature
pub, err := crypto.Ecrecover(sighash[:], sig)
if err != nil {
return common.Address{}, err
return nil, err
}
if len(pub) == 0 || pub[0] != 4 {
return common.Address{}, errors.New("invalid public key")
return nil, errors.New("invalid public key")
}
return pub, nil
}

func recoverPlain(sighash common.Hash, R, S, Vb *big.Int, homestead bool) (common.Address, error) {
pub, err := recoverPub(sighash, R, S, Vb, homestead)
if err != nil {
return common.Address{}, err
}
var addr common.Address
copy(addr[:], crypto.Keccak256(pub[1:])[12:])
Expand Down
5 changes: 5 additions & 0 deletions ethclient/signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ func (s *senderFromServer) Sender(tx *types.Transaction) (common.Address, error)
return s.addr, nil
}

func (s *senderFromServer) PubKey(tx *types.Transaction) ([]byte, error) {
// not implemented
return nil, nil
}

func (s *senderFromServer) ChainID() *big.Int {
panic("can't sign with senderFromServer")
}
Expand Down

0 comments on commit 79bc906

Please sign in to comment.