...

Source file src/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/ed448.go

Documentation: github.com/ProtonMail/go-crypto/openpgp/internal/ecc

     1  // Package ecc implements a generic interface for ECDH, ECDSA, and EdDSA.
     2  package ecc
     3  
     4  import (
     5  	"crypto/subtle"
     6  	"io"
     7  
     8  	"github.com/ProtonMail/go-crypto/openpgp/errors"
     9  	ed448lib "github.com/cloudflare/circl/sign/ed448"
    10  )
    11  
    12  type ed448 struct{}
    13  
    14  func NewEd448() *ed448 {
    15  	return &ed448{}
    16  }
    17  
    18  func (c *ed448) GetCurveName() string {
    19  	return "ed448"
    20  }
    21  
    22  // MarshalBytePoint encodes the public point from native format, adding the prefix.
    23  // See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.5
    24  func (c *ed448) MarshalBytePoint(x []byte) []byte {
    25  	// Return prefixed
    26  	return append([]byte{0x40}, x...)
    27  }
    28  
    29  // UnmarshalBytePoint decodes a point from prefixed format to native.
    30  // See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.5
    31  func (c *ed448) UnmarshalBytePoint(point []byte) (x []byte) {
    32  	if len(point) != ed448lib.PublicKeySize+1 {
    33  		return nil
    34  	}
    35  
    36  	// Strip prefix
    37  	return point[1:]
    38  }
    39  
    40  // MarshalByteSecret encoded a scalar from native format to prefixed.
    41  // See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.5
    42  func (c *ed448) MarshalByteSecret(d []byte) []byte {
    43  	// Return prefixed
    44  	return append([]byte{0x40}, d...)
    45  }
    46  
    47  // UnmarshalByteSecret decodes a scalar from prefixed format to native.
    48  // See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.5
    49  func (c *ed448) UnmarshalByteSecret(s []byte) (d []byte) {
    50  	// Check prefixed size
    51  	if len(s) != ed448lib.SeedSize+1 {
    52  		return nil
    53  	}
    54  
    55  	// Strip prefix
    56  	return s[1:]
    57  }
    58  
    59  // MarshalSignature splits a signature in R and S, where R is in prefixed native format and
    60  // S is an MPI with value zero.
    61  // See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.2.3.3.2
    62  func (c *ed448) MarshalSignature(sig []byte) (r, s []byte) {
    63  	return append([]byte{0x40}, sig...), []byte{}
    64  }
    65  
    66  // UnmarshalSignature decodes R and S in the native format. Only R is used, in prefixed native format.
    67  // See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.2.3.3.2
    68  func (c *ed448) UnmarshalSignature(r, s []byte) (sig []byte) {
    69  	if len(r) != ed448lib.SignatureSize+1 {
    70  		return nil
    71  	}
    72  
    73  	return r[1:]
    74  }
    75  
    76  func (c *ed448) GenerateEdDSA(rand io.Reader) (pub, priv []byte, err error) {
    77  	pk, sk, err := ed448lib.GenerateKey(rand)
    78  
    79  	if err != nil {
    80  		return nil, nil, err
    81  	}
    82  
    83  	return pk, sk[:ed448lib.SeedSize], nil
    84  }
    85  
    86  func getEd448Sk(publicKey, privateKey []byte) ed448lib.PrivateKey {
    87  	return append(privateKey, publicKey...)
    88  }
    89  
    90  func (c *ed448) Sign(publicKey, privateKey, message []byte) (sig []byte, err error) {
    91  	// Ed448 is used with the empty string as a context string.
    92  	// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-13.7
    93  	sig = ed448lib.Sign(getEd448Sk(publicKey, privateKey), message, "")
    94  
    95  	return sig, nil
    96  }
    97  
    98  func (c *ed448) Verify(publicKey, message, sig []byte) bool {
    99  	// Ed448 is used with the empty string as a context string.
   100  	// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-13.7
   101  	return ed448lib.Verify(publicKey, message, sig, "")
   102  }
   103  
   104  func (c *ed448) ValidateEdDSA(publicKey, privateKey []byte) (err error) {
   105  	priv := getEd448Sk(publicKey, privateKey)
   106  	expectedPriv := ed448lib.NewKeyFromSeed(priv.Seed())
   107  	if subtle.ConstantTimeCompare(priv, expectedPriv) == 0 {
   108  		return errors.KeyInvalidError("ecc: invalid ed448 secret")
   109  	}
   110  	return nil
   111  }
   112  

View as plain text