xref: /freebsd/contrib/bearssl/src/ec/ec_prime_i31.c (revision cc9e6590773dba57440750c124173ed531349a06)
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