in native/src/seal/util/uintarith.cpp [16:102]
void multiply_uint(
const uint64_t *operand1, size_t operand1_uint64_count, const uint64_t *operand2,
size_t operand2_uint64_count, size_t result_uint64_count, uint64_t *result)
{
#ifdef SEAL_DEBUG
if (!operand1 && operand1_uint64_count > 0)
{
throw invalid_argument("operand1");
}
if (!operand2 && operand2_uint64_count > 0)
{
throw invalid_argument("operand2");
}
if (!result_uint64_count)
{
throw invalid_argument("result_uint64_count");
}
if (!result)
{
throw invalid_argument("result");
}
if (result != nullptr && (operand1 == result || operand2 == result))
{
throw invalid_argument("result cannot point to the same value as operand1 or operand2");
}
#endif
// Handle fast cases.
if (!operand1_uint64_count || !operand2_uint64_count)
{
// If either operand is 0, then result is 0.
set_zero_uint(result_uint64_count, result);
return;
}
if (result_uint64_count == 1)
{
*result = *operand1 * *operand2;
return;
}
// In some cases these improve performance.
operand1_uint64_count = get_significant_uint64_count_uint(operand1, operand1_uint64_count);
operand2_uint64_count = get_significant_uint64_count_uint(operand2, operand2_uint64_count);
// More fast cases
if (operand1_uint64_count == 1)
{
multiply_uint(operand2, operand2_uint64_count, *operand1, result_uint64_count, result);
return;
}
if (operand2_uint64_count == 1)
{
multiply_uint(operand1, operand1_uint64_count, *operand2, result_uint64_count, result);
return;
}
// Clear out result.
set_zero_uint(result_uint64_count, result);
// Multiply operand1 and operand2.
size_t operand1_index_max = min(operand1_uint64_count, result_uint64_count);
for (size_t operand1_index = 0; operand1_index < operand1_index_max; operand1_index++)
{
const uint64_t *inner_operand2 = operand2;
uint64_t *inner_result = result++;
uint64_t carry = 0;
size_t operand2_index = 0;
size_t operand2_index_max = min(operand2_uint64_count, result_uint64_count - operand1_index);
for (; operand2_index < operand2_index_max; operand2_index++)
{
// Perform 64-bit multiplication of operand1 and operand2
unsigned long long temp_result[2];
multiply_uint64(*operand1, *inner_operand2++, temp_result);
carry = temp_result[1] + add_uint64(temp_result[0], carry, 0, temp_result);
unsigned long long temp;
carry += add_uint64(*inner_result, temp_result[0], 0, &temp);
*inner_result++ = temp;
}
// Write carry if there is room in result
if (operand1_index + operand2_index_max < result_uint64_count)
{
*inner_result = carry;
}
operand1++;
}
}