github.com/nebulouslabs/sia@v1.3.7/crypto/signatures.go (about) 1 package crypto 2 3 import ( 4 "bytes" 5 "errors" 6 "io" 7 8 "github.com/NebulousLabs/Sia/encoding" 9 "github.com/NebulousLabs/fastrand" 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).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 }