/*------------------------------------------------------------ * * mpa_exp_mod * * Calculates dest = op1 ^ op2 mod n * */ void mpa_exp_mod(mpanum dest, const mpanum op1, const mpanum op2, const mpanum n, const mpanum r_modn, const mpanum r2_modn, const mpa_word_t n_inv, mpa_scratch_mem pool) { mpanum A; mpanum B; mpanum xtilde; mpanum *ptr_a; mpanum *ptr_b; mpanum *swapper; int idx; mpa_alloc_static_temp_var(&A, pool); mpa_alloc_static_temp_var(&B, pool); mpa_alloc_static_temp_var(&xtilde, pool); /* transform to Montgomery space */ /* use internal version since xtidle is big enough */ __mpa_montgomery_mul(xtilde, op1, r2_modn, n, n_inv); mpa_copy(A, r_modn); ptr_a = &A; ptr_b = &B; __mpa_set_unused_digits_to_zero(A); __mpa_set_unused_digits_to_zero(B); for (idx = mpa_highest_bit_index(op2); idx >= 0; idx--) { __mpa_montgomery_mul(*ptr_b, *ptr_a, *ptr_a, n, n_inv); if (mpa_get_bit(op2, idx) == 1) { __mpa_montgomery_mul(*ptr_a, *ptr_b, xtilde, n, n_inv); } else { swapper = ptr_a; ptr_a = ptr_b; ptr_b = swapper; } } /* transform back form Montgomery space */ __mpa_montgomery_mul(*ptr_b, (const mpanum)&const_one, *ptr_a, n, n_inv); mpa_copy(dest, *ptr_b); mpa_free_static_temp_var(&A, pool); mpa_free_static_temp_var(&B, pool); mpa_free_static_temp_var(&xtilde, pool); }
static int copy(void *a, void *b) { LTC_ARGCHK(a != NULL); LTC_ARGCHK(b != NULL); mpa_copy((mpanum)b, (const mpanum)a); return CRYPT_OK; }
/* * TEE_BigIntConvertFromFMM */ void TEE_BigIntConvertFromFMM(TEE_BigInt *dest, const TEE_BigIntFMM *src, const TEE_BigInt *n, const TEE_BigIntFMMContext *context) { mpanum mpa_dest = (mpa_num_base *)dest; mpanum mpa_op2 = (mpa_num_base *)src; mpanum mpa_n = (mpa_num_base *)n; mpa_fmm_context mpa_context = (mpa_fmm_context_base *)context; mpanum temp_dest; /* * Since dest in BigIntFFMCompute (i.e. dest in mpa_montgomery_mul) * must have alloc one word more than the size of n, we must * use a temp variable during the conversion. */ mpa_alloc_static_temp_var(&temp_dest, mempool); /* calculate dest = Mont(1,src) */ mpa_montgomery_mul(temp_dest, mpa_constant_one(), mpa_op2, mpa_n, mpa_context->n_inv, mempool); mpa_copy(mpa_dest, temp_dest); mpa_free_static_temp_var(&temp_dest, mempool); }
/* * TEE_BigIntMulMod */ void TEE_BigIntMulMod(TEE_BigInt *dest, const TEE_BigInt *op1, const TEE_BigInt *op2, const TEE_BigInt *n) { mpanum mpa_dest = (mpa_num_base *)dest; mpanum mpa_op1 = (mpa_num_base *)op1; mpanum mpa_op2 = (mpa_num_base *)op2; mpanum mpa_n = (mpa_num_base *)n; mpanum tmp_dest; if (TEE_BigIntCmpS32(n, 2) < 0) TEE_BigInt_Panic("Modulus is too short"); /* * From the spec, mpa_dest must be of magnitude "mpa_n" * But internal computations in mpa do not have such assumptions * (as __mpa_div_q_r, where "r" must be of magnitude "op1", * whereas GP provides a magnitude of "op2") * This is a tempory variable is used, before storing the * final result. */ mpa_alloc_static_temp_var(&tmp_dest, mempool); mpa_mul_mod(tmp_dest, mpa_op1, mpa_op2, mpa_n, mempool); if (mpa_cmp_short(tmp_dest, 0) < 0) mpa_add(tmp_dest, tmp_dest, mpa_n, mempool); mpa_copy(mpa_dest, tmp_dest); mpa_free_static_temp_var(&tmp_dest, mempool); }
/*------------------------------------------------------------ * * 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++; } }
/* reduce */ static int montgomery_reduce(void *a, void *b, void *c) { LTC_ARGCHK(a != NULL); LTC_ARGCHK(b != NULL); LTC_ARGCHK(c != NULL); mpanum tmp; init((void **)&tmp); // WARNING // Workaround for a bug when a > b (a greater than the modulus) if (compare(a, b) == LTC_MP_GT) { mpa_mod((mpanum) a, (const mpanum) a, (const mpanum) b, external_mem_pool); } mpa_montgomery_mul(tmp, (mpanum) a, mpa_constant_one(), (mpanum) b, ((mpa_fmm_context) c)->n_inv, external_mem_pool); mpa_copy(a, tmp); deinit(tmp); return CRYPT_OK; }
/*------------------------------------------------------------ * * mpa_inv_mod * */ int mpa_inv_mod(mpanum dest, const mpanum op, const mpanum n, mpa_scratch_mem pool) { mpanum gcd; mpanum tmp_dest; int mem_marker; int res; if (mpa_cmp_short(op, 1) == 0) { mpa_set_S32(dest, 1); return 0; } mem_marker = (dest == op); if (mem_marker) mpa_alloc_static_temp_var(&tmp_dest, pool); else tmp_dest = dest; mpa_alloc_static_temp_var(&gcd, pool); /* The function mpa_extended_gcd behaves badly if tmp_dest = op */ mpa_extended_gcd(gcd, tmp_dest, NULL, op, n, pool); res = mpa_cmp_short(gcd, 1); if (mem_marker) { mpa_copy(dest, tmp_dest); mpa_free_static_temp_var(&tmp_dest, pool); } mpa_free_static_temp_var(&gcd, pool); if (res == 0) { while (mpa_cmp_short(dest, 0) < 0) mpa_add(dest, dest, n, pool); return 0; } else { return -1; } }
/* -------------------------------------------------------------------- * Function: mpa_abs * Computes the absolut value of src and puts it in dest * dest and src can be the same mpanum */ void mpa_abs(mpanum dest, const mpanum src) { mpa_copy(dest, src); __mpanum_set_sign(dest, MPA_POS_SIGN); }
/* -------------------------------------------------------------------- * 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; }