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