/*------------------------------------------------------------ * * 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++; } }
int mpa_set_oct_str(mpanum dest, const uint8_t *buffer, size_t buffer_len, bool negative) { const uint8_t *buf = buffer; int bufidx = buffer_len; mpa_word_t *w; /* Strip of leading zero octets */ while (bufidx > 0) { if (*buf != 0) break; bufidx--; buf++; } if (bufidx == 0) { mpa_set_word(dest, 0); return 0; } /* * bufidx is now indexing one byte past past the last byte in the octet * string relative to buf. */ if ((size_t) (bufidx - 1) > (BYTES_PER_WORD * __mpanum_alloced(dest))) return -1; /* No space */ w = dest->d; mpa_set_word(dest, 0); /* start converting */ dest->size = 0; while (bufidx > 0) { int l = __MIN(BYTES_PER_WORD, bufidx); bufidx -= l; *w = set_word(buf + bufidx, l); w++; dest->size++; } if (negative) __mpanum_neg(dest); return 0; }
/* ---- trivial ---- */ static int set_int(void *a, unsigned long b) { LTC_ARGCHK(a != NULL); if (b > (unsigned long) UINT32_MAX) { return CRYPT_INVALID_ARG; } mpa_set_word((mpanum) a, (mpa_word_t)b); return CRYPT_OK; }
/*------------------------------------------------------------ * * __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; }
/* -------------------------------------------------------------------- * Function: mpa_set_str * * Assigns dest the value of the digitstr, where digitstr is a character * string. * If the digitstr starts with a valid number, the valid part will be * converted and the rest of the digitstr will not be parsed further. * digitstr is assumed to be in base 16. * Returns -1 if the digitstr was malformed, and the number of base digits * converted (not including leading zeros) if the conversion was OK. * If the digitstr is a null-ptr we return -1. * If the digitstr is empty, we don't touch dest and just returns 0. * If the digitstr only consists of white spaces, we set dest to zero * returns 0. */ int mpa_set_str(mpanum dest, const char *digitstr) { /* length of digitstr after removal of base indicator and spaces */ int dlen; int negative; /* ==1 if number is negative, 0 otherwise */ int c; /* value of characters in digitstr */ /* a buffer holding the integer values of the digits */ static unsigned char buf[MPA_STR_MAX_SIZE]; /* number of digits in digitstr which has been place in buf */ int bufidx; const char *endp; /* points to the end of digitstr */ int retval; /* * Pointer intto dest->d where we should put the next word during * conversion. */ mpa_word_t *w; int i; /* loop variable */ /* some basic sanity checks first */ if (*digitstr == 0) { DPRINT("digitstr was empty, leaving dest unchanged\n"); return 0; } /* remove leading spaces */ do { c = (unsigned char)*digitstr++; } while (__mpa_isspace(c)); /* check negative sign */ negative = 0; if (c == '-') { negative = 1; c = (unsigned char)*digitstr++; } if (c == '\0') { DPRINT("digitstr consisted of only white spaces and possibly a single '-' sign. Setting dest to zero\n"); mpa_set_word(dest, 0); return 0; } /* see if we have a '0x' prefix */ if (c == '0') { c = (unsigned char)*digitstr++; if (c == 'x' || c == 'X') c = (unsigned char)*digitstr++; } /* skip leading zeros and spaces */ while (c == '0' || __mpa_isspace(c)) c = (unsigned char)*digitstr++; /* check if we had a simple "0" string */ if (c == '\0') { mpa_set_word(dest, 0); return 0; } /* find the end of digitstr */ endp = digitstr; while (*endp != 0) endp++; /* + 1 since we have one character in 'c' */ dlen = (int)(endp - digitstr) + 1; ASSERT(dlen <= MPA_STR_MAX_SIZE, "String max size is too small"); /* convert to a buffer of bytes */ bufidx = 0; while (__mpa_is_char_in_base(16, c)) { if (!__mpa_isspace(c)) buf[bufidx++] = __mpa_digit_value(c); c = (unsigned char)*digitstr++; } if (bufidx == 0) { retval = -1; goto cleanup; } ASSERT((__mpa_digitstr_to_binary_wsize_base_16(bufidx) <= __mpanum_alloced(dest)), "Dest is too small."); retval = bufidx; w = dest->d; mpa_set_word(dest, 0); /* start converting */ *w = 0; i = BYTES_PER_WORD; dest->size = 1; bufidx--; /* dec to get inside buf range */ while (bufidx > 1) { *w ^= (((buf[bufidx - 1] << 4) ^ (buf[bufidx])) << ((BYTES_PER_WORD - i) << 3)); i--; bufidx -= 2; if (i == 0) { w++; *w = 0; i = BYTES_PER_WORD; dest->size++; } } if (bufidx == 1) *w ^= (((buf[bufidx - 1] << 4) ^ (buf[bufidx])) << ((BYTES_PER_WORD - i) << 3)); if (bufidx == 0) *w ^= (buf[bufidx] << ((BYTES_PER_WORD - i) << 3)); if (negative) __mpanum_neg(dest); cleanup: return retval; }