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