github.com/cloudflare/circl@v1.5.0/sign/eddilithium2/eddilithium.go (about)

     1  // Package eddilithium2 implements the hybrid signature scheme Ed25519-Dilithium2.
     2  package eddilithium2
     3  
     4  import (
     5  	"crypto"
     6  	cryptoRand "crypto/rand"
     7  	"errors"
     8  	"io"
     9  
    10  	"github.com/cloudflare/circl/internal/sha3"
    11  	"github.com/cloudflare/circl/sign"
    12  	"github.com/cloudflare/circl/sign/dilithium/mode2"
    13  	"github.com/cloudflare/circl/sign/ed25519"
    14  )
    15  
    16  const (
    17  	// SeedSize is the length of the seed for NewKeyFromSeed
    18  	SeedSize = mode2.SeedSize // = ed25519.SeedSize = 32
    19  
    20  	// PublicKeySize is the length in bytes of the packed public key.
    21  	PublicKeySize = mode2.PublicKeySize + ed25519.PublicKeySize
    22  
    23  	// PrivateKeySize is the length in bytes of the packed public key.
    24  	PrivateKeySize = mode2.PrivateKeySize + ed25519.SeedSize
    25  
    26  	// SignatureSize is the length in bytes of the signatures.
    27  	SignatureSize = mode2.SignatureSize + ed25519.SignatureSize
    28  )
    29  
    30  // PublicKey is the type of an EdDilithium2 public key.
    31  type PublicKey struct {
    32  	e ed25519.PublicKey
    33  	d mode2.PublicKey
    34  }
    35  
    36  // PrivateKey is the type of an EdDilithium2 private key.
    37  type PrivateKey struct {
    38  	e ed25519.PrivateKey
    39  	d mode2.PrivateKey
    40  }
    41  
    42  // GenerateKey generates a public/private key pair using entropy from rand.
    43  // If rand is nil, crypto/rand.Reader will be used.
    44  func GenerateKey(rand io.Reader) (*PublicKey, *PrivateKey, error) {
    45  	var seed [SeedSize]byte
    46  	if rand == nil {
    47  		rand = cryptoRand.Reader
    48  	}
    49  	_, err := io.ReadFull(rand, seed[:])
    50  	if err != nil {
    51  		return nil, nil, err
    52  	}
    53  
    54  	pk, sk := NewKeyFromSeed(&seed)
    55  	return pk, sk, nil
    56  }
    57  
    58  // NewKeyFromSeed derives a public/private key pair using the given seed.
    59  func NewKeyFromSeed(seed *[SeedSize]byte) (*PublicKey, *PrivateKey) {
    60  	var seed1 [32]byte
    61  	var seed2 [ed25519.SeedSize]byte
    62  
    63  	// Internally, Ed25519 and Dilithium hash the seeds they are passed again
    64  	// with different hash functions, so it would be safe to use exactly the
    65  	// same seed for Ed25519 and Dilithium here.  However, in general, when
    66  	// combining any two signature schemes it might not be the case that this
    67  	// is safe.  Setting a bad example here isn't worth the tiny gain in
    68  	// performance.
    69  
    70  	h := sha3.NewShake256()
    71  	_, _ = h.Write(seed[:])
    72  	_, _ = h.Read(seed1[:])
    73  	_, _ = h.Read(seed2[:])
    74  	dpk, dsk := mode2.NewKeyFromSeed(&seed1)
    75  	esk := ed25519.NewKeyFromSeed(seed2[:])
    76  
    77  	return &PublicKey{esk.Public().(ed25519.PublicKey), *dpk}, &PrivateKey{esk, *dsk}
    78  }
    79  
    80  // SignTo signs the given message and writes the signature into signature.
    81  // It will panic if signature is not of length at least SignatureSize.
    82  func SignTo(sk *PrivateKey, msg []byte, signature []byte) {
    83  	mode2.SignTo(
    84  		&sk.d,
    85  		msg,
    86  		signature[:mode2.SignatureSize],
    87  	)
    88  	esig := ed25519.Sign(
    89  		sk.e,
    90  		msg,
    91  	)
    92  	copy(signature[mode2.SignatureSize:], esig[:])
    93  }
    94  
    95  // Verify checks whether the given signature by pk on msg is valid.
    96  func Verify(pk *PublicKey, msg []byte, signature []byte) bool {
    97  	if !mode2.Verify(
    98  		&pk.d,
    99  		msg,
   100  		signature[:mode2.SignatureSize],
   101  	) {
   102  		return false
   103  	}
   104  	if !ed25519.Verify(
   105  		pk.e,
   106  		msg,
   107  		signature[mode2.SignatureSize:],
   108  	) {
   109  		return false
   110  	}
   111  	return true
   112  }
   113  
   114  // Unpack unpacks pk to the public key encoded in buf.
   115  func (pk *PublicKey) Unpack(buf *[PublicKeySize]byte) {
   116  	var tmp [mode2.PublicKeySize]byte
   117  	copy(tmp[:], buf[:mode2.PublicKeySize])
   118  	pk.d.Unpack(&tmp)
   119  	pk.e = make([]byte, ed25519.PublicKeySize)
   120  	copy(pk.e, buf[mode2.PublicKeySize:])
   121  }
   122  
   123  // Unpack sets sk to the private key encoded in buf.
   124  func (sk *PrivateKey) Unpack(buf *[PrivateKeySize]byte) {
   125  	var tmp [mode2.PrivateKeySize]byte
   126  	copy(tmp[:], buf[:mode2.PrivateKeySize])
   127  	sk.d.Unpack(&tmp)
   128  	sk.e = ed25519.NewKeyFromSeed(buf[mode2.PrivateKeySize:])
   129  }
   130  
   131  // Pack packs the public key into buf.
   132  func (pk *PublicKey) Pack(buf *[PublicKeySize]byte) {
   133  	var tmp [mode2.PublicKeySize]byte
   134  	pk.d.Pack(&tmp)
   135  	copy(buf[:mode2.PublicKeySize], tmp[:])
   136  	copy(buf[mode2.PublicKeySize:], pk.e)
   137  }
   138  
   139  // Pack packs the private key into buf.
   140  func (sk *PrivateKey) Pack(buf *[PrivateKeySize]byte) {
   141  	var tmp [mode2.PrivateKeySize]byte
   142  	sk.d.Pack(&tmp)
   143  	copy(buf[:mode2.PrivateKeySize], tmp[:])
   144  	copy(buf[mode2.PrivateKeySize:], sk.e.Seed())
   145  }
   146  
   147  // Bytes packs the public key.
   148  func (pk *PublicKey) Bytes() []byte {
   149  	return append(pk.d.Bytes(), pk.e...)
   150  }
   151  
   152  // Bytes packs the private key.
   153  func (sk *PrivateKey) Bytes() []byte {
   154  	return append(sk.d.Bytes(), sk.e.Seed()...)
   155  }
   156  
   157  // MarshalBinary packs the public key.
   158  func (pk *PublicKey) MarshalBinary() ([]byte, error) {
   159  	return pk.Bytes(), nil
   160  }
   161  
   162  // MarshalBinary packs the private key.
   163  func (sk *PrivateKey) MarshalBinary() ([]byte, error) {
   164  	return sk.Bytes(), nil
   165  }
   166  
   167  // UnmarshalBinary the public key from data.
   168  func (pk *PublicKey) UnmarshalBinary(data []byte) error {
   169  	if len(data) != PublicKeySize {
   170  		return errors.New("packed public key must be of eddilithium2.PublicKeySize bytes")
   171  	}
   172  	var buf [PublicKeySize]byte
   173  	copy(buf[:], data)
   174  	pk.Unpack(&buf)
   175  	return nil
   176  }
   177  
   178  // UnmarshalBinary unpacks the private key from data.
   179  func (sk *PrivateKey) UnmarshalBinary(data []byte) error {
   180  	if len(data) != PrivateKeySize {
   181  		return errors.New("packed private key must be of eddilithium2.PrivateKeySize bytes")
   182  	}
   183  	var buf [PrivateKeySize]byte
   184  	copy(buf[:], data)
   185  	sk.Unpack(&buf)
   186  	return nil
   187  }
   188  
   189  func (sk *PrivateKey) Scheme() sign.Scheme { return sch }
   190  func (pk *PublicKey) Scheme() sign.Scheme  { return sch }
   191  
   192  func (sk *PrivateKey) Equal(other crypto.PrivateKey) bool {
   193  	castOther, ok := other.(*PrivateKey)
   194  	if !ok {
   195  		return false
   196  	}
   197  	return castOther.e.Equal(sk.e) && castOther.d.Equal(&sk.d)
   198  }
   199  
   200  func (pk *PublicKey) Equal(other crypto.PublicKey) bool {
   201  	castOther, ok := other.(*PublicKey)
   202  	if !ok {
   203  		return false
   204  	}
   205  	return castOther.e.Equal(pk.e) && castOther.d.Equal(&pk.d)
   206  }
   207  
   208  // Sign signs the given message.
   209  //
   210  // opts.HashFunc() must return zero, which can be achieved by passing
   211  // crypto.Hash(0) for opts.  rand is ignored.  Will only return an error
   212  // if opts.HashFunc() is non-zero.
   213  //
   214  // This function is used to make PrivateKey implement the crypto.Signer
   215  // interface.  The package-level SignTo function might be more convenient
   216  // to use.
   217  func (sk *PrivateKey) Sign(
   218  	rand io.Reader, msg []byte, opts crypto.SignerOpts,
   219  ) (signature []byte, err error) {
   220  	var sig [SignatureSize]byte
   221  
   222  	if opts.HashFunc() != crypto.Hash(0) {
   223  		return nil, errors.New("eddilithium2: cannot sign hashed message")
   224  	}
   225  
   226  	SignTo(sk, msg, sig[:])
   227  	return sig[:], nil
   228  }
   229  
   230  // Public computes the public key corresponding to this private key.
   231  //
   232  // Returns a *PublicKey.  The type crypto.PublicKey is used to make
   233  // PrivateKey implement the crypto.Signer interface.
   234  func (sk *PrivateKey) Public() crypto.PublicKey {
   235  	return &PublicKey{
   236  		sk.e.Public().(ed25519.PublicKey),
   237  		*sk.d.Public().(*mode2.PublicKey),
   238  	}
   239  }