Skip to content

Commit

Permalink
Implement karatsuba multiplication...
Browse files Browse the repository at this point in the history
...and integrate it to baseline multiplication.
  • Loading branch information
rafael-santiago committed Feb 4, 2025
1 parent 2fac0f3 commit 908f0f4
Show file tree
Hide file tree
Showing 5 changed files with 399 additions and 8 deletions.
233 changes: 232 additions & 1 deletion src/kryptos_mp.c
Original file line number Diff line number Diff line change
Expand Up @@ -991,6 +991,230 @@ static kryptos_mp_value_t *kryptos_mp_multibyte_mul(const kryptos_mp_value_t *a,

#endif

int kryptos_mp_split(kryptos_mp_value_t **hi, kryptos_mp_value_t **lo, const kryptos_mp_value_t *src) {
size_t split_bitsize = 0;
int done = 1;
size_t pad = src->data_size & 1;
ssize_t d;
ssize_t s;

split_bitsize = kryptos_mp_byte2bit((src->data_size + pad) >> 1);
*hi = kryptos_new_mp_value(split_bitsize);
if (*hi == NULL) {
done = 0;
goto kryptos_mp_split_epilogue;
}

*lo = kryptos_new_mp_value(split_bitsize);
if (*lo == NULL) {
done = 0;
goto kryptos_mp_split_epilogue;
}
s = (*hi)->data_size - 1;
for (d = (src->data_size - 1); d > (src->data_size >> 1) - (pad == 0); d--) {
(*hi)->data[s - pad] = src->data[d];
s--;
}

s = (*lo)->data_size - 1;
for (d = (src->data_size >> 1) - (pad == 0); d >= 0; d--) {
(*lo)->data[s] = src->data[d];
s--;
}
/*
for (d = 0; d < (src->data_size >> 1); d++) {
(*lo)->data[d + pad] = src->data[d];
}
s = 0;
for (d = (src->data_size >> 1); d < src->data_size; d++) {
(*hi)->data[s++] = src->data[d];
}
*/
kryptos_mp_split_epilogue:

/*
printf("SRC(%lu) = ", src->data_size);
kryptos_print_mp(src);
printf("HI = ");
kryptos_print_mp(*hi);
printf("LO = ");
kryptos_print_mp(*lo);
printf("--\n");
*/
return done;
}

kryptos_mp_value_t *kryptos_mp_karatsuba(kryptos_mp_value_t **dest, const kryptos_mp_value_t *src) {
kryptos_mp_value_t *dest_l = NULL;
kryptos_mp_value_t *dest_r = NULL;
kryptos_mp_value_t *src_l = NULL;
kryptos_mp_value_t *src_r = NULL;
kryptos_mp_value_t *a = NULL;
kryptos_mp_value_t *b = NULL;
kryptos_mp_value_t *c = NULL;
kryptos_mp_value_t *src_l_plus_src_r = NULL;
int done = 0;
int shlv = 0;

#define mp_max(a, b) ( (a) > (b) ? (a) : (b) )

shlv = (int)kryptos_mp_byte2bit(mp_max((*dest)->data_size, src->data_size));
// INFO(Rafael): This is tricky, but maybe it would be necessary to align one more digit
// to the left during the final sum. It will happen in cases of odd number
// of digits. In this case the split function will return one more zeroed
// digit to the left.
shlv += ((src->data_size & 1) || ((*dest)->data_size & 1)) * (sizeof(kryptos_mp_digit_t) << 3);

#undef mp_max

done = kryptos_mp_split(&dest_l, &dest_r, *dest);
if (!done) {
goto kryptos_mp_karatsuba_epilogue;
}
done = kryptos_mp_split(&src_l, &src_r, src);
if (!done) {
goto kryptos_mp_karatsuba_epilogue;
}

a = kryptos_assign_mp_value(&a, dest_l);
if (a == NULL) {
done = 0;
goto kryptos_mp_karatsuba_epilogue;
}
b = kryptos_assign_mp_value(&b, dest_r);
if (b == NULL) {
done = 0;
goto kryptos_mp_karatsuba_epilogue;
}

// INFO(Rafael): a = Xl . Yl

a = kryptos_mp_mul(&a, src_l);
if (a == NULL) {
done = 0;
goto kryptos_mp_karatsuba_epilogue;
}

// INFO(Rafael): b = Xr . Yr

b = kryptos_mp_mul(&b, src_r);
if (a == NULL) {
done = 0;
goto kryptos_mp_karatsuba_epilogue;
}

// INFO(Rafael): c = (Xl + Xr) . (Yl + Yr)

c = kryptos_assign_mp_value(&c, dest_l);
if (c == NULL) {
done = 0;
goto kryptos_mp_karatsuba_epilogue;
}
c = kryptos_mp_add(&c, dest_r);
if (c == NULL) {
done = 0;
goto kryptos_mp_karatsuba_epilogue;
}

src_l_plus_src_r = kryptos_assign_mp_value(&src_l_plus_src_r, src_l);
if (src_l_plus_src_r == NULL) {
done = 0;
goto kryptos_mp_karatsuba_epilogue;
}
src_l_plus_src_r = kryptos_mp_add(&src_l_plus_src_r, src_r);
if (src_l_plus_src_r == NULL) {
done = 0;
goto kryptos_mp_karatsuba_epilogue;
}

c = kryptos_mp_mul(&c, src_l_plus_src_r);

// INFO(Rafael): c = c - a - b
c = kryptos_mp_sub(&c, a);
if (c == NULL) {
done = 0;
goto kryptos_mp_karatsuba_epilogue;
}

c = kryptos_mp_sub(&c, b);
if (c == NULL) {
done = 0;
goto kryptos_mp_karatsuba_epilogue;
}

// INFO(Rafael): XY = aB^n + cB^{n/2} + b
//printf("Xr = ");kryptos_print_mp(dest_r);
//printf("Yr = ");kryptos_print_mp(src_r);
//printf("B = ");kryptos_print_mp(b);
a = kryptos_mp_lsh(&a, shlv);
if (a == NULL) {
done = 0;
goto kryptos_mp_karatsuba_epilogue;
}
c = kryptos_mp_lsh(&c, shlv >> 1);
if (c == NULL) {
done = 0;
goto kryptos_mp_karatsuba_epilogue;
}

a = kryptos_mp_add(&a, c);
if (a == NULL) {
done = 0;
goto kryptos_mp_karatsuba_epilogue;
}
a = kryptos_mp_add(&a, b);
if (a == NULL) {
done = 0;
goto kryptos_mp_karatsuba_epilogue;
}
(*dest) = kryptos_assign_mp_value(dest, a);
if ((*dest) == NULL) {
done = 0;
goto kryptos_mp_karatsuba_epilogue;
}

kryptos_mp_karatsuba_epilogue:

if (!done) {
kryptos_del_mp_value((*dest));
(*dest) = NULL;
}

if (dest_l != NULL) {
kryptos_del_mp_value(dest_l);
}

if (dest_r != NULL) {
kryptos_del_mp_value(dest_r);
}

if (src_l != NULL) {
kryptos_del_mp_value(src_l);
}

if (src_r != NULL) {
kryptos_del_mp_value(src_r);
}

if (a != NULL) {
kryptos_del_mp_value(a);
}

if (b != NULL) {
kryptos_del_mp_value(b);
}

if (c != NULL) {
kryptos_del_mp_value(c);
}

if (src_l_plus_src_r != NULL) {
kryptos_del_mp_value(src_l_plus_src_r);
}

return (*dest);
}

kryptos_mp_value_t *kryptos_mp_mul(kryptos_mp_value_t **dest, const kryptos_mp_value_t *src) {
size_t r;
kryptos_mp_value_t *m;
Expand All @@ -1006,6 +1230,7 @@ kryptos_mp_value_t *kryptos_mp_mul(kryptos_mp_value_t **dest, const kryptos_mp_v
kryptos_mp_digit_t mc;
kryptos_u8_t ac;
#endif
size_t result_bitsize = 0;

if (src == NULL || dest == NULL) {
return NULL;
Expand All @@ -1017,6 +1242,12 @@ kryptos_mp_value_t *kryptos_mp_mul(kryptos_mp_value_t **dest, const kryptos_mp_v
return (*dest);
}

result_bitsize = kryptos_mp_byte2bit((*dest)->data_size + src->data_size + 1);

if (result_bitsize > 2048) {
return kryptos_mp_karatsuba(dest, src);
}

kryptos_mp_max_min(x, y, (*dest), src);

#ifndef KRYPTOS_MP_U32_DIGIT
Expand All @@ -1029,7 +1260,7 @@ kryptos_mp_value_t *kryptos_mp_mul(kryptos_mp_value_t **dest, const kryptos_mp_v

// CLUE(Rafael): Encantamentos baseados em algumas propriedades que talvez a tia Tetéia não quis te contar.

m = kryptos_new_mp_value(kryptos_mp_byte2bit((*dest)->data_size + src->data_size + 1));
m = kryptos_new_mp_value(result_bitsize);

if (m == NULL) {
// WARN(Rafael): Better let a memory leak than return a wrong result.
Expand Down
2 changes: 2 additions & 0 deletions src/kryptos_mp.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ int kryptos_mp_is_zero(const kryptos_mp_value_t *value);

kryptos_u8_t *kryptos_mp_get_bitmap(const kryptos_mp_value_t *src, size_t *bitmap_size);

int kryptos_mp_split(kryptos_mp_value_t **hi, kryptos_mp_value_t **lo, const kryptos_mp_value_t *src);

#ifdef __cplusplus
}
#endif
Expand Down
12 changes: 7 additions & 5 deletions src/tests/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ CUTE_TEST_CASE(kryptos_test_monkey)
// At first glance you should consider the utility that it implements into the library.

// INFO(Rafael): Generic/shared stuff.

/*
CUTE_RUN_TEST(kryptos_memcmp_tests);
CUTE_RUN_TEST(kryptos_memset_tests);
CUTE_RUN_TEST(kryptos_memory_tests);
Expand Down Expand Up @@ -56,13 +56,13 @@ CUTE_TEST_CASE(kryptos_test_monkey)
CUTE_RUN_TEST(kryptos_hex_tests);
CUTE_RUN_TEST(kryptos_u8_ptr_to_hex_tests);
CUTE_RUN_TEST(kryptos_hash_common_tests);

*/
// -=-=-=-=- If you have just added a new cipher take a look in "kryptos_dsl_tests" case, there is some work to
// be done there too! -=-=-=-=-=-=-

// -=-=-=-=- If you have just added a new cipher you must implement a GCM test case for this new cipher, even being
// a unsupported mode for this cipher, take a look at previous gcm test cases -=-=-=-=-

/*
// INFO(Rafael): Internal DSL stuff.
CUTE_RUN_TEST(kryptos_dsl_tests);
Expand Down Expand Up @@ -367,9 +367,10 @@ CUTE_TEST_CASE(kryptos_test_monkey)
CUTE_RUN_TEST(kryptos_mp_le_tests);
CUTE_RUN_TEST(kryptos_mp_is_neg_tests);
CUTE_RUN_TEST(kryptos_mp_add_tests);
CUTE_RUN_TEST(kryptos_mp_sub_tests);
CUTE_RUN_TEST(kryptos_mp_sub_tests);*/
CUTE_RUN_TEST(kryptos_mp_split_tests);
CUTE_RUN_TEST(kryptos_mp_mul_tests);
CUTE_RUN_TEST(kryptos_mp_mul_digit_tests);
/* CUTE_RUN_TEST(kryptos_mp_mul_digit_tests);
CUTE_RUN_TEST(kryptos_mp_not_tests);
CUTE_RUN_TEST(kryptos_mp_inv_tests);
CUTE_RUN_TEST(kryptos_mp_lsh_tests);
Expand Down Expand Up @@ -491,6 +492,7 @@ CUTE_TEST_CASE(kryptos_test_monkey)
} else {
printf("WARN: The ECDSA signature tests were skipped.\n");
}
*/
// CUTE_RUN_TEST(poke_bloody_poke);
CUTE_TEST_CASE_END

Expand Down
Loading

0 comments on commit 908f0f4

Please sign in to comment.