/* * Karatsuba improves on regular multiplication due to only 3 multiplications * being done instead of 4. The additional additions/subtractions are O(N) * rather than O(N^2) and so for big numbers it saves on a few operations */ static bigint * ICACHE_FLASH_ATTR karatsuba(BI_CTX *ctx, bigint *bia, bigint *bib, int is_square) { bigint *x0, *x1; bigint *p0, *p1, *p2; int m; if (is_square) { m = (bia->size + 1)/2; } else { m = (max(bia->size, bib->size) + 1)/2; } x0 = bi_clone(ctx, bia); x0->size = m; x1 = bi_clone(ctx, bia); comp_right_shift(x1, m); bi_free(ctx, bia); /* work out the 3 partial products */ if (is_square) { p0 = bi_square(ctx, bi_copy(x0)); p2 = bi_square(ctx, bi_copy(x1)); p1 = bi_square(ctx, bi_add(ctx, x0, x1)); } else /* normal multiply */ { bigint *y0, *y1; y0 = bi_clone(ctx, bib); y0->size = m; y1 = bi_clone(ctx, bib); comp_right_shift(y1, m); bi_free(ctx, bib); p0 = bi_multiply(ctx, bi_copy(x0), bi_copy(y0)); p2 = bi_multiply(ctx, bi_copy(x1), bi_copy(y1)); p1 = bi_multiply(ctx, bi_add(ctx, x0, x1), bi_add(ctx, y0, y1)); } p1 = bi_subtract(ctx, bi_subtract(ctx, p1, bi_copy(p2), NULL), bi_copy(p0), NULL); comp_left_shift(p1, m); comp_left_shift(p2, 2*m); return bi_add(ctx, p1, bi_add(ctx, p0, p2)); }
/** * @brief Perform a single montgomery reduction. * @param ctx [in] The bigint session context. * @param bixy [in] A bigint. * @return The result of the montgomery reduction. */ bigint * ICACHE_FLASH_ATTR bi_mont(BI_CTX *ctx, bigint *bixy) { int i = 0, n; uint8_t mod_offset = ctx->mod_offset; bigint *bim = ctx->bi_mod[mod_offset]; comp mod_inv = ctx->N0_dash[mod_offset]; check(bixy); if (ctx->use_classical) /* just use classical instead */ { return bi_mod(ctx, bixy); } n = bim->size; do { bixy = bi_add(ctx, bixy, comp_left_shift( bi_int_multiply(ctx, bim, bixy->comps[i]*mod_inv), i)); } while (++i < n); comp_right_shift(bixy, n); if (bi_compare(bixy, bim) >= 0) { bixy = bi_subtract(ctx, bixy, bim, NULL); } return bixy; }