Path: blob/main/contrib/bearssl/src/int/i15_muladd.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/*27* Constant-time division. The divisor must not be larger than 16 bits,28* and the quotient must fit on 17 bits.29*/30static uint32_t31divrem16(uint32_t x, uint32_t d, uint32_t *r)32{33int i;34uint32_t q;3536q = 0;37d <<= 16;38for (i = 16; i >= 0; i --) {39uint32_t ctl;4041ctl = LE(d, x);42q |= ctl << i;43x -= (-ctl) & d;44d >>= 1;45}46if (r != NULL) {47*r = x;48}49return q;50}5152/* see inner.h */53void54br_i15_muladd_small(uint16_t *x, uint16_t z, const uint16_t *m)55{56/*57* Constant-time: we accept to leak the exact bit length of the58* modulus m.59*/60unsigned m_bitlen, mblr;61size_t u, mlen;62uint32_t hi, a0, a, b, q;63uint32_t cc, tb, over, under;6465/*66* Simple case: the modulus fits on one word.67*/68m_bitlen = m[0];69if (m_bitlen == 0) {70return;71}72if (m_bitlen <= 15) {73uint32_t rem;7475divrem16(((uint32_t)x[1] << 15) | z, m[1], &rem);76x[1] = rem;77return;78}79mlen = (m_bitlen + 15) >> 4;80mblr = m_bitlen & 15;8182/*83* Principle: we estimate the quotient (x*2^15+z)/m by84* doing a 30/15 division with the high words.85*86* Let:87* w = 2^1588* a = (w*a0 + a1) * w^N + a289* b = b0 * w^N + b290* such that:91* 0 <= a0 < w92* 0 <= a1 < w93* 0 <= a2 < w^N94* w/2 <= b0 < w95* 0 <= b2 < w^N96* a < w*b97* I.e. the two top words of a are a0:a1, the top word of b is98* b0, we ensured that b0 is "full" (high bit set), and a is99* such that the quotient q = a/b fits on one word (0 <= q < w).100*101* If a = b*q + r (with 0 <= r < q), then we can estimate q by102* using a division on the top words:103* a0*w + a1 = b0*u + v (with 0 <= v < b0)104* Then the following holds:105* 0 <= u <= w106* u-2 <= q <= u107*/108hi = x[mlen];109if (mblr == 0) {110a0 = x[mlen];111memmove(x + 2, x + 1, (mlen - 1) * sizeof *x);112x[1] = z;113a = (a0 << 15) + x[mlen];114b = m[mlen];115} else {116a0 = (x[mlen] << (15 - mblr)) | (x[mlen - 1] >> mblr);117memmove(x + 2, x + 1, (mlen - 1) * sizeof *x);118x[1] = z;119a = (a0 << 15) | (((x[mlen] << (15 - mblr))120| (x[mlen - 1] >> mblr)) & 0x7FFF);121b = (m[mlen] << (15 - mblr)) | (m[mlen - 1] >> mblr);122}123q = divrem16(a, b, NULL);124125/*126* We computed an estimate for q, but the real one may be q,127* q-1 or q-2; moreover, the division may have returned a value128* 8000 or even 8001 if the two high words were identical, and129* we want to avoid values beyond 7FFF. We thus adjust q so130* that the "true" multiplier will be q+1, q or q-1, and q is131* in the 0000..7FFF range.132*/133q = MUX(EQ(b, a0), 0x7FFF, q - 1 + ((q - 1) >> 31));134135/*136* We subtract q*m from x (x has an extra high word of value 'hi').137* Since q may be off by 1 (in either direction), we may have to138* add or subtract m afterwards.139*140* The 'tb' flag will be true (1) at the end of the loop if the141* result is greater than or equal to the modulus (not counting142* 'hi' or the carry).143*/144cc = 0;145tb = 1;146for (u = 1; u <= mlen; u ++) {147uint32_t mw, zl, xw, nxw;148149mw = m[u];150zl = MUL15(mw, q) + cc;151cc = zl >> 15;152zl &= 0x7FFF;153xw = x[u];154nxw = xw - zl;155cc += nxw >> 31;156nxw &= 0x7FFF;157x[u] = nxw;158tb = MUX(EQ(nxw, mw), tb, GT(nxw, mw));159}160161/*162* If we underestimated q, then either cc < hi (one extra bit163* beyond the top array word), or cc == hi and tb is true (no164* extra bit, but the result is not lower than the modulus).165*166* If we overestimated q, then cc > hi.167*/168over = GT(cc, hi);169under = ~over & (tb | LT(cc, hi));170br_i15_add(x, m, over);171br_i15_sub(x, m, under);172}173174175