/*1* Copyright (C) 2021 - 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/nn/nn_mul_redc1.h>16#include <libecc/nn/nn_div_public.h>17#include <libecc/nn/nn_logical.h>18#include <libecc/nn/nn_mod_pow.h>19#include <libecc/nn/nn_rand.h>20#include <libecc/nn/nn.h>2122/*23* NOT constant time with regard to the bitlength of exp.24*25* Implements a left to right Montgomery Ladder for modular exponentiation.26* This is an internal common helper and assumes that all the initialization27* and aliasing of inputs/outputs are handled by the callers. Depending on28* the inputs, redcification is optionally used.29* The base is reduced if necessary.30*31* Montgomery Ladder is masked using Itoh et al. anti-ADPA32* (Address-bit DPA) countermeasure.33* See "A Practical Countermeasure against Address-Bit Differential Power Analysis"34* by Itoh, Izu and Takenaka for more information.3536* Returns 0 on success, -1 on error.37*/38ATTRIBUTE_WARN_UNUSED_RET static int _nn_exp_monty_ladder_ltr(nn_t out, nn_src_t base, nn_src_t exp, nn_src_t mod, nn_src_t r, nn_src_t r_square, word_t mpinv)39{40nn T[3];41nn mask;42bitcnt_t explen, oldexplen;43u8 expbit, rbit;44int ret, cmp;45T[0].magic = T[1].magic = T[2].magic = mask.magic = WORD(0);4647/* Initialize out */48ret = nn_init(out, 0); EG(ret, err);4950ret = nn_init(&T[0], 0); EG(ret, err);51ret = nn_init(&T[1], 0); EG(ret, err);52ret = nn_init(&T[2], 0); EG(ret, err);5354/* Generate our Itoh random mask */55ret = nn_get_random_len(&mask, NN_MAX_BYTE_LEN); EG(ret, err);5657ret = nn_bitlen(exp, &explen); EG(ret, err);585960/* From now on, since we deal with Itoh's countermeasure, we must have at61* least 2 bits in the exponent. We will deal with the particular cases of 0 and 162* bit exponents later.63*/64oldexplen = explen;65explen = (explen < 2) ? 2 : explen;6667ret = nn_getbit(&mask, (bitcnt_t)(explen - 1), &rbit); EG(ret, err);6869/* Reduce the base if necessary */70ret = nn_cmp(base, mod, &cmp); EG(ret, err);71if(cmp >= 0){72/* Modular reduction */73ret = nn_mod(&T[rbit], base, mod); EG(ret, err);74if(r != NULL){75/* Redcify the base if necessary */76ret = nn_mul_redc1(&T[rbit], &T[rbit], r_square, mod, mpinv); EG(ret, err);77}78}79else{80if(r != NULL){81/* Redcify the base if necessary */82ret = nn_mul_redc1(&T[rbit], base, r_square, mod, mpinv); EG(ret, err);83}84else{85ret = nn_copy(&T[rbit], base); EG(ret, err);86}87}8889/* We implement the Montgomery ladder exponentiation with Itoh masking using three90* registers T[0], T[1] and T[2]. The random mask is in 'mask'.91*/92if(r != NULL){93ret = nn_mul_redc1(&T[1-rbit], &T[rbit], &T[rbit], mod, mpinv); EG(ret, err);94}95else{96ret = nn_mod_mul(&T[1-rbit], &T[rbit], &T[rbit], mod); EG(ret, err);97}9899/* Now proceed with the Montgomery Ladder algorithm.100*/101explen = (bitcnt_t)(explen - 1);102while (explen > 0) {103u8 rbit_next;104explen = (bitcnt_t)(explen - 1);105106/* rbit is r[i+1], and rbit_next is r[i] */107ret = nn_getbit(&mask, explen, &rbit_next); EG(ret, err);108/* Get the exponent bit */109ret = nn_getbit(exp, explen, &expbit); EG(ret, err);110111/* Square */112if(r != NULL){113ret = nn_mul_redc1(&T[2], &T[expbit ^ rbit], &T[expbit ^ rbit], mod, mpinv); EG(ret, err);114}115else{116ret = nn_mod_mul(&T[2], &T[expbit ^ rbit], &T[expbit ^ rbit], mod); EG(ret, err);117}118/* Multiply */119if(r != NULL){120ret = nn_mul_redc1(&T[1], &T[0], &T[1], mod, mpinv); EG(ret, err);121}122else{123ret = nn_mod_mul(&T[1], &T[0], &T[1], mod); EG(ret, err);124}125/* Copy */126ret = nn_copy(&T[0], &T[2 - (expbit ^ rbit_next)]); EG(ret, err);127ret = nn_copy(&T[1], &T[1 + (expbit ^ rbit_next)]); EG(ret, err);128/* Update rbit */129rbit = rbit_next;130}131ret = nn_one(&T[1 - rbit]);132if(r != NULL){133/* Unredcify in out */134ret = nn_mul_redc1(&T[rbit], &T[rbit], &T[1 - rbit], mod, mpinv); EG(ret, err);135}136137/* Deal with the particular cases of 0 and 1 bit exponents */138/* Case with 0 bit exponent: T[1 - rbit] contains 1 modulo mod */139ret = nn_mod(&T[1 - rbit], &T[1 - rbit], mod); EG(ret, err);140/* Case with 1 bit exponent */141ret = nn_mod(&T[2], base, mod); EG(ret, err);142/* Proceed with the output */143ret = nn_cnd_swap((oldexplen == 0), out, &T[1 - rbit]);144ret = nn_cnd_swap((oldexplen == 1), out, &T[2]);145ret = nn_cnd_swap(((oldexplen != 0) && (oldexplen != 1)), out, &T[rbit]);146147err:148nn_uninit(&T[0]);149nn_uninit(&T[1]);150nn_uninit(&T[2]);151nn_uninit(&mask);152153return ret;154}155156/*157* NOT constant time with regard to the bitlength of exp.158*159* Reduces the base modulo mod if it is not already reduced,160* which is also a small divergence wrt constant time leaking161* the information that base <= mod or not: please use with care162* in the callers if this information is sensitive.163*164* Aliasing not supported. Expects caller to check parameters165* have been initialized. This is an internal helper.166*167* Compute (base ** exp) mod (mod) using a Montgomery Ladder algorithm168* with Montgomery redcification, hence the Montgomery coefficients as input.169* The module "mod" is expected to be odd for redcification to be used.170*171* Returns 0 on success, -1 on error.172*/173ATTRIBUTE_WARN_UNUSED_RET static int _nn_mod_pow_redc(nn_t out, nn_src_t base, nn_src_t exp, nn_src_t mod, nn_src_t r, nn_src_t r_square, word_t mpinv)174{175return _nn_exp_monty_ladder_ltr(out, base, exp, mod, r, r_square, mpinv);176}177178/*179* NOT constant time with regard to the bitlength of exp.180*181* Reduces the base modulo mod if it is not already reduced,182* which is also a small divergence wrt constant time leaking183* the information that base <= mod or not: please use with care184* in the callers if this information is sensitive.185*186* Aliasing is supported. Expects caller to check parameters187* have been initialized. This is an internal helper.188*189* Compute (base ** exp) mod (mod) using a Montgomery Ladder algorithm.190* This function works for all values of "mod", but is slower that the one191* using Montgomery multiplication (which only works for odd "mod"). Hence,192* it is only used on even "mod" by upper layers.193*194* Returns 0 on success, -1 on error.195*/196ATTRIBUTE_WARN_UNUSED_RET static int _nn_mod_pow(nn_t out, nn_src_t base, nn_src_t exp, nn_src_t mod)197{198int ret;199200if ((out == base) || (out == exp) || (out == mod)) {201nn _out;202_out.magic = WORD(0);203204ret = nn_init(&_out, 0); EG(ret, err);205ret = _nn_exp_monty_ladder_ltr(&_out, base, exp, mod, NULL, NULL, WORD(0)); EG(ret, err);206ret = nn_copy(out, &_out);207}208else{209ret = _nn_exp_monty_ladder_ltr(out, base, exp, mod, NULL, NULL, WORD(0));210}211212err:213return ret;214}215216/*217* Same purpose as above but handles aliasing.218* Expects caller to check parameters219* have been initialized. This is an internal helper.220*/221ATTRIBUTE_WARN_UNUSED_RET static int _nn_mod_pow_redc_aliased(nn_t out, nn_src_t base, nn_src_t exp, nn_src_t mod, nn_src_t r, nn_src_t r_square, word_t mpinv)222{223nn _out;224int ret;225_out.magic = WORD(0);226227ret = nn_init(&_out, 0); EG(ret, err);228ret = _nn_mod_pow_redc(&_out, base, exp, mod, r, r_square, mpinv); EG(ret, err);229ret = nn_copy(out, &_out);230231err:232nn_uninit(&_out);233234return ret;235}236237/* Aliased version of previous one.238* NOTE: our nn_mod_pow_redc primitives suppose that the modulo is odd for Montgomery multiplication239* primitives to provide consistent results.240*241* Aliasing is supported.242*/243int nn_mod_pow_redc(nn_t out, nn_src_t base, nn_src_t exp, nn_src_t mod, nn_src_t r, nn_src_t r_square, word_t mpinv)244{245int ret, isodd;246247ret = nn_check_initialized(base); EG(ret, err);248ret = nn_check_initialized(exp); EG(ret, err);249ret = nn_check_initialized(mod); EG(ret, err);250ret = nn_check_initialized(r); EG(ret, err);251ret = nn_check_initialized(r_square); EG(ret, err);252253/* Check that we have an odd number for our modulo */254ret = nn_isodd(mod, &isodd); EG(ret, err);255MUST_HAVE(isodd, ret, err);256257/* Handle the case where our prime is less than two words size.258* We need it to be >= 2 words size for the Montgomery multiplication to be259* usable.260*/261if(mod->wlen < 2){262/* Local copy our modulo */263nn _mod;264_mod.magic = WORD(0);265266/* And set its length accordingly */267ret = nn_copy(&_mod, mod); EG(ret, err1);268ret = nn_set_wlen(&_mod, 2); EG(ret, err1);269/* Handle output aliasing */270if ((out == base) || (out == exp) || (out == mod) || (out == r) || (out == r_square)) {271ret = _nn_mod_pow_redc_aliased(out, base, exp, &_mod, r, r_square, mpinv); EG(ret, err1);272} else {273ret = _nn_mod_pow_redc(out, base, exp, &_mod, r, r_square, mpinv); EG(ret, err1);274}275err1:276nn_uninit(&_mod);277EG(ret, err);278}279else{280/* Handle output aliasing */281if ((out == base) || (out == exp) || (out == mod) || (out == r) || (out == r_square)) {282ret = _nn_mod_pow_redc_aliased(out, base, exp, mod, r, r_square, mpinv);283} else {284ret = _nn_mod_pow_redc(out, base, exp, mod, r, r_square, mpinv);285}286}287288err:289return ret;290}291292293/*294* NOT constant time with regard to the bitlength of exp.295* Aliasing is supported.296*297* Compute (base ** exp) mod (mod) using a Montgomery Ladder algorithm.298* Internally, this computes Montgomery coefficients and uses the redc299* function.300*301* Returns 0 on success, -1 on error.302*/303int nn_mod_pow(nn_t out, nn_src_t base, nn_src_t exp, nn_src_t mod)304{305nn r, r_square;306word_t mpinv;307int ret, isodd;308r.magic = r_square.magic = WORD(0);309310/* Handle the case where our modulo is even: in this case, we cannot311* use our Montgomery multiplication primitives as they are only suitable312* for odd numbers. We fallback to less efficient regular modular exponentiation.313*/314ret = nn_isodd(mod, &isodd); EG(ret, err);315if(!isodd){316/* mod is even: use the regular unoptimized modular exponentiation */317ret = _nn_mod_pow(out, base, exp, mod);318}319else{320/* mod is odd */321/* Compute the Montgomery coefficients */322ret = nn_compute_redc1_coefs(&r, &r_square, mod, &mpinv); EG(ret, err);323324/* Now use the redc version */325ret = nn_mod_pow_redc(out, base, exp, mod, &r, &r_square, mpinv);326}327328err:329nn_uninit(&r);330nn_uninit(&r_square);331332return ret;333}334335336