e85b68ef53
We need those operations for p2p/enr. Also upgrade github.com/btcsuite/btcd/btcec to the latest version and improve BenchmarkSha3. The benchmark printed extra output that confused tools like benchstat and ignored N.
109 lines
3.5 KiB
Go
109 lines
3.5 KiB
Go
// Copyright 2017 The go-ethereum Authors
|
|
// This file is part of the go-ethereum library.
|
|
//
|
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Lesser General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
// +build nacl js nocgo
|
|
|
|
package crypto
|
|
|
|
import (
|
|
"crypto/ecdsa"
|
|
"crypto/elliptic"
|
|
"errors"
|
|
"fmt"
|
|
"math/big"
|
|
|
|
"github.com/btcsuite/btcd/btcec"
|
|
)
|
|
|
|
// Ecrecover returns the uncompressed public key that created the given signature.
|
|
func Ecrecover(hash, sig []byte) ([]byte, error) {
|
|
pub, err := SigToPub(hash, sig)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
bytes := (*btcec.PublicKey)(pub).SerializeUncompressed()
|
|
return bytes, err
|
|
}
|
|
|
|
// SigToPub returns the public key that created the given signature.
|
|
func SigToPub(hash, sig []byte) (*ecdsa.PublicKey, error) {
|
|
// Convert to btcec input format with 'recovery id' v at the beginning.
|
|
btcsig := make([]byte, 65)
|
|
btcsig[0] = sig[64] + 27
|
|
copy(btcsig[1:], sig)
|
|
|
|
pub, _, err := btcec.RecoverCompact(btcec.S256(), btcsig, hash)
|
|
return (*ecdsa.PublicKey)(pub), err
|
|
}
|
|
|
|
// Sign calculates an ECDSA signature.
|
|
//
|
|
// This function is susceptible to chosen plaintext attacks that can leak
|
|
// information about the private key that is used for signing. Callers must
|
|
// be aware that the given hash cannot be chosen by an adversery. Common
|
|
// solution is to hash any input before calculating the signature.
|
|
//
|
|
// The produced signature is in the [R || S || V] format where V is 0 or 1.
|
|
func Sign(hash []byte, prv *ecdsa.PrivateKey) ([]byte, error) {
|
|
if len(hash) != 32 {
|
|
return nil, fmt.Errorf("hash is required to be exactly 32 bytes (%d)", len(hash))
|
|
}
|
|
if prv.Curve != btcec.S256() {
|
|
return nil, fmt.Errorf("private key curve is not secp256k1")
|
|
}
|
|
sig, err := btcec.SignCompact(btcec.S256(), (*btcec.PrivateKey)(prv), hash, false)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
// Convert to Ethereum signature format with 'recovery id' v at the end.
|
|
v := sig[0] - 27
|
|
copy(sig, sig[1:])
|
|
sig[64] = v
|
|
return sig, nil
|
|
}
|
|
|
|
// VerifySignature checks that the given public key created signature over hash.
|
|
// The public key should be in compressed (33 bytes) or uncompressed (65 bytes) format.
|
|
// The signature should have the 64 byte [R || S] format.
|
|
func VerifySignature(pubkey, hash, signature []byte) bool {
|
|
if len(signature) != 64 {
|
|
return false
|
|
}
|
|
sig := &btcec.Signature{R: new(big.Int).SetBytes(signature[:32]), S: new(big.Int).SetBytes(signature[32:])}
|
|
key, err := btcec.ParsePubKey(pubkey, btcec.S256())
|
|
if err != nil {
|
|
return false
|
|
}
|
|
return sig.Verify(hash, key)
|
|
}
|
|
|
|
// DecompressPubkey parses a public key in the 33-byte compressed format.
|
|
func DecompressPubkey(pubkey []byte) (*ecdsa.PublicKey, error) {
|
|
if len(pubkey) != 33 {
|
|
return nil, errors.New("invalid compressed public key length")
|
|
}
|
|
key, err := btcec.ParsePubKey(pubkey, btcec.S256())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return key.ToECDSA(), nil
|
|
}
|
|
|
|
// S256 returns an instance of the secp256k1 curve.
|
|
func S256() elliptic.Curve {
|
|
return btcec.S256()
|
|
}
|