Path: blob/main/contrib/bearssl/src/int/i31_modpow2.c
39483 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/* see inner.h */27uint32_t28br_i31_modpow_opt(uint32_t *x,29const unsigned char *e, size_t elen,30const uint32_t *m, uint32_t m0i, uint32_t *tmp, size_t twlen)31{32size_t mlen, mwlen;33uint32_t *t1, *t2, *base;34size_t u, v;35uint32_t acc;36int acc_len, win_len;3738/*39* Get modulus size.40*/41mwlen = (m[0] + 63) >> 5;42mlen = mwlen * sizeof m[0];43mwlen += (mwlen & 1);44t1 = tmp;45t2 = tmp + mwlen;4647/*48* Compute possible window size, with a maximum of 5 bits.49* When the window has size 1 bit, we use a specific code50* that requires only two temporaries. Otherwise, for a51* window of k bits, we need 2^k+1 temporaries.52*/53if (twlen < (mwlen << 1)) {54return 0;55}56for (win_len = 5; win_len > 1; win_len --) {57if ((((uint32_t)1 << win_len) + 1) * mwlen <= twlen) {58break;59}60}6162/*63* Everything is done in Montgomery representation.64*/65br_i31_to_monty(x, m);6667/*68* Compute window contents. If the window has size one bit only,69* then t2 is set to x; otherwise, t2[0] is left untouched, and70* t2[k] is set to x^k (for k >= 1).71*/72if (win_len == 1) {73memcpy(t2, x, mlen);74} else {75memcpy(t2 + mwlen, x, mlen);76base = t2 + mwlen;77for (u = 2; u < ((unsigned)1 << win_len); u ++) {78br_i31_montymul(base + mwlen, base, x, m, m0i);79base += mwlen;80}81}8283/*84* We need to set x to 1, in Montgomery representation. This can85* be done efficiently by setting the high word to 1, then doing86* one word-sized shift.87*/88br_i31_zero(x, m[0]);89x[(m[0] + 31) >> 5] = 1;90br_i31_muladd_small(x, 0, m);9192/*93* We process bits from most to least significant. At each94* loop iteration, we have acc_len bits in acc.95*/96acc = 0;97acc_len = 0;98while (acc_len > 0 || elen > 0) {99int i, k;100uint32_t bits;101102/*103* Get the next bits.104*/105k = win_len;106if (acc_len < win_len) {107if (elen > 0) {108acc = (acc << 8) | *e ++;109elen --;110acc_len += 8;111} else {112k = acc_len;113}114}115bits = (acc >> (acc_len - k)) & (((uint32_t)1 << k) - 1);116acc_len -= k;117118/*119* We could get exactly k bits. Compute k squarings.120*/121for (i = 0; i < k; i ++) {122br_i31_montymul(t1, x, x, m, m0i);123memcpy(x, t1, mlen);124}125126/*127* Window lookup: we want to set t2 to the window128* lookup value, assuming the bits are non-zero. If129* the window length is 1 bit only, then t2 is130* already set; otherwise, we do a constant-time lookup.131*/132if (win_len > 1) {133br_i31_zero(t2, m[0]);134base = t2 + mwlen;135for (u = 1; u < ((uint32_t)1 << k); u ++) {136uint32_t mask;137138mask = -EQ(u, bits);139for (v = 1; v < mwlen; v ++) {140t2[v] |= mask & base[v];141}142base += mwlen;143}144}145146/*147* Multiply with the looked-up value. We keep the148* product only if the exponent bits are not all-zero.149*/150br_i31_montymul(t1, x, t2, m, m0i);151CCOPY(NEQ(bits, 0), x, t1, mlen);152}153154/*155* Convert back from Montgomery representation, and exit.156*/157br_i31_from_monty(x, m, m0i);158return 1;159}160161162