aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/math/mp/mp_core.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/math/mp/mp_core.h')
-rw-r--r--src/lib/math/mp/mp_core.h198
1 files changed, 166 insertions, 32 deletions
diff --git a/src/lib/math/mp/mp_core.h b/src/lib/math/mp/mp_core.h
index 40ff5fadd..9a19a46be 100644
--- a/src/lib/math/mp/mp_core.h
+++ b/src/lib/math/mp/mp_core.h
@@ -15,6 +15,7 @@
#include <botan/mem_ops.h>
#include <botan/internal/mp_asmi.h>
#include <botan/internal/ct_utils.h>
+#include <algorithm>
namespace Botan {
@@ -170,6 +171,46 @@ inline void bigint_cnd_addsub(word mask, word x[], const word y[], size_t size)
}
/*
+* Equivalent to
+* bigint_cnd_add( mask, x, size, y, size);
+* bigint_cnd_sub(~mask, x, size, z, size);
+*
+* Mask must be either 0 or all 1 bits
+*
+* Returns the carry or borrow resp
+*/
+inline word bigint_cnd_addsub(word mask, word x[],
+ const word y[], const word z[],
+ size_t size)
+ {
+ const size_t blocks = size - (size % 8);
+
+ word carry = 0;
+ word borrow = 0;
+
+ word t0[8] = { 0 };
+ word t1[8] = { 0 };
+
+ for(size_t i = 0; i != blocks; i += 8)
+ {
+ carry = word8_add3(t0, x + i, y + i, carry);
+ borrow = word8_sub3(t1, x + i, z + i, borrow);
+
+ for(size_t j = 0; j != 8; ++j)
+ x[i+j] = CT::select(mask, t0[j], t1[j]);
+ }
+
+ for(size_t i = blocks; i != size; ++i)
+ {
+ t0[0] = word_add(x[i], y[i], &carry);
+ t1[0] = word_sub(x[i], z[i], &borrow);
+ x[i] = CT::select(mask, t0[0], t1[0]);
+ }
+
+ return CT::select(mask, carry, borrow);
+ }
+
+/*
* 2s complement absolute value
* If cond > 0 sets x to ~x + 1
* Runs in constant time
@@ -331,7 +372,7 @@ inline word bigint_sub3(word z[],
* Otherwise compute z = y - x
* No borrow is possible since the result is always >= 0
*
-* Returns 1 if x >= y or 0 if x < y
+* Returns ~0 if x >= y or 0 if x < y
* @param z output array of at least N words
* @param x input array of N words
* @param y input array of N words
@@ -364,9 +405,7 @@ inline word bigint_sub_abs(word z[],
ws1[i] = word_sub(y[i], x[i], &borrow1);
}
- word mask = CT::conditional_copy_mem(borrow1, z, ws0, ws1, N);
-
- return CT::select<word>(mask, 0, 1);
+ return CT::conditional_copy_mem(borrow0, z, ws1, ws0, N);
}
/*
@@ -495,23 +534,6 @@ inline void bigint_linmul3(word z[], const word x[], size_t x_size, word y)
}
/**
-* Montgomery Reduction
-* @param z integer to reduce, of size exactly 2*(p_size+1).
- Output is in the first p_size+1 words, higher
- words are set to zero.
-* @param p modulus
-* @param p_size size of p
-* @param p_dash Montgomery value
-* @param workspace array of at least 2*(p_size+1) words
-* @param ws_size size of workspace in words
-*/
-void bigint_monty_redc(word z[],
- const word p[], size_t p_size,
- word p_dash,
- word workspace[],
- size_t ws_size);
-
-/**
* Compare x and y
* Return -1 if x < y
* Return 0 if x == y
@@ -520,24 +542,116 @@ void bigint_monty_redc(word z[],
inline int32_t bigint_cmp(const word x[], size_t x_size,
const word y[], size_t y_size)
{
- if(x_size < y_size) { return (-bigint_cmp(y, y_size, x, x_size)); }
+ static_assert(sizeof(word) >= sizeof(uint32_t), "Size assumption");
+
+ const uint32_t LT = static_cast<uint32_t>(-1);
+ const uint32_t EQ = 0;
+ const uint32_t GT = 1;
+
+ const size_t common_elems = std::min(x_size, y_size);
+
+ uint32_t result = EQ; // until found otherwise
+
+ for(size_t i = 0; i != common_elems; i++)
+ {
+ const word is_eq = CT::is_equal(x[i], y[i]);
+ const word is_lt = CT::is_less(x[i], y[i]);
+ result = CT::select<uint32_t>(is_eq, result, CT::select<uint32_t>(is_lt, LT, GT));
+ }
+
+ if(x_size < y_size)
+ {
+ word mask = 0;
+ for(size_t i = x_size; i != y_size; i++)
+ mask |= y[i];
+
+ // If any bits were set in high part of y, then x < y
+ result = CT::select<uint32_t>(CT::is_zero(mask), result, LT);
+ }
+ else if(y_size < x_size)
+ {
+ word mask = 0;
+ for(size_t i = y_size; i != x_size; i++)
+ mask |= x[i];
+
+ // If any bits were set in high part of x, then x > y
+ result = CT::select<uint32_t>(CT::is_zero(mask), result, GT);
+ }
+
+ CT::unpoison(result);
+ BOTAN_DEBUG_ASSERT(result == LT || result == GT || result == EQ);
+ return static_cast<int32_t>(result);
+ }
+
+/**
+* Compare x and y
+* Return ~0 if x[0:x_size] < y[0:y_size] or 0 otherwise
+* If lt_or_equal is true, returns ~0 also for x == y
+*/
+inline word bigint_ct_is_lt(const word x[], size_t x_size,
+ const word y[], size_t y_size,
+ bool lt_or_equal = false)
+ {
+ const size_t common_elems = std::min(x_size, y_size);
+
+ word is_lt = CT::expand_mask<word>(lt_or_equal);
- while(x_size > y_size)
+ for(size_t i = 0; i != common_elems; i++)
{
- if(x[x_size-1])
- return 1;
- x_size--;
+ const word eq = CT::is_equal(x[i], y[i]);
+ const word lt = CT::is_less(x[i], y[i]);
+ is_lt = CT::select(eq, is_lt, lt);
}
- for(size_t i = x_size; i > 0; --i)
+ if(x_size < y_size)
{
- if(x[i-1] > y[i-1])
- return 1;
- if(x[i-1] < y[i-1])
- return -1;
+ word mask = 0;
+ for(size_t i = x_size; i != y_size; i++)
+ mask |= y[i];
+ // If any bits were set in high part of y, then is_lt should be forced true
+ is_lt |= ~CT::is_zero(mask);
}
+ else if(y_size < x_size)
+ {
+ word mask = 0;
+ for(size_t i = y_size; i != x_size; i++)
+ mask |= x[i];
- return 0;
+ // If any bits were set in high part of x, then is_lt should be false
+ is_lt &= CT::is_zero(mask);
+ }
+
+ CT::unpoison(is_lt);
+ return is_lt;
+ }
+
+inline word bigint_ct_is_eq(const word x[], size_t x_size,
+ const word y[], size_t y_size)
+ {
+ const size_t common_elems = std::min(x_size, y_size);
+
+ word diff = 0;
+
+ for(size_t i = 0; i != common_elems; i++)
+ {
+ diff |= (x[i] ^ y[i]);
+ }
+
+ // If any bits were set in high part of x/y, then they are not equal
+ if(x_size < y_size)
+ {
+ for(size_t i = x_size; i != y_size; i++)
+ diff |= y[i];
+ }
+ else if(y_size < x_size)
+ {
+ for(size_t i = y_size; i != x_size; i++)
+ diff |= x[i];
+ }
+
+ const word is_equal = CT::is_zero(diff);
+ CT::unpoison(is_equal);
+ return is_equal;
}
/**
@@ -578,6 +692,9 @@ inline word bigint_divop(word n1, word n0, word d)
*/
inline word bigint_modop(word n1, word n0, word d)
{
+ if(d == 0)
+ throw Invalid_Argument("bigint_modop divide by zero");
+
#if defined(BOTAN_HAS_MP_DWORD)
return ((static_cast<dword>(n1) << BOTAN_MP_WORD_BITS) | n0) % d;
#else
@@ -605,6 +722,23 @@ void bigint_comba_sqr9(word out[18], const word in[9]);
void bigint_comba_sqr16(word out[32], const word in[16]);
void bigint_comba_sqr24(word out[48], const word in[24]);
+/**
+* Montgomery Reduction
+* @param z integer to reduce, of size exactly 2*(p_size+1).
+ Output is in the first p_size+1 words, higher
+ words are set to zero.
+* @param p modulus
+* @param p_size size of p
+* @param p_dash Montgomery value
+* @param workspace array of at least 2*(p_size+1) words
+* @param ws_size size of workspace in words
+*/
+void bigint_monty_redc(word z[],
+ const word p[], size_t p_size,
+ word p_dash,
+ word workspace[],
+ size_t ws_size);
+
/*
* High Level Multiplication/Squaring Interfaces
*/