/*------------------------------------------------------------ * * mpa_shift_right * * Shifts src right by "steps" step and put result in dest. * It does not care about signs. Dest will have same sign as src. * */ void mpa_shift_right(mpanum dest, mpanum src, mpa_word_t steps) { mpa_word_t q; /* quotient of steps div WORD_SIZE */ mpa_word_t r; /* remainder of steps div WORD_SIZE */ mpa_word_t i; /* the bits of the word which will be shifted into another word */ mpa_word_t rbits; /* * Copy first, then check, since even a shifted zero should * be copied. */ mpa_copy(dest, src); __mpa_set_unused_digits_to_zero(dest); if (steps == 0 || __mpanum_is_zero(dest)) return; r = steps & (WORD_SIZE - 1); /* 0 <= r < WORD_SIZE */ q = steps >> LOG_OF_WORD_SIZE; /* 0 <= q */ if (q >= __mpanum_size(dest)) { mpa_set_word(dest, 0); return; } /* * Here we have: * 0 <= r < WORD_SIZE - 1 * 0 <= q < _mpanumSize(dest) */ if (r == 0) { /* and q > 0 */ /* Simple shift by words */ for (i = 0; i < __mpanum_size(dest) - q; i++) dest->d[i] = dest->d[i + q]; } else { /* combination of word and bit shifting */ for (i = 0; i < __mpanum_size(dest) - q - 1; i++) { dest->d[i] = dest->d[i + q]; rbits = dest->d[i + q + 1] & ((1 << r) - 1); dest->d[i] = (dest->d[i] >> r) ^ (rbits << (WORD_SIZE - r)); } /* final word is special */ dest->d[i] = dest->d[i + q] >> r; } /* update the size of dest */ if (dest->size > 0) dest->size -= q; else dest->size += q; /* Take care of the case when we shifted out all bits from MSW */ if (__mpanum_msw(dest) == 0) { if (dest->size > 0) dest->size--; else dest->size++; } }
/* -------------------------------------------------------------------- * Function: __mpa_dbg_dump_mpanum * Prints the internal values of a TEE_BigInt * */ void __mpa_dbg_dump_mpanum(mpanum a) { int i; map_fprintf(logfd, " ---- Dump :\n"); map_fprintf(logfd, " mpanum->size = %d\n", a->size); map_fprintf(logfd, " mpanum->alloc = %u\n", a->alloc); map_fprintf(logfd, " mpanum->d (MSW to LSW) :\n"); for (i = __mpanum_alloced(a) - 1; i >= __mpanum_size(a); i--) map_fprintf(logfd, "%.8X ", a->d[i]); map_fprintf(logfd, "\n"); for (i = __mpanum_size(a) - 1; i >= 0; i--) map_fprintf(logfd, "[%d] : %.8X\n", i, a->d[i]); map_fflush(logfd); }
/* -------------------------------------------------------------------- * Function: mpa_SizeInBase * * Returns the number of characters needed to print |n| in base 255. */ static mpa_word_t __mpa_size_in_base_255(const mpanum n) { mpa_word_t totalbits; /* number of leading zero bits in the msw of n */ mpa_word_t zerobits_msw; if (__mpanum_is_zero(n)) return 1; zerobits_msw = __mpa_count_leading_zero_bits( n->d[__mpanum_size(n) - 1]); totalbits = WORD_SIZE * __mpanum_size(n) - zerobits_msw; return (totalbits + 7) / 8; }
/*------------------------------------------------------------ * * is_small_prime * * Returns 1 if n is prime, Returns 0 if n is composite * Returns -1 if we cannot decide * */ static int is_small_prime(mpanum n) { mpa_word_t v; /* If n is larger than a mpa_word_t, we can only decide if */ /* n is even. If it's odd we cannot tell. */ if (__mpanum_size(n) > 1) return ((mpa_parity(n) == MPA_EVEN_PARITY) ? 0 : -1); v = mpa_get_word(n); /* will convert negative n:s to positive v:s. */ if ((v | 1) == 1) /* 0 and 1 are not prime */ return DEF_COMPOSITE; if (v == 2) /* 2 is prime */ return DEF_PRIME; if ((v & 1) == 0) return DEF_COMPOSITE; /* but no other even number */ #if defined(USE_PRIME_TABLE) if (mpa_cmp_short(n, MAX_TABULATED_PRIME) > 0) return -1; v = (v - 3) >> 1; return check_table(v); #else return -1; #endif }
/*------------------------------------------------------------ * * mpa_copy * * Copies src to dest. * * Doesn't check if src fits into dest * */ void mpa_copy(mpanum dest, const mpanum src) { if (dest == src) return; mpa_memcpy(dest->d, src->d, __mpanum_size(src) * BYTES_PER_WORD); dest->size = src->size; }
/* get normalization value */ static int montgomery_normalization(void *a, void *b) { LTC_ARGCHK(a != NULL); LTC_ARGCHK(b != NULL); mpa_asize_t s; s = __mpanum_size((mpanum) b); twoexpt(a, s * MPA_WORD_SIZE); mpa_mod((mpanum) a, (const mpanum) a, (const mpanum) b, external_mem_pool); return CRYPT_OK; }
/* -------------------------------------------------------------------- * Function: __mpa_set_unused_digits_to_zero * * */ void __mpa_set_unused_digits_to_zero(mpanum n) { int i; /* * Pointer arithmetics on *mpa_word_t will put the * pointer at the right place. */ i = __mpanum_size(n); mpa_memset((n->d) + i, 0, (n->alloc - i) * BYTES_PER_WORD); }
/*------------------------------------------------------------ * * __mpa_shift_words_right * */ void __mpa_shift_words_right(mpanum op, mpa_word_t q) { mpa_word_t i; if (q == 0 || __mpanum_is_zero(op)) return; if (q >= __mpanum_size(op)) { mpa_set_word(op, 0); return; } for (i = 0; i < __mpanum_size(op) - q; i++) op->d[i] = op->d[i + q]; /* update the size of dest */ if (op->size > 0) op->size -= q; else op->size += q; }
/*------------------------------------------------------------ * * mpa_get_bit * * Returns the value of the idx:th bit in src. * if idx is larger than the number of bits in src, * it returns zero. * */ uint32_t mpa_get_bit(const mpanum src, uint32_t idx) { mpa_word_t w; /* word of bitIndex */ unsigned long b; /* bit number in that word */ w = idx >> LOG_OF_WORD_SIZE; b = idx & (WORD_SIZE - 1); if (w > __mpanum_size(src)) return 0; b = (1 << b); return ((src->d[w] & b) != 0); }
/* -------------------------------------------------------------------- * Function: mpa_highest_bit_index * Returns the index of the highest 1 in |src|. * The index starts at 0 for the least significant bit. * If src == zero, it will return -1 * */ int mpa_highest_bit_index(const mpanum src) { mpa_word_t w; mpa_word_t b; if (__mpanum_is_zero(src)) return -1; w = __mpanum_msw(src); for (b = 0; b < WORD_SIZE; b++) { w >>= 1; if (w == 0) break; } return (int)(__mpanum_size(src) - 1) * WORD_SIZE + b; }
/*------------------------------------------------------------ * * __mpa_shift_words_left * */ void __mpa_shift_words_left(mpanum op, mpa_word_t q) { mpa_word_t i; if (q == 0 || __mpanum_is_zero(op)) return; for (i = __mpanum_size(op) + q - 1; i > q - 1; i--) op->d[i] = op->d[i - q]; mpa_memset(op->d, 0, BYTES_PER_WORD * q); /* update the size of op */ if (op->size > 0) op->size += q; else op->size -= q; }
int mpa_get_oct_str(uint8_t *buffer, size_t *buffer_len, const mpanum n) { size_t req_blen = __mpa_size_in_base_255(n); uint8_t first_word[BYTES_PER_WORD]; size_t bufidx = 0; int d_idx; int i; if (*buffer_len < req_blen) { *buffer_len = req_blen; return -1; } /* get high word with data in, watch out for zero case */ d_idx = __mpanum_size(n); if (d_idx == 0) { memset(buffer, 0, *buffer_len); goto out; } d_idx--; /* Strip of leading zero octets */ get_word(n->d[d_idx], first_word); for (i = 0; i < BYTES_PER_WORD; i++) { if (first_word[i] != 0) { memcpy(buffer, first_word + i, BYTES_PER_WORD - i); bufidx = BYTES_PER_WORD - i; break; } } d_idx--; while (d_idx >= 0) { if (bufidx > req_blen) return -1; get_word(n->d[d_idx], buffer + bufidx); bufidx += BYTES_PER_WORD; d_idx--; } out: *buffer_len = req_blen; return 0; }
/* -------------------------------------------------------------------- * Function: __mpa_mpanum_to_hexstr * * caseing = 1 is lower case, 0 is uppercase */ static int __mpa_mpanum_to_hexstr(char *str, int caseing, const mpanum n) { int d_idx; char digits[NIBBLES_PER_WORD]; int i; char *cptr; int hex_digits; /* get high word with data in, watch out for zero case */ d_idx = __mpanum_size(n); if (d_idx == 0) { *str++ = '0'; *str = '\0'; return 1; } d_idx--; cptr = str; /* the msw is special, since if we should not print leading zeros. */ __mpa_word_to_hexstr(digits, n->d[d_idx], caseing); /* find the left-most non-zero digit */ i = NIBBLES_PER_WORD; while (i-- > 0) if (digits[i] != '0') break; while (i >= 0) *str++ = digits[i--]; /* convert each word to a hex string */ d_idx--; while (d_idx >= 0) { __mpa_word_to_hexstr(digits, n->d[d_idx], caseing); i = NIBBLES_PER_WORD - 1; while (i >= 0) *str++ = digits[i--]; d_idx--; } hex_digits = (int)(str - cptr); *str++ = '\0'; return hex_digits; }
static int get_digit_count(void *a) { LTC_ARGCHK(a != NULL); return __mpanum_size((mpanum) a); }
/*------------------------------------------------------------ * * mpa_CanHold * * returns 1 if dest can hold src without overflowing, 0 otherwise */ int mpa_can_hold(mpanum dest, const mpanum src) { return (__mpanum_alloced(dest) >= __mpanum_size(src) ? 1 : 0); }
/* -------------------------------------------------------------------- * mpa_shift_left * * Shifts src left by "steps" step and put result in dest. * It does not care about signs. Dest will have same sign as src. */ void mpa_shift_left(mpanum dest, mpanum src, mpa_word_t steps) { mpa_word_t q; /* quotient of steps div WORD_SIZE */ mpa_word_t r; /* remainder of steps div WORD_SIZE */ mpa_word_t i; /* the bits of the word which will be shifted into another word */ mpa_word_t rbits; mpa_word_t need_extra_word; /* * Copy first, then check, since even a shifted zero should * be copied. */ mpa_copy(dest, src); __mpa_set_unused_digits_to_zero(dest); if (steps == 0 || __mpanum_is_zero(dest)) return; r = steps & (WORD_SIZE - 1); /* 0 <= r < WORD_SIZE */ q = steps >> LOG_OF_WORD_SIZE; /* 0 <= q */ /* * The size of dest will always increase by at least q. * If we're shifting r bits and the r highest bits in * the MSW of dest is zero, we don't need the extra word * Note: * We cannot do * if (_mpanumMSW(dest) >> (WORD_SIZE - r)) * since some compilers (MS) does not shift the word * if the shift quantity is larger or equal to the word size... * Otherwise it would be natural to say that (a >> b) is just zero * if b is larger than the number of bit of a, but no no... */ need_extra_word = 0; if (__mpanum_msw(dest) & (((1 << r) - 1) << (WORD_SIZE - r))) need_extra_word = 1; if (r == 0) { /* and q > 0 */ /* * We have a simple shift by words */ for (i = __mpanum_size(dest) + q - 1; i > q - 1; i--) dest->d[i] = dest->d[i - q]; } else { /* * We have a combination of word and bit shifting. * * If need_extra_word is 1, the MSW is special and handled * here */ i = __mpanum_size(dest) + q + need_extra_word; if (need_extra_word) { rbits = dest->d[i - q - 1] >> (WORD_SIZE - r); dest->d[i] ^= rbits; } i--; dest->d[i] = dest->d[i - q] << r; while (i > q) { rbits = dest->d[i - q - 1] >> (WORD_SIZE - r); dest->d[i] ^= rbits; i--; dest->d[i] = dest->d[i - q] << r; } } mpa_memset(dest->d, 0, BYTES_PER_WORD * q); /* update the size of dest */ if (dest->size > 0) dest->size += q + need_extra_word; else dest->size -= q + need_extra_word; }