]>
Commit | Line | Data |
---|---|---|
b394396b PW |
1 | #ifndef _SECP256K1_GROUP_ |
2 | #define _SECP256K1_GROUP_ | |
3 | ||
4 | #include "field.h" | |
5 | ||
6 | namespace secp256k1 { | |
7 | ||
cb4d29c8 PW |
8 | class GroupElemJac; |
9 | ||
b394396b PW |
10 | /** Defines a point on the secp256k1 curve (y^2 = x^3 + 7) */ |
11 | class GroupElem { | |
12 | protected: | |
13 | bool fInfinity; | |
14 | FieldElem x; | |
15 | FieldElem y; | |
16 | ||
17 | public: | |
18 | ||
19 | /** Creates the point at infinity */ | |
20 | GroupElem() { | |
21 | fInfinity = true; | |
22 | } | |
23 | ||
24 | /** Creates the point with given affine coordinates */ | |
25 | GroupElem(const FieldElem &xin, const FieldElem &yin) { | |
26 | fInfinity = false; | |
27 | x = xin; | |
28 | y = yin; | |
29 | } | |
30 | ||
31 | /** Checks whether this is the point at infinity */ | |
32 | bool IsInfinity() const { | |
33 | return fInfinity; | |
34 | } | |
35 | ||
cb4d29c8 PW |
36 | void SetNeg(const GroupElem &p) { |
37 | *this = p; | |
38 | y.Normalize(); | |
39 | y.SetNeg(y, 1); | |
b394396b PW |
40 | } |
41 | ||
83e640f0 PW |
42 | void GetX(FieldElem &xout) const { |
43 | xout = x; | |
44 | } | |
45 | ||
46 | void GetY(FieldElem &yout) const { | |
47 | yout = y; | |
48 | } | |
49 | ||
7ba40aa4 | 50 | std::string ToString() const { |
b394396b PW |
51 | if (fInfinity) |
52 | return "(inf)"; | |
7ba40aa4 PW |
53 | FieldElem xc = x, yc = y; |
54 | return "(" + xc.ToString() + "," + yc.ToString() + ")"; | |
b394396b PW |
55 | } |
56 | ||
e8c2a8ec | 57 | void SetJac(Context &ctx, GroupElemJac &jac); |
cb4d29c8 | 58 | |
b394396b PW |
59 | friend class GroupElemJac; |
60 | }; | |
61 | ||
62 | /** Represents a point on the secp256k1 curve, with jacobian coordinates */ | |
7ba40aa4 | 63 | class GroupElemJac : private GroupElem { |
b394396b PW |
64 | protected: |
65 | FieldElem z; | |
66 | ||
67 | public: | |
68 | /** Creates the point at infinity */ | |
69 | GroupElemJac() : GroupElem(), z(1) {} | |
70 | ||
71 | /** Creates the point with given affine coordinates */ | |
72 | GroupElemJac(const FieldElem &xin, const FieldElem &yin) : GroupElem(xin,yin), z(1) {} | |
73 | ||
cb4d29c8 PW |
74 | GroupElemJac(const GroupElem &in) : GroupElem(in), z(1) {} |
75 | ||
e8c2a8ec | 76 | void SetJac(Context &ctx, GroupElemJac &jac) { |
cb4d29c8 PW |
77 | *this = jac; |
78 | } | |
79 | ||
b394396b | 80 | /** Checks whether this is a non-infinite point on the curve */ |
4e0ed539 | 81 | bool IsValid() const { |
b394396b PW |
82 | if (IsInfinity()) |
83 | return false; | |
84 | // y^2 = x^3 + 7 | |
85 | // (Y/Z^3)^2 = (X/Z^2)^3 + 7 | |
86 | // Y^2 / Z^6 = X^3 / Z^6 + 7 | |
87 | // Y^2 = X^3 + 7*Z^6 | |
88 | FieldElem y2; y2.SetSquare(y); | |
89 | FieldElem x3; x3.SetSquare(x); x3.SetMult(x3,x); | |
90 | FieldElem z2; z2.SetSquare(z); | |
91 | FieldElem z6; z6.SetSquare(z2); z6.SetMult(z6,z2); | |
92 | z6 *= 7; | |
93 | x3 += z6; | |
94 | return y2 == x3; | |
95 | } | |
96 | ||
97 | /** Returns the affine coordinates of this point */ | |
e8c2a8ec PW |
98 | void GetAffine(Context &ctx, GroupElem &aff) { |
99 | z.SetInverse(ctx, z); | |
b394396b PW |
100 | FieldElem z2; |
101 | z2.SetSquare(z); | |
102 | FieldElem z3; | |
103 | z3.SetMult(z,z2); | |
104 | x.SetMult(x,z2); | |
105 | y.SetMult(y,z3); | |
106 | z = FieldElem(1); | |
7ba40aa4 | 107 | aff.fInfinity = fInfinity; |
b394396b PW |
108 | aff.x = x; |
109 | aff.y = y; | |
110 | } | |
111 | ||
e8c2a8ec | 112 | void GetX(Context &ctx, FieldElem &xout) { |
83e640f0 | 113 | FieldElem zi; |
e8c2a8ec | 114 | zi.SetInverse(ctx, z); |
83e640f0 PW |
115 | zi.SetSquare(zi); |
116 | xout.SetMult(x, zi); | |
117 | } | |
118 | ||
119 | bool IsInfinity() const { | |
120 | return fInfinity; | |
121 | } | |
122 | ||
e8c2a8ec | 123 | void GetY(Context &ctx, FieldElem &yout) { |
83e640f0 | 124 | FieldElem zi; |
e8c2a8ec | 125 | zi.SetInverse(ctx, z); |
83e640f0 PW |
126 | FieldElem zi3; zi3.SetSquare(zi); zi3.SetMult(zi, zi3); |
127 | yout.SetMult(y, zi3); | |
128 | } | |
129 | ||
cb4d29c8 PW |
130 | void SetNeg(const GroupElemJac &p) { |
131 | *this = p; | |
132 | y.Normalize(); | |
133 | y.SetNeg(y, 1); | |
134 | } | |
135 | ||
b394396b PW |
136 | /** Sets this point to have a given X coordinate & given Y oddness */ |
137 | void SetCompressed(const FieldElem &xin, bool fOdd) { | |
138 | x = xin; | |
139 | FieldElem x2; x2.SetSquare(x); | |
140 | FieldElem x3; x3.SetMult(x,x2); | |
141 | fInfinity = false; | |
142 | FieldElem c(7); | |
143 | c += x3; | |
144 | y.SetSquareRoot(c); | |
145 | z = FieldElem(1); | |
146 | if (y.IsOdd() != fOdd) | |
147 | y.SetNeg(y,1); | |
148 | } | |
149 | ||
150 | /** Sets this point to be the EC double of another */ | |
151 | void SetDouble(const GroupElemJac &p) { | |
7ba40aa4 PW |
152 | FieldElem t5 = p.y; |
153 | if (p.fInfinity || t5.IsZero()) { | |
b394396b PW |
154 | fInfinity = true; |
155 | return; | |
156 | } | |
157 | ||
7ba40aa4 PW |
158 | FieldElem t1,t2,t3,t4; |
159 | z.SetMult(t5,p.z); | |
b394396b PW |
160 | z *= 2; // Z' = 2*Y*Z (2) |
161 | t1.SetSquare(p.x); | |
162 | t1 *= 3; // T1 = 3*X^2 (3) | |
163 | t2.SetSquare(t1); // T2 = 9*X^4 (1) | |
7ba40aa4 | 164 | t3.SetSquare(t5); |
b394396b PW |
165 | t3 *= 2; // T3 = 2*Y^2 (2) |
166 | t4.SetSquare(t3); | |
167 | t4 *= 2; // T4 = 8*Y^4 (2) | |
168 | t3.SetMult(p.x,t3); // T3 = 2*X*Y^2 (1) | |
169 | x = t3; | |
170 | x *= 4; // X' = 8*X*Y^2 (4) | |
171 | x.SetNeg(x,4); // X' = -8*X*Y^2 (5) | |
172 | x += t2; // X' = 9*X^4 - 8*X*Y^2 (6) | |
173 | t2.SetNeg(t2,1); // T2 = -9*X^4 (2) | |
174 | t3 *= 6; // T3 = 12*X*Y^2 (6) | |
175 | t3 += t2; // T3 = 12*X*Y^2 - 9*X^4 (8) | |
176 | y.SetMult(t1,t3); // Y' = 36*X^3*Y^2 - 27*X^6 (1) | |
177 | t2.SetNeg(t4,2); // T2 = -8*Y^4 (3) | |
178 | y += t2; // Y' = 36*X^3*Y^2 - 27*X^6 - 8*Y^4 (4) | |
7ba40aa4 | 179 | fInfinity = false; |
b394396b PW |
180 | } |
181 | ||
182 | /** Sets this point to be the EC addition of two others */ | |
183 | void SetAdd(const GroupElemJac &p, const GroupElemJac &q) { | |
184 | if (p.fInfinity) { | |
185 | *this = q; | |
186 | return; | |
187 | } | |
188 | if (q.fInfinity) { | |
189 | *this = p; | |
190 | return; | |
191 | } | |
192 | fInfinity = false; | |
193 | const FieldElem &x1 = p.x, &y1 = p.y, &z1 = p.z, &x2 = q.x, &y2 = q.y, &z2 = q.z; | |
194 | FieldElem z22; z22.SetSquare(z2); | |
195 | FieldElem z12; z12.SetSquare(z1); | |
196 | FieldElem u1; u1.SetMult(x1, z22); | |
197 | FieldElem u2; u2.SetMult(x2, z12); | |
198 | FieldElem s1; s1.SetMult(y1, z22); s1.SetMult(s1, z2); | |
199 | FieldElem s2; s2.SetMult(y2, z12); s2.SetMult(s2, z1); | |
200 | if (u1 == u2) { | |
201 | if (s1 == s2) { | |
202 | SetDouble(p); | |
203 | } else { | |
204 | fInfinity = true; | |
205 | } | |
206 | return; | |
207 | } | |
208 | FieldElem h; h.SetNeg(u1,1); h += u2; | |
209 | FieldElem r; r.SetNeg(s1,1); r += s2; | |
210 | FieldElem r2; r2.SetSquare(r); | |
211 | FieldElem h2; h2.SetSquare(h); | |
212 | FieldElem h3; h3.SetMult(h,h2); | |
213 | z.SetMult(z1,z2); z.SetMult(z, h); | |
214 | FieldElem t; t.SetMult(u1,h2); | |
215 | x = t; x *= 2; x += h3; x.SetNeg(x,3); x += r2; | |
216 | y.SetNeg(x,5); y += t; y.SetMult(y,r); | |
217 | h3.SetMult(h3,s1); h3.SetNeg(h3,1); | |
218 | y += h3; | |
219 | } | |
220 | ||
221 | /** Sets this point to be the EC addition of two others (one of which is in affine coordinates) */ | |
222 | void SetAdd(const GroupElemJac &p, const GroupElem &q) { | |
223 | if (p.fInfinity) { | |
224 | x = q.x; | |
225 | y = q.y; | |
226 | fInfinity = q.fInfinity; | |
227 | z = FieldElem(1); | |
228 | return; | |
229 | } | |
230 | if (q.fInfinity) { | |
231 | *this = p; | |
232 | return; | |
233 | } | |
234 | fInfinity = false; | |
235 | const FieldElem &x1 = p.x, &y1 = p.y, &z1 = p.z, &x2 = q.x, &y2 = q.y; | |
236 | FieldElem z12; z12.SetSquare(z1); | |
237 | FieldElem u1 = x1; u1.Normalize(); | |
238 | FieldElem u2; u2.SetMult(x2, z12); | |
239 | FieldElem s1 = y1; s1.Normalize(); | |
240 | FieldElem s2; s2.SetMult(y2, z12); s2.SetMult(s2, z1); | |
241 | if (u1 == u2) { | |
242 | if (s1 == s2) { | |
243 | SetDouble(p); | |
244 | } else { | |
245 | fInfinity = true; | |
246 | } | |
247 | return; | |
248 | } | |
249 | FieldElem h; h.SetNeg(u1,1); h += u2; | |
250 | FieldElem r; r.SetNeg(s1,1); r += s2; | |
251 | FieldElem r2; r2.SetSquare(r); | |
252 | FieldElem h2; h2.SetSquare(h); | |
253 | FieldElem h3; h3.SetMult(h,h2); | |
254 | z = p.z; z.SetMult(z, h); | |
255 | FieldElem t; t.SetMult(u1,h2); | |
256 | x = t; x *= 2; x += h3; x.SetNeg(x,3); x += r2; | |
257 | y.SetNeg(x,5); y += t; y.SetMult(y,r); | |
258 | h3.SetMult(h3,s1); h3.SetNeg(h3,1); | |
259 | y += h3; | |
260 | } | |
261 | ||
7ba40aa4 | 262 | std::string ToString() const { |
e8c2a8ec | 263 | Context ctx; |
7ba40aa4 | 264 | GroupElemJac cop = *this; |
b394396b | 265 | GroupElem aff; |
e8c2a8ec | 266 | cop.GetAffine(ctx, aff); |
b394396b PW |
267 | return aff.ToString(); |
268 | } | |
949bea92 PW |
269 | |
270 | void SetMulLambda(const GroupElemJac &p); | |
b394396b PW |
271 | }; |
272 | ||
e8c2a8ec PW |
273 | void GroupElem::SetJac(Context &ctx, GroupElemJac &jac) { |
274 | jac.GetAffine(ctx, *this); | |
cb4d29c8 PW |
275 | } |
276 | ||
277 | static const unsigned char order_[] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | |
278 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE, | |
279 | 0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B, | |
280 | 0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x41}; | |
281 | ||
282 | static const unsigned char g_x_[] = {0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC, | |
283 | 0x55,0xA0,0x62,0x95,0xCE,0x87,0x0B,0x07, | |
284 | 0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9, | |
285 | 0x59,0xF2,0x81,0x5B,0x16,0xF8,0x17,0x98}; | |
286 | ||
287 | static const unsigned char g_y_[] = {0x48,0x3A,0xDA,0x77,0x26,0xA3,0xC4,0x65, | |
288 | 0x5D,0xA4,0xFB,0xFC,0x0E,0x11,0x08,0xA8, | |
289 | 0xFD,0x17,0xB4,0x48,0xA6,0x85,0x54,0x19, | |
290 | 0x9C,0x47,0xD0,0x8F,0xFB,0x10,0xD4,0xB8}; | |
291 | ||
949bea92 PW |
292 | // properties of secp256k1's efficiently computable endomorphism |
293 | static const unsigned char lambda_[] = {0x53,0x63,0xad,0x4c,0xc0,0x5c,0x30,0xe0, | |
294 | 0xa5,0x26,0x1c,0x02,0x88,0x12,0x64,0x5a, | |
295 | 0x12,0x2e,0x22,0xea,0x20,0x81,0x66,0x78, | |
296 | 0xdf,0x02,0x96,0x7c,0x1b,0x23,0xbd,0x72}; | |
297 | static const unsigned char beta_[] = {0x7a,0xe9,0x6a,0x2b,0x65,0x7c,0x07,0x10, | |
298 | 0x6e,0x64,0x47,0x9e,0xac,0x34,0x34,0xe9, | |
299 | 0x9c,0xf0,0x49,0x75,0x12,0xf5,0x89,0x95, | |
300 | 0xc1,0x39,0x6c,0x28,0x71,0x95,0x01,0xee}; | |
301 | static const unsigned char a1b2_[] = {0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd, | |
302 | 0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15}; | |
303 | static const unsigned char b1_[] = {0xe4,0x43,0x7e,0xd6,0x01,0x0e,0x88,0x28, | |
304 | 0x6f,0x54,0x7f,0xa9,0x0a,0xbf,0xe4,0xc3}; | |
305 | static const unsigned char a2_[] = {0x01, | |
306 | 0x14,0xca,0x50,0xf7,0xa8,0xe2,0xf3,0xf6, | |
307 | 0x57,0xc1,0x10,0x8d,0x9d,0x44,0xcf,0xd8}; | |
cb4d29c8 PW |
308 | class GroupConstants { |
309 | private: | |
310 | Context ctx; | |
311 | const FieldElem g_x; | |
312 | const FieldElem g_y; | |
313 | ||
314 | public: | |
315 | const Number order; | |
316 | const GroupElem g; | |
949bea92 PW |
317 | const FieldElem beta; |
318 | const Number lambda, a1b2, b1, a2; | |
cb4d29c8 PW |
319 | |
320 | GroupConstants() : order(ctx, order_, sizeof(order_)), | |
949bea92 PW |
321 | g_x(g_x_), g_y(g_y_), g(g_x,g_y), |
322 | beta(beta_), | |
323 | lambda(ctx, lambda_, sizeof(lambda_)), | |
324 | a1b2(ctx, a1b2_, sizeof(a1b2_)), | |
325 | b1(ctx, b1_, sizeof(b1_)), | |
326 | a2(ctx, a2_, sizeof(a2_)) {} | |
cb4d29c8 PW |
327 | }; |
328 | ||
329 | const GroupConstants &GetGroupConst() { | |
330 | static const GroupConstants group_const; | |
331 | return group_const; | |
332 | } | |
333 | ||
949bea92 PW |
334 | void GroupElemJac::SetMulLambda(const GroupElemJac &p) { |
335 | FieldElem beta = GetGroupConst().beta; | |
336 | *this = p; | |
337 | x.SetMult(x, beta); | |
338 | } | |
339 | ||
a41f32e6 | 340 | void SplitExp(Context &ctx, const Number &exp, Number &exp1, Number &exp2) { |
949bea92 PW |
341 | const GroupConstants &c = GetGroupConst(); |
342 | Context ct(ctx); | |
343 | Number bnc1(ct), bnc2(ct), bnt1(ct), bnt2(ct), bnn2(ct); | |
344 | bnn2.SetNumber(c.order); | |
345 | bnn2.Shift1(); | |
346 | ||
347 | bnc1.SetMult(ct, exp, c.a1b2); | |
348 | bnc1.SetAdd(ct, bnc1, bnn2); | |
349 | bnc1.SetDiv(ct, bnc1, c.order); | |
350 | ||
351 | bnc2.SetMult(ct, exp, c.b1); | |
352 | bnc2.SetAdd(ct, bnc2, bnn2); | |
353 | bnc2.SetDiv(ct, bnc2, c.order); | |
354 | ||
355 | bnt1.SetMult(ct, bnc1, c.a1b2); | |
356 | bnt2.SetMult(ct, bnc2, c.a2); | |
357 | bnt1.SetAdd(ct, bnt1, bnt2); | |
358 | exp1.SetSub(ct, exp, bnt1); | |
359 | bnt1.SetMult(ct, bnc1, c.b1); | |
360 | bnt2.SetMult(ct, bnc2, c.a1b2); | |
361 | exp2.SetSub(ct, bnt1, bnt2); | |
362 | } | |
363 | ||
b394396b PW |
364 | } |
365 | ||
366 | #endif |