LCOV - code coverage report
Current view: top level - common/src - bigdigits.c (source / functions) Hit Total Coverage
Test: powHSM firmware Lines: 225 305 73.8 %
Date: 2025-07-10 13:49:13 Functions: 17 17 100.0 %

          Line data    Source code
       1             : /**
       2             :  * The MIT License (MIT)
       3             :  *
       4             :  * Copyright (c) 2021 RSK Labs Ltd
       5             :  *
       6             :  * Permission is hereby granted, free of charge, to any person obtaining a copy
       7             :  * of this software and associated documentation files (the "Software"), to
       8             :  * deal in the Software without restriction, including without limitation the
       9             :  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
      10             :  * sell copies of the Software, and to permit persons to whom the Software is
      11             :  * furnished to do so, subject to the following conditions:
      12             :  *
      13             :  * The above copyright notice and this permission notice shall be included in
      14             :  * all copies or substantial portions of the Software.
      15             :  *
      16             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      17             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      18             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      19             :  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      20             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      21             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
      22             :  * IN THE SOFTWARE.
      23             :  */
      24             : 
      25             : /* $Id: bigdigits.c $ */
      26             : 
      27             : /***** BEGIN LICENSE BLOCK *****
      28             :  *
      29             :  * This Source Code Form is subject to the terms of the Mozilla Public
      30             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
      31             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
      32             :  *
      33             :  * Copyright (c) 2001-16 David Ireland, D.I. Management Services Pty Limited
      34             :  * <http://www.di-mgt.com.au/bigdigits.html>. All rights reserved.
      35             :  *
      36             :  ***** END LICENSE BLOCK *****/
      37             : /*
      38             :  * Last updated:
      39             :  * $Date: 2016-03-31 09:51:00 $
      40             :  * $Revision: 2.6.1 $
      41             :  * $Author: dai $
      42             :  */
      43             : 
      44             : /* Core code for BigDigits library "mp" functions */
      45             : 
      46             : /* No asserts in stripped down version of this library */
      47             : #define assert(x)
      48             : 
      49             : #include "bigdigits.h"
      50             : 
      51             : #define BITS_PER_HALF_DIGIT (BITS_PER_DIGIT / 2)
      52             : #define LOHALF(x) ((DIGIT_T)((x) & MAX_HALF_DIGIT))
      53             : #define HIHALF(x) ((DIGIT_T)((x) >> BITS_PER_HALF_DIGIT & MAX_HALF_DIGIT))
      54             : #define TOHIGH(x) ((DIGIT_T)((x) << BITS_PER_HALF_DIGIT))
      55             : 
      56        1491 : DIGIT_T mpSetZero(volatile DIGIT_T a[], size_t ndigits)
      57             : {    /* Sets a = 0 */
      58             : 
      59             :     /* Prevent optimiser ignoring this */
      60             :     volatile DIGIT_T optdummy;
      61        1491 :     volatile DIGIT_T *p = a;
      62             : 
      63       14914 :     while (ndigits--)
      64       13423 :         a[ndigits] = 0;
      65             :     
      66        1491 :     optdummy = *p;
      67        1491 :     return optdummy;
      68             : }
      69             : 
      70         833 : void mpSetDigit(DIGIT_T a[], DIGIT_T d, size_t ndigits)
      71             : {    /* Sets a = d where d is a single digit */
      72             :     size_t i;
      73             :     
      74        7497 :     for (i = 1; i < ndigits; i++)
      75             :     {
      76        6664 :         a[i] = 0;
      77             :     }
      78         833 :     a[0] = d;
      79         833 : }
      80             : 
      81             : /** Returns number of significant digits in a */
      82         710 : size_t mpSizeof(const DIGIT_T a[], size_t ndigits)
      83             : {        
      84        3168 :     while(ndigits--)
      85             :     {
      86        3168 :         if (a[ndigits] != 0)
      87         710 :             return (++ndigits);
      88             :     }
      89           0 :     return 0;
      90             : }
      91             : 
      92          38 : void mpSetEqual(DIGIT_T a[], const DIGIT_T b[], size_t ndigits)
      93             : {    /* Sets a = b */
      94             :     size_t i;
      95             :     
      96         380 :     for (i = 0; i < ndigits; i++)
      97             :     {
      98         342 :         a[i] = b[i];
      99             :     }
     100          38 : }
     101             : 
     102         228 : DIGIT_T mpAdd(DIGIT_T w[], const DIGIT_T u[], const DIGIT_T v[], size_t ndigits)
     103             : {
     104             :     /*    Calculates w = u + v
     105             :         where w, u, v are multiprecision integers of ndigits each
     106             :         Returns carry if overflow. Carry = 0 or 1.
     107             : 
     108             :         Ref: Knuth Vol 2 Ch 4.3.1 p 266 Algorithm A.
     109             :     */
     110             : 
     111             :     DIGIT_T k;
     112             :     size_t j;
     113             : 
     114             :     /*     w can't be the same as v
     115             :         Stop if assert is working, else return error (overflow = -1)
     116             :     */
     117         228 :     if (w == v) {
     118             :         assert(w != v);
     119           0 :         return MAX_DIGIT;
     120             :     }
     121             : 
     122             :     /* Step A1. Initialise */
     123         228 :     k = 0;
     124             : 
     125        2280 :     for (j = 0; j < ndigits; j++)
     126             :     {
     127             :         /*    Step A2. Add digits w_j = (u_j + v_j + k)
     128             :             Set k = 1 if carry (overflow) occurs
     129             :         */
     130        2052 :         w[j] = u[j] + k;
     131        2052 :         if (w[j] < k)
     132           0 :             k = 1;
     133             :         else
     134        2052 :             k = 0;
     135             :         
     136        2052 :         w[j] += v[j];
     137        2052 :         if (w[j] < v[j])
     138         238 :             k++;
     139             : 
     140             :     }    /* Step A3. Loop on j */
     141             : 
     142         228 :     return k;    /* w_n = k */
     143             : }
     144             : 
     145          22 : static int QhatTooBig(DIGIT_T qhat, DIGIT_T rhat,
     146             :                       DIGIT_T vn2, DIGIT_T ujn2)
     147             : {    /*    Returns true if Qhat is too big
     148             :         i.e. if (Qhat * Vn-2) > (b.Rhat + Uj+n-2)
     149             :     */
     150             :     DIGIT_T t[2];
     151             : 
     152          22 :     spMultiply(t, qhat, vn2);
     153          22 :     if (t[1] < rhat)
     154          22 :         return 0;
     155           0 :     else if (t[1] > rhat)
     156           0 :         return 1;
     157           0 :     else if (t[0] > ujn2)
     158           0 :         return 1;
     159             : 
     160           0 :     return 0;
     161             : }
     162             : 
     163          44 : static DIGIT_T mpMultSub(DIGIT_T wn, DIGIT_T w[], const DIGIT_T v[],
     164             :                        DIGIT_T q, size_t n)
     165             : {    /*    Compute w = w - qv
     166             :         where w = (WnW[n-1]...W[0])
     167             :         return modified Wn.
     168             :     */
     169             :     DIGIT_T k, t[2];
     170             :     size_t i;
     171             : 
     172          44 :     if (q == 0)    /* No change */
     173          22 :         return wn;
     174             : 
     175          22 :     k = 0;
     176             : 
     177         198 :     for (i = 0; i < n; i++)
     178             :     {
     179         176 :         spMultiply(t, q, v[i]);
     180         176 :         w[i] -= k;
     181         176 :         if (w[i] > MAX_DIGIT - k)
     182           0 :             k = 1;
     183             :         else
     184         176 :             k = 0;
     185         176 :         w[i] -= t[0];
     186         176 :         if (w[i] > MAX_DIGIT - t[0])
     187         149 :             k++;
     188         176 :         k += t[1];
     189             :     }
     190             : 
     191             :     /* Cope with Wn not stored in array w[0..n-1] */
     192          22 :     wn -= k;
     193             : 
     194          22 :     return wn;
     195             : }
     196             : 
     197         355 : int mpDivide(DIGIT_T q[], DIGIT_T r[], const DIGIT_T u[],
     198             :     size_t udigits, DIGIT_T v[], size_t vdigits)
     199             : {    /*    Computes quotient q = u / v and remainder r = u mod v
     200             :         where q, r, u are multiple precision digits
     201             :         all of udigits and the divisor v is vdigits.
     202             : 
     203             :         Ref: Knuth Vol 2 Ch 4.3.1 p 272 Algorithm D.
     204             : 
     205             :         Do without extra storage space, i.e. use r[] for
     206             :         normalised u[], unnormalise v[] at end, and cope with
     207             :         extra digit Uj+n added to u after normalisation.
     208             : 
     209             :         WARNING: this trashes q and r first, so cannot do
     210             :         u = u / v or v = u mod v.
     211             :         It also changes v temporarily so cannot make it const.
     212             :     */
     213             :     size_t shift;
     214             :     int n, m, j;
     215             :     DIGIT_T bitmask, overflow;
     216             :     DIGIT_T qhat, rhat, t[2];
     217             :     DIGIT_T *uu, *ww;
     218             :     int qhatOK, cmp;
     219             : 
     220             :     /* Clear q and r */
     221         355 :     mpSetZero(q, udigits);
     222         355 :     mpSetZero(r, udigits);
     223             : 
     224             :     /* Work out exact sizes of u and v */
     225         355 :     n = (int)mpSizeof(v, vdigits);
     226         355 :     m = (int)mpSizeof(u, udigits);
     227         355 :     m -= n;
     228             : 
     229             :     /* Catch special cases */
     230         355 :     if (n == 0)
     231           0 :         return -1;    /* Error: divide by zero */
     232             : 
     233         355 :     if (n == 1)
     234             :     {    /* Use short division instead */
     235         295 :         r[0] = mpShortDiv(q, u, v[0], udigits);
     236         295 :         return 0;
     237             :     }
     238             : 
     239          60 :     if (m < 0)
     240             :     {    /* v > u, so just set q = 0 and r = u */
     241           0 :         mpSetEqual(r, u, udigits);
     242           0 :         return 0;
     243             :     }
     244             : 
     245          60 :     if (m == 0)
     246             :     {    /* u and v are the same length */
     247          38 :         cmp = mpCompare(u, v, (size_t)n);
     248          38 :         if (cmp < 0)
     249             :         {    /* v > u, as above */
     250          38 :             mpSetEqual(r, u, udigits);
     251          38 :             return 0;
     252             :         }
     253           0 :         else if (cmp == 0)
     254             :         {    /* v == u, so set q = 1 and r = 0 */
     255           0 :             mpSetDigit(q, 1, udigits);
     256           0 :             return 0;
     257             :         }
     258             :     }
     259             : 
     260             :     /*    In Knuth notation, we have:
     261             :         Given
     262             :         u = (Um+n-1 ... U1U0)
     263             :         v = (Vn-1 ... V1V0)
     264             :         Compute
     265             :         q = u/v = (QmQm-1 ... Q0)
     266             :         r = u mod v = (Rn-1 ... R1R0)
     267             :     */
     268             : 
     269             :     /*    Step D1. Normalise */
     270             :     /*    Requires high bit of Vn-1
     271             :         to be set, so find most signif. bit then shift left,
     272             :         i.e. d = 2^shift, u' = u * d, v' = v * d.
     273             :     */
     274          22 :     bitmask = HIBITMASK;
     275          22 :     for (shift = 0; shift < BITS_PER_DIGIT; shift++)
     276             :     {
     277          22 :         if (v[n-1] & bitmask)
     278          22 :             break;
     279           0 :         bitmask >>= 1;
     280             :     }
     281             : 
     282             :     /* Normalise v in situ - NB only shift non-zero digits */
     283          22 :     overflow = mpShiftLeft(v, v, shift, n);
     284             : 
     285             :     /* Copy normalised dividend u*d into r */
     286          22 :     overflow = mpShiftLeft(r, u, shift, n + m);
     287          22 :     uu = r;    /* Use ptr to keep notation constant */
     288             : 
     289          22 :     t[0] = overflow;    /* Extra digit Um+n */
     290             : 
     291             :     /* Step D2. Initialise j. Set j = m */
     292          66 :     for (j = m; j >= 0; j--)
     293             :     {
     294             :         /* Step D3. Set Qhat = [(b.Uj+n + Uj+n-1)/Vn-1] 
     295             :            and Rhat = remainder */
     296          44 :         qhatOK = 0;
     297          44 :         t[1] = t[0];    /* This is Uj+n */
     298          44 :         t[0] = uu[j+n-1];
     299          44 :         overflow = spDivide(&qhat, &rhat, t, v[n-1]);
     300             : 
     301             :         /* Test Qhat */
     302          44 :         if (overflow)
     303             :         {    /* Qhat == b so set Qhat = b - 1 */
     304           0 :             qhat = MAX_DIGIT;
     305           0 :             rhat = uu[j+n-1];
     306           0 :             rhat += v[n-1];
     307           0 :             if (rhat < v[n-1])    /* Rhat >= b, so no re-test */
     308           0 :                 qhatOK = 1;
     309             :         }
     310             :         /* [VERSION 2: Added extra test "qhat && "] */
     311          44 :         if (qhat && !qhatOK && QhatTooBig(qhat, rhat, v[n-2], uu[j+n-2]))
     312             :         {    /* If Qhat.Vn-2 > b.Rhat + Uj+n-2 
     313             :                decrease Qhat by one, increase Rhat by Vn-1
     314             :             */
     315           0 :             qhat--;
     316           0 :             rhat += v[n-1];
     317             :             /* Repeat this test if Rhat < b */
     318           0 :             if (!(rhat < v[n-1]))
     319           0 :                 if (QhatTooBig(qhat, rhat, v[n-2], uu[j+n-2]))
     320           0 :                     qhat--;
     321             :         }
     322             : 
     323             : 
     324             :         /* Step D4. Multiply and subtract */
     325          44 :         ww = &uu[j];
     326          44 :         overflow = mpMultSub(t[1], ww, v, qhat, (size_t)n);
     327             : 
     328             :         /* Step D5. Test remainder. Set Qj = Qhat */
     329          44 :         q[j] = qhat;
     330          44 :         if (overflow)
     331             :         {    /* Step D6. Add back if D4 was negative */
     332           0 :             q[j]--;
     333           0 :             overflow = mpAdd(ww, ww, v, (size_t)n);
     334             :         }
     335             : 
     336          44 :         t[0] = uu[j+n-1];    /* Uj+n on next round */
     337             : 
     338             :     }    /* Step D7. Loop on j */
     339             : 
     340             :     /* Clear high digits in uu */
     341          44 :     for (j = n; j < m+n; j++)
     342          22 :         uu[j] = 0;
     343             : 
     344             :     /* Step D8. Unnormalise. */
     345             : 
     346          22 :     mpShiftRight(r, r, shift, n);
     347          22 :     mpShiftRight(v, v, shift, n);
     348             : 
     349          22 :     return 0;
     350             : }
     351             : 
     352         295 : DIGIT_T mpShortDiv(DIGIT_T q[], const DIGIT_T u[], DIGIT_T v, 
     353             :                    size_t ndigits)
     354             : {
     355             :     /*    Calculates quotient q = u div v
     356             :         Returns remainder r = u mod v
     357             :         where q, u are multiprecision integers of ndigits each
     358             :         and r, v are single precision digits.
     359             : 
     360             :         Makes no assumptions about normalisation.
     361             :         
     362             :         Ref: Knuth Vol 2 Ch 4.3.1 Exercise 16 p625
     363             :     */
     364             :     size_t j;
     365             :     DIGIT_T t[2], r;
     366             :     size_t shift;
     367             :     DIGIT_T bitmask, overflow, *uu;
     368             : 
     369         295 :     if (ndigits == 0) return 0;
     370         295 :     if (v == 0)    return 0;    /* Divide by zero error */
     371             : 
     372             :     /*    Normalise first */
     373             :     /*    Requires high bit of V
     374             :         to be set, so find most signif. bit then shift left,
     375             :         i.e. d = 2^shift, u' = u * d, v' = v * d.
     376             :     */
     377         295 :     bitmask = HIBITMASK;
     378        9017 :     for (shift = 0; shift < BITS_PER_DIGIT; shift++)
     379             :     {
     380        9017 :         if (v & bitmask)
     381         295 :             break;
     382        8722 :         bitmask >>= 1;
     383             :     }
     384             : 
     385         295 :     v <<= shift;
     386         295 :     overflow = mpShiftLeft(q, u, shift, ndigits);
     387         295 :     uu = q;
     388             :     
     389             :     /* Step S1 - modified for extra digit. */
     390         295 :     r = overflow;    /* New digit Un */
     391         295 :     j = ndigits;
     392        2950 :     while (j--)
     393             :     {
     394             :         /* Step S2. */
     395        2655 :         t[1] = r;
     396        2655 :         t[0] = uu[j];
     397        2655 :         overflow = spDivide(&q[j], &r, t, v);
     398             :     }
     399             : 
     400             :     /* Unnormalise */
     401         295 :     r >>= shift;
     402             :     
     403         295 :     return r;
     404             : }
     405             : 
     406         339 : DIGIT_T mpShiftLeft(DIGIT_T a[], const DIGIT_T *b,
     407             :     size_t shift, size_t ndigits)
     408             : {    /* Computes a = b << shift */
     409             :     /* [v2.1] Modified to cope with shift > BITS_PERDIGIT */
     410             :     size_t i, y, nw, bits;
     411             :     DIGIT_T mask, carry, nextcarry;
     412             : 
     413             :     /* Do we shift whole digits? */
     414         339 :     if (shift >= BITS_PER_DIGIT)
     415             :     {
     416           0 :         nw = shift / BITS_PER_DIGIT;
     417           0 :         i = ndigits;
     418           0 :         while (i--)
     419             :         {
     420           0 :             if (i >= nw)
     421           0 :                 a[i] = b[i-nw];
     422             :             else
     423           0 :                 a[i] = 0;
     424             :         }
     425             :         /* Call again to shift bits inside digits */
     426           0 :         bits = shift % BITS_PER_DIGIT;
     427           0 :         carry = b[ndigits-nw] << bits;
     428           0 :         if (bits) 
     429           0 :             carry |= mpShiftLeft(a, a, bits, ndigits);
     430           0 :         return carry;
     431             :     }
     432             :     else
     433             :     {
     434         339 :         bits = shift;
     435             :     }
     436             : 
     437             :     /* Construct mask = high bits set */
     438         339 :     mask = ~(~(DIGIT_T)0 >> bits);
     439             :     
     440         339 :     y = BITS_PER_DIGIT - bits;
     441         339 :     carry = 0;
     442        3368 :     for (i = 0; i < ndigits; i++)
     443             :     {
     444        3029 :         nextcarry = (b[i] & mask) >> y;
     445        3029 :         a[i] = b[i] << bits | carry;
     446        3029 :         carry = nextcarry;
     447             :     }
     448             : 
     449         339 :     return carry;
     450             : }
     451             : 
     452          44 : DIGIT_T mpShiftRight(DIGIT_T a[], const DIGIT_T b[], size_t shift, size_t ndigits)
     453             : {    /* Computes a = b >> shift */
     454             :     /* [v2.1] Modified to cope with shift > BITS_PERDIGIT */
     455             :     size_t i, y, nw, bits;
     456             :     DIGIT_T mask, carry, nextcarry;
     457             : 
     458             :     /* Do we shift whole digits? */
     459          44 :     if (shift >= BITS_PER_DIGIT)
     460             :     {
     461           0 :         nw = shift / BITS_PER_DIGIT;
     462           0 :         for (i = 0; i < ndigits; i++)
     463             :         {
     464           0 :             if ((i+nw) < ndigits)
     465           0 :                 a[i] = b[i+nw];
     466             :             else
     467           0 :                 a[i] = 0;
     468             :         }
     469             :         /* Call again to shift bits inside digits */
     470           0 :         bits = shift % BITS_PER_DIGIT;
     471           0 :         carry = b[nw-1] >> bits;
     472           0 :         if (bits) 
     473           0 :             carry |= mpShiftRight(a, a, bits, ndigits);
     474           0 :         return carry;
     475             :     }
     476             :     else
     477             :     {
     478          44 :         bits = shift;
     479             :     }
     480             : 
     481             :     /* Construct mask to set low bits */
     482             :     /* (thanks to Jesse Chisholm for suggesting this improved technique) */
     483          44 :     mask = ~(~(DIGIT_T)0 << bits);
     484             :     
     485          44 :     y = BITS_PER_DIGIT - bits;
     486          44 :     carry = 0;
     487          44 :     i = ndigits;
     488         396 :     while (i--)
     489             :     {
     490         352 :         nextcarry = (b[i] & mask) << y;
     491         352 :         a[i] = b[i] >> bits | carry;
     492         352 :         carry = nextcarry;
     493             :     }
     494             : 
     495          44 :     return carry;
     496             : }
     497             : 
     498             : /** Returns sign of (a - b) as 0, +1 or -1 (constant-time) */
     499        1094 : int mpCompare_ct(const DIGIT_T a[], const DIGIT_T b[], size_t ndigits)
     500             : {
     501             :     /* All these vars are either 0 or 1 */
     502        1094 :     unsigned int gt = 0;
     503        1094 :     unsigned int lt = 0;
     504        1094 :     unsigned int mask = 1;    /* Set to zero once first inequality found */
     505             :     unsigned int c;
     506             : 
     507       10940 :     while (ndigits--) {
     508        9846 :         gt |= (a[ndigits] > b[ndigits]) & mask;
     509        9846 :         lt |= (a[ndigits] < b[ndigits]) & mask;
     510        9846 :         c = (gt | lt);
     511        9846 :         mask &= (c-1);    /* Unchanged if c==0 or mask==0, else mask=0 */
     512             :     }
     513             : 
     514        1094 :     return (int)gt - (int)lt;    /* EQ=0 GT=+1 LT=-1 */
     515             : }
     516             : 
     517             : /** Returns sign of (a - b) as 0, +1 or -1. Not constant-time. */
     518          38 : int mpCompare(const DIGIT_T a[], const DIGIT_T b[], size_t ndigits)
     519             : {
     520             :     /* if (ndigits == 0) return 0; // deleted [v2.5] */
     521             : 
     522          38 :     while (ndigits--)
     523             :     {
     524          38 :         if (a[ndigits] > b[ndigits])
     525           0 :             return 1;    /* GT */
     526          38 :         if (a[ndigits] < b[ndigits])
     527          38 :             return -1;    /* LT */
     528             :     }
     529             : 
     530           0 :     return 0;    /* EQ */
     531             : }
     532             : 
     533         198 : int spMultiply(DIGIT_T p[2], DIGIT_T x, DIGIT_T y)
     534             : {    /*    Computes p = x * y */
     535             :     /*    Ref: Arbitrary Precision Computation
     536             :     http://numbers.computation.free.fr/Constants/constants.html
     537             : 
     538             :          high    p1                p0     low
     539             :         +--------+--------+--------+--------+
     540             :         |      x1*y1      |      x0*y0      |
     541             :         +--------+--------+--------+--------+
     542             :                +-+--------+--------+
     543             :                |1| (x0*y1 + x1*y1) |
     544             :                +-+--------+--------+
     545             :                 ^carry from adding (x0*y1+x1*y1) together
     546             :                         +-+
     547             :                         |1|< carry from adding LOHALF t
     548             :                         +-+  to high half of p0
     549             :     */
     550             :     DIGIT_T x0, y0, x1, y1;
     551             :     DIGIT_T t, u, carry;
     552             : 
     553             :     /*    Split each x,y into two halves
     554             :         x = x0 + B*x1
     555             :         y = y0 + B*y1
     556             :         where B = 2^16, half the digit size
     557             :         Product is
     558             :         xy = x0y0 + B(x0y1 + x1y0) + B^2(x1y1)
     559             :     */
     560             : 
     561         198 :     x0 = LOHALF(x);
     562         198 :     x1 = HIHALF(x);
     563         198 :     y0 = LOHALF(y);
     564         198 :     y1 = HIHALF(y);
     565             : 
     566             :     /* Calc low part - no carry */
     567         198 :     p[0] = x0 * y0;
     568             : 
     569             :     /* Calc middle part */
     570         198 :     t = x0 * y1;
     571         198 :     u = x1 * y0;
     572         198 :     t += u;
     573         198 :     if (t < u)
     574           0 :         carry = 1;
     575             :     else
     576         198 :         carry = 0;
     577             : 
     578             :     /*    This carry will go to high half of p[1]
     579             :         + high half of t into low half of p[1] */
     580         198 :     carry = TOHIGH(carry) + HIHALF(t);
     581             : 
     582             :     /* Add low half of t to high half of p[0] */
     583         198 :     t = TOHIGH(t);
     584         198 :     p[0] += t;
     585         198 :     if (p[0] < t)
     586           0 :         carry++;
     587             : 
     588         198 :     p[1] = x1 * y1;
     589         198 :     p[1] += carry;
     590             : 
     591             : 
     592         198 :     return 0;
     593             : }
     594             : 
     595             : /* spDivide */
     596             : 
     597             : #define B (MAX_HALF_DIGIT + 1)
     598             : 
     599        5398 : static void spMultSub(DIGIT_T uu[2], DIGIT_T qhat, DIGIT_T v1, DIGIT_T v0)
     600             : {
     601             :     /*    Compute uu = uu - q(v1v0) 
     602             :         where uu = u3u2u1u0, u3 = 0
     603             :         and u_n, v_n are all half-digits
     604             :         even though v1, v2 are passed as full digits.
     605             :     */
     606             :     DIGIT_T p0, p1, t;
     607             : 
     608        5398 :     p0 = qhat * v0;
     609        5398 :     p1 = qhat * v1;
     610        5398 :     t = p0 + TOHIGH(LOHALF(p1));
     611        5398 :     uu[0] -= t;
     612        5398 :     if (uu[0] > MAX_DIGIT - t)
     613        4646 :         uu[1]--;    /* Borrow */
     614        5398 :     uu[1] -= HIHALF(p1);
     615        5398 : }
     616             : 
     617        2699 : DIGIT_T spDivide(DIGIT_T *q, DIGIT_T *r, const DIGIT_T u[2], DIGIT_T v)
     618             : {    /*    Computes quotient q = u / v, remainder r = u mod v
     619             :         where u is a double digit
     620             :         and q, v, r are single precision digits.
     621             :         Returns high digit of quotient (max value is 1)
     622             :         CAUTION: Assumes normalised such that v1 >= b/2
     623             :         where b is size of HALF_DIGIT
     624             :         i.e. the most significant bit of v should be one
     625             : 
     626             :         In terms of half-digits in Knuth notation:
     627             :         (q2q1q0) = (u4u3u2u1u0) / (v1v0)
     628             :         (r1r0) = (u4u3u2u1u0) mod (v1v0)
     629             :         for m = 2, n = 2 where u4 = 0
     630             :         q2 is either 0 or 1.
     631             :         We set q = (q1q0) and return q2 as "overflow"
     632             :     */
     633             :     DIGIT_T qhat, rhat, t, v0, v1, u0, u1, u2, u3;
     634             :     DIGIT_T uu[2], q2;
     635             : 
     636             :     /* Check for normalisation */
     637        2699 :     if (!(v & HIBITMASK))
     638             :     {    /* Stop if assert is working, else return error */
     639             :         assert(v & HIBITMASK);
     640           0 :         *q = *r = 0;
     641           0 :         return MAX_DIGIT;
     642             :     }
     643             :     
     644             :     /* Split up into half-digits */
     645        2699 :     v0 = LOHALF(v);
     646        2699 :     v1 = HIHALF(v);
     647        2699 :     u0 = LOHALF(u[0]);
     648        2699 :     u1 = HIHALF(u[0]);
     649        2699 :     u2 = LOHALF(u[1]);
     650        2699 :     u3 = HIHALF(u[1]);
     651             : 
     652             :     /* Do three rounds of Knuth Algorithm D Vol 2 p272 */
     653             : 
     654             :     /*    ROUND 1. Set j = 2 and calculate q2 */
     655             :     /*    Estimate qhat = (u4u3)/v1  = 0 or 1 
     656             :         then set (u4u3u2) -= qhat(v1v0)
     657             :         where u4 = 0.
     658             :     */
     659             : /* [Replaced in Version 2] -->
     660             :     qhat = u3 / v1;
     661             :     if (qhat > 0)
     662             :     {
     663             :         rhat = u3 - qhat * v1;
     664             :         t = TOHIGH(rhat) | u2;
     665             :         if (qhat * v0 > t)
     666             :             qhat--;
     667             :     }
     668             : <-- */
     669        2699 :     qhat = (u3 < v1 ? 0 : 1);
     670        2699 :     if (qhat > 0)
     671             :     {    /* qhat is one, so no need to mult */
     672           0 :         rhat = u3 - v1;
     673             :         /* t = r.b + u2 */
     674           0 :         t = TOHIGH(rhat) | u2;
     675           0 :         if (v0 > t)
     676           0 :             qhat--;
     677             :     }
     678             : 
     679        2699 :     uu[1] = 0;        /* (u4) */
     680        2699 :     uu[0] = u[1];    /* (u3u2) */
     681        2699 :     if (qhat > 0)
     682             :     {
     683             :         /* (u4u3u2) -= qhat(v1v0) where u4 = 0 */
     684           0 :         spMultSub(uu, qhat, v1, v0);
     685           0 :         if (HIHALF(uu[1]) != 0)
     686             :         {    /* Add back */
     687           0 :             qhat--;
     688           0 :             uu[0] += v;
     689           0 :             uu[1] = 0;
     690             :         }
     691             :     }
     692        2699 :     q2 = qhat;
     693             : 
     694             :     /*    ROUND 2. Set j = 1 and calculate q1 */
     695             :     /*    Estimate qhat = (u3u2) / v1 
     696             :         then set (u3u2u1) -= qhat(v1v0)
     697             :     */
     698        2699 :     t = uu[0];
     699        2699 :     qhat = t / v1;
     700        2699 :     rhat = t - qhat * v1;
     701             :     /* Test on v0 */
     702        2699 :     t = TOHIGH(rhat) | u1;
     703        2699 :     if ((qhat == B) || (qhat * v0 > t))
     704             :     {
     705           0 :         qhat--;
     706           0 :         rhat += v1;
     707           0 :         t = TOHIGH(rhat) | u1;
     708           0 :         if ((rhat < B) && (qhat * v0 > t))
     709           0 :             qhat--;
     710             :     }
     711             : 
     712             :     /*    Multiply and subtract 
     713             :         (u3u2u1)' = (u3u2u1) - qhat(v1v0)    
     714             :     */
     715        2699 :     uu[1] = HIHALF(uu[0]);    /* (0u3) */
     716        2699 :     uu[0] = TOHIGH(LOHALF(uu[0])) | u1;    /* (u2u1) */
     717        2699 :     spMultSub(uu, qhat, v1, v0);
     718        2699 :     if (HIHALF(uu[1]) != 0)
     719             :     {    /* Add back */
     720           0 :         qhat--;
     721           0 :         uu[0] += v;
     722           0 :         uu[1] = 0;
     723             :     }
     724             : 
     725             :     /* q1 = qhat */
     726        2699 :     *q = TOHIGH(qhat);
     727             : 
     728             :     /* ROUND 3. Set j = 0 and calculate q0 */
     729             :     /*    Estimate qhat = (u2u1) / v1
     730             :         then set (u2u1u0) -= qhat(v1v0)
     731             :     */
     732        2699 :     t = uu[0];
     733        2699 :     qhat = t / v1;
     734        2699 :     rhat = t - qhat * v1;
     735             :     /* Test on v0 */
     736        2699 :     t = TOHIGH(rhat) | u0;
     737        2699 :     if ((qhat == B) || (qhat * v0 > t))
     738             :     {
     739           0 :         qhat--;
     740           0 :         rhat += v1;
     741           0 :         t = TOHIGH(rhat) | u0;
     742           0 :         if ((rhat < B) && (qhat * v0 > t))
     743           0 :             qhat--;
     744             :     }
     745             : 
     746             :     /*    Multiply and subtract 
     747             :         (u2u1u0)" = (u2u1u0)' - qhat(v1v0)
     748             :     */
     749        2699 :     uu[1] = HIHALF(uu[0]);    /* (0u2) */
     750        2699 :     uu[0] = TOHIGH(LOHALF(uu[0])) | u0;    /* (u1u0) */
     751        2699 :     spMultSub(uu, qhat, v1, v0);
     752        2699 :     if (HIHALF(uu[1]) != 0)
     753             :     {    /* Add back */
     754           0 :         qhat--;
     755           0 :         uu[0] += v;
     756           0 :         uu[1] = 0;
     757             :     }
     758             : 
     759             :     /* q0 = qhat */
     760        2699 :     *q |= LOHALF(qhat);
     761             : 
     762             :     /* Remainder is in (u1u0) i.e. uu[0] */
     763        2699 :     *r = uu[0];
     764        2699 :     return q2;
     765             : }
     766             : 
     767             : // Platform-dependent code
     768             : #ifndef HSM_PLATFORM_LEDGER
     769             : 
     770             : #include "hal/log.h"
     771             : 
     772        2022 : void LOG_BIGD_HEX(const char *prefix,
     773             :                   const DIGIT_T *a,
     774             :                   size_t len,
     775             :                   const char *suffix) {
     776        2022 :     if (prefix) {
     777        2022 :         LOG("%s", prefix);
     778             :     }
     779             :     /* Trim leading digits which are zero */
     780       11728 :     while (len--) {
     781       11708 :         if (a[len] != 0)
     782        2002 :             break;
     783             :     }
     784        2022 :     len++;
     785        2022 :     if (0 == len)
     786          20 :         len = 1;
     787             :     /* print first digit without leading zeros */
     788        2022 :     LOG("0x%" PRIxBIGD, a[--len]);
     789        8512 :     while (len--) {
     790        6490 :         LOG("%08" PRIxBIGD, a[len]);
     791             :     }
     792        2022 :     if (suffix) {
     793        2022 :         LOG("%s", suffix);
     794             :     }
     795        2022 : }
     796             : 
     797             : #endif

Generated by: LCOV version 1.16