/*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/nn/nn_add.h>16#include <libecc/nn/nn.h>17/* Use internal API header */18#include "nn_mul.h"1920/*21* Compute out = (in1 * in2) & (2^(WORD_BYTES * wlimits) - 1).22*23* The function is constant time for all sets of parameters of given24* lengths.25*26* Implementation: while most generic library implement some advanced27* algorithm (Karatsuba, Toom-Cook, or FFT based algorithms)28* which provide a performance advantage for large numbers, the code29* below is mainly oriented towards simplicity and readibility. It is30* a direct writing of the naive multiplication algorithm one has31* learned in school.32*33* Portability: in order for the code to be portable, all word by34* word multiplication are actually performed by an helper macro35* on half words.36*37* Note: 'out' is initialized by the function (caller can omit it)38*39* Internal use only. Check on input nn left to the caller.40*41* The function returns 0 on succes, -1 on error.42*/43ATTRIBUTE_WARN_UNUSED_RET static int _nn_mul_low(nn_t out, nn_src_t in1, nn_src_t in2,44u8 wlimit)45{46word_t carry, prod_high, prod_low;47u8 i, j, pos;48int ret;4950/* We have to check that wlimit does not exceed our NN_MAX_WORD_LEN */51MUST_HAVE(((wlimit * WORD_BYTES) <= NN_MAX_BYTE_LEN), ret, err);5253ret = nn_init(out, (u16)(wlimit * WORD_BYTES)); EG(ret, err);5455for (i = 0; i < in1->wlen; i++) {56carry = 0;57pos = 0;5859for (j = 0; j < in2->wlen; j++) {60pos = (u8)(i + j);6162/*63* size of the result provided by the caller may not64* be large enough for what multiplication may65* generate.66*/67if (pos >= wlimit) {68continue;69}7071/*72* Compute the result of the multiplication of73* two words.74*/75WORD_MUL(prod_high, prod_low,76in1->val[i], in2->val[j]);77/*78* And add previous carry.79*/80prod_low = (word_t)(prod_low + carry);81prod_high = (word_t)(prod_high + (prod_low < carry));8283/*84* Add computed word to what we can currently85* find at current position in result.86*/87out->val[pos] = (word_t)(out->val[pos] + prod_low);88carry = (word_t)(prod_high + (out->val[pos] < prod_low));89}9091/*92* What remains in acc_high at end of previous loop should93* be added to next word after pos in result.94*/95if ((pos + 1) < wlimit) {96out->val[pos + 1] = (word_t)(out->val[pos + 1] + carry);97}98}99100err:101return ret;102}103104/* Aliased version. Internal use only. Check on input nn left to the caller */105ATTRIBUTE_WARN_UNUSED_RET static int _nn_mul_low_aliased(nn_t out, nn_src_t in1, nn_src_t in2,106u8 wlimit)107{108nn out_cpy;109int ret;110out_cpy.magic = WORD(0);111112ret = _nn_mul_low(&out_cpy, in1, in2, wlimit); EG(ret, err);113ret = nn_init(out, out_cpy.wlen); EG(ret, err);114ret = nn_copy(out, &out_cpy);115116err:117nn_uninit(&out_cpy);118119return ret;120}121122/* Public version supporting aliasing. */123int nn_mul_low(nn_t out, nn_src_t in1, nn_src_t in2, u8 wlimit)124{125int ret;126127ret = nn_check_initialized(in1); EG(ret, err);128ret = nn_check_initialized(in2); EG(ret, err);129130/* Handle output aliasing */131if ((out == in1) || (out == in2)) {132ret = _nn_mul_low_aliased(out, in1, in2, wlimit);133} else {134ret = _nn_mul_low(out, in1, in2, wlimit);135}136137err:138return ret;139}140141/*142* Compute out = in1 * in2. 'out' is initialized by the function.143* The function returns 0 on success, -1 on error.144*145* Aliasing supported.146*/147int nn_mul(nn_t out, nn_src_t in1, nn_src_t in2)148{149int ret;150151ret = nn_check_initialized(in1); EG(ret, err);152ret = nn_check_initialized(in2); EG(ret, err);153ret = nn_mul_low(out, in1, in2, (u8)(in1->wlen + in2->wlen));154155err:156return ret;157}158159int nn_sqr_low(nn_t out, nn_src_t in, u8 wlimit)160{161return nn_mul_low(out, in, in, wlimit);162}163164/*165* Compute out = in * in. 'out' is initialized by the function.166* The function returns 0 on success, -1 on error.167*168* Aliasing supported.169*/170int nn_sqr(nn_t out, nn_src_t in)171{172return nn_mul(out, in, in);173}174175/*176* Multiply a multiprecision number by a word, i.e. out = in * w. The function177* returns 0 on success, -1 on error.178*179* Aliasing supported.180*/181int nn_mul_word(nn_t out, nn_src_t in, word_t w)182{183nn w_nn;184int ret;185w_nn.magic = WORD(0);186187ret = nn_check_initialized(in); EG(ret, err);188ret = nn_init(&w_nn, WORD_BYTES); EG(ret, err);189w_nn.val[0] = w;190ret = nn_mul(out, in, &w_nn);191192err:193nn_uninit(&w_nn);194195return ret;196}197198199