gitlab.com/SiaPrime/SiaPrime@v1.4.1/crypto/signatures.go (about)

     1  package crypto
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"io"
     7  
     8  	"gitlab.com/NebulousLabs/fastrand"
     9  	"gitlab.com/SiaPrime/SiaPrime/encoding"
    10  
    11  	"golang.org/x/crypto/ed25519"
    12  )
    13  
    14  const (
    15  	// EntropySize defines the amount of entropy necessary to do secure
    16  	// cryptographic operations, in bytes.
    17  	EntropySize = 32
    18  
    19  	// PublicKeySize defines the size of public keys in bytes.
    20  	PublicKeySize = ed25519.PublicKeySize
    21  
    22  	// SecretKeySize defines the size of secret keys in bytes.
    23  	SecretKeySize = ed25519.PrivateKeySize
    24  
    25  	// SignatureSize defines the size of signatures in bytes.
    26  	SignatureSize = ed25519.SignatureSize
    27  )
    28  
    29  var (
    30  	// ErrInvalidSignature is returned if a signature is provided that does not
    31  	// match the data and public key.
    32  	ErrInvalidSignature = errors.New("invalid signature")
    33  )
    34  
    35  type (
    36  	// PublicKey is an object that can be used to verify signatures.
    37  	PublicKey [PublicKeySize]byte
    38  
    39  	// SecretKey can be used to sign data for the corresponding public key.
    40  	SecretKey [SecretKeySize]byte
    41  
    42  	// Signature proves that data was signed by the owner of a particular
    43  	// public key's corresponding secret key.
    44  	Signature [SignatureSize]byte
    45  )
    46  
    47  // PublicKey returns the public key that corresponds to a secret key.
    48  func (sk SecretKey) PublicKey() (pk PublicKey) {
    49  	copy(pk[:], sk[SecretKeySize-PublicKeySize:])
    50  	return
    51  }
    52  
    53  // GenerateKeyPair creates a public-secret keypair that can be used to sign and verify
    54  // messages.
    55  func GenerateKeyPair() (sk SecretKey, pk PublicKey) {
    56  	// no error possible when using fastrand.Reader
    57  	epk, esk, _ := ed25519.GenerateKey(fastrand.Reader)
    58  	copy(sk[:], esk)
    59  	copy(pk[:], epk)
    60  	return
    61  }
    62  
    63  // GenerateKeyPairDeterministic generates keys deterministically using the input
    64  // entropy. The input entropy must be 32 bytes in length.
    65  func GenerateKeyPairDeterministic(entropy [EntropySize]byte) (sk SecretKey, pk PublicKey) {
    66  	// no error possible when using bytes.Reader
    67  	epk, esk, _ := ed25519.GenerateKey(bytes.NewReader(entropy[:]))
    68  	copy(sk[:], esk)
    69  	copy(pk[:], epk)
    70  	return
    71  }
    72  
    73  // ReadSignedObject reads a length-prefixed object prefixed by its signature,
    74  // and verifies the signature.
    75  func ReadSignedObject(r io.Reader, obj interface{}, maxLen uint64, pk PublicKey) error {
    76  	// read the signature
    77  	var sig Signature
    78  	err := encoding.NewDecoder(r, encoding.DefaultAllocLimit).Decode(&sig)
    79  	if err != nil {
    80  		return err
    81  	}
    82  	// read the encoded object
    83  	encObj, err := encoding.ReadPrefixedBytes(r, maxLen)
    84  	if err != nil {
    85  		return err
    86  	}
    87  	// verify the signature
    88  	if err := VerifyHash(HashBytes(encObj), pk, sig); err != nil {
    89  		return err
    90  	}
    91  	// decode the object
    92  	return encoding.Unmarshal(encObj, obj)
    93  }
    94  
    95  // SignHash signs a message using a secret key.
    96  func SignHash(data Hash, sk SecretKey) (sig Signature) {
    97  	copy(sig[:], ed25519.Sign(sk[:], data[:]))
    98  	return
    99  }
   100  
   101  // VerifyHash uses a public key and input data to verify a signature.
   102  func VerifyHash(data Hash, pk PublicKey, sig Signature) error {
   103  	verifies := ed25519.Verify(pk[:], data[:], sig[:])
   104  	if !verifies {
   105  		return ErrInvalidSignature
   106  	}
   107  	return nil
   108  }
   109  
   110  // WriteSignedObject writes a length-prefixed object prefixed by its signature.
   111  func WriteSignedObject(w io.Writer, obj interface{}, sk SecretKey) error {
   112  	objBytes := encoding.Marshal(obj)
   113  	sig := SignHash(HashBytes(objBytes), sk)
   114  	return encoding.NewEncoder(w).EncodeAll(sig, objBytes)
   115  }