-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathec.go
64 lines (53 loc) · 1.69 KB
/
ec.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
package main
import (
"crypto/elliptic"
"crypto/rand"
"io"
"math/big"
)
type Point struct {
X, Y *big.Int
}
// This is just a bitmask with the number of ones starting at 8 then
// incrementing by index. To account for fields with bitsizes that are not a whole
// number of bytes, we mask off the unnecessary bits. h/t agl
var mask = []byte{0xff, 0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f}
// NewRandomPoint: Generates a new random point on the curve specified in curveParams.
func NewRandomPoint(curve elliptic.Curve) ([]byte, *Point, error) {
s, _, err := RandomCurveScalar(curve, rand.Reader)
if err != nil {
return nil, nil, err
}
x, y := curve.ScalarBaseMult(s)
return s, &Point{x, y}, nil
}
func RandomCurveScalar(curve elliptic.Curve, rand io.Reader) ([]byte, *big.Int, error) {
N := curve.Params().N // base point subgroup order
bitLen := N.BitLen()
byteLen := (bitLen + 7) >> 3
buf := make([]byte, byteLen)
// When in doubt, do what agl does in elliptic.go. Presumably
// new(big.Int).SetBytes(b).Mod(N) would introduce bias, so we're sampling.
for {
_, err := io.ReadFull(rand, buf)
if err != nil {
return nil, nil, err
}
// Mask to account for field sizes that are not a whole number of bytes.
buf[0] &= mask[bitLen%8]
// Check if scalar is in the correct range.
if new(big.Int).SetBytes(buf).Cmp(N) >= 0 {
continue
}
break
}
return buf, new(big.Int).SetBytes(buf), nil
}
func curvePointScalarMult(curve elliptic.Curve, scalar *big.Int) *Point {
x, y := curve.ScalarBaseMult(scalar.Bytes())
return &Point{x, y}
}
func curvePointAdd(curve elliptic.Curve, pointA, pointB *Point) *Point {
x, y := curve.Add(pointA.X, pointA.Y, pointB.X, pointB.Y)
return &Point{x, y}
}