Path: blob/main/crypto/libecc/src/examples/basic/curve_basic_examples.c
34889 views
/*1* Copyright (C) 2017 - This file is part of libecc project2*3* Authors:4* Ryad BENADJILA <[email protected]>5* Arnaud EBALARD <[email protected]>6* Jean-Pierre FLORI <[email protected]>7*8* Contributors:9* Nicolas VIVET <[email protected]>10* Karim KHALFALLAH <[email protected]>11*12* This software is licensed under a dual BSD and GPL v2 license.13* See LICENSE file at the root folder of the project.14*/15#include <libecc/libec.h>16/* We include the printf external dependency for printf output */17#include <libecc/external_deps/print.h>18/* We include the time external dependency for performance measurement */19#include <libecc/external_deps/time.h>2021/* The followin function picks a random Fp element x, where Fp is the22* curve underlying prime field, and computes y in Fp such that:23* y^2 = x^3 + ax + b, where a and b are the input elliptic24* curve parameters.25*26* This means that (x, y) are the affine coordinates of a "random"27* point on our curve. The function then outputs the projective28* coordinates of (x, y), i.e. the triplet (x, y, 1).29* PS: all our operations on points are done with projective coordinates.30*31* Computing y means computing a quadratic residue in Fp, for which we32* use the Tonelli-Shanks algorithm implemented in the Fp source example33* (fp_square_residue.c).34*/35ATTRIBUTE_WARN_UNUSED_RET int get_random_point_on_curve(ec_params *curve_params, prj_pt *out_point);36int get_random_point_on_curve(ec_params *curve_params, prj_pt *out_point)37{38nn nn_tmp;39int ret, is_oncurve;4041/* Inside our internal representation, curve_params->ec_curve42* contains the curve coefficients a and b.43* curve_params->ec_fp is the Fp context of the curve.44*/45fp x, y, fp_tmp1, fp_tmp2;46fp_ctx_src_t ctx;4748MUST_HAVE((curve_params != NULL), ret, err);4950nn_tmp.magic = WORD(0);51x.magic = y.magic = fp_tmp1.magic = fp_tmp2.magic = WORD(0);5253/* Initialize our x value with the curve Fp context */54ctx = &(curve_params->ec_fp);5556ret = fp_init(&x, ctx); EG(ret, err);57ret = fp_init(&y, ctx); EG(ret, err);58ret = fp_init(&fp_tmp1, ctx); EG(ret, err);59ret = fp_init(&fp_tmp2, ctx); EG(ret, err);6061ret = nn_init(&nn_tmp, 0); EG(ret, err);62ret = nn_set_word_value(&nn_tmp, WORD(3)); EG(ret, err);63while (1) {64/* Get a random Fp */65ret = fp_get_random(&x, ctx); EG(ret, err);66ret = fp_copy(&fp_tmp1, &x); EG(ret, err);67ret = fp_copy(&fp_tmp2, &x); EG(ret, err);68/* Compute x^3 + ax + b */69ret = fp_pow(&fp_tmp1, &fp_tmp1, &nn_tmp); EG(ret, err);70ret = fp_mul(&fp_tmp2, &fp_tmp2, &(curve_params->ec_curve.a)); EG(ret, err);71ret = fp_add(&fp_tmp1, &fp_tmp1, &fp_tmp2); EG(ret, err);72ret = fp_add(&fp_tmp1, &fp_tmp1, &(curve_params->ec_curve.b)); EG(ret, err);73/*74* Get any of the two square roots, corresponding to (x, y)75* and (x, -y) both on the curve. If no square root exist,76* go to next random Fp.77*/78if (fp_sqrt(&y, &fp_tmp2, &fp_tmp1) == 0) {79/* Check that we indeed satisfy the curve equation */80ret = is_on_shortw_curve(&x, &y, &(curve_params->ec_curve), &is_oncurve); EG(ret, err);81if (!is_oncurve) {82/* This should not happen ... */83ext_printf("Error: Tonelli-Shanks found a bad "84"solution to curve equation ...\n");85continue;86}87break;88}89}90/* Now initialize our point with the coordinates (x, y, 1) */91ret = fp_one(&fp_tmp1); EG(ret, err);92ret = prj_pt_init_from_coords(out_point, &(curve_params->ec_curve), &x, &y,93&fp_tmp1); EG(ret, err);9495err:96fp_uninit(&x);97fp_uninit(&y);98fp_uninit(&fp_tmp1);99fp_uninit(&fp_tmp2);100nn_uninit(&nn_tmp);101102return ret;103}104105#define PERF_SCALAR_MUL 40106ATTRIBUTE_WARN_UNUSED_RET int check_curve(const u8 *curve_name);107int check_curve(const u8 *curve_name)108{109unsigned int i;110u64 t1, t2;111int ret, is_oncurve, isone, iszero;112113nn nn_k;114/* libecc internal structure holding the curve parameters */115ec_params curve_params;116/* libecc internal structure holding projective points on curves */117prj_pt A, B, C, D;118prj_pt TMP;119aff_pt T;120u32 len;121122/* Importing a specific curve parameters from the constant static123* buffers describing it:124* It is possible to import a curves parameters by its name.125*/126const ec_str_params *the_curve_const_parameters;127128nn_k.magic = WORD(0);129A.magic = B.magic = C.magic = D.magic = WORD(0);130TMP.magic = T.magic = WORD(0);131132MUST_HAVE((curve_name != NULL), ret, err);133134ret = local_strnlen((const char *)curve_name, MAX_CURVE_NAME_LEN, &len); EG(ret, err);135len += 1;136MUST_HAVE((len < 256), ret, err);137ret = ec_get_curve_params_by_name(curve_name,138(u8)len, &the_curve_const_parameters); EG(ret, err);139140141/* Get out if getting the parameters went wrong */142if (the_curve_const_parameters == NULL) {143ext_printf("Error: error when importing curve %s "144"parameters ...\n", curve_name);145ret = -1;146goto err;147}148/* Now map the curve parameters to our libecc internal representation */149ret = import_params(&curve_params, the_curve_const_parameters); EG(ret, err);150/* Get two random points on the curve */151ret = get_random_point_on_curve(&curve_params, &A); EG(ret, err);152ret = get_random_point_on_curve(&curve_params, &B); EG(ret, err);153154/*155* Let's add the two points156* C = A + B with regular point addition157*/158ret = prj_pt_add(&C, &A, &B); EG(ret, err);159160/*161* Check that the resulting additive point C = A+B is indeed on the162* curve.163*/164ret = prj_pt_to_aff(&T, &C); EG(ret, err);165ret = prj_pt_is_on_curve(&C, &is_oncurve); EG(ret, err);166if (!is_oncurve) {167ext_printf("Error: C = A+B is not on the %s curve!\n",168curve_params.curve_name);169ret = -1;170goto err;171}172ret = aff_pt_is_on_curve(&T, &is_oncurve); EG(ret, err);173if (!is_oncurve) {174ext_printf("Error: C = A+B is not on the %s curve!\n",175curve_params.curve_name);176ret = -1;177goto err;178}179/* Same check with doubling180* C = 2A = A+A181*/182ret = prj_pt_dbl(&C, &A); EG(ret, err);183184/* Check that the resulting point C = 2A is indeed on the curve.185*186*/187ret = prj_pt_to_aff(&T, &C); EG(ret, err);188ret = prj_pt_is_on_curve(&C, &is_oncurve); EG(ret, err);189if (!is_oncurve) {190ext_printf("Error: C = A+B is not on the %s curve!\n",191curve_params.curve_name);192ret = -1;193goto err;194}195ret = aff_pt_is_on_curve(&T, &is_oncurve); EG(ret, err);196if (!is_oncurve) {197ext_printf("Error: C = A+B is not on the %s curve!\n",198curve_params.curve_name);199ret = -1;200goto err;201}202/*203* If the cofactor of the curve is 1, this means that the order of the204* generator is the cardinal of the curve (and hence the order of the205* curve points group). This means that for any point P on the curve,206* we should have qP = 0 (the inifinity point, i.e. the zero neutral207* element of the curve additive group).208*/209ret = prj_pt_add(&C, &A, &B); EG(ret, err);210ret = prj_pt_dbl(&D, &A); EG(ret, err);211ret = nn_isone(&(curve_params.ec_gen_cofactor), &isone); EG(ret, err);212if (isone) {213ret = prj_pt_mul(&TMP, &(curve_params.ec_gen_order), &A); EG(ret, err);214ret = prj_pt_iszero(&TMP, &iszero); EG(ret, err);215if (!iszero) {216ext_printf("Error: qA is not 0! (regular mul)\n");217ret = -1;218goto err;219}220/**/221ret = prj_pt_mul_blind(&TMP, &(curve_params.ec_gen_order), &A); EG(ret, err);222ret = prj_pt_iszero(&TMP, &iszero); EG(ret, err);223if (!iszero) {224ext_printf("Error: qA is not 0! (regular blind mul)\n");225ret = -1;226goto err;227}228/**/229ret = prj_pt_mul(&TMP, &(curve_params.ec_gen_order), &B); EG(ret, err);230ret = prj_pt_iszero(&TMP, &iszero); EG(ret, err);231if (!iszero) {232ext_printf("Error: qB is not 0! (regular mul)\n");233ret = -1;234goto err;235}236/**/237ret = prj_pt_mul_blind(&TMP, &(curve_params.ec_gen_order), &B); EG(ret, err);238ret = prj_pt_iszero(&TMP, &iszero); EG(ret, err);239if (!iszero) {240ext_printf("Error: qB is not 0! (regular blind mul)\n");241ret = -1;242goto err;243}244/**/245ret = prj_pt_mul(&TMP, &(curve_params.ec_gen_order), &C); EG(ret, err);246ret = prj_pt_iszero(&TMP, &iszero); EG(ret, err);247if (!iszero) {248ext_printf("Error: qC is not 0! (regular mul)\n");249ret = -1;250goto err;251}252/**/253ret = prj_pt_mul_blind(&TMP, &(curve_params.ec_gen_order), &C); EG(ret, err);254ret = prj_pt_iszero(&TMP, &iszero); EG(ret, err);255if (!iszero) {256ext_printf("Error: qC is not 0! (regular bind mul)\n");257ret = -1;258goto err;259}260/**/261ret = prj_pt_mul(&TMP, &(curve_params.ec_gen_order), &D); EG(ret, err);262ret = prj_pt_iszero(&TMP, &iszero); EG(ret, err);263if (!iszero) {264ext_printf("Error: qD is not 0! (regular mul)\n");265ret = -1;266goto err;267}268/**/269ret = prj_pt_mul_blind(&TMP, &(curve_params.ec_gen_order), &D); EG(ret, err);270ret = prj_pt_iszero(&TMP, &iszero); EG(ret, err);271if (!iszero) {272ext_printf("Error: qD is not 0! (regular blind mul)\n");273ret = -1;274goto err;275}276}277/* Let's do some performance tests for point addition and doubling!278* We compute kA many times to have a decent performance measurement,279* where k is chose random at each iteration. We also check that kA280* is indeed on the curve.281*/282ret = nn_init(&nn_k, 0); EG(ret, err);283/**/284if (get_ms_time(&t1)) {285ext_printf("Error: cannot get time with get_ms_time\n");286ret = -1;287goto err;288}289for (i = 0; i < PERF_SCALAR_MUL; i++) {290/* k = random mod (q) */291ret = nn_get_random_mod(&nn_k, &(curve_params.ec_gen_order)); EG(ret, err);292/* Compute kA with montgomery implementation w/o blinding */293ret = prj_pt_mul(&TMP, &nn_k, &A); EG(ret, err);294ret = prj_pt_to_aff(&T, &TMP); EG(ret, err);295ret = prj_pt_is_on_curve(&TMP, &is_oncurve); EG(ret, err);296if (!is_oncurve) {297ext_printf("Error: kA is not on the %s curve!\n",298curve_params.curve_name);299nn_print("k=", &nn_k);300ret = -1;301goto err;302}303ret = aff_pt_is_on_curve(&T, &is_oncurve); EG(ret, err);304if (!is_oncurve) {305ext_printf("Error: kA is not on the %s curve!\n",306curve_params.curve_name);307nn_print("k=", &nn_k);308ret = -1;309goto err;310}311}312if (get_ms_time(&t2)) {313ext_printf("Error: cannot get time with get_ms_time\n");314ret = -1;315goto err;316}317ext_printf(" [*] Regular EC scalar multiplication took %f seconds "318"on average\n",319(double)(t2 - t1) / (double)(PERF_SCALAR_MUL * 1000ULL));320/**/321if (get_ms_time(&t1)) {322ext_printf("Error: cannot get time with get_ms_time\n");323ret = -1;324goto err;325}326for (i = 0; i < PERF_SCALAR_MUL; i++) {327/* k = random mod (q) */328ret = nn_get_random_mod(&nn_k, &(curve_params.ec_gen_order)); EG(ret, err);329/* Compute kA using montgomery implementation w/ blinding */330ret = prj_pt_mul_blind(&TMP, &nn_k, &A); EG(ret, err);331ret = prj_pt_to_aff(&T, &TMP); EG(ret, err);332ret = prj_pt_is_on_curve(&TMP, &is_oncurve); EG(ret, err);333if (!is_oncurve) {334ext_printf("Error: kA is not on the %s curve!\n",335curve_params.curve_name);336nn_print("k=", &nn_k);337ret = -1;338goto err;339}340ret = aff_pt_is_on_curve(&T, &is_oncurve); EG(ret, err);341if (!is_oncurve) {342ext_printf("Error: kA is not on the %s curve!\n",343curve_params.curve_name);344nn_print("k=", &nn_k);345ret = -1;346goto err;347}348}349if (get_ms_time(&t2)) {350ext_printf("Error: cannot get time with get_ms_time\n");351ret = -1;352goto err;353}354ext_printf(" [*] Regular blind EC scalar multiplication took %f seconds "355"on average\n",356(double)(t2 - t1) / (double)(PERF_SCALAR_MUL * 1000ULL));357358err:359prj_pt_uninit(&A);360prj_pt_uninit(&B);361prj_pt_uninit(&C);362prj_pt_uninit(&D);363prj_pt_uninit(&TMP);364aff_pt_uninit(&T);365nn_uninit(&nn_k);366367return ret;368}369370#ifdef CURVE_BASIC_EXAMPLES371int main(int argc, char *argv[])372{373unsigned int i;374u8 curve_name[MAX_CURVE_NAME_LEN] = { 0 };375FORCE_USED_VAR(argc);376FORCE_USED_VAR(argv);377378/* Traverse all the possible curves we have at our disposal (known curves and379* user defined curves).380*/381for (i = 0; i < EC_CURVES_NUM; i++) {382/* All our possible curves are in ../curves/curves_list.h383* We can get the curve name from its internal type.384*/385if(ec_get_curve_name_by_type(ec_maps[i].type, curve_name,386sizeof(curve_name))){387ext_printf("Error when treating %s\n", curve_name);388return -1;389}390/* Check our curve! */391ext_printf("[+] Checking curve %s\n", curve_name);392if (check_curve(curve_name)) {393ext_printf("Error: error performing check on "394"curve %s\n", curve_name);395return -1;396}397}398return 0;399}400#endif401402403