LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/hcrypto/libtommath - bn_mp_log_u32.c (source / functions) Hit Total Coverage
Test: coverage report for master 70ed9daf Lines: 0 98 0.0 %
Date: 2024-01-11 09:59:51 Functions: 0 3 0.0 %

          Line data    Source code
       1             : #include "tommath_private.h"
       2             : #ifdef BN_MP_LOG_U32_C
       3             : /* LibTomMath, multiple-precision integer library -- Tom St Denis */
       4             : /* SPDX-License-Identifier: Unlicense */
       5             : 
       6             : /* Compute log_{base}(a) */
       7           0 : static mp_word s_pow(mp_word base, mp_word exponent)
       8             : {
       9           0 :    mp_word result = 1uLL;
      10           0 :    while (exponent != 0u) {
      11           0 :       if ((exponent & 1u) == 1u) {
      12           0 :          result *= base;
      13             :       }
      14           0 :       exponent >>= 1;
      15           0 :       base *= base;
      16             :    }
      17             : 
      18           0 :    return result;
      19             : }
      20             : 
      21           0 : static mp_digit s_digit_ilogb(mp_digit base, mp_digit n)
      22             : {
      23           0 :    mp_word bracket_low = 1uLL, bracket_mid, bracket_high, N;
      24           0 :    mp_digit ret, high = 1uL, low = 0uL, mid;
      25             : 
      26           0 :    if (n < base) {
      27           0 :       return 0uL;
      28             :    }
      29           0 :    if (n == base) {
      30           0 :       return 1uL;
      31             :    }
      32             : 
      33           0 :    bracket_high = (mp_word) base ;
      34           0 :    N = (mp_word) n;
      35             : 
      36           0 :    while (bracket_high < N) {
      37           0 :       low = high;
      38           0 :       bracket_low = bracket_high;
      39           0 :       high <<= 1;
      40           0 :       bracket_high *= bracket_high;
      41             :    }
      42             : 
      43           0 :    while (((mp_digit)(high - low)) > 1uL) {
      44           0 :       mid = (low + high) >> 1;
      45           0 :       bracket_mid = bracket_low * s_pow(base, (mp_word)(mid - low));
      46             : 
      47           0 :       if (N < bracket_mid) {
      48           0 :          high = mid ;
      49           0 :          bracket_high = bracket_mid ;
      50             :       }
      51           0 :       if (N > bracket_mid) {
      52           0 :          low = mid ;
      53           0 :          bracket_low = bracket_mid ;
      54             :       }
      55           0 :       if (N == bracket_mid) {
      56           0 :          return (mp_digit) mid;
      57             :       }
      58             :    }
      59             : 
      60           0 :    if (bracket_high == N) {
      61           0 :       ret = high;
      62             :    } else {
      63           0 :       ret = low;
      64             :    }
      65             : 
      66           0 :    return ret;
      67             : }
      68             : 
      69             : /* TODO: output could be "int" because the output of mp_radix_size is int, too,
      70             :          as is the output of mp_bitcount.
      71             :          With the same problem: max size is INT_MAX * MP_DIGIT not INT_MAX only!
      72             : */
      73           0 : mp_err mp_log_u32(const mp_int *a, uint32_t base, uint32_t *c)
      74             : {
      75           0 :    mp_err err;
      76           0 :    mp_ord cmp;
      77           0 :    uint32_t high, low, mid;
      78           0 :    mp_int bracket_low, bracket_high, bracket_mid, t, bi_base;
      79             : 
      80           0 :    err = MP_OKAY;
      81             : 
      82           0 :    if (a->sign == MP_NEG) {
      83           0 :       return MP_VAL;
      84             :    }
      85             : 
      86           0 :    if (MP_IS_ZERO(a)) {
      87           0 :       return MP_VAL;
      88             :    }
      89             : 
      90           0 :    if (base < 2u) {
      91           0 :       return MP_VAL;
      92             :    }
      93             : 
      94             :    /* `base' is at least 2 */
      95             : 
      96             :    /* A small shortcut for bases that are powers of two. */
      97           0 :    if ((base & (base - 1u)) == 0u) {
      98             :       int y, bit_count;
      99             : 
     100           0 :       for (y=0; (y < 7) && ((base & 1u) == 0u); y++) {
     101             :          /* We must go through this loop at least once */
     102           0 :          base >>= 1;
     103             :       }
     104           0 :       bit_count = mp_count_bits(a) - 1;
     105             :       /*
     106             :        * `y' is necessarily at least 1 because `base' is a power of two and
     107             :        * larger than 1, so we must have gone through the loop at least once, so
     108             :        * we can't be dividing by zero.
     109             :        *
     110             :        * scan-build thinks we can be dividing by zero...  WAT.
     111             :        */
     112           0 :       *c = (uint32_t)(bit_count/y);
     113           0 :       return MP_OKAY;
     114             :    }
     115             : 
     116           0 :    if (a->used == 1) {
     117           0 :       *c = (uint32_t)s_digit_ilogb(base, a->dp[0]);
     118           0 :       return err;
     119             :    }
     120             : 
     121           0 :    cmp = mp_cmp_d(a, base);
     122           0 :    if ((cmp == MP_LT) || (cmp == MP_EQ)) {
     123           0 :       *c = cmp == MP_EQ;
     124           0 :       return err;
     125             :    }
     126             : 
     127           0 :    if ((err =
     128           0 :            mp_init_multi(&bracket_low, &bracket_high,
     129             :                          &bracket_mid, &t, &bi_base, NULL)) != MP_OKAY) {
     130           0 :       return err;
     131             :    }
     132             : 
     133           0 :    low = 0u;
     134           0 :    mp_set(&bracket_low, 1uL);
     135           0 :    high = 1u;
     136             : 
     137           0 :    mp_set(&bracket_high, base);
     138             : 
     139             :    /*
     140             :        A kind of Giant-step/baby-step algorithm.
     141             :        Idea shamelessly stolen from https://programmingpraxis.com/2010/05/07/integer-logarithms/2/
     142             :        The effect is asymptotic, hence needs benchmarks to test if the Giant-step should be skipped
     143             :        for small n.
     144             :     */
     145           0 :    while (mp_cmp(&bracket_high, a) == MP_LT) {
     146           0 :       low = high;
     147           0 :       if ((err = mp_copy(&bracket_high, &bracket_low)) != MP_OKAY) {
     148           0 :          goto LBL_ERR;
     149             :       }
     150           0 :       high <<= 1;
     151           0 :       if ((err = mp_sqr(&bracket_high, &bracket_high)) != MP_OKAY) {
     152           0 :          goto LBL_ERR;
     153             :       }
     154             :    }
     155           0 :    mp_set(&bi_base, base);
     156             : 
     157           0 :    while ((high - low) > 1u) {
     158           0 :       mid = (high + low) >> 1;
     159             : 
     160           0 :       if ((err = mp_expt_u32(&bi_base, (uint32_t)(mid - low), &t)) != MP_OKAY) {
     161           0 :          goto LBL_ERR;
     162             :       }
     163           0 :       if ((err = mp_mul(&bracket_low, &t, &bracket_mid)) != MP_OKAY) {
     164           0 :          goto LBL_ERR;
     165             :       }
     166           0 :       cmp = mp_cmp(a, &bracket_mid);
     167           0 :       if (cmp == MP_LT) {
     168           0 :          high = mid;
     169           0 :          mp_exch(&bracket_mid, &bracket_high);
     170             :       }
     171           0 :       if (cmp == MP_GT) {
     172           0 :          low = mid;
     173           0 :          mp_exch(&bracket_mid, &bracket_low);
     174             :       }
     175           0 :       if (cmp == MP_EQ) {
     176           0 :          *c = mid;
     177           0 :          goto LBL_END;
     178             :       }
     179             :    }
     180             : 
     181           0 :    *c = (mp_cmp(&bracket_high, a) == MP_EQ) ? high : low;
     182             : 
     183           0 : LBL_END:
     184           0 : LBL_ERR:
     185           0 :    mp_clear_multi(&bracket_low, &bracket_high, &bracket_mid,
     186             :                   &t, &bi_base, NULL);
     187           0 :    return err;
     188             : }
     189             : 
     190             : 
     191             : #endif

Generated by: LCOV version 1.14