// Package eddsa implements EdDSA signature, suitable for OpenPGP, as specified in // https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-13.7 package eddsa import ( "errors" "github.com/ProtonMail/go-crypto/openpgp/internal/ecc" "io" ) type PublicKey struct { X []byte curve ecc.EdDSACurve } type PrivateKey struct { PublicKey D []byte } func NewPublicKey(curve ecc.EdDSACurve) *PublicKey { return &PublicKey{ curve: curve, } } func NewPrivateKey(key PublicKey) *PrivateKey { return &PrivateKey{ PublicKey: key, } } func (pk *PublicKey) GetCurve() ecc.EdDSACurve { return pk.curve } func (pk *PublicKey) MarshalPoint() []byte { return pk.curve.MarshalBytePoint(pk.X) } func (pk *PublicKey) UnmarshalPoint(x []byte) error { pk.X = pk.curve.UnmarshalBytePoint(x) if pk.X == nil { return errors.New("eddsa: failed to parse EC point") } return nil } func (sk *PrivateKey) MarshalByteSecret() []byte { return sk.curve.MarshalByteSecret(sk.D) } func (sk *PrivateKey) UnmarshalByteSecret(d []byte) error { sk.D = sk.curve.UnmarshalByteSecret(d) if sk.D == nil { return errors.New("eddsa: failed to parse scalar") } return nil } func GenerateKey(rand io.Reader, c ecc.EdDSACurve) (priv *PrivateKey, err error) { priv = new(PrivateKey) priv.PublicKey.curve = c priv.PublicKey.X, priv.D, err = c.GenerateEdDSA(rand) return } func Sign(priv *PrivateKey, message []byte) (r, s []byte, err error) { sig, err := priv.PublicKey.curve.Sign(priv.PublicKey.X, priv.D, message) if err != nil { return nil, nil, err } r, s = priv.PublicKey.curve.MarshalSignature(sig) return } func Verify(pub *PublicKey, message, r, s []byte) bool { sig := pub.curve.UnmarshalSignature(r, s) if sig == nil { return false } return pub.curve.Verify(pub.X, message, sig) } func Validate(priv *PrivateKey) error { return priv.curve.ValidateEdDSA(priv.PublicKey.X, priv.D) }