10957b409SSimon J. Gerraty /*
20957b409SSimon J. Gerraty * Copyright (c) 2017 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:
290957b409SSimon J. Gerraty * - field modulus p
300957b409SSimon J. Gerraty * - R^2 mod p (R = 2^(15k) for the smallest k such that R >= p)
310957b409SSimon J. Gerraty * - b*R mod p (b is the second curve equation parameter)
320957b409SSimon J. Gerraty */
330957b409SSimon J. Gerraty
340957b409SSimon J. Gerraty static const uint16_t P256_P[] = {
350957b409SSimon J. Gerraty 0x0111,
360957b409SSimon J. Gerraty 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x003F, 0x0000,
370957b409SSimon J. Gerraty 0x0000, 0x0000, 0x0000, 0x0000, 0x1000, 0x0000, 0x4000, 0x7FFF,
380957b409SSimon J. Gerraty 0x7FFF, 0x0001
390957b409SSimon J. Gerraty };
400957b409SSimon J. Gerraty
410957b409SSimon J. Gerraty static const uint16_t P256_R2[] = {
420957b409SSimon J. Gerraty 0x0111,
430957b409SSimon J. Gerraty 0x0000, 0x6000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7FFC, 0x7FFF,
440957b409SSimon J. Gerraty 0x7FBF, 0x7FFF, 0x7FBF, 0x7FFF, 0x7FFF, 0x7FFF, 0x77FF, 0x7FFF,
450957b409SSimon J. Gerraty 0x4FFF, 0x0000
460957b409SSimon J. Gerraty };
470957b409SSimon J. Gerraty
480957b409SSimon J. Gerraty static const uint16_t P256_B[] = {
490957b409SSimon J. Gerraty 0x0111,
500957b409SSimon J. Gerraty 0x770C, 0x5EEF, 0x29C4, 0x3EC4, 0x6273, 0x0486, 0x4543, 0x3993,
510957b409SSimon J. Gerraty 0x3C01, 0x6B56, 0x212E, 0x57EE, 0x4882, 0x204B, 0x7483, 0x3C16,
520957b409SSimon J. Gerraty 0x0187, 0x0000
530957b409SSimon J. Gerraty };
540957b409SSimon J. Gerraty
550957b409SSimon J. Gerraty static const uint16_t P384_P[] = {
560957b409SSimon J. Gerraty 0x0199,
570957b409SSimon J. Gerraty 0x7FFF, 0x7FFF, 0x0003, 0x0000, 0x0000, 0x0000, 0x7FC0, 0x7FFF,
580957b409SSimon J. Gerraty 0x7EFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
590957b409SSimon J. Gerraty 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
600957b409SSimon J. Gerraty 0x7FFF, 0x01FF
610957b409SSimon J. Gerraty };
620957b409SSimon J. Gerraty
630957b409SSimon J. Gerraty static const uint16_t P384_R2[] = {
640957b409SSimon J. Gerraty 0x0199,
650957b409SSimon J. Gerraty 0x1000, 0x0000, 0x0000, 0x7FFF, 0x7FFF, 0x0001, 0x0000, 0x0010,
660957b409SSimon J. Gerraty 0x0000, 0x0000, 0x0000, 0x7F00, 0x7FFF, 0x01FF, 0x0000, 0x1000,
670957b409SSimon J. Gerraty 0x0000, 0x2000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
680957b409SSimon J. Gerraty 0x0000, 0x0000
690957b409SSimon J. Gerraty };
700957b409SSimon J. Gerraty
710957b409SSimon J. Gerraty static const uint16_t P384_B[] = {
720957b409SSimon J. Gerraty 0x0199,
730957b409SSimon J. Gerraty 0x7333, 0x2096, 0x70D1, 0x2310, 0x3020, 0x6197, 0x1464, 0x35BB,
740957b409SSimon J. Gerraty 0x70CA, 0x0117, 0x1920, 0x4136, 0x5FC8, 0x5713, 0x4938, 0x7DD2,
750957b409SSimon J. Gerraty 0x4DD2, 0x4A71, 0x0220, 0x683E, 0x2C87, 0x4DB1, 0x7BFF, 0x6C09,
760957b409SSimon J. Gerraty 0x0452, 0x0084
770957b409SSimon J. Gerraty };
780957b409SSimon J. Gerraty
790957b409SSimon J. Gerraty static const uint16_t P521_P[] = {
800957b409SSimon J. Gerraty 0x022B,
810957b409SSimon J. Gerraty 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
820957b409SSimon J. Gerraty 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
830957b409SSimon J. Gerraty 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
840957b409SSimon J. Gerraty 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
850957b409SSimon J. Gerraty 0x7FFF, 0x7FFF, 0x07FF
860957b409SSimon J. Gerraty };
870957b409SSimon J. Gerraty
880957b409SSimon J. Gerraty static const uint16_t P521_R2[] = {
890957b409SSimon J. Gerraty 0x022B,
900957b409SSimon J. Gerraty 0x0100, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
910957b409SSimon J. Gerraty 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
920957b409SSimon J. Gerraty 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
930957b409SSimon J. Gerraty 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
940957b409SSimon J. Gerraty 0x0000, 0x0000, 0x0000
950957b409SSimon J. Gerraty };
960957b409SSimon J. Gerraty
970957b409SSimon J. Gerraty static const uint16_t P521_B[] = {
980957b409SSimon J. Gerraty 0x022B,
990957b409SSimon J. Gerraty 0x7002, 0x6A07, 0x751A, 0x228F, 0x71EF, 0x5869, 0x20F4, 0x1EFC,
1000957b409SSimon J. Gerraty 0x7357, 0x37E0, 0x4EEC, 0x605E, 0x1652, 0x26F6, 0x31FA, 0x4A8F,
1010957b409SSimon J. Gerraty 0x6193, 0x3C2A, 0x3C42, 0x48C7, 0x3489, 0x6771, 0x4C57, 0x5CCD,
1020957b409SSimon J. Gerraty 0x2725, 0x545B, 0x503B, 0x5B42, 0x21A0, 0x2534, 0x687E, 0x70E4,
1030957b409SSimon J. Gerraty 0x1618, 0x27D7, 0x0465
1040957b409SSimon J. Gerraty };
1050957b409SSimon J. Gerraty
1060957b409SSimon J. Gerraty typedef struct {
1070957b409SSimon J. Gerraty const uint16_t *p;
1080957b409SSimon J. Gerraty const uint16_t *b;
1090957b409SSimon J. Gerraty const uint16_t *R2;
1100957b409SSimon J. Gerraty uint16_t p0i;
1110957b409SSimon J. Gerraty size_t point_len;
1120957b409SSimon J. Gerraty } curve_params;
1130957b409SSimon J. Gerraty
1140957b409SSimon J. Gerraty static inline const curve_params *
id_to_curve(int curve)1150957b409SSimon J. Gerraty id_to_curve(int curve)
1160957b409SSimon J. Gerraty {
1170957b409SSimon J. Gerraty static const curve_params pp[] = {
1180957b409SSimon J. Gerraty { P256_P, P256_B, P256_R2, 0x0001, 65 },
1190957b409SSimon J. Gerraty { P384_P, P384_B, P384_R2, 0x0001, 97 },
1200957b409SSimon J. Gerraty { P521_P, P521_B, P521_R2, 0x0001, 133 }
1210957b409SSimon J. Gerraty };
1220957b409SSimon J. Gerraty
1230957b409SSimon J. Gerraty return &pp[curve - BR_EC_secp256r1];
1240957b409SSimon J. Gerraty }
1250957b409SSimon J. Gerraty
1260957b409SSimon J. Gerraty #define I15_LEN ((BR_MAX_EC_SIZE + 29) / 15)
1270957b409SSimon J. Gerraty
1280957b409SSimon J. Gerraty /*
1290957b409SSimon J. Gerraty * Type for a point in Jacobian coordinates:
1300957b409SSimon J. Gerraty * -- three values, x, y and z, in Montgomery representation
1310957b409SSimon J. Gerraty * -- affine coordinates are X = x / z^2 and Y = y / z^3
1320957b409SSimon J. Gerraty * -- for the point at infinity, z = 0
1330957b409SSimon J. Gerraty */
1340957b409SSimon J. Gerraty typedef struct {
1350957b409SSimon J. Gerraty uint16_t c[3][I15_LEN];
1360957b409SSimon J. Gerraty } jacobian;
1370957b409SSimon J. Gerraty
1380957b409SSimon J. Gerraty /*
1390957b409SSimon J. Gerraty * We use a custom interpreter that uses a dozen registers, and
1400957b409SSimon J. Gerraty * only six operations:
1410957b409SSimon J. Gerraty * MSET(d, a) copy a into d
1420957b409SSimon J. Gerraty * MADD(d, a) d = d+a (modular)
1430957b409SSimon J. Gerraty * MSUB(d, a) d = d-a (modular)
1440957b409SSimon J. Gerraty * MMUL(d, a, b) d = a*b (Montgomery multiplication)
1450957b409SSimon J. Gerraty * MINV(d, a, b) invert d modulo p; a and b are used as scratch registers
1460957b409SSimon J. Gerraty * MTZ(d) clear return value if d = 0
1470957b409SSimon J. Gerraty * Destination of MMUL (d) must be distinct from operands (a and b).
1480957b409SSimon J. Gerraty * There is no such constraint for MSUB and MADD.
1490957b409SSimon J. Gerraty *
1500957b409SSimon J. Gerraty * Registers include the operand coordinates, and temporaries.
1510957b409SSimon J. Gerraty */
1520957b409SSimon J. Gerraty #define MSET(d, a) (0x0000 + ((d) << 8) + ((a) << 4))
1530957b409SSimon J. Gerraty #define MADD(d, a) (0x1000 + ((d) << 8) + ((a) << 4))
1540957b409SSimon J. Gerraty #define MSUB(d, a) (0x2000 + ((d) << 8) + ((a) << 4))
1550957b409SSimon J. Gerraty #define MMUL(d, a, b) (0x3000 + ((d) << 8) + ((a) << 4) + (b))
1560957b409SSimon J. Gerraty #define MINV(d, a, b) (0x4000 + ((d) << 8) + ((a) << 4) + (b))
1570957b409SSimon J. Gerraty #define MTZ(d) (0x5000 + ((d) << 8))
1580957b409SSimon J. Gerraty #define ENDCODE 0
1590957b409SSimon J. Gerraty
1600957b409SSimon J. Gerraty /*
1610957b409SSimon J. Gerraty * Registers for the input operands.
1620957b409SSimon J. Gerraty */
1630957b409SSimon J. Gerraty #define P1x 0
1640957b409SSimon J. Gerraty #define P1y 1
1650957b409SSimon J. Gerraty #define P1z 2
1660957b409SSimon J. Gerraty #define P2x 3
1670957b409SSimon J. Gerraty #define P2y 4
1680957b409SSimon J. Gerraty #define P2z 5
1690957b409SSimon J. Gerraty
1700957b409SSimon J. Gerraty /*
1710957b409SSimon J. Gerraty * Alternate names for the first input operand.
1720957b409SSimon J. Gerraty */
1730957b409SSimon J. Gerraty #define Px 0
1740957b409SSimon J. Gerraty #define Py 1
1750957b409SSimon J. Gerraty #define Pz 2
1760957b409SSimon J. Gerraty
1770957b409SSimon J. Gerraty /*
1780957b409SSimon J. Gerraty * Temporaries.
1790957b409SSimon J. Gerraty */
1800957b409SSimon J. Gerraty #define t1 6
1810957b409SSimon J. Gerraty #define t2 7
1820957b409SSimon J. Gerraty #define t3 8
1830957b409SSimon J. Gerraty #define t4 9
1840957b409SSimon J. Gerraty #define t5 10
1850957b409SSimon J. Gerraty #define t6 11
1860957b409SSimon J. Gerraty #define t7 12
1870957b409SSimon J. Gerraty
1880957b409SSimon J. Gerraty /*
1890957b409SSimon J. Gerraty * Extra scratch registers available when there is no second operand (e.g.
1900957b409SSimon J. Gerraty * for "double" and "affine").
1910957b409SSimon J. Gerraty */
1920957b409SSimon J. Gerraty #define t8 3
1930957b409SSimon J. Gerraty #define t9 4
1940957b409SSimon J. Gerraty #define t10 5
1950957b409SSimon J. Gerraty
1960957b409SSimon J. Gerraty /*
1970957b409SSimon J. Gerraty * Doubling formulas are:
1980957b409SSimon J. Gerraty *
1990957b409SSimon J. Gerraty * s = 4*x*y^2
2000957b409SSimon J. Gerraty * m = 3*(x + z^2)*(x - z^2)
2010957b409SSimon J. Gerraty * x' = m^2 - 2*s
2020957b409SSimon J. Gerraty * y' = m*(s - x') - 8*y^4
2030957b409SSimon J. Gerraty * z' = 2*y*z
2040957b409SSimon J. Gerraty *
2050957b409SSimon J. Gerraty * If y = 0 (P has order 2) then this yields infinity (z' = 0), as it
2060957b409SSimon J. Gerraty * should. This case should not happen anyway, because our curves have
2070957b409SSimon J. Gerraty * prime order, and thus do not contain any point of order 2.
2080957b409SSimon J. Gerraty *
2090957b409SSimon J. Gerraty * If P is infinity (z = 0), then again the formulas yield infinity,
2100957b409SSimon J. Gerraty * which is correct. Thus, this code works for all points.
2110957b409SSimon J. Gerraty *
2120957b409SSimon J. Gerraty * Cost: 8 multiplications
2130957b409SSimon J. Gerraty */
2140957b409SSimon J. Gerraty static const uint16_t code_double[] = {
2150957b409SSimon J. Gerraty /*
2160957b409SSimon J. Gerraty * Compute z^2 (in t1).
2170957b409SSimon J. Gerraty */
2180957b409SSimon J. Gerraty MMUL(t1, Pz, Pz),
2190957b409SSimon J. Gerraty
2200957b409SSimon J. Gerraty /*
2210957b409SSimon J. Gerraty * Compute x-z^2 (in t2) and then x+z^2 (in t1).
2220957b409SSimon J. Gerraty */
2230957b409SSimon J. Gerraty MSET(t2, Px),
2240957b409SSimon J. Gerraty MSUB(t2, t1),
2250957b409SSimon J. Gerraty MADD(t1, Px),
2260957b409SSimon J. Gerraty
2270957b409SSimon J. Gerraty /*
2280957b409SSimon J. Gerraty * Compute m = 3*(x+z^2)*(x-z^2) (in t1).
2290957b409SSimon J. Gerraty */
2300957b409SSimon J. Gerraty MMUL(t3, t1, t2),
2310957b409SSimon J. Gerraty MSET(t1, t3),
2320957b409SSimon J. Gerraty MADD(t1, t3),
2330957b409SSimon J. Gerraty MADD(t1, t3),
2340957b409SSimon J. Gerraty
2350957b409SSimon J. Gerraty /*
2360957b409SSimon J. Gerraty * Compute s = 4*x*y^2 (in t2) and 2*y^2 (in t3).
2370957b409SSimon J. Gerraty */
2380957b409SSimon J. Gerraty MMUL(t3, Py, Py),
2390957b409SSimon J. Gerraty MADD(t3, t3),
2400957b409SSimon J. Gerraty MMUL(t2, Px, t3),
2410957b409SSimon J. Gerraty MADD(t2, t2),
2420957b409SSimon J. Gerraty
2430957b409SSimon J. Gerraty /*
2440957b409SSimon J. Gerraty * Compute x' = m^2 - 2*s.
2450957b409SSimon J. Gerraty */
2460957b409SSimon J. Gerraty MMUL(Px, t1, t1),
2470957b409SSimon J. Gerraty MSUB(Px, t2),
2480957b409SSimon J. Gerraty MSUB(Px, t2),
2490957b409SSimon J. Gerraty
2500957b409SSimon J. Gerraty /*
2510957b409SSimon J. Gerraty * Compute z' = 2*y*z.
2520957b409SSimon J. Gerraty */
2530957b409SSimon J. Gerraty MMUL(t4, Py, Pz),
2540957b409SSimon J. Gerraty MSET(Pz, t4),
2550957b409SSimon J. Gerraty MADD(Pz, t4),
2560957b409SSimon J. Gerraty
2570957b409SSimon J. Gerraty /*
2580957b409SSimon J. Gerraty * Compute y' = m*(s - x') - 8*y^4. Note that we already have
2590957b409SSimon J. Gerraty * 2*y^2 in t3.
2600957b409SSimon J. Gerraty */
2610957b409SSimon J. Gerraty MSUB(t2, Px),
2620957b409SSimon J. Gerraty MMUL(Py, t1, t2),
2630957b409SSimon J. Gerraty MMUL(t4, t3, t3),
2640957b409SSimon J. Gerraty MSUB(Py, t4),
2650957b409SSimon J. Gerraty MSUB(Py, t4),
2660957b409SSimon J. Gerraty
2670957b409SSimon J. Gerraty ENDCODE
2680957b409SSimon J. Gerraty };
2690957b409SSimon J. Gerraty
2700957b409SSimon J. Gerraty /*
2710957b409SSimon J. Gerraty * Addtions formulas are:
2720957b409SSimon J. Gerraty *
2730957b409SSimon J. Gerraty * u1 = x1 * z2^2
2740957b409SSimon J. Gerraty * u2 = x2 * z1^2
2750957b409SSimon J. Gerraty * s1 = y1 * z2^3
2760957b409SSimon J. Gerraty * s2 = y2 * z1^3
2770957b409SSimon J. Gerraty * h = u2 - u1
2780957b409SSimon J. Gerraty * r = s2 - s1
2790957b409SSimon J. Gerraty * x3 = r^2 - h^3 - 2 * u1 * h^2
2800957b409SSimon J. Gerraty * y3 = r * (u1 * h^2 - x3) - s1 * h^3
2810957b409SSimon J. Gerraty * z3 = h * z1 * z2
2820957b409SSimon J. Gerraty *
2830957b409SSimon J. Gerraty * If both P1 and P2 are infinity, then z1 == 0 and z2 == 0, implying that
2840957b409SSimon J. Gerraty * z3 == 0, so the result is correct.
2850957b409SSimon J. Gerraty * If either of P1 or P2 is infinity, but not both, then z3 == 0, which is
2860957b409SSimon J. Gerraty * not correct.
2870957b409SSimon J. Gerraty * h == 0 only if u1 == u2; this happens in two cases:
2880957b409SSimon J. Gerraty * -- if s1 == s2 then P1 and/or P2 is infinity, or P1 == P2
2890957b409SSimon J. Gerraty * -- if s1 != s2 then P1 + P2 == infinity (but neither P1 or P2 is infinity)
2900957b409SSimon J. Gerraty *
2910957b409SSimon J. Gerraty * Thus, the following situations are not handled correctly:
2920957b409SSimon J. Gerraty * -- P1 = 0 and P2 != 0
2930957b409SSimon J. Gerraty * -- P1 != 0 and P2 = 0
2940957b409SSimon J. Gerraty * -- P1 = P2
2950957b409SSimon J. Gerraty * All other cases are properly computed. However, even in "incorrect"
2960957b409SSimon J. Gerraty * situations, the three coordinates still are properly formed field
2970957b409SSimon J. Gerraty * elements.
2980957b409SSimon J. Gerraty *
2990957b409SSimon J. Gerraty * The returned flag is cleared if r == 0. This happens in the following
3000957b409SSimon J. Gerraty * cases:
3010957b409SSimon J. Gerraty * -- Both points are on the same horizontal line (same Y coordinate).
3020957b409SSimon J. Gerraty * -- Both points are infinity.
3030957b409SSimon J. Gerraty * -- One point is infinity and the other is on line Y = 0.
3040957b409SSimon J. Gerraty * The third case cannot happen with our curves (there is no valid point
3050957b409SSimon J. Gerraty * on line Y = 0 since that would be a point of order 2). If the two
3060957b409SSimon J. Gerraty * source points are non-infinity, then remains only the case where the
3070957b409SSimon J. Gerraty * two points are on the same horizontal line.
3080957b409SSimon J. Gerraty *
3090957b409SSimon J. Gerraty * This allows us to detect the "P1 == P2" case, assuming that P1 != 0 and
3100957b409SSimon J. Gerraty * P2 != 0:
3110957b409SSimon J. Gerraty * -- If the returned value is not the point at infinity, then it was properly
3120957b409SSimon J. Gerraty * computed.
3130957b409SSimon J. Gerraty * -- Otherwise, if the returned flag is 1, then P1+P2 = 0, and the result
3140957b409SSimon J. Gerraty * is indeed the point at infinity.
3150957b409SSimon J. Gerraty * -- Otherwise (result is infinity, flag is 0), then P1 = P2 and we should
3160957b409SSimon J. Gerraty * use the 'double' code.
3170957b409SSimon J. Gerraty *
3180957b409SSimon J. Gerraty * Cost: 16 multiplications
3190957b409SSimon J. Gerraty */
3200957b409SSimon J. Gerraty static const uint16_t code_add[] = {
3210957b409SSimon J. Gerraty /*
3220957b409SSimon J. Gerraty * Compute u1 = x1*z2^2 (in t1) and s1 = y1*z2^3 (in t3).
3230957b409SSimon J. Gerraty */
3240957b409SSimon J. Gerraty MMUL(t3, P2z, P2z),
3250957b409SSimon J. Gerraty MMUL(t1, P1x, t3),
3260957b409SSimon J. Gerraty MMUL(t4, P2z, t3),
3270957b409SSimon J. Gerraty MMUL(t3, P1y, t4),
3280957b409SSimon J. Gerraty
3290957b409SSimon J. Gerraty /*
3300957b409SSimon J. Gerraty * Compute u2 = x2*z1^2 (in t2) and s2 = y2*z1^3 (in t4).
3310957b409SSimon J. Gerraty */
3320957b409SSimon J. Gerraty MMUL(t4, P1z, P1z),
3330957b409SSimon J. Gerraty MMUL(t2, P2x, t4),
3340957b409SSimon J. Gerraty MMUL(t5, P1z, t4),
3350957b409SSimon J. Gerraty MMUL(t4, P2y, t5),
3360957b409SSimon J. Gerraty
3370957b409SSimon J. Gerraty /*
3380957b409SSimon J. Gerraty * Compute h = u2 - u1 (in t2) and r = s2 - s1 (in t4).
3390957b409SSimon J. Gerraty */
3400957b409SSimon J. Gerraty MSUB(t2, t1),
3410957b409SSimon J. Gerraty MSUB(t4, t3),
3420957b409SSimon J. Gerraty
3430957b409SSimon J. Gerraty /*
3440957b409SSimon J. Gerraty * Report cases where r = 0 through the returned flag.
3450957b409SSimon J. Gerraty */
3460957b409SSimon J. Gerraty MTZ(t4),
3470957b409SSimon J. Gerraty
3480957b409SSimon J. Gerraty /*
3490957b409SSimon J. Gerraty * Compute u1*h^2 (in t6) and h^3 (in t5).
3500957b409SSimon J. Gerraty */
3510957b409SSimon J. Gerraty MMUL(t7, t2, t2),
3520957b409SSimon J. Gerraty MMUL(t6, t1, t7),
3530957b409SSimon J. Gerraty MMUL(t5, t7, t2),
3540957b409SSimon J. Gerraty
3550957b409SSimon J. Gerraty /*
3560957b409SSimon J. Gerraty * Compute x3 = r^2 - h^3 - 2*u1*h^2.
3570957b409SSimon J. Gerraty * t1 and t7 can be used as scratch registers.
3580957b409SSimon J. Gerraty */
3590957b409SSimon J. Gerraty MMUL(P1x, t4, t4),
3600957b409SSimon J. Gerraty MSUB(P1x, t5),
3610957b409SSimon J. Gerraty MSUB(P1x, t6),
3620957b409SSimon J. Gerraty MSUB(P1x, t6),
3630957b409SSimon J. Gerraty
3640957b409SSimon J. Gerraty /*
3650957b409SSimon J. Gerraty * Compute y3 = r*(u1*h^2 - x3) - s1*h^3.
3660957b409SSimon J. Gerraty */
3670957b409SSimon J. Gerraty MSUB(t6, P1x),
3680957b409SSimon J. Gerraty MMUL(P1y, t4, t6),
3690957b409SSimon J. Gerraty MMUL(t1, t5, t3),
3700957b409SSimon J. Gerraty MSUB(P1y, t1),
3710957b409SSimon J. Gerraty
3720957b409SSimon J. Gerraty /*
3730957b409SSimon J. Gerraty * Compute z3 = h*z1*z2.
3740957b409SSimon J. Gerraty */
3750957b409SSimon J. Gerraty MMUL(t1, P1z, P2z),
3760957b409SSimon J. Gerraty MMUL(P1z, t1, t2),
3770957b409SSimon J. Gerraty
3780957b409SSimon J. Gerraty ENDCODE
3790957b409SSimon J. Gerraty };
3800957b409SSimon J. Gerraty
3810957b409SSimon J. Gerraty /*
3820957b409SSimon J. Gerraty * Check that the point is on the curve. This code snippet assumes the
3830957b409SSimon J. Gerraty * following conventions:
3840957b409SSimon J. Gerraty * -- Coordinates x and y have been freshly decoded in P1 (but not
3850957b409SSimon J. Gerraty * converted to Montgomery coordinates yet).
3860957b409SSimon J. Gerraty * -- P2x, P2y and P2z are set to, respectively, R^2, b*R and 1.
3870957b409SSimon J. Gerraty */
3880957b409SSimon J. Gerraty static const uint16_t code_check[] = {
3890957b409SSimon J. Gerraty
3900957b409SSimon J. Gerraty /* Convert x and y to Montgomery representation. */
3910957b409SSimon J. Gerraty MMUL(t1, P1x, P2x),
3920957b409SSimon J. Gerraty MMUL(t2, P1y, P2x),
3930957b409SSimon J. Gerraty MSET(P1x, t1),
3940957b409SSimon J. Gerraty MSET(P1y, t2),
3950957b409SSimon J. Gerraty
3960957b409SSimon J. Gerraty /* Compute x^3 in t1. */
3970957b409SSimon J. Gerraty MMUL(t2, P1x, P1x),
3980957b409SSimon J. Gerraty MMUL(t1, P1x, t2),
3990957b409SSimon J. Gerraty
4000957b409SSimon J. Gerraty /* Subtract 3*x from t1. */
4010957b409SSimon J. Gerraty MSUB(t1, P1x),
4020957b409SSimon J. Gerraty MSUB(t1, P1x),
4030957b409SSimon J. Gerraty MSUB(t1, P1x),
4040957b409SSimon J. Gerraty
4050957b409SSimon J. Gerraty /* Add b. */
4060957b409SSimon J. Gerraty MADD(t1, P2y),
4070957b409SSimon J. Gerraty
4080957b409SSimon J. Gerraty /* Compute y^2 in t2. */
4090957b409SSimon J. Gerraty MMUL(t2, P1y, P1y),
4100957b409SSimon J. Gerraty
4110957b409SSimon J. Gerraty /* Compare y^2 with x^3 - 3*x + b; they must match. */
4120957b409SSimon J. Gerraty MSUB(t1, t2),
4130957b409SSimon J. Gerraty MTZ(t1),
4140957b409SSimon J. Gerraty
4150957b409SSimon J. Gerraty /* Set z to 1 (in Montgomery representation). */
4160957b409SSimon J. Gerraty MMUL(P1z, P2x, P2z),
4170957b409SSimon J. Gerraty
4180957b409SSimon J. Gerraty ENDCODE
4190957b409SSimon J. Gerraty };
4200957b409SSimon J. Gerraty
4210957b409SSimon J. Gerraty /*
4220957b409SSimon J. Gerraty * Conversion back to affine coordinates. This code snippet assumes that
4230957b409SSimon J. Gerraty * the z coordinate of P2 is set to 1 (not in Montgomery representation).
4240957b409SSimon J. Gerraty */
4250957b409SSimon J. Gerraty static const uint16_t code_affine[] = {
4260957b409SSimon J. Gerraty
4270957b409SSimon J. Gerraty /* Save z*R in t1. */
4280957b409SSimon J. Gerraty MSET(t1, P1z),
4290957b409SSimon J. Gerraty
4300957b409SSimon J. Gerraty /* Compute z^3 in t2. */
4310957b409SSimon J. Gerraty MMUL(t2, P1z, P1z),
4320957b409SSimon J. Gerraty MMUL(t3, P1z, t2),
4330957b409SSimon J. Gerraty MMUL(t2, t3, P2z),
4340957b409SSimon J. Gerraty
4350957b409SSimon J. Gerraty /* Invert to (1/z^3) in t2. */
4360957b409SSimon J. Gerraty MINV(t2, t3, t4),
4370957b409SSimon J. Gerraty
4380957b409SSimon J. Gerraty /* Compute y. */
4390957b409SSimon J. Gerraty MSET(t3, P1y),
4400957b409SSimon J. Gerraty MMUL(P1y, t2, t3),
4410957b409SSimon J. Gerraty
4420957b409SSimon J. Gerraty /* Compute (1/z^2) in t3. */
4430957b409SSimon J. Gerraty MMUL(t3, t2, t1),
4440957b409SSimon J. Gerraty
4450957b409SSimon J. Gerraty /* Compute x. */
4460957b409SSimon J. Gerraty MSET(t2, P1x),
4470957b409SSimon J. Gerraty MMUL(P1x, t2, t3),
4480957b409SSimon J. Gerraty
4490957b409SSimon J. Gerraty ENDCODE
4500957b409SSimon J. Gerraty };
4510957b409SSimon J. Gerraty
4520957b409SSimon J. Gerraty static uint32_t
run_code(jacobian * P1,const jacobian * P2,const curve_params * cc,const uint16_t * code)4530957b409SSimon J. Gerraty run_code(jacobian *P1, const jacobian *P2,
4540957b409SSimon J. Gerraty const curve_params *cc, const uint16_t *code)
4550957b409SSimon J. Gerraty {
4560957b409SSimon J. Gerraty uint32_t r;
4570957b409SSimon J. Gerraty uint16_t t[13][I15_LEN];
4580957b409SSimon J. Gerraty size_t u;
4590957b409SSimon J. Gerraty
4600957b409SSimon J. Gerraty r = 1;
4610957b409SSimon J. Gerraty
4620957b409SSimon J. Gerraty /*
4630957b409SSimon J. Gerraty * Copy the two operands in the dedicated registers.
4640957b409SSimon J. Gerraty */
4650957b409SSimon J. Gerraty memcpy(t[P1x], P1->c, 3 * I15_LEN * sizeof(uint16_t));
4660957b409SSimon J. Gerraty memcpy(t[P2x], P2->c, 3 * I15_LEN * sizeof(uint16_t));
4670957b409SSimon J. Gerraty
4680957b409SSimon J. Gerraty /*
4690957b409SSimon J. Gerraty * Run formulas.
4700957b409SSimon J. Gerraty */
4710957b409SSimon J. Gerraty for (u = 0;; u ++) {
4720957b409SSimon J. Gerraty unsigned op, d, a, b;
4730957b409SSimon J. Gerraty
4740957b409SSimon J. Gerraty op = code[u];
4750957b409SSimon J. Gerraty if (op == 0) {
4760957b409SSimon J. Gerraty break;
4770957b409SSimon J. Gerraty }
4780957b409SSimon J. Gerraty d = (op >> 8) & 0x0F;
4790957b409SSimon J. Gerraty a = (op >> 4) & 0x0F;
4800957b409SSimon J. Gerraty b = op & 0x0F;
4810957b409SSimon J. Gerraty op >>= 12;
4820957b409SSimon J. Gerraty switch (op) {
4830957b409SSimon J. Gerraty uint32_t ctl;
4840957b409SSimon J. Gerraty size_t plen;
4850957b409SSimon J. Gerraty unsigned char tp[(BR_MAX_EC_SIZE + 7) >> 3];
4860957b409SSimon J. Gerraty
4870957b409SSimon J. Gerraty case 0:
4880957b409SSimon J. Gerraty memcpy(t[d], t[a], I15_LEN * sizeof(uint16_t));
4890957b409SSimon J. Gerraty break;
4900957b409SSimon J. Gerraty case 1:
4910957b409SSimon J. Gerraty ctl = br_i15_add(t[d], t[a], 1);
4920957b409SSimon J. Gerraty ctl |= NOT(br_i15_sub(t[d], cc->p, 0));
4930957b409SSimon J. Gerraty br_i15_sub(t[d], cc->p, ctl);
4940957b409SSimon J. Gerraty break;
4950957b409SSimon J. Gerraty case 2:
4960957b409SSimon J. Gerraty br_i15_add(t[d], cc->p, br_i15_sub(t[d], t[a], 1));
4970957b409SSimon J. Gerraty break;
4980957b409SSimon J. Gerraty case 3:
4990957b409SSimon J. Gerraty br_i15_montymul(t[d], t[a], t[b], cc->p, cc->p0i);
5000957b409SSimon J. Gerraty break;
5010957b409SSimon J. Gerraty case 4:
5020957b409SSimon J. Gerraty plen = (cc->p[0] - (cc->p[0] >> 4) + 7) >> 3;
5030957b409SSimon J. Gerraty br_i15_encode(tp, plen, cc->p);
5040957b409SSimon J. Gerraty tp[plen - 1] -= 2;
5050957b409SSimon J. Gerraty br_i15_modpow(t[d], tp, plen,
5060957b409SSimon J. Gerraty cc->p, cc->p0i, t[a], t[b]);
5070957b409SSimon J. Gerraty break;
5080957b409SSimon J. Gerraty default:
5090957b409SSimon J. Gerraty r &= ~br_i15_iszero(t[d]);
5100957b409SSimon J. Gerraty break;
5110957b409SSimon J. Gerraty }
5120957b409SSimon J. Gerraty }
5130957b409SSimon J. Gerraty
5140957b409SSimon J. Gerraty /*
5150957b409SSimon J. Gerraty * Copy back result.
5160957b409SSimon J. Gerraty */
5170957b409SSimon J. Gerraty memcpy(P1->c, t[P1x], 3 * I15_LEN * sizeof(uint16_t));
5180957b409SSimon J. Gerraty return r;
5190957b409SSimon J. Gerraty }
5200957b409SSimon J. Gerraty
5210957b409SSimon J. Gerraty static void
set_one(uint16_t * x,const uint16_t * p)5220957b409SSimon J. Gerraty set_one(uint16_t *x, const uint16_t *p)
5230957b409SSimon J. Gerraty {
5240957b409SSimon J. Gerraty size_t plen;
5250957b409SSimon J. Gerraty
5260957b409SSimon J. Gerraty plen = (p[0] + 31) >> 4;
5270957b409SSimon J. Gerraty memset(x, 0, plen * sizeof *x);
5280957b409SSimon J. Gerraty x[0] = p[0];
5290957b409SSimon J. Gerraty x[1] = 0x0001;
5300957b409SSimon J. Gerraty }
5310957b409SSimon J. Gerraty
5320957b409SSimon J. Gerraty static void
point_zero(jacobian * P,const curve_params * cc)5330957b409SSimon J. Gerraty point_zero(jacobian *P, const curve_params *cc)
5340957b409SSimon J. Gerraty {
5350957b409SSimon J. Gerraty memset(P, 0, sizeof *P);
5360957b409SSimon J. Gerraty P->c[0][0] = P->c[1][0] = P->c[2][0] = cc->p[0];
5370957b409SSimon J. Gerraty }
5380957b409SSimon J. Gerraty
5390957b409SSimon J. Gerraty static inline void
point_double(jacobian * P,const curve_params * cc)5400957b409SSimon J. Gerraty point_double(jacobian *P, const curve_params *cc)
5410957b409SSimon J. Gerraty {
5420957b409SSimon J. Gerraty run_code(P, P, cc, code_double);
5430957b409SSimon J. Gerraty }
5440957b409SSimon J. Gerraty
5450957b409SSimon J. Gerraty static inline uint32_t
point_add(jacobian * P1,const jacobian * P2,const curve_params * cc)5460957b409SSimon J. Gerraty point_add(jacobian *P1, const jacobian *P2, const curve_params *cc)
5470957b409SSimon J. Gerraty {
5480957b409SSimon J. Gerraty return run_code(P1, P2, cc, code_add);
5490957b409SSimon J. Gerraty }
5500957b409SSimon J. Gerraty
5510957b409SSimon J. Gerraty static void
point_mul(jacobian * P,const unsigned char * x,size_t xlen,const curve_params * cc)5520957b409SSimon J. Gerraty point_mul(jacobian *P, const unsigned char *x, size_t xlen,
5530957b409SSimon J. Gerraty const curve_params *cc)
5540957b409SSimon J. Gerraty {
5550957b409SSimon J. Gerraty /*
5560957b409SSimon J. Gerraty * We do a simple double-and-add ladder with a 2-bit window
5570957b409SSimon J. Gerraty * to make only one add every two doublings. We thus first
5580957b409SSimon J. Gerraty * precompute 2P and 3P in some local buffers.
5590957b409SSimon J. Gerraty *
5600957b409SSimon J. Gerraty * We always perform two doublings and one addition; the
5610957b409SSimon J. Gerraty * addition is with P, 2P and 3P and is done in a temporary
5620957b409SSimon J. Gerraty * array.
5630957b409SSimon J. Gerraty *
5640957b409SSimon J. Gerraty * The addition code cannot handle cases where one of the
5650957b409SSimon J. Gerraty * operands is infinity, which is the case at the start of the
5660957b409SSimon J. Gerraty * ladder. We therefore need to maintain a flag that controls
5670957b409SSimon J. Gerraty * this situation.
5680957b409SSimon J. Gerraty */
5690957b409SSimon J. Gerraty uint32_t qz;
5700957b409SSimon J. Gerraty jacobian P2, P3, Q, T, U;
5710957b409SSimon J. Gerraty
5720957b409SSimon J. Gerraty memcpy(&P2, P, sizeof P2);
5730957b409SSimon J. Gerraty point_double(&P2, cc);
5740957b409SSimon J. Gerraty memcpy(&P3, P, sizeof P3);
5750957b409SSimon J. Gerraty point_add(&P3, &P2, cc);
5760957b409SSimon J. Gerraty
5770957b409SSimon J. Gerraty point_zero(&Q, cc);
5780957b409SSimon J. Gerraty qz = 1;
5790957b409SSimon J. Gerraty while (xlen -- > 0) {
5800957b409SSimon J. Gerraty int k;
5810957b409SSimon J. Gerraty
5820957b409SSimon J. Gerraty for (k = 6; k >= 0; k -= 2) {
5830957b409SSimon J. Gerraty uint32_t bits;
5840957b409SSimon J. Gerraty uint32_t bnz;
5850957b409SSimon J. Gerraty
5860957b409SSimon J. Gerraty point_double(&Q, cc);
5870957b409SSimon J. Gerraty point_double(&Q, cc);
5880957b409SSimon J. Gerraty memcpy(&T, P, sizeof T);
5890957b409SSimon J. Gerraty memcpy(&U, &Q, sizeof U);
5900957b409SSimon J. Gerraty bits = (*x >> k) & (uint32_t)3;
5910957b409SSimon J. Gerraty bnz = NEQ(bits, 0);
5920957b409SSimon J. Gerraty CCOPY(EQ(bits, 2), &T, &P2, sizeof T);
5930957b409SSimon J. Gerraty CCOPY(EQ(bits, 3), &T, &P3, sizeof T);
5940957b409SSimon J. Gerraty point_add(&U, &T, cc);
5950957b409SSimon J. Gerraty CCOPY(bnz & qz, &Q, &T, sizeof Q);
5960957b409SSimon J. Gerraty CCOPY(bnz & ~qz, &Q, &U, sizeof Q);
5970957b409SSimon J. Gerraty qz &= ~bnz;
5980957b409SSimon J. Gerraty }
5990957b409SSimon J. Gerraty x ++;
6000957b409SSimon J. Gerraty }
6010957b409SSimon J. Gerraty memcpy(P, &Q, sizeof Q);
6020957b409SSimon J. Gerraty }
6030957b409SSimon J. Gerraty
6040957b409SSimon J. Gerraty /*
6050957b409SSimon J. Gerraty * Decode point into Jacobian coordinates. This function does not support
6060957b409SSimon J. Gerraty * the point at infinity. If the point is invalid then this returns 0, but
6070957b409SSimon J. Gerraty * the coordinates are still set to properly formed field elements.
6080957b409SSimon J. Gerraty */
6090957b409SSimon J. Gerraty static uint32_t
point_decode(jacobian * P,const void * src,size_t len,const curve_params * cc)6100957b409SSimon J. Gerraty point_decode(jacobian *P, const void *src, size_t len, const curve_params *cc)
6110957b409SSimon J. Gerraty {
6120957b409SSimon J. Gerraty /*
6130957b409SSimon J. Gerraty * Points must use uncompressed format:
6140957b409SSimon J. Gerraty * -- first byte is 0x04;
6150957b409SSimon J. Gerraty * -- coordinates X and Y use unsigned big-endian, with the same
6160957b409SSimon J. Gerraty * length as the field modulus.
6170957b409SSimon J. Gerraty *
6180957b409SSimon J. Gerraty * We don't support hybrid format (uncompressed, but first byte
6190957b409SSimon J. Gerraty * has value 0x06 or 0x07, depending on the least significant bit
6200957b409SSimon J. Gerraty * of Y) because it is rather useless, and explicitly forbidden
6210957b409SSimon J. Gerraty * by PKIX (RFC 5480, section 2.2).
6220957b409SSimon J. Gerraty *
6230957b409SSimon J. Gerraty * We don't support compressed format either, because it is not
6240957b409SSimon J. Gerraty * much used in practice (there are or were patent-related
6250957b409SSimon J. Gerraty * concerns about point compression, which explains the lack of
6260957b409SSimon J. Gerraty * generalised support). Also, point compression support would
6270957b409SSimon J. Gerraty * need a bit more code.
6280957b409SSimon J. Gerraty */
6290957b409SSimon J. Gerraty const unsigned char *buf;
6300957b409SSimon J. Gerraty size_t plen, zlen;
6310957b409SSimon J. Gerraty uint32_t r;
6320957b409SSimon J. Gerraty jacobian Q;
6330957b409SSimon J. Gerraty
6340957b409SSimon J. Gerraty buf = src;
6350957b409SSimon J. Gerraty point_zero(P, cc);
6360957b409SSimon J. Gerraty plen = (cc->p[0] - (cc->p[0] >> 4) + 7) >> 3;
6370957b409SSimon J. Gerraty if (len != 1 + (plen << 1)) {
6380957b409SSimon J. Gerraty return 0;
6390957b409SSimon J. Gerraty }
6400957b409SSimon J. Gerraty r = br_i15_decode_mod(P->c[0], buf + 1, plen, cc->p);
6410957b409SSimon J. Gerraty r &= br_i15_decode_mod(P->c[1], buf + 1 + plen, plen, cc->p);
6420957b409SSimon J. Gerraty
6430957b409SSimon J. Gerraty /*
6440957b409SSimon J. Gerraty * Check first byte.
6450957b409SSimon J. Gerraty */
6460957b409SSimon J. Gerraty r &= EQ(buf[0], 0x04);
6470957b409SSimon J. Gerraty /* obsolete
6480957b409SSimon J. Gerraty r &= EQ(buf[0], 0x04) | (EQ(buf[0] & 0xFE, 0x06)
6490957b409SSimon J. Gerraty & ~(uint32_t)(buf[0] ^ buf[plen << 1]));
6500957b409SSimon J. Gerraty */
6510957b409SSimon J. Gerraty
6520957b409SSimon J. Gerraty /*
6530957b409SSimon J. Gerraty * Convert coordinates and check that the point is valid.
6540957b409SSimon J. Gerraty */
6550957b409SSimon J. Gerraty zlen = ((cc->p[0] + 31) >> 4) * sizeof(uint16_t);
6560957b409SSimon J. Gerraty memcpy(Q.c[0], cc->R2, zlen);
6570957b409SSimon J. Gerraty memcpy(Q.c[1], cc->b, zlen);
6580957b409SSimon J. Gerraty set_one(Q.c[2], cc->p);
6590957b409SSimon J. Gerraty r &= ~run_code(P, &Q, cc, code_check);
6600957b409SSimon J. Gerraty return r;
6610957b409SSimon J. Gerraty }
6620957b409SSimon J. Gerraty
6630957b409SSimon J. Gerraty /*
6640957b409SSimon J. Gerraty * Encode a point. This method assumes that the point is correct and is
6650957b409SSimon J. Gerraty * not the point at infinity. Encoded size is always 1+2*plen, where
6660957b409SSimon J. Gerraty * plen is the field modulus length, in bytes.
6670957b409SSimon J. Gerraty */
6680957b409SSimon J. Gerraty static void
point_encode(void * dst,const jacobian * P,const curve_params * cc)6690957b409SSimon J. Gerraty point_encode(void *dst, const jacobian *P, const curve_params *cc)
6700957b409SSimon J. Gerraty {
6710957b409SSimon J. Gerraty unsigned char *buf;
6720957b409SSimon J. Gerraty size_t plen;
6730957b409SSimon J. Gerraty jacobian Q, T;
6740957b409SSimon J. Gerraty
6750957b409SSimon J. Gerraty buf = dst;
6760957b409SSimon J. Gerraty plen = (cc->p[0] - (cc->p[0] >> 4) + 7) >> 3;
6770957b409SSimon J. Gerraty buf[0] = 0x04;
6780957b409SSimon J. Gerraty memcpy(&Q, P, sizeof *P);
6790957b409SSimon J. Gerraty set_one(T.c[2], cc->p);
6800957b409SSimon J. Gerraty run_code(&Q, &T, cc, code_affine);
6810957b409SSimon J. Gerraty br_i15_encode(buf + 1, plen, Q.c[0]);
6820957b409SSimon J. Gerraty br_i15_encode(buf + 1 + plen, plen, Q.c[1]);
6830957b409SSimon J. Gerraty }
6840957b409SSimon J. Gerraty
6850957b409SSimon J. Gerraty static const br_ec_curve_def *
id_to_curve_def(int curve)6860957b409SSimon J. Gerraty id_to_curve_def(int curve)
6870957b409SSimon J. Gerraty {
6880957b409SSimon J. Gerraty switch (curve) {
6890957b409SSimon J. Gerraty case BR_EC_secp256r1:
6900957b409SSimon J. Gerraty return &br_secp256r1;
6910957b409SSimon J. Gerraty case BR_EC_secp384r1:
6920957b409SSimon J. Gerraty return &br_secp384r1;
6930957b409SSimon J. Gerraty case BR_EC_secp521r1:
6940957b409SSimon J. Gerraty return &br_secp521r1;
6950957b409SSimon J. Gerraty }
6960957b409SSimon J. Gerraty return NULL;
6970957b409SSimon J. Gerraty }
6980957b409SSimon J. Gerraty
6990957b409SSimon J. Gerraty static const unsigned char *
api_generator(int curve,size_t * len)7000957b409SSimon J. Gerraty api_generator(int curve, size_t *len)
7010957b409SSimon J. Gerraty {
7020957b409SSimon J. Gerraty const br_ec_curve_def *cd;
7030957b409SSimon J. Gerraty
7040957b409SSimon J. Gerraty cd = id_to_curve_def(curve);
7050957b409SSimon J. Gerraty *len = cd->generator_len;
7060957b409SSimon J. Gerraty return cd->generator;
7070957b409SSimon J. Gerraty }
7080957b409SSimon J. Gerraty
7090957b409SSimon J. Gerraty static const unsigned char *
api_order(int curve,size_t * len)7100957b409SSimon J. Gerraty api_order(int curve, size_t *len)
7110957b409SSimon J. Gerraty {
7120957b409SSimon J. Gerraty const br_ec_curve_def *cd;
7130957b409SSimon J. Gerraty
7140957b409SSimon J. Gerraty cd = id_to_curve_def(curve);
7150957b409SSimon J. Gerraty *len = cd->order_len;
7160957b409SSimon J. Gerraty return cd->order;
7170957b409SSimon J. Gerraty }
7180957b409SSimon J. Gerraty
7190957b409SSimon J. Gerraty static size_t
api_xoff(int curve,size_t * len)7200957b409SSimon J. Gerraty api_xoff(int curve, size_t *len)
7210957b409SSimon J. Gerraty {
7220957b409SSimon J. Gerraty api_generator(curve, len);
7230957b409SSimon J. Gerraty *len >>= 1;
7240957b409SSimon J. Gerraty return 1;
7250957b409SSimon J. Gerraty }
7260957b409SSimon J. Gerraty
7270957b409SSimon J. Gerraty static uint32_t
api_mul(unsigned char * G,size_t Glen,const unsigned char * x,size_t xlen,int curve)7280957b409SSimon J. Gerraty api_mul(unsigned char *G, size_t Glen,
7290957b409SSimon J. Gerraty const unsigned char *x, size_t xlen, int curve)
7300957b409SSimon J. Gerraty {
7310957b409SSimon J. Gerraty uint32_t r;
7320957b409SSimon J. Gerraty const curve_params *cc;
7330957b409SSimon J. Gerraty jacobian P;
7340957b409SSimon J. Gerraty
7350957b409SSimon J. Gerraty cc = id_to_curve(curve);
736*cc9e6590SSimon J. Gerraty if (Glen != cc->point_len) {
737*cc9e6590SSimon J. Gerraty return 0;
738*cc9e6590SSimon J. Gerraty }
7390957b409SSimon J. Gerraty r = point_decode(&P, G, Glen, cc);
7400957b409SSimon J. Gerraty point_mul(&P, x, xlen, cc);
7410957b409SSimon J. Gerraty point_encode(G, &P, cc);
7420957b409SSimon J. Gerraty return r;
7430957b409SSimon J. Gerraty }
7440957b409SSimon J. Gerraty
7450957b409SSimon J. Gerraty static size_t
api_mulgen(unsigned char * R,const unsigned char * x,size_t xlen,int curve)7460957b409SSimon J. Gerraty api_mulgen(unsigned char *R,
7470957b409SSimon J. Gerraty const unsigned char *x, size_t xlen, int curve)
7480957b409SSimon J. Gerraty {
7490957b409SSimon J. Gerraty const unsigned char *G;
7500957b409SSimon J. Gerraty size_t Glen;
7510957b409SSimon J. Gerraty
7520957b409SSimon J. Gerraty G = api_generator(curve, &Glen);
7530957b409SSimon J. Gerraty memcpy(R, G, Glen);
7540957b409SSimon J. Gerraty api_mul(R, Glen, x, xlen, curve);
7550957b409SSimon J. Gerraty return Glen;
7560957b409SSimon J. Gerraty }
7570957b409SSimon J. Gerraty
7580957b409SSimon 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)7590957b409SSimon J. Gerraty api_muladd(unsigned char *A, const unsigned char *B, size_t len,
7600957b409SSimon J. Gerraty const unsigned char *x, size_t xlen,
7610957b409SSimon J. Gerraty const unsigned char *y, size_t ylen, int curve)
7620957b409SSimon J. Gerraty {
7630957b409SSimon J. Gerraty uint32_t r, t, z;
7640957b409SSimon J. Gerraty const curve_params *cc;
7650957b409SSimon J. Gerraty jacobian P, Q;
7660957b409SSimon J. Gerraty
7670957b409SSimon J. Gerraty /*
7680957b409SSimon J. Gerraty * TODO: see about merging the two ladders. Right now, we do
7690957b409SSimon J. Gerraty * two independent point multiplications, which is a bit
7700957b409SSimon J. Gerraty * wasteful of CPU resources (but yields short code).
7710957b409SSimon J. Gerraty */
7720957b409SSimon J. Gerraty
7730957b409SSimon J. Gerraty cc = id_to_curve(curve);
774*cc9e6590SSimon J. Gerraty if (len != cc->point_len) {
775*cc9e6590SSimon J. Gerraty return 0;
776*cc9e6590SSimon J. Gerraty }
7770957b409SSimon J. Gerraty r = point_decode(&P, A, len, cc);
7780957b409SSimon J. Gerraty if (B == NULL) {
7790957b409SSimon J. Gerraty size_t Glen;
7800957b409SSimon J. Gerraty
7810957b409SSimon J. Gerraty B = api_generator(curve, &Glen);
7820957b409SSimon J. Gerraty }
7830957b409SSimon J. Gerraty r &= point_decode(&Q, B, len, cc);
7840957b409SSimon J. Gerraty point_mul(&P, x, xlen, cc);
7850957b409SSimon J. Gerraty point_mul(&Q, y, ylen, cc);
7860957b409SSimon J. Gerraty
7870957b409SSimon J. Gerraty /*
7880957b409SSimon J. Gerraty * We want to compute P+Q. Since the base points A and B are distinct
7890957b409SSimon J. Gerraty * from infinity, and the multipliers are non-zero and lower than the
7900957b409SSimon J. Gerraty * curve order, then we know that P and Q are non-infinity. This
7910957b409SSimon J. Gerraty * leaves two special situations to test for:
7920957b409SSimon J. Gerraty * -- If P = Q then we must use point_double().
7930957b409SSimon J. Gerraty * -- If P+Q = 0 then we must report an error.
7940957b409SSimon J. Gerraty */
7950957b409SSimon J. Gerraty t = point_add(&P, &Q, cc);
7960957b409SSimon J. Gerraty point_double(&Q, cc);
7970957b409SSimon J. Gerraty z = br_i15_iszero(P.c[2]);
7980957b409SSimon J. Gerraty
7990957b409SSimon J. Gerraty /*
8000957b409SSimon J. Gerraty * If z is 1 then either P+Q = 0 (t = 1) or P = Q (t = 0). So we
8010957b409SSimon J. Gerraty * have the following:
8020957b409SSimon J. Gerraty *
8030957b409SSimon J. Gerraty * z = 0, t = 0 return P (normal addition)
8040957b409SSimon J. Gerraty * z = 0, t = 1 return P (normal addition)
8050957b409SSimon J. Gerraty * z = 1, t = 0 return Q (a 'double' case)
8060957b409SSimon J. Gerraty * z = 1, t = 1 report an error (P+Q = 0)
8070957b409SSimon J. Gerraty */
8080957b409SSimon J. Gerraty CCOPY(z & ~t, &P, &Q, sizeof Q);
8090957b409SSimon J. Gerraty point_encode(A, &P, cc);
8100957b409SSimon J. Gerraty r &= ~(z & t);
8110957b409SSimon J. Gerraty
8120957b409SSimon J. Gerraty return r;
8130957b409SSimon J. Gerraty }
8140957b409SSimon J. Gerraty
8150957b409SSimon J. Gerraty /* see bearssl_ec.h */
8160957b409SSimon J. Gerraty const br_ec_impl br_ec_prime_i15 = {
8170957b409SSimon J. Gerraty (uint32_t)0x03800000,
8180957b409SSimon J. Gerraty &api_generator,
8190957b409SSimon J. Gerraty &api_order,
8200957b409SSimon J. Gerraty &api_xoff,
8210957b409SSimon J. Gerraty &api_mul,
8220957b409SSimon J. Gerraty &api_mulgen,
8230957b409SSimon J. Gerraty &api_muladd
8240957b409SSimon J. Gerraty };
825