Path: blob/main/contrib/bearssl/src/ec/ec_prime_i15.c
39507 views
/*1* Copyright (c) 2017 Thomas Pornin <[email protected]>2*3* Permission is hereby granted, free of charge, to any person obtaining4* a copy of this software and associated documentation files (the5* "Software"), to deal in the Software without restriction, including6* without limitation the rights to use, copy, modify, merge, publish,7* distribute, sublicense, and/or sell copies of the Software, and to8* permit persons to whom the Software is furnished to do so, subject to9* the following conditions:10*11* The above copyright notice and this permission notice shall be12* included in all copies or substantial portions of the Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,15* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF16* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND17* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS18* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN19* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN20* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE21* SOFTWARE.22*/2324#include "inner.h"2526/*27* Parameters for supported curves:28* - field modulus p29* - R^2 mod p (R = 2^(15k) for the smallest k such that R >= p)30* - b*R mod p (b is the second curve equation parameter)31*/3233static const uint16_t P256_P[] = {340x0111,350x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x003F, 0x0000,360x0000, 0x0000, 0x0000, 0x0000, 0x1000, 0x0000, 0x4000, 0x7FFF,370x7FFF, 0x000138};3940static const uint16_t P256_R2[] = {410x0111,420x0000, 0x6000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7FFC, 0x7FFF,430x7FBF, 0x7FFF, 0x7FBF, 0x7FFF, 0x7FFF, 0x7FFF, 0x77FF, 0x7FFF,440x4FFF, 0x000045};4647static const uint16_t P256_B[] = {480x0111,490x770C, 0x5EEF, 0x29C4, 0x3EC4, 0x6273, 0x0486, 0x4543, 0x3993,500x3C01, 0x6B56, 0x212E, 0x57EE, 0x4882, 0x204B, 0x7483, 0x3C16,510x0187, 0x000052};5354static const uint16_t P384_P[] = {550x0199,560x7FFF, 0x7FFF, 0x0003, 0x0000, 0x0000, 0x0000, 0x7FC0, 0x7FFF,570x7EFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,580x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,590x7FFF, 0x01FF60};6162static const uint16_t P384_R2[] = {630x0199,640x1000, 0x0000, 0x0000, 0x7FFF, 0x7FFF, 0x0001, 0x0000, 0x0010,650x0000, 0x0000, 0x0000, 0x7F00, 0x7FFF, 0x01FF, 0x0000, 0x1000,660x0000, 0x2000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,670x0000, 0x000068};6970static const uint16_t P384_B[] = {710x0199,720x7333, 0x2096, 0x70D1, 0x2310, 0x3020, 0x6197, 0x1464, 0x35BB,730x70CA, 0x0117, 0x1920, 0x4136, 0x5FC8, 0x5713, 0x4938, 0x7DD2,740x4DD2, 0x4A71, 0x0220, 0x683E, 0x2C87, 0x4DB1, 0x7BFF, 0x6C09,750x0452, 0x008476};7778static const uint16_t P521_P[] = {790x022B,800x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,810x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,820x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,830x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,840x7FFF, 0x7FFF, 0x07FF85};8687static const uint16_t P521_R2[] = {880x022B,890x0100, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,900x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,910x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,920x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,930x0000, 0x0000, 0x000094};9596static const uint16_t P521_B[] = {970x022B,980x7002, 0x6A07, 0x751A, 0x228F, 0x71EF, 0x5869, 0x20F4, 0x1EFC,990x7357, 0x37E0, 0x4EEC, 0x605E, 0x1652, 0x26F6, 0x31FA, 0x4A8F,1000x6193, 0x3C2A, 0x3C42, 0x48C7, 0x3489, 0x6771, 0x4C57, 0x5CCD,1010x2725, 0x545B, 0x503B, 0x5B42, 0x21A0, 0x2534, 0x687E, 0x70E4,1020x1618, 0x27D7, 0x0465103};104105typedef struct {106const uint16_t *p;107const uint16_t *b;108const uint16_t *R2;109uint16_t p0i;110size_t point_len;111} curve_params;112113static inline const curve_params *114id_to_curve(int curve)115{116static const curve_params pp[] = {117{ P256_P, P256_B, P256_R2, 0x0001, 65 },118{ P384_P, P384_B, P384_R2, 0x0001, 97 },119{ P521_P, P521_B, P521_R2, 0x0001, 133 }120};121122return &pp[curve - BR_EC_secp256r1];123}124125#define I15_LEN ((BR_MAX_EC_SIZE + 29) / 15)126127/*128* Type for a point in Jacobian coordinates:129* -- three values, x, y and z, in Montgomery representation130* -- affine coordinates are X = x / z^2 and Y = y / z^3131* -- for the point at infinity, z = 0132*/133typedef struct {134uint16_t c[3][I15_LEN];135} jacobian;136137/*138* We use a custom interpreter that uses a dozen registers, and139* only six operations:140* MSET(d, a) copy a into d141* MADD(d, a) d = d+a (modular)142* MSUB(d, a) d = d-a (modular)143* MMUL(d, a, b) d = a*b (Montgomery multiplication)144* MINV(d, a, b) invert d modulo p; a and b are used as scratch registers145* MTZ(d) clear return value if d = 0146* Destination of MMUL (d) must be distinct from operands (a and b).147* There is no such constraint for MSUB and MADD.148*149* Registers include the operand coordinates, and temporaries.150*/151#define MSET(d, a) (0x0000 + ((d) << 8) + ((a) << 4))152#define MADD(d, a) (0x1000 + ((d) << 8) + ((a) << 4))153#define MSUB(d, a) (0x2000 + ((d) << 8) + ((a) << 4))154#define MMUL(d, a, b) (0x3000 + ((d) << 8) + ((a) << 4) + (b))155#define MINV(d, a, b) (0x4000 + ((d) << 8) + ((a) << 4) + (b))156#define MTZ(d) (0x5000 + ((d) << 8))157#define ENDCODE 0158159/*160* Registers for the input operands.161*/162#define P1x 0163#define P1y 1164#define P1z 2165#define P2x 3166#define P2y 4167#define P2z 5168169/*170* Alternate names for the first input operand.171*/172#define Px 0173#define Py 1174#define Pz 2175176/*177* Temporaries.178*/179#define t1 6180#define t2 7181#define t3 8182#define t4 9183#define t5 10184#define t6 11185#define t7 12186187/*188* Extra scratch registers available when there is no second operand (e.g.189* for "double" and "affine").190*/191#define t8 3192#define t9 4193#define t10 5194195/*196* Doubling formulas are:197*198* s = 4*x*y^2199* m = 3*(x + z^2)*(x - z^2)200* x' = m^2 - 2*s201* y' = m*(s - x') - 8*y^4202* z' = 2*y*z203*204* If y = 0 (P has order 2) then this yields infinity (z' = 0), as it205* should. This case should not happen anyway, because our curves have206* prime order, and thus do not contain any point of order 2.207*208* If P is infinity (z = 0), then again the formulas yield infinity,209* which is correct. Thus, this code works for all points.210*211* Cost: 8 multiplications212*/213static const uint16_t code_double[] = {214/*215* Compute z^2 (in t1).216*/217MMUL(t1, Pz, Pz),218219/*220* Compute x-z^2 (in t2) and then x+z^2 (in t1).221*/222MSET(t2, Px),223MSUB(t2, t1),224MADD(t1, Px),225226/*227* Compute m = 3*(x+z^2)*(x-z^2) (in t1).228*/229MMUL(t3, t1, t2),230MSET(t1, t3),231MADD(t1, t3),232MADD(t1, t3),233234/*235* Compute s = 4*x*y^2 (in t2) and 2*y^2 (in t3).236*/237MMUL(t3, Py, Py),238MADD(t3, t3),239MMUL(t2, Px, t3),240MADD(t2, t2),241242/*243* Compute x' = m^2 - 2*s.244*/245MMUL(Px, t1, t1),246MSUB(Px, t2),247MSUB(Px, t2),248249/*250* Compute z' = 2*y*z.251*/252MMUL(t4, Py, Pz),253MSET(Pz, t4),254MADD(Pz, t4),255256/*257* Compute y' = m*(s - x') - 8*y^4. Note that we already have258* 2*y^2 in t3.259*/260MSUB(t2, Px),261MMUL(Py, t1, t2),262MMUL(t4, t3, t3),263MSUB(Py, t4),264MSUB(Py, t4),265266ENDCODE267};268269/*270* Addtions formulas are:271*272* u1 = x1 * z2^2273* u2 = x2 * z1^2274* s1 = y1 * z2^3275* s2 = y2 * z1^3276* h = u2 - u1277* r = s2 - s1278* x3 = r^2 - h^3 - 2 * u1 * h^2279* y3 = r * (u1 * h^2 - x3) - s1 * h^3280* z3 = h * z1 * z2281*282* If both P1 and P2 are infinity, then z1 == 0 and z2 == 0, implying that283* z3 == 0, so the result is correct.284* If either of P1 or P2 is infinity, but not both, then z3 == 0, which is285* not correct.286* h == 0 only if u1 == u2; this happens in two cases:287* -- if s1 == s2 then P1 and/or P2 is infinity, or P1 == P2288* -- if s1 != s2 then P1 + P2 == infinity (but neither P1 or P2 is infinity)289*290* Thus, the following situations are not handled correctly:291* -- P1 = 0 and P2 != 0292* -- P1 != 0 and P2 = 0293* -- P1 = P2294* All other cases are properly computed. However, even in "incorrect"295* situations, the three coordinates still are properly formed field296* elements.297*298* The returned flag is cleared if r == 0. This happens in the following299* cases:300* -- Both points are on the same horizontal line (same Y coordinate).301* -- Both points are infinity.302* -- One point is infinity and the other is on line Y = 0.303* The third case cannot happen with our curves (there is no valid point304* on line Y = 0 since that would be a point of order 2). If the two305* source points are non-infinity, then remains only the case where the306* two points are on the same horizontal line.307*308* This allows us to detect the "P1 == P2" case, assuming that P1 != 0 and309* P2 != 0:310* -- If the returned value is not the point at infinity, then it was properly311* computed.312* -- Otherwise, if the returned flag is 1, then P1+P2 = 0, and the result313* is indeed the point at infinity.314* -- Otherwise (result is infinity, flag is 0), then P1 = P2 and we should315* use the 'double' code.316*317* Cost: 16 multiplications318*/319static const uint16_t code_add[] = {320/*321* Compute u1 = x1*z2^2 (in t1) and s1 = y1*z2^3 (in t3).322*/323MMUL(t3, P2z, P2z),324MMUL(t1, P1x, t3),325MMUL(t4, P2z, t3),326MMUL(t3, P1y, t4),327328/*329* Compute u2 = x2*z1^2 (in t2) and s2 = y2*z1^3 (in t4).330*/331MMUL(t4, P1z, P1z),332MMUL(t2, P2x, t4),333MMUL(t5, P1z, t4),334MMUL(t4, P2y, t5),335336/*337* Compute h = u2 - u1 (in t2) and r = s2 - s1 (in t4).338*/339MSUB(t2, t1),340MSUB(t4, t3),341342/*343* Report cases where r = 0 through the returned flag.344*/345MTZ(t4),346347/*348* Compute u1*h^2 (in t6) and h^3 (in t5).349*/350MMUL(t7, t2, t2),351MMUL(t6, t1, t7),352MMUL(t5, t7, t2),353354/*355* Compute x3 = r^2 - h^3 - 2*u1*h^2.356* t1 and t7 can be used as scratch registers.357*/358MMUL(P1x, t4, t4),359MSUB(P1x, t5),360MSUB(P1x, t6),361MSUB(P1x, t6),362363/*364* Compute y3 = r*(u1*h^2 - x3) - s1*h^3.365*/366MSUB(t6, P1x),367MMUL(P1y, t4, t6),368MMUL(t1, t5, t3),369MSUB(P1y, t1),370371/*372* Compute z3 = h*z1*z2.373*/374MMUL(t1, P1z, P2z),375MMUL(P1z, t1, t2),376377ENDCODE378};379380/*381* Check that the point is on the curve. This code snippet assumes the382* following conventions:383* -- Coordinates x and y have been freshly decoded in P1 (but not384* converted to Montgomery coordinates yet).385* -- P2x, P2y and P2z are set to, respectively, R^2, b*R and 1.386*/387static const uint16_t code_check[] = {388389/* Convert x and y to Montgomery representation. */390MMUL(t1, P1x, P2x),391MMUL(t2, P1y, P2x),392MSET(P1x, t1),393MSET(P1y, t2),394395/* Compute x^3 in t1. */396MMUL(t2, P1x, P1x),397MMUL(t1, P1x, t2),398399/* Subtract 3*x from t1. */400MSUB(t1, P1x),401MSUB(t1, P1x),402MSUB(t1, P1x),403404/* Add b. */405MADD(t1, P2y),406407/* Compute y^2 in t2. */408MMUL(t2, P1y, P1y),409410/* Compare y^2 with x^3 - 3*x + b; they must match. */411MSUB(t1, t2),412MTZ(t1),413414/* Set z to 1 (in Montgomery representation). */415MMUL(P1z, P2x, P2z),416417ENDCODE418};419420/*421* Conversion back to affine coordinates. This code snippet assumes that422* the z coordinate of P2 is set to 1 (not in Montgomery representation).423*/424static const uint16_t code_affine[] = {425426/* Save z*R in t1. */427MSET(t1, P1z),428429/* Compute z^3 in t2. */430MMUL(t2, P1z, P1z),431MMUL(t3, P1z, t2),432MMUL(t2, t3, P2z),433434/* Invert to (1/z^3) in t2. */435MINV(t2, t3, t4),436437/* Compute y. */438MSET(t3, P1y),439MMUL(P1y, t2, t3),440441/* Compute (1/z^2) in t3. */442MMUL(t3, t2, t1),443444/* Compute x. */445MSET(t2, P1x),446MMUL(P1x, t2, t3),447448ENDCODE449};450451static uint32_t452run_code(jacobian *P1, const jacobian *P2,453const curve_params *cc, const uint16_t *code)454{455uint32_t r;456uint16_t t[13][I15_LEN];457size_t u;458459r = 1;460461/*462* Copy the two operands in the dedicated registers.463*/464memcpy(t[P1x], P1->c, 3 * I15_LEN * sizeof(uint16_t));465memcpy(t[P2x], P2->c, 3 * I15_LEN * sizeof(uint16_t));466467/*468* Run formulas.469*/470for (u = 0;; u ++) {471unsigned op, d, a, b;472473op = code[u];474if (op == 0) {475break;476}477d = (op >> 8) & 0x0F;478a = (op >> 4) & 0x0F;479b = op & 0x0F;480op >>= 12;481switch (op) {482uint32_t ctl;483size_t plen;484unsigned char tp[(BR_MAX_EC_SIZE + 7) >> 3];485486case 0:487memcpy(t[d], t[a], I15_LEN * sizeof(uint16_t));488break;489case 1:490ctl = br_i15_add(t[d], t[a], 1);491ctl |= NOT(br_i15_sub(t[d], cc->p, 0));492br_i15_sub(t[d], cc->p, ctl);493break;494case 2:495br_i15_add(t[d], cc->p, br_i15_sub(t[d], t[a], 1));496break;497case 3:498br_i15_montymul(t[d], t[a], t[b], cc->p, cc->p0i);499break;500case 4:501plen = (cc->p[0] - (cc->p[0] >> 4) + 7) >> 3;502br_i15_encode(tp, plen, cc->p);503tp[plen - 1] -= 2;504br_i15_modpow(t[d], tp, plen,505cc->p, cc->p0i, t[a], t[b]);506break;507default:508r &= ~br_i15_iszero(t[d]);509break;510}511}512513/*514* Copy back result.515*/516memcpy(P1->c, t[P1x], 3 * I15_LEN * sizeof(uint16_t));517return r;518}519520static void521set_one(uint16_t *x, const uint16_t *p)522{523size_t plen;524525plen = (p[0] + 31) >> 4;526memset(x, 0, plen * sizeof *x);527x[0] = p[0];528x[1] = 0x0001;529}530531static void532point_zero(jacobian *P, const curve_params *cc)533{534memset(P, 0, sizeof *P);535P->c[0][0] = P->c[1][0] = P->c[2][0] = cc->p[0];536}537538static inline void539point_double(jacobian *P, const curve_params *cc)540{541run_code(P, P, cc, code_double);542}543544static inline uint32_t545point_add(jacobian *P1, const jacobian *P2, const curve_params *cc)546{547return run_code(P1, P2, cc, code_add);548}549550static void551point_mul(jacobian *P, const unsigned char *x, size_t xlen,552const curve_params *cc)553{554/*555* We do a simple double-and-add ladder with a 2-bit window556* to make only one add every two doublings. We thus first557* precompute 2P and 3P in some local buffers.558*559* We always perform two doublings and one addition; the560* addition is with P, 2P and 3P and is done in a temporary561* array.562*563* The addition code cannot handle cases where one of the564* operands is infinity, which is the case at the start of the565* ladder. We therefore need to maintain a flag that controls566* this situation.567*/568uint32_t qz;569jacobian P2, P3, Q, T, U;570571memcpy(&P2, P, sizeof P2);572point_double(&P2, cc);573memcpy(&P3, P, sizeof P3);574point_add(&P3, &P2, cc);575576point_zero(&Q, cc);577qz = 1;578while (xlen -- > 0) {579int k;580581for (k = 6; k >= 0; k -= 2) {582uint32_t bits;583uint32_t bnz;584585point_double(&Q, cc);586point_double(&Q, cc);587memcpy(&T, P, sizeof T);588memcpy(&U, &Q, sizeof U);589bits = (*x >> k) & (uint32_t)3;590bnz = NEQ(bits, 0);591CCOPY(EQ(bits, 2), &T, &P2, sizeof T);592CCOPY(EQ(bits, 3), &T, &P3, sizeof T);593point_add(&U, &T, cc);594CCOPY(bnz & qz, &Q, &T, sizeof Q);595CCOPY(bnz & ~qz, &Q, &U, sizeof Q);596qz &= ~bnz;597}598x ++;599}600memcpy(P, &Q, sizeof Q);601}602603/*604* Decode point into Jacobian coordinates. This function does not support605* the point at infinity. If the point is invalid then this returns 0, but606* the coordinates are still set to properly formed field elements.607*/608static uint32_t609point_decode(jacobian *P, const void *src, size_t len, const curve_params *cc)610{611/*612* Points must use uncompressed format:613* -- first byte is 0x04;614* -- coordinates X and Y use unsigned big-endian, with the same615* length as the field modulus.616*617* We don't support hybrid format (uncompressed, but first byte618* has value 0x06 or 0x07, depending on the least significant bit619* of Y) because it is rather useless, and explicitly forbidden620* by PKIX (RFC 5480, section 2.2).621*622* We don't support compressed format either, because it is not623* much used in practice (there are or were patent-related624* concerns about point compression, which explains the lack of625* generalised support). Also, point compression support would626* need a bit more code.627*/628const unsigned char *buf;629size_t plen, zlen;630uint32_t r;631jacobian Q;632633buf = src;634point_zero(P, cc);635plen = (cc->p[0] - (cc->p[0] >> 4) + 7) >> 3;636if (len != 1 + (plen << 1)) {637return 0;638}639r = br_i15_decode_mod(P->c[0], buf + 1, plen, cc->p);640r &= br_i15_decode_mod(P->c[1], buf + 1 + plen, plen, cc->p);641642/*643* Check first byte.644*/645r &= EQ(buf[0], 0x04);646/* obsolete647r &= EQ(buf[0], 0x04) | (EQ(buf[0] & 0xFE, 0x06)648& ~(uint32_t)(buf[0] ^ buf[plen << 1]));649*/650651/*652* Convert coordinates and check that the point is valid.653*/654zlen = ((cc->p[0] + 31) >> 4) * sizeof(uint16_t);655memcpy(Q.c[0], cc->R2, zlen);656memcpy(Q.c[1], cc->b, zlen);657set_one(Q.c[2], cc->p);658r &= ~run_code(P, &Q, cc, code_check);659return r;660}661662/*663* Encode a point. This method assumes that the point is correct and is664* not the point at infinity. Encoded size is always 1+2*plen, where665* plen is the field modulus length, in bytes.666*/667static void668point_encode(void *dst, const jacobian *P, const curve_params *cc)669{670unsigned char *buf;671size_t plen;672jacobian Q, T;673674buf = dst;675plen = (cc->p[0] - (cc->p[0] >> 4) + 7) >> 3;676buf[0] = 0x04;677memcpy(&Q, P, sizeof *P);678set_one(T.c[2], cc->p);679run_code(&Q, &T, cc, code_affine);680br_i15_encode(buf + 1, plen, Q.c[0]);681br_i15_encode(buf + 1 + plen, plen, Q.c[1]);682}683684static const br_ec_curve_def *685id_to_curve_def(int curve)686{687switch (curve) {688case BR_EC_secp256r1:689return &br_secp256r1;690case BR_EC_secp384r1:691return &br_secp384r1;692case BR_EC_secp521r1:693return &br_secp521r1;694}695return NULL;696}697698static const unsigned char *699api_generator(int curve, size_t *len)700{701const br_ec_curve_def *cd;702703cd = id_to_curve_def(curve);704*len = cd->generator_len;705return cd->generator;706}707708static const unsigned char *709api_order(int curve, size_t *len)710{711const br_ec_curve_def *cd;712713cd = id_to_curve_def(curve);714*len = cd->order_len;715return cd->order;716}717718static size_t719api_xoff(int curve, size_t *len)720{721api_generator(curve, len);722*len >>= 1;723return 1;724}725726static uint32_t727api_mul(unsigned char *G, size_t Glen,728const unsigned char *x, size_t xlen, int curve)729{730uint32_t r;731const curve_params *cc;732jacobian P;733734cc = id_to_curve(curve);735if (Glen != cc->point_len) {736return 0;737}738r = point_decode(&P, G, Glen, cc);739point_mul(&P, x, xlen, cc);740point_encode(G, &P, cc);741return r;742}743744static size_t745api_mulgen(unsigned char *R,746const unsigned char *x, size_t xlen, int curve)747{748const unsigned char *G;749size_t Glen;750751G = api_generator(curve, &Glen);752memcpy(R, G, Glen);753api_mul(R, Glen, x, xlen, curve);754return Glen;755}756757static uint32_t758api_muladd(unsigned char *A, const unsigned char *B, size_t len,759const unsigned char *x, size_t xlen,760const unsigned char *y, size_t ylen, int curve)761{762uint32_t r, t, z;763const curve_params *cc;764jacobian P, Q;765766/*767* TODO: see about merging the two ladders. Right now, we do768* two independent point multiplications, which is a bit769* wasteful of CPU resources (but yields short code).770*/771772cc = id_to_curve(curve);773if (len != cc->point_len) {774return 0;775}776r = point_decode(&P, A, len, cc);777if (B == NULL) {778size_t Glen;779780B = api_generator(curve, &Glen);781}782r &= point_decode(&Q, B, len, cc);783point_mul(&P, x, xlen, cc);784point_mul(&Q, y, ylen, cc);785786/*787* We want to compute P+Q. Since the base points A and B are distinct788* from infinity, and the multipliers are non-zero and lower than the789* curve order, then we know that P and Q are non-infinity. This790* leaves two special situations to test for:791* -- If P = Q then we must use point_double().792* -- If P+Q = 0 then we must report an error.793*/794t = point_add(&P, &Q, cc);795point_double(&Q, cc);796z = br_i15_iszero(P.c[2]);797798/*799* If z is 1 then either P+Q = 0 (t = 1) or P = Q (t = 0). So we800* have the following:801*802* z = 0, t = 0 return P (normal addition)803* z = 0, t = 1 return P (normal addition)804* z = 1, t = 0 return Q (a 'double' case)805* z = 1, t = 1 report an error (P+Q = 0)806*/807CCOPY(z & ~t, &P, &Q, sizeof Q);808point_encode(A, &P, cc);809r &= ~(z & t);810811return r;812}813814/* see bearssl_ec.h */815const br_ec_impl br_ec_prime_i15 = {816(uint32_t)0x03800000,817&api_generator,818&api_order,819&api_xoff,820&api_mul,821&api_mulgen,822&api_muladd823};824825826