tutus-consensus/internal/crypto/ecdsa.go

86 lines
1.8 KiB
Go

package crypto
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/sha256"
"errors"
"io"
"math/big"
"github.com/tutus-one/tutus-consensus"
)
type (
// ECDSAPub is a wrapper over *ecsda.PublicKey.
ECDSAPub struct {
*ecdsa.PublicKey
}
// ECDSAPriv is a wrapper over *ecdsa.PrivateKey.
ECDSAPriv struct {
*ecdsa.PrivateKey
}
)
func generateECDSA(r io.Reader) (dbft.PrivateKey, dbft.PublicKey) {
key, err := ecdsa.GenerateKey(elliptic.P256(), r)
if err != nil {
return nil, nil
}
return NewECDSAPrivateKey(key), NewECDSAPublicKey(&key.PublicKey)
}
// NewECDSAPublicKey returns new PublicKey from *ecdsa.PublicKey.
func NewECDSAPublicKey(pub *ecdsa.PublicKey) dbft.PublicKey {
return &ECDSAPub{
PublicKey: pub,
}
}
// NewECDSAPrivateKey returns new PublicKey from *ecdsa.PrivateKey.
func NewECDSAPrivateKey(key *ecdsa.PrivateKey) dbft.PrivateKey {
return &ECDSAPriv{
PrivateKey: key,
}
}
// Sign signs message using P-256 curve.
func (e ECDSAPriv) Sign(msg []byte) ([]byte, error) {
h := sha256.Sum256(msg)
r, s, err := ecdsa.Sign(rand.Reader, e.PrivateKey, h[:])
if err != nil {
return nil, err
}
sig := make([]byte, 32*2)
_ = r.FillBytes(sig[:32])
_ = s.FillBytes(sig[32:])
return sig, nil
}
// Equals implements dbft.PublicKey interface.
func (e *ECDSAPub) Equals(other dbft.PublicKey) bool {
return e.Equal(other.(*ECDSAPub).PublicKey)
}
// Compare does three-way comparison of ECDSAPub.
func (e *ECDSAPub) Compare(p *ECDSAPub) int {
return e.X.Cmp(p.X)
}
// Verify verifies signature using P-256 curve.
func (e ECDSAPub) Verify(msg, sig []byte) error {
h := sha256.Sum256(msg)
rBytes := new(big.Int).SetBytes(sig[0:32])
sBytes := new(big.Int).SetBytes(sig[32:64])
res := ecdsa.Verify(e.PublicKey, h[:], rBytes, sBytes)
if !res {
return errors.New("bad signature")
}
return nil
}