-
Notifications
You must be signed in to change notification settings - Fork 8
/
ristretto.go
414 lines (373 loc) · 11.7 KB
/
ristretto.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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
// Pure Go implementation of the Ristretto prime-order group built from
// the Edwards curve Edwards25519.
//
// Many cryptographic schemes need a group of prime order. Popular and
// efficient elliptic curves like (Edwards25519 of `ed25519` fame) are
// rarely of prime order. There is, however, a convenient method
// to construct a prime order group from such curves, using a method
// called Ristretto proposed by Mike Hamburg.
//
// This package implements the Ristretto group constructed from Edwards25519.
// The Point type represents a group element. The API mimics that of the
// math/big package. For instance, to set c to a+b, one writes
//
// var c ristretto.Point
// c.Add(&a, &b) // sets c to a + b
//
// Warning: contrary to math.Big's interface, an uninitialized Point is not
// the same thing as the zero (neutral element) of the group:
//
// var c ristretto.Point // c is uninitialized now --- not zero!
// c.SetZero() // c is zero now; ready to use!
//
// Most methods return the receiver, so that function can be chained:
//
// s.Add(&a, &b).Add(&s, &c) // sets s to a + b + c
//
// The order of the Ristretto group is l =
// 2^252 + 27742317777372353535851937790883648493 =
// 7237005577332262213973186563042994240857116359379907606001950938285454250989.
// The Scalar type implement the numbers modulo l and also has an API similar
// to math/big.
package ristretto
import (
"crypto/rand"
"crypto/sha256"
"crypto/sha512"
"crypto/subtle"
"encoding/base64"
"encoding/hex"
"errors"
"fmt"
"github.com/bwesterb/go-ristretto/edwards25519"
)
// Represents an element of the Ristretto group over Edwards25519.
//
// Warning: an uninitialized Point is not the same thing as a zero. Use
// the SetZero() method to set an (uninitialized) Point to zero.
type Point edwards25519.ExtendedPoint
// A table to speed up scalar multiplication of a fixed point
type ScalarMultTable edwards25519.ScalarMultTable
// Sets p to zero (the neutral element). Returns p.
func (p *Point) SetZero() *Point {
p.e().SetZero()
return p
}
// Sets p to the Edwards25519 basepoint. Returns p
func (p *Point) SetBase() *Point {
p.e().SetBase()
return p
}
// Sets p to q. Returns p
func (p *Point) Set(q *Point) *Point {
p.e().Set(q.e())
return p
}
// Sets p to q + r. Returns p.
func (p *Point) Add(q, r *Point) *Point {
p.e().Add(q.e(), r.e())
return p
}
// Sets p to q + q. Returns p.
func (p *Point) Double(q *Point) *Point {
p.e().Double(q.e())
return p
}
// Sets p to q - r. Returns p.
func (p *Point) Sub(q, r *Point) *Point {
p.e().Sub(q.e(), r.e())
return p
}
// Sets p to -q. Returns p.
func (p *Point) Neg(q *Point) *Point {
p.e().Neg(q.e())
return p
}
// Packs p into the given buffer. Returns p.
func (p *Point) BytesInto(buf *[32]byte) *Point {
p.e().RistrettoInto(buf)
return p
}
// Returns a packed version of p.
func (p *Point) Bytes() []byte {
return p.e().Ristretto()
}
// Sets p to the point encoded in buf using Bytes().
// Not every input encodes a point. Returns whether the buffer encoded a point.
func (p *Point) SetBytes(buf *[32]byte) bool {
return p.e().SetRistretto(buf)
}
// Sets p to the point corresponding to buf using the Elligator2 encoding.
//
// In contrast to SetBytes() (1) Every input buffer will decode to a point
// and (2) SetElligator() is not injective: for every point there are
// approximately four buffers that will encode to it.
func (p *Point) SetElligator(buf *[32]byte) *Point {
var fe edwards25519.FieldElement
var cp edwards25519.CompletedPoint
fe.SetBytes(buf)
cp.SetRistrettoElligator2(&fe)
p.e().SetCompleted(&cp)
return p
}
// Sets p to s * q, where q is the point for which the table t was
// computed. Returns p.
func (p *Point) ScalarMultTable(t *ScalarMultTable, s *Scalar) *Point {
var buf [32]byte
s.BytesInto(&buf)
t.t().ScalarMult(p.e(), &buf)
return p
}
// Sets p to s * q, where q is the point for which the table t was
// computed. Returns p.
//
// Warning: this method uses a non-constant time implementation and thus leaks
// information about s. Use this function only if s is public knowledge.
func (p *Point) PublicScalarMultTable(t *ScalarMultTable, s *Scalar) *Point {
var buf [32]byte
s.BytesInto(&buf)
t.t().VarTimeScalarMult(p.e(), &buf)
return p
}
// Sets p to s * q. Returns p.
func (p *Point) ScalarMult(q *Point, s *Scalar) *Point {
var buf [32]byte
s.BytesInto(&buf)
p.e().ScalarMult(q.e(), &buf)
return p
}
// Sets p to s * q assuming s is *not* secret. Returns p.
//
// Warning: this method uses a non-constant time implementation and thus leaks
// information about s. Use this function only if s is public knowledge.
func (p *Point) PublicScalarMult(q *Point, s *Scalar) *Point {
var buf [32]byte
s.BytesInto(&buf)
p.e().VarTimeScalarMult(q.e(), &buf)
return p
}
// Sets p to s * B, where B is the edwards25519 basepoint. Returns p.
//
// Warning: this method uses a non-constant time implementation and thus leaks
// information about s. Use this function only if s is public knowledge.
func (p *Point) PublicScalarMultBase(s *Scalar) *Point {
var buf [32]byte
s.BytesInto(&buf)
edwards25519.BaseScalarMultTable.VarTimeScalarMult(p.e(), &buf)
return p
}
// Sets p to s * B, where B is the edwards25519 basepoint. Returns p.
func (p *Point) ScalarMultBase(s *Scalar) *Point {
var buf [32]byte
s.BytesInto(&buf)
edwards25519.BaseScalarMultTable.ScalarMult(p.e(), &buf)
return p
}
// Sets p to a random point. Returns p.
func (p *Point) Rand() *Point {
var buf [32]byte
if _, err := rand.Read(buf[:]); err != nil {
panic(err)
}
return p.SetElligator(&buf)
}
// Sets p to the point derived from the buffer using SHA512 and Elligator2.
// Returns p.
//
// NOTE curve25519-dalek uses a different (more conservative) method to derive
// a point from raw data with a hash. This is implemented in
// Point.DeriveDalek().
func (p *Point) Derive(buf []byte) *Point {
var ptBuf [32]byte
h := sha512.Sum512(buf)
copy(ptBuf[:], h[:32])
return p.SetElligator(&ptBuf)
}
// Encode 16 bytes into a point using the Lizard method.
//
// Use Lizard() or LizardInto() to decode the bytes from a Point.
//
// Notes on usage:
//
// - If you want to create a Point from random data, you should rather
// create a random Point with Point.Rand() and then use (a hash of)
// Point.Bytes() as the random data.
//
// - If you want to derive a Point from data, but you do not care about
// decoding the data back from the point, you should use
// the Point.Derive() method instead.
//
// - There are some (and with high probability at most 80) inputs to
// SetLizard() which cannot be decoded. The chance that you hit such
// an input is around 1 in 2^122.
//
// In Lizard there are 256 - 128 - 3 = 125 check bits to pick out the
// right preimage among at most eight. Conservatively assuming there are
// seven other preimages, the chance that one of them passes the check as
// well is given by:
//
// 1 - (1 - 2^-125)^7 = 7*2^-125 + 21*2^-250 - ...
// =~ 2^(-125 - 2log(7))
// = 2^-122.192...
//
// Presuming a random hash function, the number of "bad" inputs is binomially
// distributed with n=2^128 and p=2^-122.192... For such large n, the Poisson
// distribution with lambda=n*p=56 is a very good approximation. In fact:
// the cumulative distribution function (CDF) of the Poission distribution
// is larger than that of the binomial distribution for k > lambda.[1] The value
// of the former on k=80 is larger than 0.999 and so with a probability of 99.9%,
// there are fewer than 80 bad inputs.
//
// [1] See "Some Inequalities Among Binomial and Poisson Probabilities"
// by Anderson and Samuels in Proc. Fifth Berkeley Symp. on
// Math. Statist. and Prob., Vol. 1 (Univ. of Calif. Press, 1967).
func (p *Point) SetLizard(data *[16]byte) *Point {
var fe edwards25519.FieldElement
var cp edwards25519.CompletedPoint
buf := sha256.Sum256(data[:])
copy(buf[8:], data[:])
buf[0] &= 254 // clear lowest bit to make the FieldElement positive
buf[31] &= 63 // clear highest two bits to ensure below 2^255-19.
fe.SetBytes(&buf)
cp.SetRistrettoElligator2(&fe)
p.e().SetCompleted(&cp)
return p
}
// Decodes 16 bytes encoded into this point using SetLizard().
//
// Returns nil if this point does not contain data encoded using Lizard.
//
// See SetLizard() for notes on usage.
func (p *Point) Lizard() []byte {
var ret [16]byte
if p.LizardInto(&ret) != nil {
return nil
}
return ret[:]
}
// Decodes 16 bytes into the given buffer encoded into this point
// using SetLizard().
//
// See SetLizard() for notes on usage.
func (p *Point) LizardInto(buf *[16]byte) error {
var fes [8]edwards25519.FieldElement
var buf2 [32]byte
var nFound uint8
mask := p.e().RistrettoElligator2Inverse(&fes)
for j := 0; j < 8; j++ {
ok := (mask >> uint(j)) & 1
fes[j].BytesInto(&buf2)
h := sha256.Sum256(buf2[8:24])
copy(h[8:], buf2[8:24])
h[0] &= 254
h[31] &= 63
ok &= uint8(subtle.ConstantTimeCompare(h[:], buf2[:]))
subtle.ConstantTimeCopy(int(ok), buf[:], buf2[8:24])
nFound += ok
}
if nFound == 1 {
return nil
}
if nFound == 0 {
return errors.New("No Lizard preimage")
}
return errors.New("Multiple Lizard preimages")
}
// Returns 1 if p == q and 0 otherwise.
func (p *Point) EqualsI(q *Point) int32 {
return p.e().RistrettoEqualsI(q.e())
}
// Returns whether p == q
func (p *Point) Equals(q *Point) bool {
return p.EqualsI(q) == 1
}
// Set p to q if b=1 in constant-time. b must be either 0 or 1.
func (p *Point) ConditionalSet(q *Point, b int32) {
p.e().ConditionalSet(q.e(), b)
}
// Sets p to the point derived from the buffer using SHA512 and Elligator2
// in the fashion of curve25519-dalek.
//
// NOTE See also Derive(), which is a different method which is twice as fast,
// but which might not be as secure as this method.
func (p *Point) DeriveDalek(data []byte) *Point {
hash := sha512.Sum512(data)
var p2 Point
var buf [32]byte
copy(buf[:], hash[:32])
p.SetElligator(&buf)
copy(buf[:], hash[32:])
p2.SetElligator(&buf)
p.Add(p, &p2)
return p
}
// Implements encoding/BinaryUnmarshaler. Use SetBytes, if convenient, instead.
func (p *Point) UnmarshalBinary(data []byte) error {
if len(data) != 32 {
return fmt.Errorf("ristretto.Point should be 32 bytes; not %d", len(data))
}
var buf [32]byte
copy(buf[:], data)
if !p.SetBytes(&buf) {
return errors.New("Buffer does not encode a ristretto.Point")
}
return nil
}
// Implements encoding/BinaryMarshaler. Use BytesInto, if convenient, instead.
func (p *Point) MarshalBinary() ([]byte, error) {
var buf [32]byte
p.BytesInto(&buf)
return buf[:], nil
}
func (p *Point) MarshalText() ([]byte, error) {
enc := base64.RawURLEncoding
var buf [32]byte
p.BytesInto(&buf)
ret := make([]byte, enc.EncodedLen(32))
enc.Encode(ret, buf[:])
return ret, nil
}
func textToBuf(dst, src []byte) error {
var n int
var err error
if len(src) == 64 {
n, err = hex.Decode(dst, src)
if n == 32 && err == nil {
return nil
}
}
enc := base64.RawURLEncoding
n, err = enc.Decode(dst, src)
if err != nil {
return err
}
if n != 32 {
return fmt.Errorf("ristretto.Point should be 32 bytes; not %d", n)
}
return nil
}
func (p *Point) UnmarshalText(txt []byte) error {
var buf [32]byte
err := textToBuf(buf[:], txt)
if err != nil {
return err
}
if !p.SetBytes(&buf) {
return errors.New("Buffer does not encode a ristretto.Point")
}
return nil
}
func (p Point) String() string {
text, _ := p.MarshalText()
return string(text)
}
func (p *Point) e() *edwards25519.ExtendedPoint {
return (*edwards25519.ExtendedPoint)(p)
}
func (t *ScalarMultTable) t() *edwards25519.ScalarMultTable {
return (*edwards25519.ScalarMultTable)(t)
}
// Fills the table for point p.
func (t *ScalarMultTable) Compute(p *Point) {
t.t().Compute(p.e())
}