github.com/avahowell/sia@v0.5.1-beta.0.20160524050156-83dcc3d37c94/crypto/signatures.go (about)

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