Skip to content

Commit 036d4ba

Browse files
committed
First version of custom interpreter in FCryptoEC_Prime
1 parent 2cc9cd6 commit 036d4ba

File tree

2 files changed

+246
-5
lines changed

2 files changed

+246
-5
lines changed

Classes/FCryptoEC_Prime.uc

Lines changed: 244 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,6 @@ struct Jacobian
8282
var _Monty C[3];
8383
};
8484

85-
static final function CurveParams IdToCurve(EFCEllipticCurve Curve)
86-
{
87-
return default._PP[Curve - FCEC_Secp256r1];
88-
};
89-
9085
/*
9186
* We use a custom interpreter that uses a dozen registers, and
9287
* only six operations:
@@ -145,6 +140,163 @@ static final function CurveParams IdToCurve(EFCEllipticCurve Curve)
145140
`define T9 4
146141
`define T10 5
147142

143+
/*
144+
* Doubling formulas are:
145+
*
146+
* s = 4*x*y^2
147+
* m = 3*(x + z^2)*(x - z^2)
148+
* x' = m^2 - 2*s
149+
* y' = m*(s - x') - 8*y^4
150+
* z' = 2*y*z
151+
*
152+
* If y = 0 (P has order 2) then this yields infinity (z' = 0), as it
153+
* should. This case should not happen anyway, because our curves have
154+
* prime order, and thus do not contain any point of order 2.
155+
*
156+
* If P is infinity (z = 0), then again the formulas yield infinity,
157+
* which is correct. Thus, this code works for all points.
158+
*
159+
* Cost: 8 multiplications
160+
*/
161+
var const array<int> CodeDouble;
162+
163+
/*
164+
* Additions formulas are:
165+
*
166+
* u1 = x1 * z2^2
167+
* u2 = x2 * z1^2
168+
* s1 = y1 * z2^3
169+
* s2 = y2 * z1^3
170+
* h = u2 - u1
171+
* r = s2 - s1
172+
* x3 = r^2 - h^3 - 2 * u1 * h^2
173+
* y3 = r * (u1 * h^2 - x3) - s1 * h^3
174+
* z3 = h * z1 * z2
175+
*
176+
* If both P1 and P2 are infinity, then z1 == 0 and z2 == 0, implying that
177+
* z3 == 0, so the result is correct.
178+
* If either of P1 or P2 is infinity, but not both, then z3 == 0, which is
179+
* not correct.
180+
* h == 0 only if u1 == u2; this happens in two cases:
181+
* -- if s1 == s2 then P1 and/or P2 is infinity, or P1 == P2
182+
* -- if s1 != s2 then P1 + P2 == infinity (but neither P1 or P2 is infinity)
183+
*
184+
* Thus, the following situations are not handled correctly:
185+
* -- P1 = 0 and P2 != 0
186+
* -- P1 != 0 and P2 = 0
187+
* -- P1 = P2
188+
* All other cases are properly computed. However, even in "incorrect"
189+
* situations, the three coordinates still are properly formed field
190+
* elements.
191+
*
192+
* The returned flag is cleared if r == 0. This happens in the following
193+
* cases:
194+
* -- Both points are on the same horizontal line (same Y coordinate).
195+
* -- Both points are infinity.
196+
* -- One point is infinity and the other is on line Y = 0.
197+
* The third case cannot happen with our curves (there is no valid point
198+
* on line Y = 0 since that would be a point of order 2). If the two
199+
* source points are non-infinity, then remains only the case where the
200+
* two points are on the same horizontal line.
201+
*
202+
* This allows us to detect the "P1 == P2" case, assuming that P1 != 0 and
203+
* P2 != 0:
204+
* -- If the returned value is not the point at infinity, then it was properly
205+
* computed.
206+
* -- Otherwise, if the returned flag is 1, then P1+P2 = 0, and the result
207+
* is indeed the point at infinity.
208+
* -- Otherwise (result is infinity, flag is 0), then P1 = P2 and we should
209+
* use the 'double' code.
210+
*
211+
* Cost: 16 multiplications
212+
*/
213+
var const array<int> CodeAdd;
214+
215+
/*
216+
* Check that the point is on the curve. This code snippet assumes the
217+
* following conventions:
218+
* -- Coordinates x and y have been freshly decoded in P1 (but not
219+
* converted to Montgomery coordinates yet).
220+
* -- P2x, P2y and P2z are set to, respectively, R^2, b*R and 1.
221+
*/
222+
var const array<int> CodeCheck;
223+
224+
/*
225+
* Conversion back to affine coordinates. This code snippet assumes that
226+
* the z coordinate of P2 is set to 1 (not in Montgomery representation).
227+
*/
228+
var const array<int> CodeAffine;
229+
230+
// TODO: finish implementation.
231+
static final function int RunCode(
232+
out Jacobian P1,
233+
const out Jacobian P2,
234+
const out CurveParams Cc,
235+
const out array<int> Code
236+
)
237+
{
238+
local int R;
239+
local _Monty T[13];
240+
local int U;
241+
local int Op;
242+
local int D;
243+
local int A;
244+
local int B;
245+
local int Ctl;
246+
local int PLen;
247+
local byte Tp[66]; /* (BR_MAX_EC_SIZE + 7) >> 3 */
248+
249+
R = 1;
250+
251+
/*
252+
* Copy the two operands in the dedicated registers.
253+
*/
254+
// memcpy(t[P1x], P1->c, 3 * I15_LEN * sizeof(uint16_t));
255+
// memcpy(t[P2x], P2->c, 3 * I15_LEN * sizeof(uint16_t));
256+
// TODO: need static memcpy for these array sizes.
257+
258+
/*
259+
* Run formulas.
260+
*/
261+
for (U = 0; True; ++U)
262+
{
263+
Op = Code[U];
264+
if (Op == 0)
265+
{
266+
break;
267+
}
268+
269+
D = (Op >>> 8) & 0x0F;
270+
A = (Op >>> 4) & 0x0F;
271+
B = Op & 0x0F;
272+
Op = Op >>> 12;
273+
switch (Op)
274+
{
275+
case 0:
276+
break;
277+
case 1:
278+
break;
279+
case 2:
280+
break;
281+
case 3:
282+
break;
283+
case 4:
284+
break;
285+
default:
286+
// TODO: need static variant for this too.
287+
// R = R & (class'FCryptoBigInt'.static.BIsZero(T[D]));
288+
break;
289+
}
290+
}
291+
292+
return R;
293+
}
294+
295+
static final function CurveParams IdToCurve(EFCEllipticCurve Curve)
296+
{
297+
return default._PP[Curve - FCEC_Secp256r1];
298+
};
299+
148300
static function array<byte> Generator(EFCEllipticCurve Curve, out int Len)
149301
{
150302
local array<byte> TODO;
@@ -215,4 +367,91 @@ DefaultProperties
215367
_PP(0)={(P=(`P256_P_VALUES), B=(`P256_B_VALUES), R2=(`P256_R2_VALUES), P0i=0x001, PointLen=65)}
216368
_PP(1)={(P=(`P384_P_VALUES), B=(`P384_B_VALUES), R2=(`P384_R2_VALUES), P0i=0x001, PointLen=97)}
217369
_PP(2)={(P=(`P521_P_VALUES), B=(`P521_B_VALUES), R2=(`P521_R2_VALUES), P0i=0x001, PointLen=133)}
370+
371+
CodeDouble={(
372+
/*
373+
* Compute z^2 (in t1).
374+
*/
375+
// `MMUL(`t1, `Pz, `Pz),
376+
13858,
377+
378+
/*
379+
* Compute x-z^2 (in t2) and then x+z^2 (in t1).
380+
*/
381+
// `MSET(`t2, `Px),
382+
// `MSUB(`t2, `t1),
383+
// `MADD(`t1, `Px),
384+
1792,
385+
10080,
386+
5632,
387+
388+
/*
389+
* Compute m = 3*(x+z^2)*(x-z^2) (in t1).
390+
*/
391+
// `MMUL(`t3, `t1, `t2),
392+
// `MSET(`t1, `t3),
393+
// `MADD(`t1, `t3),
394+
// `MADD(`t1, `t3),
395+
14439,
396+
1664,
397+
5760,
398+
5760,
399+
400+
/*
401+
* Compute s = 4*x*y^2 (in t2) and 2*y^2 (in t3).
402+
*/
403+
// `MMUL(`t3, `Py, `Py),
404+
// `MADD(`t3, `t3),
405+
// `MMUL(`t2, `Px, `t3),
406+
// `MADD(`t2, `t2),
407+
14353,
408+
6272,
409+
14088,
410+
6000,
411+
412+
/*
413+
* Compute x' = m^2 - 2*s.
414+
*/
415+
// `MMUL(`Px, `t1, `t1),
416+
// `MSUB(`Px, `t2),
417+
// `MSUB(`Px, `t2),
418+
12390,
419+
8304,
420+
8304,
421+
422+
/*
423+
* Compute z' = 2*y*z.
424+
*/
425+
// `MMUL(`t4, `Py, `Pz),
426+
// `MSET(`Pz, `t4),
427+
// `MADD(`Pz, `t4),
428+
14610,
429+
656,
430+
4752,
431+
432+
/*
433+
* Compute y' = m*(s - x') - 8*y^4. Note that we already have
434+
* 2*y^2 in t3.
435+
*/
436+
// `MSUB(`t2, `Px),
437+
// `MMUL(`Py, `t1, `t2),
438+
// `MMUL(`t4, `t3, `t3),
439+
// `MSUB(`Py, `t4),
440+
// `MSUB(`Py, `t4),
441+
9984,
442+
12647,
443+
14728,
444+
8592,
445+
8592,
446+
447+
`ENDCODE
448+
)}
449+
450+
CodeAdd={(
451+
452+
)}
453+
454+
CodeCheck={(
455+
456+
)}
218457
}

Classes/FCryptoTestMutator.uc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1567,6 +1567,8 @@ private final simulated function int TestSpeed()
15671567
}
15681568
UnClock(QWClock);
15691569
`fclog("QWClock (decode2)=" $ QWClock);
1570+
1571+
return 0;
15701572
}
15711573

15721574
DefaultProperties

0 commit comments

Comments
 (0)