void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **ptr) { byte *p = *ptr; mp_uint_t align; size_t size = mp_binary_get_size(struct_type, val_type, &align); if (struct_type == '@') { // Make pointer aligned p = (byte*)MP_ALIGN(p, (size_t)align); if (MP_ENDIANNESS_LITTLE) { struct_type = '<'; } else { struct_type = '>'; } } *ptr = p + size; mp_uint_t val; switch (val_type) { case 'O': val = (mp_uint_t)val_in; break; #if MICROPY_PY_BUILTINS_FLOAT case 'f': { union { uint32_t i; float f; } fp_sp; fp_sp.f = mp_obj_get_float(val_in); val = fp_sp.i; break; } case 'd': { union { uint64_t i64; uint32_t i32[2]; double f; } fp_dp; fp_dp.f = mp_obj_get_float(val_in); if (BYTES_PER_WORD == 8) { val = fp_dp.i64; } else { int be = struct_type == '>'; mp_binary_set_int(sizeof(uint32_t), be, p, fp_dp.i32[MP_ENDIANNESS_BIG ^ be]); p += sizeof(uint32_t); val = fp_dp.i32[MP_ENDIANNESS_LITTLE ^ be]; } break; } #endif default: #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE if (MP_OBJ_IS_TYPE(val_in, &mp_type_int)) { mp_obj_int_to_bytes_impl(val_in, struct_type == '>', size, p); return; } else #endif { val = mp_obj_get_int(val_in); // sign extend if needed if (BYTES_PER_WORD < 8 && size > sizeof(val) && is_signed(val_type) && (mp_int_t)val < 0) { memset(p + sizeof(val), 0xff, size - sizeof(val)); } } } mp_binary_set_int(MIN((size_t)size, sizeof(val)), struct_type == '>', p, val); }
mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) { byte *p = *ptr; mp_uint_t align; size_t size = mp_binary_get_size(struct_type, val_type, &align); if (struct_type == '@') { // Make pointer aligned p = (byte*)MP_ALIGN(p, (size_t)align); #if MP_ENDIANNESS_LITTLE struct_type = '<'; #else struct_type = '>'; #endif } *ptr = p + size; long long val = mp_binary_get_int(size, is_signed(val_type), (struct_type == '>'), p); if (val_type == 'O') { return (mp_obj_t)(mp_uint_t)val; } else if (val_type == 'S') { const char *s_val = (const char*)(uintptr_t)(mp_uint_t)val; return mp_obj_new_str(s_val, strlen(s_val), false); #if MICROPY_PY_BUILTINS_FLOAT } else if (val_type == 'f') { union { uint32_t i; float f; } fpu = {val}; return mp_obj_new_float(fpu.f); } else if (val_type == 'd') { union { uint64_t i; double f; } fpu = {val}; return mp_obj_new_float(fpu.f); #endif } else if (is_signed(val_type)) { if ((long long)MP_SMALL_INT_MIN <= val && val <= (long long)MP_SMALL_INT_MAX) { return mp_obj_new_int((mp_int_t)val); } else { return mp_obj_new_int_from_ll(val); } } else { if ((unsigned long long)val <= (unsigned long long)MP_SMALL_INT_MAX) { return mp_obj_new_int_from_uint((mp_uint_t)val); } else { return mp_obj_new_int_from_ull(val); } } }
/* Do modular exponentiation using integer multiply code. */ mp_err mp_exptmod_safe_i(const mp_int * montBase, const mp_int * exponent, const mp_int * modulus, mp_int * result, mp_mont_modulus *mmm, int nLen, mp_size bits_in_exponent, mp_size window_bits, mp_size num_powers) { mp_int *pa1, *pa2, *ptmp; mp_size i; mp_size first_window; mp_err res; int expOff; mp_int accum1, accum2, accum[WEAVE_WORD_SIZE]; mp_int tmp; unsigned char *powersArray; unsigned char *powers; MP_DIGITS(&accum1) = 0; MP_DIGITS(&accum2) = 0; MP_DIGITS(&accum[0]) = 0; MP_DIGITS(&accum[1]) = 0; MP_DIGITS(&accum[2]) = 0; MP_DIGITS(&accum[3]) = 0; MP_DIGITS(&tmp) = 0; powersArray = (unsigned char *)malloc(num_powers*(nLen*sizeof(mp_digit)+1)); if (powersArray == NULL) { res = MP_MEM; goto CLEANUP; } /* powers[i] = base ** (i); */ powers = (unsigned char *)MP_ALIGN(powersArray,num_powers); /* grab the first window value. This allows us to preload accumulator1 * and save a conversion, some squares and a multiple*/ MP_CHECKOK( mpl_get_bits(exponent, bits_in_exponent-window_bits, window_bits) ); first_window = (mp_size)res; MP_CHECKOK( mp_init_size(&accum1, 3 * nLen + 2) ); MP_CHECKOK( mp_init_size(&accum2, 3 * nLen + 2) ); MP_CHECKOK( mp_init_size(&tmp, 3 * nLen + 2) ); /* build the first WEAVE_WORD powers inline */ /* if WEAVE_WORD_SIZE is not 4, this code will have to change */ if (num_powers > 2) { MP_CHECKOK( mp_init_size(&accum[0], 3 * nLen + 2) ); MP_CHECKOK( mp_init_size(&accum[1], 3 * nLen + 2) ); MP_CHECKOK( mp_init_size(&accum[2], 3 * nLen + 2) ); MP_CHECKOK( mp_init_size(&accum[3], 3 * nLen + 2) ); mp_set(&accum[0], 1); MP_CHECKOK( s_mp_to_mont(&accum[0], mmm, &accum[0]) ); MP_CHECKOK( mp_copy(montBase, &accum[1]) ); SQR(montBase, &accum[2]); MUL_NOWEAVE(montBase, &accum[2], &accum[3]); MP_CHECKOK( mpi_to_weave(accum, powers, nLen, num_powers) ); if (first_window < 4) { MP_CHECKOK( mp_copy(&accum[first_window], &accum1) ); first_window = num_powers; } } else { if (first_window == 0) { mp_set(&accum1, 1); MP_CHECKOK( s_mp_to_mont(&accum1, mmm, &accum1) ); } else { /* assert first_window == 1? */ MP_CHECKOK( mp_copy(montBase, &accum1) ); } } /* * calculate all the powers in the powers array. * this adds 2**(k-1)-2 square operations over just calculating the * odd powers where k is the window size in the two other mp_modexpt * implementations in this file. We will get some of that * back by not needing the first 'k' squares and one multiply for the * first window */ for (i = WEAVE_WORD_SIZE; i < num_powers; i++) { int acc_index = i & (WEAVE_WORD_SIZE-1); /* i % WEAVE_WORD_SIZE */ if ( i & 1 ) { MUL_NOWEAVE(montBase, &accum[acc_index-1] , &accum[acc_index]); /* we've filled the array do our 'per array' processing */ if (acc_index == (WEAVE_WORD_SIZE-1)) { MP_CHECKOK( mpi_to_weave(accum, powers + i - (WEAVE_WORD_SIZE-1), nLen, num_powers) ); if (first_window <= i) { MP_CHECKOK( mp_copy(&accum[first_window & (WEAVE_WORD_SIZE-1)], &accum1) ); first_window = num_powers; } } } else { /* up to 8 we can find 2^i-1 in the accum array, but at 8 we our source * and target are the same so we need to copy.. After that, the * value is overwritten, so we need to fetch it from the stored * weave array */ if (i > 2* WEAVE_WORD_SIZE) { MP_CHECKOK(weave_to_mpi(&accum2, powers+i/2, nLen, num_powers)); SQR(&accum2, &accum[acc_index]); } else { int half_power_index = (i/2) & (WEAVE_WORD_SIZE-1); if (half_power_index == acc_index) { /* copy is cheaper than weave_to_mpi */ MP_CHECKOK(mp_copy(&accum[half_power_index], &accum2)); SQR(&accum2,&accum[acc_index]); } else { SQR(&accum[half_power_index],&accum[acc_index]); } } } } /* if the accum1 isn't set, Then there is something wrong with our logic * above and is an internal programming error. */ #if MP_ARGCHK == 2 assert(MP_USED(&accum1) != 0); #endif /* set accumulator to montgomery residue of 1 */ pa1 = &accum1; pa2 = &accum2; for (expOff = bits_in_exponent - window_bits*2; expOff >= 0; expOff -= window_bits) { mp_size smallExp; MP_CHECKOK( mpl_get_bits(exponent, expOff, window_bits) ); smallExp = (mp_size)res; /* handle unroll the loops */ switch (window_bits) { case 1: if (!smallExp) { SQR(pa1,pa2); SWAPPA; } else if (smallExp & 1) { SQR(pa1,pa2); MUL_NOWEAVE(montBase,pa2,pa1); } else { abort(); } break; case 6: SQR(pa1,pa2); SQR(pa2,pa1); /* fall through */ case 4: SQR(pa1,pa2); SQR(pa2,pa1); SQR(pa1,pa2); SQR(pa2,pa1); MUL(smallExp, pa1,pa2); SWAPPA; break; case 5: SQR(pa1,pa2); SQR(pa2,pa1); SQR(pa1,pa2); SQR(pa2,pa1); SQR(pa1,pa2); MUL(smallExp,pa2,pa1); break; default: abort(); /* could do a loop? */ } } res = s_mp_redc(pa1, mmm); mp_exch(pa1, result); CLEANUP: mp_clear(&accum1); mp_clear(&accum2); mp_clear(&accum[0]); mp_clear(&accum[1]); mp_clear(&accum[2]); mp_clear(&accum[3]); mp_clear(&tmp); /* PORT_Memset(powers,0,num_powers*nLen*sizeof(mp_digit)); */ free(powersArray); return res; }