10957b409SSimon J. Gerraty /*
20957b409SSimon J. Gerraty * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
30957b409SSimon J. Gerraty *
40957b409SSimon J. Gerraty * Permission is hereby granted, free of charge, to any person obtaining
50957b409SSimon J. Gerraty * a copy of this software and associated documentation files (the
60957b409SSimon J. Gerraty * "Software"), to deal in the Software without restriction, including
70957b409SSimon J. Gerraty * without limitation the rights to use, copy, modify, merge, publish,
80957b409SSimon J. Gerraty * distribute, sublicense, and/or sell copies of the Software, and to
90957b409SSimon J. Gerraty * permit persons to whom the Software is furnished to do so, subject to
100957b409SSimon J. Gerraty * the following conditions:
110957b409SSimon J. Gerraty *
120957b409SSimon J. Gerraty * The above copyright notice and this permission notice shall be
130957b409SSimon J. Gerraty * included in all copies or substantial portions of the Software.
140957b409SSimon J. Gerraty *
150957b409SSimon J. Gerraty * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
160957b409SSimon J. Gerraty * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
170957b409SSimon J. Gerraty * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
180957b409SSimon J. Gerraty * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
190957b409SSimon J. Gerraty * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
200957b409SSimon J. Gerraty * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
210957b409SSimon J. Gerraty * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
220957b409SSimon J. Gerraty * SOFTWARE.
230957b409SSimon J. Gerraty */
240957b409SSimon J. Gerraty
250957b409SSimon J. Gerraty #include "inner.h"
260957b409SSimon J. Gerraty
270957b409SSimon J. Gerraty /*
280957b409SSimon J. Gerraty * Parameters for supported curves (field modulus, and 'b' equation
290957b409SSimon J. Gerraty * parameter; both values use the 'i31' format, and 'b' is in Montgomery
300957b409SSimon J. Gerraty * representation).
310957b409SSimon J. Gerraty */
320957b409SSimon J. Gerraty
330957b409SSimon J. Gerraty static const uint32_t P256_P[] = {
340957b409SSimon J. Gerraty 0x00000108,
350957b409SSimon J. Gerraty 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x00000007,
360957b409SSimon J. Gerraty 0x00000000, 0x00000000, 0x00000040, 0x7FFFFF80,
370957b409SSimon J. Gerraty 0x000000FF
380957b409SSimon J. Gerraty };
390957b409SSimon J. Gerraty
400957b409SSimon J. Gerraty static const uint32_t P256_R2[] = {
410957b409SSimon J. Gerraty 0x00000108,
420957b409SSimon J. Gerraty 0x00014000, 0x00018000, 0x00000000, 0x7FF40000,
430957b409SSimon J. Gerraty 0x7FEFFFFF, 0x7FF7FFFF, 0x7FAFFFFF, 0x005FFFFF,
440957b409SSimon J. Gerraty 0x00000000
450957b409SSimon J. Gerraty };
460957b409SSimon J. Gerraty
470957b409SSimon J. Gerraty static const uint32_t P256_B[] = {
480957b409SSimon J. Gerraty 0x00000108,
490957b409SSimon J. Gerraty 0x6FEE1803, 0x6229C4BD, 0x21B139BE, 0x327150AA,
500957b409SSimon J. Gerraty 0x3567802E, 0x3F7212ED, 0x012E4355, 0x782DD38D,
510957b409SSimon J. Gerraty 0x0000000E
520957b409SSimon J. Gerraty };
530957b409SSimon J. Gerraty
540957b409SSimon J. Gerraty static const uint32_t P384_P[] = {
550957b409SSimon J. Gerraty 0x0000018C,
560957b409SSimon J. Gerraty 0x7FFFFFFF, 0x00000001, 0x00000000, 0x7FFFFFF8,
570957b409SSimon J. Gerraty 0x7FFFFFEF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF,
580957b409SSimon J. Gerraty 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF,
590957b409SSimon J. Gerraty 0x00000FFF
600957b409SSimon J. Gerraty };
610957b409SSimon J. Gerraty
620957b409SSimon J. Gerraty static const uint32_t P384_R2[] = {
630957b409SSimon J. Gerraty 0x0000018C,
640957b409SSimon J. Gerraty 0x00000000, 0x00000080, 0x7FFFFE00, 0x000001FF,
650957b409SSimon J. Gerraty 0x00000800, 0x00000000, 0x7FFFE000, 0x00001FFF,
660957b409SSimon J. Gerraty 0x00008000, 0x00008000, 0x00000000, 0x00000000,
670957b409SSimon J. Gerraty 0x00000000
680957b409SSimon J. Gerraty };
690957b409SSimon J. Gerraty
700957b409SSimon J. Gerraty static const uint32_t P384_B[] = {
710957b409SSimon J. Gerraty 0x0000018C,
720957b409SSimon J. Gerraty 0x6E666840, 0x070D0392, 0x5D810231, 0x7651D50C,
730957b409SSimon J. Gerraty 0x17E218D6, 0x1B192002, 0x44EFE441, 0x3A524E2B,
740957b409SSimon J. Gerraty 0x2719BA5F, 0x41F02209, 0x36C5643E, 0x5813EFFE,
750957b409SSimon J. Gerraty 0x000008A5
760957b409SSimon J. Gerraty };
770957b409SSimon J. Gerraty
780957b409SSimon J. Gerraty static const uint32_t P521_P[] = {
790957b409SSimon J. Gerraty 0x00000219,
800957b409SSimon J. Gerraty 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF,
810957b409SSimon J. Gerraty 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF,
820957b409SSimon J. Gerraty 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF,
830957b409SSimon J. Gerraty 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF,
840957b409SSimon J. Gerraty 0x01FFFFFF
850957b409SSimon J. Gerraty };
860957b409SSimon J. Gerraty
870957b409SSimon J. Gerraty static const uint32_t P521_R2[] = {
880957b409SSimon J. Gerraty 0x00000219,
890957b409SSimon J. Gerraty 0x00001000, 0x00000000, 0x00000000, 0x00000000,
900957b409SSimon J. Gerraty 0x00000000, 0x00000000, 0x00000000, 0x00000000,
910957b409SSimon J. Gerraty 0x00000000, 0x00000000, 0x00000000, 0x00000000,
920957b409SSimon J. Gerraty 0x00000000, 0x00000000, 0x00000000, 0x00000000,
930957b409SSimon J. Gerraty 0x00000000
940957b409SSimon J. Gerraty };
950957b409SSimon J. Gerraty
960957b409SSimon J. Gerraty static const uint32_t P521_B[] = {
970957b409SSimon J. Gerraty 0x00000219,
980957b409SSimon J. Gerraty 0x540FC00A, 0x228FEA35, 0x2C34F1EF, 0x67BF107A,
990957b409SSimon J. Gerraty 0x46FC1CD5, 0x1605E9DD, 0x6937B165, 0x272A3D8F,
1000957b409SSimon J. Gerraty 0x42785586, 0x44C8C778, 0x15F3B8B4, 0x64B73366,
1010957b409SSimon J. Gerraty 0x03BA8B69, 0x0D05B42A, 0x21F929A2, 0x2C31C393,
1020957b409SSimon J. Gerraty 0x00654FAE
1030957b409SSimon J. Gerraty };
1040957b409SSimon J. Gerraty
1050957b409SSimon J. Gerraty typedef struct {
1060957b409SSimon J. Gerraty const uint32_t *p;
1070957b409SSimon J. Gerraty const uint32_t *b;
1080957b409SSimon J. Gerraty const uint32_t *R2;
1090957b409SSimon J. Gerraty uint32_t p0i;
110*cc9e6590SSimon J. Gerraty size_t point_len;
1110957b409SSimon J. Gerraty } curve_params;
1120957b409SSimon J. Gerraty
1130957b409SSimon J. Gerraty static inline const curve_params *
id_to_curve(int curve)1140957b409SSimon J. Gerraty id_to_curve(int curve)
1150957b409SSimon J. Gerraty {
1160957b409SSimon J. Gerraty static const curve_params pp[] = {
117*cc9e6590SSimon J. Gerraty { P256_P, P256_B, P256_R2, 0x00000001, 65 },
118*cc9e6590SSimon J. Gerraty { P384_P, P384_B, P384_R2, 0x00000001, 97 },
119*cc9e6590SSimon J. Gerraty { P521_P, P521_B, P521_R2, 0x00000001, 133 }
1200957b409SSimon J. Gerraty };
1210957b409SSimon J. Gerraty
1220957b409SSimon J. Gerraty return &pp[curve - BR_EC_secp256r1];
1230957b409SSimon J. Gerraty }
1240957b409SSimon J. Gerraty
1250957b409SSimon J. Gerraty #define I31_LEN ((BR_MAX_EC_SIZE + 61) / 31)
1260957b409SSimon J. Gerraty
1270957b409SSimon J. Gerraty /*
1280957b409SSimon J. Gerraty * Type for a point in Jacobian coordinates:
1290957b409SSimon J. Gerraty * -- three values, x, y and z, in Montgomery representation
1300957b409SSimon J. Gerraty * -- affine coordinates are X = x / z^2 and Y = y / z^3
1310957b409SSimon J. Gerraty * -- for the point at infinity, z = 0
1320957b409SSimon J. Gerraty */
1330957b409SSimon J. Gerraty typedef struct {
1340957b409SSimon J. Gerraty uint32_t c[3][I31_LEN];
1350957b409SSimon J. Gerraty } jacobian;
1360957b409SSimon J. Gerraty
1370957b409SSimon J. Gerraty /*
1380957b409SSimon J. Gerraty * We use a custom interpreter that uses a dozen registers, and
1390957b409SSimon J. Gerraty * only six operations:
1400957b409SSimon J. Gerraty * MSET(d, a) copy a into d
1410957b409SSimon J. Gerraty * MADD(d, a) d = d+a (modular)
1420957b409SSimon J. Gerraty * MSUB(d, a) d = d-a (modular)
1430957b409SSimon J. Gerraty * MMUL(d, a, b) d = a*b (Montgomery multiplication)
1440957b409SSimon J. Gerraty * MINV(d, a, b) invert d modulo p; a and b are used as scratch registers
1450957b409SSimon J. Gerraty * MTZ(d) clear return value if d = 0
1460957b409SSimon J. Gerraty * Destination of MMUL (d) must be distinct from operands (a and b).
1470957b409SSimon J. Gerraty * There is no such constraint for MSUB and MADD.
1480957b409SSimon J. Gerraty *
1490957b409SSimon J. Gerraty * Registers include the operand coordinates, and temporaries.
1500957b409SSimon J. Gerraty */
1510957b409SSimon J. Gerraty #define MSET(d, a) (0x0000 + ((d) << 8) + ((a) << 4))
1520957b409SSimon J. Gerraty #define MADD(d, a) (0x1000 + ((d) << 8) + ((a) << 4))
1530957b409SSimon J. Gerraty #define MSUB(d, a) (0x2000 + ((d) << 8) + ((a) << 4))
1540957b409SSimon J. Gerraty #define MMUL(d, a, b) (0x3000 + ((d) << 8) + ((a) << 4) + (b))
1550957b409SSimon J. Gerraty #define MINV(d, a, b) (0x4000 + ((d) << 8) + ((a) << 4) + (b))
1560957b409SSimon J. Gerraty #define MTZ(d) (0x5000 + ((d) << 8))
1570957b409SSimon J. Gerraty #define ENDCODE 0
1580957b409SSimon J. Gerraty
1590957b409SSimon J. Gerraty /*
1600957b409SSimon J. Gerraty * Registers for the input operands.
1610957b409SSimon J. Gerraty */
1620957b409SSimon J. Gerraty #define P1x 0
1630957b409SSimon J. Gerraty #define P1y 1
1640957b409SSimon J. Gerraty #define P1z 2
1650957b409SSimon J. Gerraty #define P2x 3
1660957b409SSimon J. Gerraty #define P2y 4
1670957b409SSimon J. Gerraty #define P2z 5
1680957b409SSimon J. Gerraty
1690957b409SSimon J. Gerraty /*
1700957b409SSimon J. Gerraty * Alternate names for the first input operand.
1710957b409SSimon J. Gerraty */
1720957b409SSimon J. Gerraty #define Px 0
1730957b409SSimon J. Gerraty #define Py 1
1740957b409SSimon J. Gerraty #define Pz 2
1750957b409SSimon J. Gerraty
1760957b409SSimon J. Gerraty /*
1770957b409SSimon J. Gerraty * Temporaries.
1780957b409SSimon J. Gerraty */
1790957b409SSimon J. Gerraty #define t1 6
1800957b409SSimon J. Gerraty #define t2 7
1810957b409SSimon J. Gerraty #define t3 8
1820957b409SSimon J. Gerraty #define t4 9
1830957b409SSimon J. Gerraty #define t5 10
1840957b409SSimon J. Gerraty #define t6 11
1850957b409SSimon J. Gerraty #define t7 12
1860957b409SSimon J. Gerraty
1870957b409SSimon J. Gerraty /*
1880957b409SSimon J. Gerraty * Extra scratch registers available when there is no second operand (e.g.
1890957b409SSimon J. Gerraty * for "double" and "affine").
1900957b409SSimon J. Gerraty */
1910957b409SSimon J. Gerraty #define t8 3
1920957b409SSimon J. Gerraty #define t9 4
1930957b409SSimon J. Gerraty #define t10 5
1940957b409SSimon J. Gerraty
1950957b409SSimon J. Gerraty /*
1960957b409SSimon J. Gerraty * Doubling formulas are:
1970957b409SSimon J. Gerraty *
1980957b409SSimon J. Gerraty * s = 4*x*y^2
1990957b409SSimon J. Gerraty * m = 3*(x + z^2)*(x - z^2)
2000957b409SSimon J. Gerraty * x' = m^2 - 2*s
2010957b409SSimon J. Gerraty * y' = m*(s - x') - 8*y^4
2020957b409SSimon J. Gerraty * z' = 2*y*z
2030957b409SSimon J. Gerraty *
2040957b409SSimon J. Gerraty * If y = 0 (P has order 2) then this yields infinity (z' = 0), as it
2050957b409SSimon J. Gerraty * should. This case should not happen anyway, because our curves have
2060957b409SSimon J. Gerraty * prime order, and thus do not contain any point of order 2.
2070957b409SSimon J. Gerraty *
2080957b409SSimon J. Gerraty * If P is infinity (z = 0), then again the formulas yield infinity,
2090957b409SSimon J. Gerraty * which is correct. Thus, this code works for all points.
2100957b409SSimon J. Gerraty *
2110957b409SSimon J. Gerraty * Cost: 8 multiplications
2120957b409SSimon J. Gerraty */
2130957b409SSimon J. Gerraty static const uint16_t code_double[] = {
2140957b409SSimon J. Gerraty /*
2150957b409SSimon J. Gerraty * Compute z^2 (in t1).
2160957b409SSimon J. Gerraty */
2170957b409SSimon J. Gerraty MMUL(t1, Pz, Pz),
2180957b409SSimon J. Gerraty
2190957b409SSimon J. Gerraty /*
2200957b409SSimon J. Gerraty * Compute x-z^2 (in t2) and then x+z^2 (in t1).
2210957b409SSimon J. Gerraty */
2220957b409SSimon J. Gerraty MSET(t2, Px),
2230957b409SSimon J. Gerraty MSUB(t2, t1),
2240957b409SSimon J. Gerraty MADD(t1, Px),
2250957b409SSimon J. Gerraty
2260957b409SSimon J. Gerraty /*
2270957b409SSimon J. Gerraty * Compute m = 3*(x+z^2)*(x-z^2) (in t1).
2280957b409SSimon J. Gerraty */
2290957b409SSimon J. Gerraty MMUL(t3, t1, t2),
2300957b409SSimon J. Gerraty MSET(t1, t3),
2310957b409SSimon J. Gerraty MADD(t1, t3),
2320957b409SSimon J. Gerraty MADD(t1, t3),
2330957b409SSimon J. Gerraty
2340957b409SSimon J. Gerraty /*
2350957b409SSimon J. Gerraty * Compute s = 4*x*y^2 (in t2) and 2*y^2 (in t3).
2360957b409SSimon J. Gerraty */
2370957b409SSimon J. Gerraty MMUL(t3, Py, Py),
2380957b409SSimon J. Gerraty MADD(t3, t3),
2390957b409SSimon J. Gerraty MMUL(t2, Px, t3),
2400957b409SSimon J. Gerraty MADD(t2, t2),
2410957b409SSimon J. Gerraty
2420957b409SSimon J. Gerraty /*
2430957b409SSimon J. Gerraty * Compute x' = m^2 - 2*s.
2440957b409SSimon J. Gerraty */
2450957b409SSimon J. Gerraty MMUL(Px, t1, t1),
2460957b409SSimon J. Gerraty MSUB(Px, t2),
2470957b409SSimon J. Gerraty MSUB(Px, t2),
2480957b409SSimon J. Gerraty
2490957b409SSimon J. Gerraty /*
2500957b409SSimon J. Gerraty * Compute z' = 2*y*z.
2510957b409SSimon J. Gerraty */
2520957b409SSimon J. Gerraty MMUL(t4, Py, Pz),
2530957b409SSimon J. Gerraty MSET(Pz, t4),
2540957b409SSimon J. Gerraty MADD(Pz, t4),
2550957b409SSimon J. Gerraty
2560957b409SSimon J. Gerraty /*
2570957b409SSimon J. Gerraty * Compute y' = m*(s - x') - 8*y^4. Note that we already have
2580957b409SSimon J. Gerraty * 2*y^2 in t3.
2590957b409SSimon J. Gerraty */
2600957b409SSimon J. Gerraty MSUB(t2, Px),
2610957b409SSimon J. Gerraty MMUL(Py, t1, t2),
2620957b409SSimon J. Gerraty MMUL(t4, t3, t3),
2630957b409SSimon J. Gerraty MSUB(Py, t4),
2640957b409SSimon J. Gerraty MSUB(Py, t4),
2650957b409SSimon J. Gerraty
2660957b409SSimon J. Gerraty ENDCODE
2670957b409SSimon J. Gerraty };
2680957b409SSimon J. Gerraty
2690957b409SSimon J. Gerraty /*
2700957b409SSimon J. Gerraty * Addtions formulas are:
2710957b409SSimon J. Gerraty *
2720957b409SSimon J. Gerraty * u1 = x1 * z2^2
2730957b409SSimon J. Gerraty * u2 = x2 * z1^2
2740957b409SSimon J. Gerraty * s1 = y1 * z2^3
2750957b409SSimon J. Gerraty * s2 = y2 * z1^3
2760957b409SSimon J. Gerraty * h = u2 - u1
2770957b409SSimon J. Gerraty * r = s2 - s1
2780957b409SSimon J. Gerraty * x3 = r^2 - h^3 - 2 * u1 * h^2
2790957b409SSimon J. Gerraty * y3 = r * (u1 * h^2 - x3) - s1 * h^3
2800957b409SSimon J. Gerraty * z3 = h * z1 * z2
2810957b409SSimon J. Gerraty *
2820957b409SSimon J. Gerraty * If both P1 and P2 are infinity, then z1 == 0 and z2 == 0, implying that
2830957b409SSimon J. Gerraty * z3 == 0, so the result is correct.
2840957b409SSimon J. Gerraty * If either of P1 or P2 is infinity, but not both, then z3 == 0, which is
2850957b409SSimon J. Gerraty * not correct.
2860957b409SSimon J. Gerraty * h == 0 only if u1 == u2; this happens in two cases:
2870957b409SSimon J. Gerraty * -- if s1 == s2 then P1 and/or P2 is infinity, or P1 == P2
2880957b409SSimon J. Gerraty * -- if s1 != s2 then P1 + P2 == infinity (but neither P1 or P2 is infinity)
2890957b409SSimon J. Gerraty *
2900957b409SSimon J. Gerraty * Thus, the following situations are not handled correctly:
2910957b409SSimon J. Gerraty * -- P1 = 0 and P2 != 0
2920957b409SSimon J. Gerraty * -- P1 != 0 and P2 = 0
2930957b409SSimon J. Gerraty * -- P1 = P2
2940957b409SSimon J. Gerraty * All other cases are properly computed. However, even in "incorrect"
2950957b409SSimon J. Gerraty * situations, the three coordinates still are properly formed field
2960957b409SSimon J. Gerraty * elements.
2970957b409SSimon J. Gerraty *
2980957b409SSimon J. Gerraty * The returned flag is cleared if r == 0. This happens in the following
2990957b409SSimon J. Gerraty * cases:
3000957b409SSimon J. Gerraty * -- Both points are on the same horizontal line (same Y coordinate).
3010957b409SSimon J. Gerraty * -- Both points are infinity.
3020957b409SSimon J. Gerraty * -- One point is infinity and the other is on line Y = 0.
3030957b409SSimon J. Gerraty * The third case cannot happen with our curves (there is no valid point
3040957b409SSimon J. Gerraty * on line Y = 0 since that would be a point of order 2). If the two
3050957b409SSimon J. Gerraty * source points are non-infinity, then remains only the case where the
3060957b409SSimon J. Gerraty * two points are on the same horizontal line.
3070957b409SSimon J. Gerraty *
3080957b409SSimon J. Gerraty * This allows us to detect the "P1 == P2" case, assuming that P1 != 0 and
3090957b409SSimon J. Gerraty * P2 != 0:
3100957b409SSimon J. Gerraty * -- If the returned value is not the point at infinity, then it was properly
3110957b409SSimon J. Gerraty * computed.
3120957b409SSimon J. Gerraty * -- Otherwise, if the returned flag is 1, then P1+P2 = 0, and the result
3130957b409SSimon J. Gerraty * is indeed the point at infinity.
3140957b409SSimon J. Gerraty * -- Otherwise (result is infinity, flag is 0), then P1 = P2 and we should
3150957b409SSimon J. Gerraty * use the 'double' code.
3160957b409SSimon J. Gerraty *
3170957b409SSimon J. Gerraty * Cost: 16 multiplications
3180957b409SSimon J. Gerraty */
3190957b409SSimon J. Gerraty static const uint16_t code_add[] = {
3200957b409SSimon J. Gerraty /*
3210957b409SSimon J. Gerraty * Compute u1 = x1*z2^2 (in t1) and s1 = y1*z2^3 (in t3).
3220957b409SSimon J. Gerraty */
3230957b409SSimon J. Gerraty MMUL(t3, P2z, P2z),
3240957b409SSimon J. Gerraty MMUL(t1, P1x, t3),
3250957b409SSimon J. Gerraty MMUL(t4, P2z, t3),
3260957b409SSimon J. Gerraty MMUL(t3, P1y, t4),
3270957b409SSimon J. Gerraty
3280957b409SSimon J. Gerraty /*
3290957b409SSimon J. Gerraty * Compute u2 = x2*z1^2 (in t2) and s2 = y2*z1^3 (in t4).
3300957b409SSimon J. Gerraty */
3310957b409SSimon J. Gerraty MMUL(t4, P1z, P1z),
3320957b409SSimon J. Gerraty MMUL(t2, P2x, t4),
3330957b409SSimon J. Gerraty MMUL(t5, P1z, t4),
3340957b409SSimon J. Gerraty MMUL(t4, P2y, t5),
3350957b409SSimon J. Gerraty
3360957b409SSimon J. Gerraty /*
3370957b409SSimon J. Gerraty * Compute h = u2 - u1 (in t2) and r = s2 - s1 (in t4).
3380957b409SSimon J. Gerraty */
3390957b409SSimon J. Gerraty MSUB(t2, t1),
3400957b409SSimon J. Gerraty MSUB(t4, t3),
3410957b409SSimon J. Gerraty
3420957b409SSimon J. Gerraty /*
3430957b409SSimon J. Gerraty * Report cases where r = 0 through the returned flag.
3440957b409SSimon J. Gerraty */
3450957b409SSimon J. Gerraty MTZ(t4),
3460957b409SSimon J. Gerraty
3470957b409SSimon J. Gerraty /*
3480957b409SSimon J. Gerraty * Compute u1*h^2 (in t6) and h^3 (in t5).
3490957b409SSimon J. Gerraty */
3500957b409SSimon J. Gerraty MMUL(t7, t2, t2),
3510957b409SSimon J. Gerraty MMUL(t6, t1, t7),
3520957b409SSimon J. Gerraty MMUL(t5, t7, t2),
3530957b409SSimon J. Gerraty
3540957b409SSimon J. Gerraty /*
3550957b409SSimon J. Gerraty * Compute x3 = r^2 - h^3 - 2*u1*h^2.
3560957b409SSimon J. Gerraty * t1 and t7 can be used as scratch registers.
3570957b409SSimon J. Gerraty */
3580957b409SSimon J. Gerraty MMUL(P1x, t4, t4),
3590957b409SSimon J. Gerraty MSUB(P1x, t5),
3600957b409SSimon J. Gerraty MSUB(P1x, t6),
3610957b409SSimon J. Gerraty MSUB(P1x, t6),
3620957b409SSimon J. Gerraty
3630957b409SSimon J. Gerraty /*
3640957b409SSimon J. Gerraty * Compute y3 = r*(u1*h^2 - x3) - s1*h^3.
3650957b409SSimon J. Gerraty */
3660957b409SSimon J. Gerraty MSUB(t6, P1x),
3670957b409SSimon J. Gerraty MMUL(P1y, t4, t6),
3680957b409SSimon J. Gerraty MMUL(t1, t5, t3),
3690957b409SSimon J. Gerraty MSUB(P1y, t1),
3700957b409SSimon J. Gerraty
3710957b409SSimon J. Gerraty /*
3720957b409SSimon J. Gerraty * Compute z3 = h*z1*z2.
3730957b409SSimon J. Gerraty */
3740957b409SSimon J. Gerraty MMUL(t1, P1z, P2z),
3750957b409SSimon J. Gerraty MMUL(P1z, t1, t2),
3760957b409SSimon J. Gerraty
3770957b409SSimon J. Gerraty ENDCODE
3780957b409SSimon J. Gerraty };
3790957b409SSimon J. Gerraty
3800957b409SSimon J. Gerraty /*
3810957b409SSimon J. Gerraty * Check that the point is on the curve. This code snippet assumes the
3820957b409SSimon J. Gerraty * following conventions:
3830957b409SSimon J. Gerraty * -- Coordinates x and y have been freshly decoded in P1 (but not
3840957b409SSimon J. Gerraty * converted to Montgomery coordinates yet).
3850957b409SSimon J. Gerraty * -- P2x, P2y and P2z are set to, respectively, R^2, b*R and 1.
3860957b409SSimon J. Gerraty */
3870957b409SSimon J. Gerraty static const uint16_t code_check[] = {
3880957b409SSimon J. Gerraty
3890957b409SSimon J. Gerraty /* Convert x and y to Montgomery representation. */
3900957b409SSimon J. Gerraty MMUL(t1, P1x, P2x),
3910957b409SSimon J. Gerraty MMUL(t2, P1y, P2x),
3920957b409SSimon J. Gerraty MSET(P1x, t1),
3930957b409SSimon J. Gerraty MSET(P1y, t2),
3940957b409SSimon J. Gerraty
3950957b409SSimon J. Gerraty /* Compute x^3 in t1. */
3960957b409SSimon J. Gerraty MMUL(t2, P1x, P1x),
3970957b409SSimon J. Gerraty MMUL(t1, P1x, t2),
3980957b409SSimon J. Gerraty
3990957b409SSimon J. Gerraty /* Subtract 3*x from t1. */
4000957b409SSimon J. Gerraty MSUB(t1, P1x),
4010957b409SSimon J. Gerraty MSUB(t1, P1x),
4020957b409SSimon J. Gerraty MSUB(t1, P1x),
4030957b409SSimon J. Gerraty
4040957b409SSimon J. Gerraty /* Add b. */
4050957b409SSimon J. Gerraty MADD(t1, P2y),
4060957b409SSimon J. Gerraty
4070957b409SSimon J. Gerraty /* Compute y^2 in t2. */
4080957b409SSimon J. Gerraty MMUL(t2, P1y, P1y),
4090957b409SSimon J. Gerraty
4100957b409SSimon J. Gerraty /* Compare y^2 with x^3 - 3*x + b; they must match. */
4110957b409SSimon J. Gerraty MSUB(t1, t2),
4120957b409SSimon J. Gerraty MTZ(t1),
4130957b409SSimon J. Gerraty
4140957b409SSimon J. Gerraty /* Set z to 1 (in Montgomery representation). */
4150957b409SSimon J. Gerraty MMUL(P1z, P2x, P2z),
4160957b409SSimon J. Gerraty
4170957b409SSimon J. Gerraty ENDCODE
4180957b409SSimon J. Gerraty };
4190957b409SSimon J. Gerraty
4200957b409SSimon J. Gerraty /*
4210957b409SSimon J. Gerraty * Conversion back to affine coordinates. This code snippet assumes that
4220957b409SSimon J. Gerraty * the z coordinate of P2 is set to 1 (not in Montgomery representation).
4230957b409SSimon J. Gerraty */
4240957b409SSimon J. Gerraty static const uint16_t code_affine[] = {
4250957b409SSimon J. Gerraty
4260957b409SSimon J. Gerraty /* Save z*R in t1. */
4270957b409SSimon J. Gerraty MSET(t1, P1z),
4280957b409SSimon J. Gerraty
4290957b409SSimon J. Gerraty /* Compute z^3 in t2. */
4300957b409SSimon J. Gerraty MMUL(t2, P1z, P1z),
4310957b409SSimon J. Gerraty MMUL(t3, P1z, t2),
4320957b409SSimon J. Gerraty MMUL(t2, t3, P2z),
4330957b409SSimon J. Gerraty
4340957b409SSimon J. Gerraty /* Invert to (1/z^3) in t2. */
4350957b409SSimon J. Gerraty MINV(t2, t3, t4),
4360957b409SSimon J. Gerraty
4370957b409SSimon J. Gerraty /* Compute y. */
4380957b409SSimon J. Gerraty MSET(t3, P1y),
4390957b409SSimon J. Gerraty MMUL(P1y, t2, t3),
4400957b409SSimon J. Gerraty
4410957b409SSimon J. Gerraty /* Compute (1/z^2) in t3. */
4420957b409SSimon J. Gerraty MMUL(t3, t2, t1),
4430957b409SSimon J. Gerraty
4440957b409SSimon J. Gerraty /* Compute x. */
4450957b409SSimon J. Gerraty MSET(t2, P1x),
4460957b409SSimon J. Gerraty MMUL(P1x, t2, t3),
4470957b409SSimon J. Gerraty
4480957b409SSimon J. Gerraty ENDCODE
4490957b409SSimon J. Gerraty };
4500957b409SSimon J. Gerraty
4510957b409SSimon J. Gerraty static uint32_t
run_code(jacobian * P1,const jacobian * P2,const curve_params * cc,const uint16_t * code)4520957b409SSimon J. Gerraty run_code(jacobian *P1, const jacobian *P2,
4530957b409SSimon J. Gerraty const curve_params *cc, const uint16_t *code)
4540957b409SSimon J. Gerraty {
4550957b409SSimon J. Gerraty uint32_t r;
4560957b409SSimon J. Gerraty uint32_t t[13][I31_LEN];
4570957b409SSimon J. Gerraty size_t u;
4580957b409SSimon J. Gerraty
4590957b409SSimon J. Gerraty r = 1;
4600957b409SSimon J. Gerraty
4610957b409SSimon J. Gerraty /*
4620957b409SSimon J. Gerraty * Copy the two operands in the dedicated registers.
4630957b409SSimon J. Gerraty */
4640957b409SSimon J. Gerraty memcpy(t[P1x], P1->c, 3 * I31_LEN * sizeof(uint32_t));
4650957b409SSimon J. Gerraty memcpy(t[P2x], P2->c, 3 * I31_LEN * sizeof(uint32_t));
4660957b409SSimon J. Gerraty
4670957b409SSimon J. Gerraty /*
4680957b409SSimon J. Gerraty * Run formulas.
4690957b409SSimon J. Gerraty */
4700957b409SSimon J. Gerraty for (u = 0;; u ++) {
4710957b409SSimon J. Gerraty unsigned op, d, a, b;
4720957b409SSimon J. Gerraty
4730957b409SSimon J. Gerraty op = code[u];
4740957b409SSimon J. Gerraty if (op == 0) {
4750957b409SSimon J. Gerraty break;
4760957b409SSimon J. Gerraty }
4770957b409SSimon J. Gerraty d = (op >> 8) & 0x0F;
4780957b409SSimon J. Gerraty a = (op >> 4) & 0x0F;
4790957b409SSimon J. Gerraty b = op & 0x0F;
4800957b409SSimon J. Gerraty op >>= 12;
4810957b409SSimon J. Gerraty switch (op) {
4820957b409SSimon J. Gerraty uint32_t ctl;
4830957b409SSimon J. Gerraty size_t plen;
4840957b409SSimon J. Gerraty unsigned char tp[(BR_MAX_EC_SIZE + 7) >> 3];
4850957b409SSimon J. Gerraty
4860957b409SSimon J. Gerraty case 0:
4870957b409SSimon J. Gerraty memcpy(t[d], t[a], I31_LEN * sizeof(uint32_t));
4880957b409SSimon J. Gerraty break;
4890957b409SSimon J. Gerraty case 1:
4900957b409SSimon J. Gerraty ctl = br_i31_add(t[d], t[a], 1);
4910957b409SSimon J. Gerraty ctl |= NOT(br_i31_sub(t[d], cc->p, 0));
4920957b409SSimon J. Gerraty br_i31_sub(t[d], cc->p, ctl);
4930957b409SSimon J. Gerraty break;
4940957b409SSimon J. Gerraty case 2:
4950957b409SSimon J. Gerraty br_i31_add(t[d], cc->p, br_i31_sub(t[d], t[a], 1));
4960957b409SSimon J. Gerraty break;
4970957b409SSimon J. Gerraty case 3:
4980957b409SSimon J. Gerraty br_i31_montymul(t[d], t[a], t[b], cc->p, cc->p0i);
4990957b409SSimon J. Gerraty break;
5000957b409SSimon J. Gerraty case 4:
5010957b409SSimon J. Gerraty plen = (cc->p[0] - (cc->p[0] >> 5) + 7) >> 3;
5020957b409SSimon J. Gerraty br_i31_encode(tp, plen, cc->p);
5030957b409SSimon J. Gerraty tp[plen - 1] -= 2;
5040957b409SSimon J. Gerraty br_i31_modpow(t[d], tp, plen,
5050957b409SSimon J. Gerraty cc->p, cc->p0i, t[a], t[b]);
5060957b409SSimon J. Gerraty break;
5070957b409SSimon J. Gerraty default:
5080957b409SSimon J. Gerraty r &= ~br_i31_iszero(t[d]);
5090957b409SSimon J. Gerraty break;
5100957b409SSimon J. Gerraty }
5110957b409SSimon J. Gerraty }
5120957b409SSimon J. Gerraty
5130957b409SSimon J. Gerraty /*
5140957b409SSimon J. Gerraty * Copy back result.
5150957b409SSimon J. Gerraty */
5160957b409SSimon J. Gerraty memcpy(P1->c, t[P1x], 3 * I31_LEN * sizeof(uint32_t));
5170957b409SSimon J. Gerraty return r;
5180957b409SSimon J. Gerraty }
5190957b409SSimon J. Gerraty
5200957b409SSimon J. Gerraty static void
set_one(uint32_t * x,const uint32_t * p)5210957b409SSimon J. Gerraty set_one(uint32_t *x, const uint32_t *p)
5220957b409SSimon J. Gerraty {
5230957b409SSimon J. Gerraty size_t plen;
5240957b409SSimon J. Gerraty
5250957b409SSimon J. Gerraty plen = (p[0] + 63) >> 5;
5260957b409SSimon J. Gerraty memset(x, 0, plen * sizeof *x);
5270957b409SSimon J. Gerraty x[0] = p[0];
5280957b409SSimon J. Gerraty x[1] = 0x00000001;
5290957b409SSimon J. Gerraty }
5300957b409SSimon J. Gerraty
5310957b409SSimon J. Gerraty static void
point_zero(jacobian * P,const curve_params * cc)5320957b409SSimon J. Gerraty point_zero(jacobian *P, const curve_params *cc)
5330957b409SSimon J. Gerraty {
5340957b409SSimon J. Gerraty memset(P, 0, sizeof *P);
5350957b409SSimon J. Gerraty P->c[0][0] = P->c[1][0] = P->c[2][0] = cc->p[0];
5360957b409SSimon J. Gerraty }
5370957b409SSimon J. Gerraty
5380957b409SSimon J. Gerraty static inline void
point_double(jacobian * P,const curve_params * cc)5390957b409SSimon J. Gerraty point_double(jacobian *P, const curve_params *cc)
5400957b409SSimon J. Gerraty {
5410957b409SSimon J. Gerraty run_code(P, P, cc, code_double);
5420957b409SSimon J. Gerraty }
5430957b409SSimon J. Gerraty
5440957b409SSimon J. Gerraty static inline uint32_t
point_add(jacobian * P1,const jacobian * P2,const curve_params * cc)5450957b409SSimon J. Gerraty point_add(jacobian *P1, const jacobian *P2, const curve_params *cc)
5460957b409SSimon J. Gerraty {
5470957b409SSimon J. Gerraty return run_code(P1, P2, cc, code_add);
5480957b409SSimon J. Gerraty }
5490957b409SSimon J. Gerraty
5500957b409SSimon J. Gerraty static void
point_mul(jacobian * P,const unsigned char * x,size_t xlen,const curve_params * cc)5510957b409SSimon J. Gerraty point_mul(jacobian *P, const unsigned char *x, size_t xlen,
5520957b409SSimon J. Gerraty const curve_params *cc)
5530957b409SSimon J. Gerraty {
5540957b409SSimon J. Gerraty /*
5550957b409SSimon J. Gerraty * We do a simple double-and-add ladder with a 2-bit window
5560957b409SSimon J. Gerraty * to make only one add every two doublings. We thus first
5570957b409SSimon J. Gerraty * precompute 2P and 3P in some local buffers.
5580957b409SSimon J. Gerraty *
5590957b409SSimon J. Gerraty * We always perform two doublings and one addition; the
5600957b409SSimon J. Gerraty * addition is with P, 2P and 3P and is done in a temporary
5610957b409SSimon J. Gerraty * array.
5620957b409SSimon J. Gerraty *
5630957b409SSimon J. Gerraty * The addition code cannot handle cases where one of the
5640957b409SSimon J. Gerraty * operands is infinity, which is the case at the start of the
5650957b409SSimon J. Gerraty * ladder. We therefore need to maintain a flag that controls
5660957b409SSimon J. Gerraty * this situation.
5670957b409SSimon J. Gerraty */
5680957b409SSimon J. Gerraty uint32_t qz;
5690957b409SSimon J. Gerraty jacobian P2, P3, Q, T, U;
5700957b409SSimon J. Gerraty
5710957b409SSimon J. Gerraty memcpy(&P2, P, sizeof P2);
5720957b409SSimon J. Gerraty point_double(&P2, cc);
5730957b409SSimon J. Gerraty memcpy(&P3, P, sizeof P3);
5740957b409SSimon J. Gerraty point_add(&P3, &P2, cc);
5750957b409SSimon J. Gerraty
5760957b409SSimon J. Gerraty point_zero(&Q, cc);
5770957b409SSimon J. Gerraty qz = 1;
5780957b409SSimon J. Gerraty while (xlen -- > 0) {
5790957b409SSimon J. Gerraty int k;
5800957b409SSimon J. Gerraty
5810957b409SSimon J. Gerraty for (k = 6; k >= 0; k -= 2) {
5820957b409SSimon J. Gerraty uint32_t bits;
5830957b409SSimon J. Gerraty uint32_t bnz;
5840957b409SSimon J. Gerraty
5850957b409SSimon J. Gerraty point_double(&Q, cc);
5860957b409SSimon J. Gerraty point_double(&Q, cc);
5870957b409SSimon J. Gerraty memcpy(&T, P, sizeof T);
5880957b409SSimon J. Gerraty memcpy(&U, &Q, sizeof U);
5890957b409SSimon J. Gerraty bits = (*x >> k) & (uint32_t)3;
5900957b409SSimon J. Gerraty bnz = NEQ(bits, 0);
5910957b409SSimon J. Gerraty CCOPY(EQ(bits, 2), &T, &P2, sizeof T);
5920957b409SSimon J. Gerraty CCOPY(EQ(bits, 3), &T, &P3, sizeof T);
5930957b409SSimon J. Gerraty point_add(&U, &T, cc);
5940957b409SSimon J. Gerraty CCOPY(bnz & qz, &Q, &T, sizeof Q);
5950957b409SSimon J. Gerraty CCOPY(bnz & ~qz, &Q, &U, sizeof Q);
5960957b409SSimon J. Gerraty qz &= ~bnz;
5970957b409SSimon J. Gerraty }
5980957b409SSimon J. Gerraty x ++;
5990957b409SSimon J. Gerraty }
6000957b409SSimon J. Gerraty memcpy(P, &Q, sizeof Q);
6010957b409SSimon J. Gerraty }
6020957b409SSimon J. Gerraty
6030957b409SSimon J. Gerraty /*
6040957b409SSimon J. Gerraty * Decode point into Jacobian coordinates. This function does not support
6050957b409SSimon J. Gerraty * the point at infinity. If the point is invalid then this returns 0, but
6060957b409SSimon J. Gerraty * the coordinates are still set to properly formed field elements.
6070957b409SSimon J. Gerraty */
6080957b409SSimon J. Gerraty static uint32_t
point_decode(jacobian * P,const void * src,size_t len,const curve_params * cc)6090957b409SSimon J. Gerraty point_decode(jacobian *P, const void *src, size_t len, const curve_params *cc)
6100957b409SSimon J. Gerraty {
6110957b409SSimon J. Gerraty /*
6120957b409SSimon J. Gerraty * Points must use uncompressed format:
6130957b409SSimon J. Gerraty * -- first byte is 0x04;
6140957b409SSimon J. Gerraty * -- coordinates X and Y use unsigned big-endian, with the same
6150957b409SSimon J. Gerraty * length as the field modulus.
6160957b409SSimon J. Gerraty *
6170957b409SSimon J. Gerraty * We don't support hybrid format (uncompressed, but first byte
6180957b409SSimon J. Gerraty * has value 0x06 or 0x07, depending on the least significant bit
6190957b409SSimon J. Gerraty * of Y) because it is rather useless, and explicitly forbidden
6200957b409SSimon J. Gerraty * by PKIX (RFC 5480, section 2.2).
6210957b409SSimon J. Gerraty *
6220957b409SSimon J. Gerraty * We don't support compressed format either, because it is not
6230957b409SSimon J. Gerraty * much used in practice (there are or were patent-related
6240957b409SSimon J. Gerraty * concerns about point compression, which explains the lack of
6250957b409SSimon J. Gerraty * generalised support). Also, point compression support would
6260957b409SSimon J. Gerraty * need a bit more code.
6270957b409SSimon J. Gerraty */
6280957b409SSimon J. Gerraty const unsigned char *buf;
6290957b409SSimon J. Gerraty size_t plen, zlen;
6300957b409SSimon J. Gerraty uint32_t r;
6310957b409SSimon J. Gerraty jacobian Q;
6320957b409SSimon J. Gerraty
6330957b409SSimon J. Gerraty buf = src;
6340957b409SSimon J. Gerraty point_zero(P, cc);
6350957b409SSimon J. Gerraty plen = (cc->p[0] - (cc->p[0] >> 5) + 7) >> 3;
6360957b409SSimon J. Gerraty if (len != 1 + (plen << 1)) {
6370957b409SSimon J. Gerraty return 0;
6380957b409SSimon J. Gerraty }
6390957b409SSimon J. Gerraty r = br_i31_decode_mod(P->c[0], buf + 1, plen, cc->p);
6400957b409SSimon J. Gerraty r &= br_i31_decode_mod(P->c[1], buf + 1 + plen, plen, cc->p);
6410957b409SSimon J. Gerraty
6420957b409SSimon J. Gerraty /*
6430957b409SSimon J. Gerraty * Check first byte.
6440957b409SSimon J. Gerraty */
6450957b409SSimon J. Gerraty r &= EQ(buf[0], 0x04);
6460957b409SSimon J. Gerraty /* obsolete
6470957b409SSimon J. Gerraty r &= EQ(buf[0], 0x04) | (EQ(buf[0] & 0xFE, 0x06)
6480957b409SSimon J. Gerraty & ~(uint32_t)(buf[0] ^ buf[plen << 1]));
6490957b409SSimon J. Gerraty */
6500957b409SSimon J. Gerraty
6510957b409SSimon J. Gerraty /*
6520957b409SSimon J. Gerraty * Convert coordinates and check that the point is valid.
6530957b409SSimon J. Gerraty */
6540957b409SSimon J. Gerraty zlen = ((cc->p[0] + 63) >> 5) * sizeof(uint32_t);
6550957b409SSimon J. Gerraty memcpy(Q.c[0], cc->R2, zlen);
6560957b409SSimon J. Gerraty memcpy(Q.c[1], cc->b, zlen);
6570957b409SSimon J. Gerraty set_one(Q.c[2], cc->p);
6580957b409SSimon J. Gerraty r &= ~run_code(P, &Q, cc, code_check);
6590957b409SSimon J. Gerraty return r;
6600957b409SSimon J. Gerraty }
6610957b409SSimon J. Gerraty
6620957b409SSimon J. Gerraty /*
6630957b409SSimon J. Gerraty * Encode a point. This method assumes that the point is correct and is
6640957b409SSimon J. Gerraty * not the point at infinity. Encoded size is always 1+2*plen, where
6650957b409SSimon J. Gerraty * plen is the field modulus length, in bytes.
6660957b409SSimon J. Gerraty */
6670957b409SSimon J. Gerraty static void
point_encode(void * dst,const jacobian * P,const curve_params * cc)6680957b409SSimon J. Gerraty point_encode(void *dst, const jacobian *P, const curve_params *cc)
6690957b409SSimon J. Gerraty {
6700957b409SSimon J. Gerraty unsigned char *buf;
6710957b409SSimon J. Gerraty uint32_t xbl;
6720957b409SSimon J. Gerraty size_t plen;
6730957b409SSimon J. Gerraty jacobian Q, T;
6740957b409SSimon J. Gerraty
6750957b409SSimon J. Gerraty buf = dst;
6760957b409SSimon J. Gerraty xbl = cc->p[0];
6770957b409SSimon J. Gerraty xbl -= (xbl >> 5);
6780957b409SSimon J. Gerraty plen = (xbl + 7) >> 3;
6790957b409SSimon J. Gerraty buf[0] = 0x04;
6800957b409SSimon J. Gerraty memcpy(&Q, P, sizeof *P);
6810957b409SSimon J. Gerraty set_one(T.c[2], cc->p);
6820957b409SSimon J. Gerraty run_code(&Q, &T, cc, code_affine);
6830957b409SSimon J. Gerraty br_i31_encode(buf + 1, plen, Q.c[0]);
6840957b409SSimon J. Gerraty br_i31_encode(buf + 1 + plen, plen, Q.c[1]);
6850957b409SSimon J. Gerraty }
6860957b409SSimon J. Gerraty
6870957b409SSimon J. Gerraty static const br_ec_curve_def *
id_to_curve_def(int curve)6880957b409SSimon J. Gerraty id_to_curve_def(int curve)
6890957b409SSimon J. Gerraty {
6900957b409SSimon J. Gerraty switch (curve) {
6910957b409SSimon J. Gerraty case BR_EC_secp256r1:
6920957b409SSimon J. Gerraty return &br_secp256r1;
6930957b409SSimon J. Gerraty case BR_EC_secp384r1:
6940957b409SSimon J. Gerraty return &br_secp384r1;
6950957b409SSimon J. Gerraty case BR_EC_secp521r1:
6960957b409SSimon J. Gerraty return &br_secp521r1;
6970957b409SSimon J. Gerraty }
6980957b409SSimon J. Gerraty return NULL;
6990957b409SSimon J. Gerraty }
7000957b409SSimon J. Gerraty
7010957b409SSimon J. Gerraty static const unsigned char *
api_generator(int curve,size_t * len)7020957b409SSimon J. Gerraty api_generator(int curve, size_t *len)
7030957b409SSimon J. Gerraty {
7040957b409SSimon J. Gerraty const br_ec_curve_def *cd;
7050957b409SSimon J. Gerraty
7060957b409SSimon J. Gerraty cd = id_to_curve_def(curve);
7070957b409SSimon J. Gerraty *len = cd->generator_len;
7080957b409SSimon J. Gerraty return cd->generator;
7090957b409SSimon J. Gerraty }
7100957b409SSimon J. Gerraty
7110957b409SSimon J. Gerraty static const unsigned char *
api_order(int curve,size_t * len)7120957b409SSimon J. Gerraty api_order(int curve, size_t *len)
7130957b409SSimon J. Gerraty {
7140957b409SSimon J. Gerraty const br_ec_curve_def *cd;
7150957b409SSimon J. Gerraty
7160957b409SSimon J. Gerraty cd = id_to_curve_def(curve);
7170957b409SSimon J. Gerraty *len = cd->order_len;
7180957b409SSimon J. Gerraty return cd->order;
7190957b409SSimon J. Gerraty }
7200957b409SSimon J. Gerraty
7210957b409SSimon J. Gerraty static size_t
api_xoff(int curve,size_t * len)7220957b409SSimon J. Gerraty api_xoff(int curve, size_t *len)
7230957b409SSimon J. Gerraty {
7240957b409SSimon J. Gerraty api_generator(curve, len);
7250957b409SSimon J. Gerraty *len >>= 1;
7260957b409SSimon J. Gerraty return 1;
7270957b409SSimon J. Gerraty }
7280957b409SSimon J. Gerraty
7290957b409SSimon J. Gerraty static uint32_t
api_mul(unsigned char * G,size_t Glen,const unsigned char * x,size_t xlen,int curve)7300957b409SSimon J. Gerraty api_mul(unsigned char *G, size_t Glen,
7310957b409SSimon J. Gerraty const unsigned char *x, size_t xlen, int curve)
7320957b409SSimon J. Gerraty {
7330957b409SSimon J. Gerraty uint32_t r;
7340957b409SSimon J. Gerraty const curve_params *cc;
7350957b409SSimon J. Gerraty jacobian P;
7360957b409SSimon J. Gerraty
7370957b409SSimon J. Gerraty cc = id_to_curve(curve);
738*cc9e6590SSimon J. Gerraty if (Glen != cc->point_len) {
739*cc9e6590SSimon J. Gerraty return 0;
740*cc9e6590SSimon J. Gerraty }
7410957b409SSimon J. Gerraty r = point_decode(&P, G, Glen, cc);
7420957b409SSimon J. Gerraty point_mul(&P, x, xlen, cc);
7430957b409SSimon J. Gerraty point_encode(G, &P, cc);
7440957b409SSimon J. Gerraty return r;
7450957b409SSimon J. Gerraty }
7460957b409SSimon J. Gerraty
7470957b409SSimon J. Gerraty static size_t
api_mulgen(unsigned char * R,const unsigned char * x,size_t xlen,int curve)7480957b409SSimon J. Gerraty api_mulgen(unsigned char *R,
7490957b409SSimon J. Gerraty const unsigned char *x, size_t xlen, int curve)
7500957b409SSimon J. Gerraty {
7510957b409SSimon J. Gerraty const unsigned char *G;
7520957b409SSimon J. Gerraty size_t Glen;
7530957b409SSimon J. Gerraty
7540957b409SSimon J. Gerraty G = api_generator(curve, &Glen);
7550957b409SSimon J. Gerraty memcpy(R, G, Glen);
7560957b409SSimon J. Gerraty api_mul(R, Glen, x, xlen, curve);
7570957b409SSimon J. Gerraty return Glen;
7580957b409SSimon J. Gerraty }
7590957b409SSimon J. Gerraty
7600957b409SSimon J. Gerraty static uint32_t
api_muladd(unsigned char * A,const unsigned char * B,size_t len,const unsigned char * x,size_t xlen,const unsigned char * y,size_t ylen,int curve)7610957b409SSimon J. Gerraty api_muladd(unsigned char *A, const unsigned char *B, size_t len,
7620957b409SSimon J. Gerraty const unsigned char *x, size_t xlen,
7630957b409SSimon J. Gerraty const unsigned char *y, size_t ylen, int curve)
7640957b409SSimon J. Gerraty {
7650957b409SSimon J. Gerraty uint32_t r, t, z;
7660957b409SSimon J. Gerraty const curve_params *cc;
7670957b409SSimon J. Gerraty jacobian P, Q;
7680957b409SSimon J. Gerraty
7690957b409SSimon J. Gerraty /*
7700957b409SSimon J. Gerraty * TODO: see about merging the two ladders. Right now, we do
7710957b409SSimon J. Gerraty * two independent point multiplications, which is a bit
7720957b409SSimon J. Gerraty * wasteful of CPU resources (but yields short code).
7730957b409SSimon J. Gerraty */
7740957b409SSimon J. Gerraty
7750957b409SSimon J. Gerraty cc = id_to_curve(curve);
776*cc9e6590SSimon J. Gerraty if (len != cc->point_len) {
777*cc9e6590SSimon J. Gerraty return 0;
778*cc9e6590SSimon J. Gerraty }
7790957b409SSimon J. Gerraty r = point_decode(&P, A, len, cc);
7800957b409SSimon J. Gerraty if (B == NULL) {
7810957b409SSimon J. Gerraty size_t Glen;
7820957b409SSimon J. Gerraty
7830957b409SSimon J. Gerraty B = api_generator(curve, &Glen);
7840957b409SSimon J. Gerraty }
7850957b409SSimon J. Gerraty r &= point_decode(&Q, B, len, cc);
7860957b409SSimon J. Gerraty point_mul(&P, x, xlen, cc);
7870957b409SSimon J. Gerraty point_mul(&Q, y, ylen, cc);
7880957b409SSimon J. Gerraty
7890957b409SSimon J. Gerraty /*
7900957b409SSimon J. Gerraty * We want to compute P+Q. Since the base points A and B are distinct
7910957b409SSimon J. Gerraty * from infinity, and the multipliers are non-zero and lower than the
7920957b409SSimon J. Gerraty * curve order, then we know that P and Q are non-infinity. This
7930957b409SSimon J. Gerraty * leaves two special situations to test for:
7940957b409SSimon J. Gerraty * -- If P = Q then we must use point_double().
7950957b409SSimon J. Gerraty * -- If P+Q = 0 then we must report an error.
7960957b409SSimon J. Gerraty */
7970957b409SSimon J. Gerraty t = point_add(&P, &Q, cc);
7980957b409SSimon J. Gerraty point_double(&Q, cc);
7990957b409SSimon J. Gerraty z = br_i31_iszero(P.c[2]);
8000957b409SSimon J. Gerraty
8010957b409SSimon J. Gerraty /*
8020957b409SSimon J. Gerraty * If z is 1 then either P+Q = 0 (t = 1) or P = Q (t = 0). So we
8030957b409SSimon J. Gerraty * have the following:
8040957b409SSimon J. Gerraty *
8050957b409SSimon J. Gerraty * z = 0, t = 0 return P (normal addition)
8060957b409SSimon J. Gerraty * z = 0, t = 1 return P (normal addition)
8070957b409SSimon J. Gerraty * z = 1, t = 0 return Q (a 'double' case)
8080957b409SSimon J. Gerraty * z = 1, t = 1 report an error (P+Q = 0)
8090957b409SSimon J. Gerraty */
8100957b409SSimon J. Gerraty CCOPY(z & ~t, &P, &Q, sizeof Q);
8110957b409SSimon J. Gerraty point_encode(A, &P, cc);
8120957b409SSimon J. Gerraty r &= ~(z & t);
8130957b409SSimon J. Gerraty
8140957b409SSimon J. Gerraty return r;
8150957b409SSimon J. Gerraty }
8160957b409SSimon J. Gerraty
8170957b409SSimon J. Gerraty /* see bearssl_ec.h */
8180957b409SSimon J. Gerraty const br_ec_impl br_ec_prime_i31 = {
8190957b409SSimon J. Gerraty (uint32_t)0x03800000,
8200957b409SSimon J. Gerraty &api_generator,
8210957b409SSimon J. Gerraty &api_order,
8220957b409SSimon J. Gerraty &api_xoff,
8230957b409SSimon J. Gerraty &api_mul,
8240957b409SSimon J. Gerraty &api_mulgen,
8250957b409SSimon J. Gerraty &api_muladd
8260957b409SSimon J. Gerraty };
827