1
2
3
4
5
6
7
8
9
10
11
12 package nistec
13
14 import (
15 "crypto/elliptic/internal/fiat"
16 "crypto/subtle"
17 "errors"
18 )
19
20 var p521B, _ = new(fiat.P521Element).SetBytes([]byte{
21 0x00, 0x51, 0x95, 0x3e, 0xb9, 0x61, 0x8e, 0x1c, 0x9a, 0x1f, 0x92, 0x9a,
22 0x21, 0xa0, 0xb6, 0x85, 0x40, 0xee, 0xa2, 0xda, 0x72, 0x5b, 0x99, 0xb3,
23 0x15, 0xf3, 0xb8, 0xb4, 0x89, 0x91, 0x8e, 0xf1, 0x09, 0xe1, 0x56, 0x19,
24 0x39, 0x51, 0xec, 0x7e, 0x93, 0x7b, 0x16, 0x52, 0xc0, 0xbd, 0x3b, 0xb1,
25 0xbf, 0x07, 0x35, 0x73, 0xdf, 0x88, 0x3d, 0x2c, 0x34, 0xf1, 0xef, 0x45,
26 0x1f, 0xd4, 0x6b, 0x50, 0x3f, 0x00})
27
28 var p521G, _ = NewP521Point().SetBytes([]byte{0x04,
29 0x00, 0xc6, 0x85, 0x8e, 0x06, 0xb7, 0x04, 0x04, 0xe9, 0xcd, 0x9e, 0x3e,
30 0xcb, 0x66, 0x23, 0x95, 0xb4, 0x42, 0x9c, 0x64, 0x81, 0x39, 0x05, 0x3f,
31 0xb5, 0x21, 0xf8, 0x28, 0xaf, 0x60, 0x6b, 0x4d, 0x3d, 0xba, 0xa1, 0x4b,
32 0x5e, 0x77, 0xef, 0xe7, 0x59, 0x28, 0xfe, 0x1d, 0xc1, 0x27, 0xa2, 0xff,
33 0xa8, 0xde, 0x33, 0x48, 0xb3, 0xc1, 0x85, 0x6a, 0x42, 0x9b, 0xf9, 0x7e,
34 0x7e, 0x31, 0xc2, 0xe5, 0xbd, 0x66, 0x01, 0x18, 0x39, 0x29, 0x6a, 0x78,
35 0x9a, 0x3b, 0xc0, 0x04, 0x5c, 0x8a, 0x5f, 0xb4, 0x2c, 0x7d, 0x1b, 0xd9,
36 0x98, 0xf5, 0x44, 0x49, 0x57, 0x9b, 0x44, 0x68, 0x17, 0xaf, 0xbd, 0x17,
37 0x27, 0x3e, 0x66, 0x2c, 0x97, 0xee, 0x72, 0x99, 0x5e, 0xf4, 0x26, 0x40,
38 0xc5, 0x50, 0xb9, 0x01, 0x3f, 0xad, 0x07, 0x61, 0x35, 0x3c, 0x70, 0x86,
39 0xa2, 0x72, 0xc2, 0x40, 0x88, 0xbe, 0x94, 0x76, 0x9f, 0xd1, 0x66, 0x50})
40
41 const p521ElementLength = 66
42
43
44 type P521Point struct {
45
46
47 x, y, z *fiat.P521Element
48 }
49
50
51 func NewP521Point() *P521Point {
52 return &P521Point{
53 x: new(fiat.P521Element),
54 y: new(fiat.P521Element).One(),
55 z: new(fiat.P521Element),
56 }
57 }
58
59
60 func NewP521Generator() *P521Point {
61 return (&P521Point{
62 x: new(fiat.P521Element),
63 y: new(fiat.P521Element),
64 z: new(fiat.P521Element),
65 }).Set(p521G)
66 }
67
68
69 func (p *P521Point) Set(q *P521Point) *P521Point {
70 p.x.Set(q.x)
71 p.y.Set(q.y)
72 p.z.Set(q.z)
73 return p
74 }
75
76
77
78
79
80 func (p *P521Point) SetBytes(b []byte) (*P521Point, error) {
81 switch {
82
83 case len(b) == 1 && b[0] == 0:
84 return p.Set(NewP521Point()), nil
85
86
87 case len(b) == 1+2*p521ElementLength && b[0] == 4:
88 x, err := new(fiat.P521Element).SetBytes(b[1 : 1+p521ElementLength])
89 if err != nil {
90 return nil, err
91 }
92 y, err := new(fiat.P521Element).SetBytes(b[1+p521ElementLength:])
93 if err != nil {
94 return nil, err
95 }
96 if err := p521CheckOnCurve(x, y); err != nil {
97 return nil, err
98 }
99 p.x.Set(x)
100 p.y.Set(y)
101 p.z.One()
102 return p, nil
103
104
105 case len(b) == 1+p521ElementLength && b[0] == 0:
106 return nil, errors.New("unimplemented")
107
108 default:
109 return nil, errors.New("invalid P521 point encoding")
110 }
111 }
112
113 func p521CheckOnCurve(x, y *fiat.P521Element) error {
114
115 x3 := new(fiat.P521Element).Square(x)
116 x3.Mul(x3, x)
117
118 threeX := new(fiat.P521Element).Add(x, x)
119 threeX.Add(threeX, x)
120
121 x3.Sub(x3, threeX)
122 x3.Add(x3, p521B)
123
124
125 y2 := new(fiat.P521Element).Square(y)
126
127 if x3.Equal(y2) != 1 {
128 return errors.New("P521 point not on curve")
129 }
130 return nil
131 }
132
133
134
135
136 func (p *P521Point) Bytes() []byte {
137
138
139 var out [133]byte
140 return p.bytes(&out)
141 }
142
143 func (p *P521Point) bytes(out *[133]byte) []byte {
144 if p.z.IsZero() == 1 {
145 return append(out[:0], 0)
146 }
147
148 zinv := new(fiat.P521Element).Invert(p.z)
149 xx := new(fiat.P521Element).Mul(p.x, zinv)
150 yy := new(fiat.P521Element).Mul(p.y, zinv)
151
152 buf := append(out[:0], 4)
153 buf = append(buf, xx.Bytes()...)
154 buf = append(buf, yy.Bytes()...)
155 return buf
156 }
157
158
159 func (q *P521Point) Add(p1, p2 *P521Point) *P521Point {
160
161
162
163 t0 := new(fiat.P521Element).Mul(p1.x, p2.x)
164 t1 := new(fiat.P521Element).Mul(p1.y, p2.y)
165 t2 := new(fiat.P521Element).Mul(p1.z, p2.z)
166 t3 := new(fiat.P521Element).Add(p1.x, p1.y)
167 t4 := new(fiat.P521Element).Add(p2.x, p2.y)
168 t3.Mul(t3, t4)
169 t4.Add(t0, t1)
170 t3.Sub(t3, t4)
171 t4.Add(p1.y, p1.z)
172 x3 := new(fiat.P521Element).Add(p2.y, p2.z)
173 t4.Mul(t4, x3)
174 x3.Add(t1, t2)
175 t4.Sub(t4, x3)
176 x3.Add(p1.x, p1.z)
177 y3 := new(fiat.P521Element).Add(p2.x, p2.z)
178 x3.Mul(x3, y3)
179 y3.Add(t0, t2)
180 y3.Sub(x3, y3)
181 z3 := new(fiat.P521Element).Mul(p521B, t2)
182 x3.Sub(y3, z3)
183 z3.Add(x3, x3)
184 x3.Add(x3, z3)
185 z3.Sub(t1, x3)
186 x3.Add(t1, x3)
187 y3.Mul(p521B, y3)
188 t1.Add(t2, t2)
189 t2.Add(t1, t2)
190 y3.Sub(y3, t2)
191 y3.Sub(y3, t0)
192 t1.Add(y3, y3)
193 y3.Add(t1, y3)
194 t1.Add(t0, t0)
195 t0.Add(t1, t0)
196 t0.Sub(t0, t2)
197 t1.Mul(t4, y3)
198 t2.Mul(t0, y3)
199 y3.Mul(x3, z3)
200 y3.Add(y3, t2)
201 x3.Mul(t3, x3)
202 x3.Sub(x3, t1)
203 z3.Mul(t4, z3)
204 t1.Mul(t3, t0)
205 z3.Add(z3, t1)
206
207 q.x.Set(x3)
208 q.y.Set(y3)
209 q.z.Set(z3)
210 return q
211 }
212
213
214 func (q *P521Point) Double(p *P521Point) *P521Point {
215
216
217
218 t0 := new(fiat.P521Element).Square(p.x)
219 t1 := new(fiat.P521Element).Square(p.y)
220 t2 := new(fiat.P521Element).Square(p.z)
221 t3 := new(fiat.P521Element).Mul(p.x, p.y)
222 t3.Add(t3, t3)
223 z3 := new(fiat.P521Element).Mul(p.x, p.z)
224 z3.Add(z3, z3)
225 y3 := new(fiat.P521Element).Mul(p521B, t2)
226 y3.Sub(y3, z3)
227 x3 := new(fiat.P521Element).Add(y3, y3)
228 y3.Add(x3, y3)
229 x3.Sub(t1, y3)
230 y3.Add(t1, y3)
231 y3.Mul(x3, y3)
232 x3.Mul(x3, t3)
233 t3.Add(t2, t2)
234 t2.Add(t2, t3)
235 z3.Mul(p521B, z3)
236 z3.Sub(z3, t2)
237 z3.Sub(z3, t0)
238 t3.Add(z3, z3)
239 z3.Add(z3, t3)
240 t3.Add(t0, t0)
241 t0.Add(t3, t0)
242 t0.Sub(t0, t2)
243 t0.Mul(t0, z3)
244 y3.Add(y3, t0)
245 t0.Mul(p.y, p.z)
246 t0.Add(t0, t0)
247 z3.Mul(t0, z3)
248 x3.Sub(x3, z3)
249 z3.Mul(t0, t1)
250 z3.Add(z3, z3)
251 z3.Add(z3, z3)
252
253 q.x.Set(x3)
254 q.y.Set(y3)
255 q.z.Set(z3)
256 return q
257 }
258
259
260 func (q *P521Point) Select(p1, p2 *P521Point, cond int) *P521Point {
261 q.x.Select(p1.x, p2.x, cond)
262 q.y.Select(p1.y, p2.y, cond)
263 q.z.Select(p1.z, p2.z, cond)
264 return q
265 }
266
267
268 func (p *P521Point) ScalarMult(q *P521Point, scalar []byte) *P521Point {
269
270
271 var table = [16]*P521Point{
272 NewP521Point(), NewP521Point(), NewP521Point(), NewP521Point(),
273 NewP521Point(), NewP521Point(), NewP521Point(), NewP521Point(),
274 NewP521Point(), NewP521Point(), NewP521Point(), NewP521Point(),
275 NewP521Point(), NewP521Point(), NewP521Point(), NewP521Point(),
276 }
277 for i := 1; i < 16; i++ {
278 table[i].Add(table[i-1], q)
279 }
280
281
282
283 t := NewP521Point()
284 p.Set(NewP521Point())
285 for _, byte := range scalar {
286 p.Double(p)
287 p.Double(p)
288 p.Double(p)
289 p.Double(p)
290
291 for i := uint8(0); i < 16; i++ {
292 cond := subtle.ConstantTimeByteEq(byte>>4, i)
293 t.Select(table[i], t, cond)
294 }
295 p.Add(p, t)
296
297 p.Double(p)
298 p.Double(p)
299 p.Double(p)
300 p.Double(p)
301
302 for i := uint8(0); i < 16; i++ {
303 cond := subtle.ConstantTimeByteEq(byte&0b1111, i)
304 t.Select(table[i], t, cond)
305 }
306 p.Add(p, t)
307 }
308
309 return p
310 }
311
View as plain text