...

Source file src/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/ed25519.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  	ed25519lib "github.com/cloudflare/circl/sign/ed25519"
    10  )
    11  
    12  const ed25519Size = 32
    13  
    14  type ed25519 struct{}
    15  
    16  func NewEd25519() *ed25519 {
    17  	return &ed25519{}
    18  }
    19  
    20  func (c *ed25519) GetCurveName() string {
    21  	return "ed25519"
    22  }
    23  
    24  // MarshalBytePoint encodes the public point from native format, adding the prefix.
    25  // See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.5
    26  func (c *ed25519) MarshalBytePoint(x []byte) []byte {
    27  	return append([]byte{0x40}, x...)
    28  }
    29  
    30  // UnmarshalBytePoint decodes a point from prefixed format to native.
    31  // See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.5
    32  func (c *ed25519) UnmarshalBytePoint(point []byte) (x []byte) {
    33  	if len(point) != ed25519lib.PublicKeySize+1 {
    34  		return nil
    35  	}
    36  
    37  	// Return unprefixed
    38  	return point[1:]
    39  }
    40  
    41  // MarshalByteSecret encodes a scalar in native format.
    42  // See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.5
    43  func (c *ed25519) MarshalByteSecret(d []byte) []byte {
    44  	return d
    45  }
    46  
    47  // UnmarshalByteSecret decodes a scalar in native format and re-adds the stripped leading zeroes
    48  // See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.5.5.5
    49  func (c *ed25519) UnmarshalByteSecret(s []byte) (d []byte) {
    50  	if len(s) > ed25519lib.SeedSize {
    51  		return nil
    52  	}
    53  
    54  	// Handle stripped leading zeroes
    55  	d = make([]byte, ed25519lib.SeedSize)
    56  	copy(d[ed25519lib.SeedSize-len(s):], s)
    57  	return
    58  }
    59  
    60  // MarshalSignature splits a signature in R and S.
    61  // See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.2.3.3.1
    62  func (c *ed25519) MarshalSignature(sig []byte) (r, s []byte) {
    63  	return sig[:ed25519Size], sig[ed25519Size:]
    64  }
    65  
    66  // UnmarshalSignature decodes R and S in the native format, re-adding the stripped leading zeroes
    67  // See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.2.3.3.1
    68  func (c *ed25519) UnmarshalSignature(r, s []byte) (sig []byte) {
    69  	// Check size
    70  	if len(r) > 32 || len(s) > 32 {
    71  		return nil
    72  	}
    73  
    74  	sig = make([]byte, ed25519lib.SignatureSize)
    75  
    76  	// Handle stripped leading zeroes
    77  	copy(sig[ed25519Size-len(r):ed25519Size], r)
    78  	copy(sig[ed25519lib.SignatureSize-len(s):], s)
    79  	return sig
    80  }
    81  
    82  func (c *ed25519) GenerateEdDSA(rand io.Reader) (pub, priv []byte, err error) {
    83  	pk, sk, err := ed25519lib.GenerateKey(rand)
    84  
    85  	if err != nil {
    86  		return nil, nil, err
    87  	}
    88  
    89  	return pk, sk[:ed25519lib.SeedSize], nil
    90  }
    91  
    92  func getEd25519Sk(publicKey, privateKey []byte) ed25519lib.PrivateKey {
    93  	return append(privateKey, publicKey...)
    94  }
    95  
    96  func (c *ed25519) Sign(publicKey, privateKey, message []byte) (sig []byte, err error) {
    97  	sig = ed25519lib.Sign(getEd25519Sk(publicKey, privateKey), message)
    98  	return sig, nil
    99  }
   100  
   101  func (c *ed25519) Verify(publicKey, message, sig []byte) bool {
   102  	return ed25519lib.Verify(publicKey, message, sig)
   103  }
   104  
   105  func (c *ed25519) ValidateEdDSA(publicKey, privateKey []byte) (err error) {
   106  	priv := getEd25519Sk(publicKey, privateKey)
   107  	expectedPriv := ed25519lib.NewKeyFromSeed(priv.Seed())
   108  	if subtle.ConstantTimeCompare(priv, expectedPriv) == 0 {
   109  		return errors.KeyInvalidError("ecc: invalid ed25519 secret")
   110  	}
   111  	return nil
   112  }
   113  

View as plain text