/
vrf_signer.go
127 lines (102 loc) · 3.19 KB
/
vrf_signer.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
116
117
118
119
120
121
122
123
124
125
126
127
package signature
import (
"encoding/base64"
"fmt"
"github.com/oasisprotocol/curve25519-voi/primitives/ed25519/extra/ecvrf"
)
const (
// ProofSize is the size of a VRF proof in bytes.
ProofSize = ecvrf.ProofSize
// BetaSize is the size of a VRF output in bytes.
BetaSize = ecvrf.OutputSize
)
// VRFSigner is a Signer that also supports generating VRF proofs,
// using the semantics from v10 of the IETF Verifiable Random Functions
// draft.
type VRFSigner interface {
Signer
// Prove generates a VRF proof with the private key over the alpha.
Prove(alphaString []byte) ([]byte, error)
}
// Prove generates a VRF proof with the private key over the alpha.
func Prove(signer Signer, alphaString []byte) (*Proof, error) {
vrfSigner, ok := signer.(VRFSigner)
if !ok {
return nil, fmt.Errorf("signature: invalid signer for VRF proofs")
}
proof, err := vrfSigner.Prove(alphaString)
if err != nil {
return nil, err
}
p := &Proof{
PublicKey: signer.Public(),
}
if err = p.Proof.UnmarshalBinary(proof); err != nil {
return nil, err
}
return p, nil
}
// Proof is a VRF proof, bundled with the signing public key.
type Proof struct {
// PublicKey is the public key that produced the proof.
PublicKey PublicKey `json:"public_key"`
// Proof is the actual raw proof.
Proof RawProof `json:"proof"`
}
// Verify verifies a VRP proof over the alpha, and returns true iff the proof
// is valid. Iff the proof is valid, beta is also returned.
func (p *Proof) Verify(alphaString []byte) (bool, []byte) {
return p.PublicKey.VerifyVRF(alphaString, p.Proof[:])
}
// UnsafeToHash extracts the hash (beta) from a VRF proof. This MUST only
// be called for proofs that are known to be valid.
func (p *Proof) UnsafeToHash() []byte {
beta, err := ecvrf.ProofToHash(p.Proof[:])
if err != nil {
panic("signature/ecvrf: failed to extract beta: " + err.Error())
}
return beta
}
// VerifyVRF returns true iff the VRF proof is valid for the public key over
// alpha. Iff the proof is valid, beta is also returned.
func (k PublicKey) VerifyVRF(alphaString, piString []byte) (bool, []byte) {
if len(piString) != ProofSize {
return false, nil
}
if k.IsBlacklisted() {
return false, nil
}
return ecvrf.Verify_v10(k[:], piString, alphaString)
}
// RawProof is a raw VRF proof.
type RawProof [ProofSize]byte
// String returns a string representation of the raw VRF proof.
func (r RawProof) String() string {
data, _ := r.MarshalText()
return string(data)
}
// MarshalBinary encodes a VRF proof into binary form.
func (r RawProof) MarshalBinary() (data []byte, err error) {
data = append([]byte{}, r[:]...)
return
}
// UnmarshalBinary decodes a binary marshaled VRF proof.
func (r *RawProof) UnmarshalBinary(data []byte) error {
if len(data) != ProofSize {
return ErrMalformedSignature
}
copy(r[:], data)
return nil
}
// MarshalText encodes a VRF proof into text form.
func (r RawProof) MarshalText() (data []byte, err error) {
return []byte(base64.StdEncoding.EncodeToString(r[:])), nil
}
// UnmarshalText decodes a text marshaled VRF proof.
func (r *RawProof) UnmarshalText(text []byte) error {
b, err := base64.StdEncoding.DecodeString(string(text))
if err != nil {
return err
}
return r.UnmarshalBinary(b)
}