/
client.go
123 lines (106 loc) 路 3.81 KB
/
client.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
package core
import (
"errors"
"github.com/dedis/drand/beacon"
"github.com/dedis/drand/ecies"
"github.com/dedis/drand/key"
"github.com/dedis/drand/net"
"github.com/dedis/drand/protobuf/crypto"
"github.com/dedis/drand/protobuf/drand"
"github.com/dedis/kyber"
"github.com/dedis/kyber/sign/bls"
"google.golang.org/grpc"
)
// Client is the endpoint logic, communicating with drand servers
type Client struct {
client net.ExternalClient
}
// NewGrpcClient returns a Client able to talk to drand instances using gRPC
// communication method
func NewGrpcClient(opts ...grpc.DialOption) *Client {
return &Client{
client: net.NewGrpcClient(opts...),
}
}
// NewGrpcClientFromCert returns a client that contact its peer over TLS
func NewGrpcClientFromCert(c *net.CertManager, opts ...grpc.DialOption) *Client {
return &Client{client: net.NewGrpcClientFromCertManager(c, opts...)}
}
// NewRESTClient returns a client that uses the HTTP Rest API delivered by drand
// nodes
func NewRESTClient() *Client {
return &Client{
client: net.NewRestClient(),
}
}
// NewRESTClientFromCert returns a client that uses the HTTP Rest API delivered
// by drand nodes, using TLS connection for peers registered
func NewRESTClientFromCert(c *net.CertManager) *Client {
return &Client{client: net.NewRestClientFromCertManager(c)}
}
// LastPublic returns the last randomness beacon from the server associated. It
// returns it if the randomness is valid. Secure indicates that the request
// must be made over a TLS protected channel.
func (c *Client) LastPublic(addr string, pub *key.DistPublic, secure bool) (*drand.PublicRandResponse, error) {
resp, err := c.client.Public(&peerAddr{addr, secure}, &drand.PublicRandRequest{})
if err != nil {
return nil, err
}
return resp, c.verify(pub.Key(), resp)
}
// Public returns the random output of the specified beacon at a given index. It
// returns it if the randomness is valid. Secure indicates that the request
// must be made over a TLS protected channel.
func (c *Client) Public(addr string, pub *key.DistPublic, secure bool, round int) (*drand.PublicRandResponse, error) {
resp, err := c.client.Public(&peerAddr{addr, secure}, &drand.PublicRandRequest{Round: uint64(round)})
if err != nil {
return nil, err
}
return resp, c.verify(pub.Key(), resp)
}
// Private retrieves a private random value from the server. It does that by
// generating an ephemeral key pair, sends it encrypted to the remote server,
// and decrypts the response, the randomness. Client will attempt a TLS
// connection to the address in the identity if id.IsTLS() returns true
func (c *Client) Private(id *key.Identity) ([]byte, error) {
ephScalar := key.G2.Scalar()
ephPoint := key.G2.Point().Mul(ephScalar, nil)
ephBuff, err := ephPoint.MarshalBinary()
if err != nil {
return nil, err
}
obj, err := ecies.Encrypt(key.G2, ecies.DefaultHash, id.Key, ephBuff)
if err != nil {
return nil, err
}
resp, err := c.client.Private(id, &drand.PrivateRandRequest{Request: obj})
if err != nil {
return nil, err
}
return ecies.Decrypt(key.G2, ecies.DefaultHash, ephScalar, resp.GetResponse())
}
// DistKey returns the distributed key the node at this address is holding.
func (c *Client) DistKey(addr string, secure bool) (*crypto.Point, error) {
resp, err := c.client.DistKey(&peerAddr{addr, secure}, &drand.DistKeyRequest{})
return resp.Key, err
}
func (c *Client) verify(public kyber.Point, resp *drand.PublicRandResponse) error {
msg := beacon.Message(resp.GetPrevious(), resp.GetRound())
rand := resp.GetRandomness()
if rand == nil {
return errors.New("drand: no randomness found...")
}
return bls.Verify(key.Pairing, public, msg, rand.GetPoint())
}
func (c *Client) peer(addr string) {
}
type peerAddr struct {
addr string
t bool
}
func (p *peerAddr) Address() string {
return p.addr
}
func (p *peerAddr) IsTLS() bool {
return p.t
}