forked from NebulousLabs/Sia
-
Notifications
You must be signed in to change notification settings - Fork 0
/
signatures.go
112 lines (95 loc) · 3.28 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
package crypto
import (
"errors"
"io"
"github.com/NebulousLabs/Sia/encoding"
"github.com/NebulousLabs/ed25519"
)
const (
// EntropySize defines the amount of entropy necessary to do secure
// cryptographic operations, in bytes.
EntropySize = ed25519.EntropySize
// PublicKeySize defines the size of public keys in bytes.
PublicKeySize = ed25519.PublicKeySize
// SecretKeySize defines the size of secret keys in bytes.
SecretKeySize = ed25519.SecretKeySize
// 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, err error) {
return stdKeyGen.generate()
}
// GenerateKeyPairDeterministic generates keys deterministically using the input
// entropy. The input entropy must be 32 bytes in length.
func GenerateKeyPairDeterministic(entropy [EntropySize]byte) (SecretKey, PublicKey) {
return stdKeyGen.generateDeterministic(entropy)
}
// 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. Though the current
// implementation will never return an error, switching libraries in the future
// may result in errors that can be returned.
func SignHash(data Hash, sk SecretKey) (sig Signature, err error) {
skNorm := [SecretKeySize]byte(sk)
sig = *ed25519.Sign(&skNorm, data[:])
return sig, nil
}
// VerifyHash uses a public key and input data to verify a signature.
func VerifyHash(data Hash, pk PublicKey, sig Signature) error {
pkNorm := [PublicKeySize]byte(pk)
sigNorm := [SignatureSize]byte(sig)
verifies := ed25519.Verify(&pkNorm, data[:], &sigNorm)
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, err := SignHash(HashBytes(objBytes), sk)
if err != nil {
return err
}
return encoding.NewEncoder(w).EncodeAll(sig, objBytes)
}