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 }