Botan 3.9.0
Crypto and TLS for C&
Botan::IntMod< Rep > Class Template Referencefinal

#include <pcurves_impl.h>

Public Types

using Self = IntMod<Rep>

Public Member Functions

constexpr void _const_time_poison () const
constexpr void _const_time_unpoison () const
constexpr void conditional_assign (CT::Choice cond, const Self &nx)
constexpr Self correct_sign (CT::Choice even) const
Self div2 () const
constexpr IntMod ()
 IntMod (const Self &other)=default
 IntMod (Self &&other)=default
constexpr Self invert () const
constexpr Self invert_vartime () const
constexpr CT::Choice is_even () const
constexpr CT::Choice is_nonzero () const
constexpr CT::Choice is_one () const
constexpr CT::Choice is_zero () const
constexpr Self mul2 () const
 Return (*this) multiplied by 2.
constexpr Self mul3 () const
 Return (*this) multiplied by 3.
constexpr Self mul4 () const
 Return (*this) multiplied by 4.
constexpr Self mul8 () const
 Return (*this) multiplied by 8.
constexpr Self negate () const
constexpr CT::Choice operator!= (const Self &other) const
constexpr Selfoperator*= (const Self &other)
IntModoperator= (const Self &other)=default
IntModoperator= (Self &&other)=default
constexpr CT::Choice operator== (const Self &other) const
constexpr Self pow_vartime (const std::array< W, N > &exp) const
constexpr void serialize_to (std::span< uint8_t, Self::BYTES > bytes) const
constexpr CT::Option< Selfsqrt () const
constexpr Self square () const
constexpr void square_n (size_t n)
template<size_t L>
std::array< W, L > stash_value () const
constexpr std::array< W, Self::N > to_words () const
 ~IntMod ()=default

Static Public Member Functions

static constexpr void _invert_vartime_div2_helper (Self &a, Self &x)
static constexpr Self choose (CT::Choice choice, const Self &x, const Self &y)
static constexpr void conditional_assign (Self &x, Self &y, CT::Choice cond, const Self &nx, const Self &ny)
static constexpr void conditional_assign (Self &x, Self &y, Self &z, CT::Choice cond, const Self &nx, const Self &ny, const Self &nz)
static constexpr void conditional_swap (CT::Choice cond, Self &x, Self &y)
static consteval Self constant (int8_t x)
static std::optional< Selfdeserialize (std::span< const uint8_t > bytes)
template<size_t L>
static Self from_stash (const std::array< W, L > &stash)
template<size_t L>
static constexpr Self from_wide_bytes (std::span< const uint8_t, L > bytes)
static constexpr std::optional< Selffrom_wide_bytes_varlen (std::span< const uint8_t > bytes)
template<size_t L>
static constexpr Self from_words (std::array< W, L > w)
static constexpr Self one ()
static Self random (RandomNumberGenerator &rng)
static constexpr Self zero ()

Static Public Attributes

static constexpr size_t BITS = count_bits(P)
static constexpr size_t BYTES = (BITS + 7) / 8
static constexpr auto P_MOD_4 = P[0] % 4

Friends

constexpr Self operator* (const Self &a, const Self &b)
constexpr Self operator+ (const Self &a, const Self &b)
constexpr Self operator- (const Self &a, const Self &b)

Detailed Description

template<typename Rep>
class Botan::IntMod< Rep >

Integers Modulo (a Prime)

This is used to store and manipulate integers modulo the field (for the affine x/y or Jacobian x/y/z coordinates) and group order (for scalar arithmetic).

This class is parameterized by Rep which handles the modular reduction step, as well (if required) any conversions into or out of the inner representation. This is primarily for Montgomery arithmetic; specialized reduction methods instead keep the integer in the "standard" form.

Most of the code in this class does work for arbitrary moduli. However at least div2 and invert make assumptions that the modulus is prime.

Any function that does not contain "vartime" or equivalent in the name is written such that it does not leak information about its arguments via control flow or memory access patterns.

Definition at line 142 of file pcurves_impl.h.

Member Typedef Documentation

◆ Self

template<typename Rep>
using Botan::IntMod< Rep >::Self = IntMod<Rep>

Definition at line 156 of file pcurves_impl.h.

Constructor & Destructor Documentation

◆ IntMod() [1/3]

template<typename Rep>
Botan::IntMod< Rep >::IntMod ( )
inlineconstexpr

Definition at line 159 of file pcurves_impl.h.

159: m_val({}) {}

◆ IntMod() [2/3]

template<typename Rep>
Botan::IntMod< Rep >::IntMod ( const Self & other)
default

◆ IntMod() [3/3]

template<typename Rep>
Botan::IntMod< Rep >::IntMod ( Self && other)
default

◆ ~IntMod()

template<typename Rep>
Botan::IntMod< Rep >::~IntMod ( )
default

Member Function Documentation

◆ _const_time_poison()

template<typename Rep>
void Botan::IntMod< Rep >::_const_time_poison ( ) const
inlineconstexpr

Definition at line 855 of file pcurves_impl.h.

855{ CT::poison(m_val); }
constexpr void poison(const T *p, size_t n)
Definition ct_utils.h:54

◆ _const_time_unpoison()

template<typename Rep>
void Botan::IntMod< Rep >::_const_time_unpoison ( ) const
inlineconstexpr

Definition at line 857 of file pcurves_impl.h.

857{ CT::unpoison(m_val); }
constexpr void unpoison(const T *p, size_t n)
Definition ct_utils.h:65

◆ _invert_vartime_div2_helper()

template<typename Rep>
constexpr void Botan::IntMod< Rep >::_invert_vartime_div2_helper ( Self & a,
Self & x )
inlinestaticconstexpr

Helper for variable time BEEA

Note this function assumes that its arguments are in the standard domain, not the Montgomery domain. invert_vartime converts its argument out of Montgomery, and then back to Montgomery when returning the result.

Definition at line 513 of file pcurves_impl.h.

513 {
514 constexpr auto INV_2 = p_div_2_plus_1(Rep::P);
515
516 // Conditional ok: this function is variable time
517 while((a.m_val[0] & 1) != 1) {
518 shift_right<1>(a.m_val);
519
520 W borrow = shift_right<1>(x.m_val);
521
522 // Conditional ok: this function is variable time
523 if(borrow) {
524 bigint_add2(x.m_val.data(), N, INV_2.data(), N);
525 }
526 }
527 }
constexpr auto bigint_add2(W x[], size_t x_size, const W y[], size_t y_size) -> W
Definition mp_core.h:96
consteval std::array< W, N > p_div_2_plus_1(const std::array< W, N > &p)
constexpr W shift_right(std::array< W, N > &x)
Definition mp_core.h:626

Referenced by Botan::IntMod< MontgomeryRep< ScalarParams > >::invert_vartime().

◆ choose()

template<typename Rep>
constexpr Self Botan::IntMod< Rep >::choose ( CT::Choice choice,
const Self & x,
const Self & y )
inlinestaticconstexpr

Return x or y depending on if choice is set or not

Definition at line 235 of file pcurves_impl.h.

235 {
236 auto r = y;
238 return r;
239 }
constexpr void conditional_assign(CT::Choice cond, const Self &nx)

Referenced by Botan::IntMod< MontgomeryRep< ScalarParams > >::correct_sign().

◆ conditional_assign() [1/3]

template<typename Rep>
void Botan::IntMod< Rep >::conditional_assign ( CT::Choice cond,
const Self & nx )
inlineconstexpr

Conditional assignment

If cond is true, sets *this to nx

Definition at line 333 of file pcurves_impl.h.

333 {
334 const W mask = CT::Mask<W>::from_choice(cond).value();
335
336 for(size_t i = 0; i != N; ++i) {
337 m_val[i] = Botan::choose(mask, nx.m_val[i], m_val[i]);
338 }
339 }
static constexpr Mask< T > from_choice(Choice c)
Definition ct_utils.h:430
BOTAN_FORCE_INLINE constexpr T choose(T mask, T a, T b)
Definition bit_ops.h:196

Referenced by Botan::IntMod< MontgomeryRep< ScalarParams > >::choose().

◆ conditional_assign() [2/3]

template<typename Rep>
constexpr void Botan::IntMod< Rep >::conditional_assign ( Self & x,
Self & y,
CT::Choice cond,
const Self & nx,
const Self & ny )
inlinestaticconstexpr

Conditional assignment

If cond is true, sets x to nx and y to ny

Definition at line 346 of file pcurves_impl.h.

346 {
347 const W mask = CT::Mask<W>::from_choice(cond).value();
348
349 for(size_t i = 0; i != N; ++i) {
350 x.m_val[i] = Botan::choose(mask, nx.m_val[i], x.m_val[i]);
351 y.m_val[i] = Botan::choose(mask, ny.m_val[i], y.m_val[i]);
352 }
353 }

◆ conditional_assign() [3/3]

template<typename Rep>
constexpr void Botan::IntMod< Rep >::conditional_assign ( Self & x,
Self & y,
Self & z,
CT::Choice cond,
const Self & nx,
const Self & ny,
const Self & nz )
inlinestaticconstexpr

Conditional assignment

If cond is true, sets x to nx, y to ny, and z to nz

Definition at line 360 of file pcurves_impl.h.

361 {
362 const W mask = CT::Mask<W>::from_choice(cond).value();
363
364 for(size_t i = 0; i != N; ++i) {
365 x.m_val[i] = Botan::choose(mask, nx.m_val[i], x.m_val[i]);
366 y.m_val[i] = Botan::choose(mask, ny.m_val[i], y.m_val[i]);
367 z.m_val[i] = Botan::choose(mask, nz.m_val[i], z.m_val[i]);
368 }
369 }

◆ conditional_swap()

template<typename Rep>
constexpr void Botan::IntMod< Rep >::conditional_swap ( CT::Choice cond,
Self & x,
Self & y )
inlinestaticconstexpr

Conditional swap

If cond is true, swaps the values of x and y

Definition at line 376 of file pcurves_impl.h.

376 {
377 const W mask = CT::Mask<W>::from_choice(cond).value();
378
379 for(size_t i = 0; i != N; ++i) {
380 auto nx = Botan::choose(mask, y.m_val[i], x.m_val[i]);
381 auto ny = Botan::choose(mask, x.m_val[i], y.m_val[i]);
382 x.m_val[i] = nx;
383 y.m_val[i] = ny;
384 }
385 }

◆ constant()

template<typename Rep>
consteval Self Botan::IntMod< Rep >::constant ( int8_t x)
inlinestaticconsteval

Create a small compile time constant

Notice this function is consteval, and so can only be called at compile time

Definition at line 848 of file pcurves_impl.h.

848 {
850 v[0] = (x >= 0) ? x : -x;
851 auto s = Self::from_words(v);
852 return (x >= 0) ? s : s.negate();
853 }
constexpr Self negate() const
static constexpr Self from_words(std::array< W, L > w)

◆ correct_sign()

template<typename Rep>
Self Botan::IntMod< Rep >::correct_sign ( CT::Choice even) const
inlineconstexpr

Return either this or -this depending on which is even

Definition at line 227 of file pcurves_impl.h.

227 {
228 const auto flip = (even != this->is_even());
229 return Self::choose(flip, this->negate(), *this);
230 }
static constexpr Self choose(CT::Choice choice, const Self &x, const Self &y)
constexpr CT::Choice is_even() const

◆ deserialize()

template<typename Rep>
std::optional< Self > Botan::IntMod< Rep >::deserialize ( std::span< const uint8_t > bytes)
inlinestatic

Deserialize an integer from a bytestring

Returns nullopt if the input is an encoding greater than or equal P

This function also requires that the bytestring be exactly of the expected length; short bytestrings, or a long bytestring with leading zero bytes, are also rejected.

Definition at line 758 of file pcurves_impl.h.

758 {
759 // Conditional ok: input length is public
760 if(bytes.size() != Self::BYTES) {
761 return {};
762 }
763
764 const auto words = bytes_to_words<W, N, BYTES>(bytes.first<Self::BYTES>());
765
766 // Conditional acceptable: std::optional is implicitly not constant time
767 if(!bigint_ct_is_lt(words.data(), N, P.data(), N).as_bool()) {
768 return {};
769 }
770
771 // Safe because we checked above that words is an integer < P
772 return Self::from_words(words);
773 }
static constexpr size_t BYTES
constexpr auto bytes_to_words(std::span< const uint8_t, L > bytes)
constexpr auto bigint_ct_is_lt(const W x[], size_t x_size, const W y[], size_t y_size, bool lt_or_equal=false) -> CT::Mask< W >
Definition mp_core.h:475

◆ div2()

template<typename Rep>
Self Botan::IntMod< Rep >::div2 ( ) const
inline

Return the value of this divided by 2

Definition at line 274 of file pcurves_impl.h.

274 {
275 // The inverse of 2 modulo P is (P/2)+1; this avoids a constexpr time
276 // general inversion, which some compilers can't handle
277 constexpr auto INV_2 = p_div_2_plus_1(Rep::P);
278
279 // We could multiply by INV_2 but there is a better way ...
280
281 std::array<W, N> t = value();
283
284 // If value was odd, add (P/2)+1
285 bigint_cnd_add(borrow, t.data(), INV_2.data(), N);
286
287 return Self(t);
288 }
IntMod< Rep > Self
constexpr W bigint_cnd_add(W cnd, W x[], const W y[], size_t size)
Definition mp_core.h:47

◆ from_stash()

template<typename Rep>
template<size_t L>
Self Botan::IntMod< Rep >::from_stash ( const std::array< W, L > & stash)
inlinestatic

Restore the value previously stashed

See pcurves_wrap.h for why/where this is used

Definition at line 740 of file pcurves_impl.h.

740 {
741 static_assert(L >= N);
743 for(size_t i = 0; i != N; ++i) {
744 val[i] = stash[i];
745 }
746 return Self(val);
747 }

◆ from_wide_bytes()

template<typename Rep>
template<size_t L>
constexpr Self Botan::IntMod< Rep >::from_wide_bytes ( std::span< const uint8_t, L > bytes)
inlinestaticconstexpr

Modular reduce a larger input

This takes a bytestring that is at most twice the length of the modulus, and modular reduces it.

Definition at line 782 of file pcurves_impl.h.

782 {
783 static_assert(8 * L <= 2 * Self::BITS);
787 }
static constexpr size_t BITS
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition mem_ops.h:145

◆ from_wide_bytes_varlen()

template<typename Rep>
constexpr std::optional< Self > Botan::IntMod< Rep >::from_wide_bytes_varlen ( std::span< const uint8_t > bytes)
inlinestaticconstexpr

Modular reduce a larger input

This takes a bytestring that is at most twice the length of the modulus, and modular reduces it.

Definition at line 795 of file pcurves_impl.h.

795 {
796 // Conditional ok: input length is public
797 if(bytes.size() > 2 * Self::BYTES) {
798 return {};
799 }
800
802 copy_mem(std::span{padded_bytes}.last(bytes.size()), bytes);
804 }

◆ from_words()

template<typename Rep>
template<size_t L>
constexpr Self Botan::IntMod< Rep >::from_words ( std::array< W, L > w)
inlinestaticconstexpr

Consume an array of words and convert it to an IntMod

This handles the Montgomery conversion, if required.

Note that this function assumes that w represents an integer that is less than the modulus.

Definition at line 190 of file pcurves_impl.h.

190 {
191 if constexpr(L == N) {
192 return Self(Rep::to_rep(w));
193 } else {
194 static_assert(L < N);
195 std::array<W, N> ew = {};
196 copy_mem(std::span{ew}.template first<L>(), w);
197 return Self(Rep::to_rep(ew));
198 }
199 }

Referenced by Botan::IntMod< MontgomeryRep< ScalarParams > >::constant(), and Botan::IntMod< MontgomeryRep< ScalarParams > >::deserialize().

◆ invert()

template<typename Rep>
Self Botan::IntMod< Rep >::invert ( ) const
inlineconstexpr

Returns the modular inverse, or 0 if no modular inverse exists.

If the modulus is prime the only value that has no modular inverse is 0.

This uses Fermat's little theorem, and so assumes that p is prime

Since P is public, P-2 is as well, thus using a variable time modular exponentiation routine is safe.

This function is only used if the curve does not provide an addition chain for specific inversions (see for example pcurves_secp256r1.cpp)

Definition at line 504 of file pcurves_impl.h.

504{ return pow_vartime(Self::P_MINUS_2); }
constexpr Self pow_vartime(const std::array< W, N > &exp) const

◆ invert_vartime()

template<typename Rep>
Self Botan::IntMod< Rep >::invert_vartime ( ) const
inlineconstexpr

Returns the modular inverse, or 0 if no modular inverse exists.

This function assumes that the modulus is prime

This function does something a bit nasty and converts from the normal representation (for scalars, Montgomery) into the "standard" representation. This relies on the fact that we aren't doing any multiplications within this function, just additions, subtractions, division by 2, and comparisons.

The reason is there is no good way to compare integers in the Montgomery domain; we could convert out for each comparison but this is slower than just doing a constant-time inversion.

This is loosely based on the algorithm BoringSSL uses in BN_mod_inverse_odd, which is a variant of the Binary Extended Euclidean algorithm. It is optimized somewhat by taking advantage of a couple of observations.

In the first two iterations, the control flow is known because a is less than the modulus and not zero, and we know that the modulus is odd. So we peel out those iterations. This also avoids having to initialize a with the modulus, because we instead set it directly to what the first loop iteration would have updated it to. This ensures that all values are always less than or equal to the modulus.

Then we take advantage of the fact that in each iteration of the loop, at the end we update either b/x or a/y, but never both. In the next iteration of the loop, we attempt to modify b/x or a/y depending on the low zero bits of b or a. But if a or b were not updated in the previous iteration than they will still be odd, and nothing will happen. Instead update just the pair we need to update, right after writing to b/x or a/y resp.

Definition at line 564 of file pcurves_impl.h.

564 {
565 // Conditional ok: this function is variable time
566 if(this->is_zero().as_bool()) {
567 return Self::zero();
568 }
569
570 auto x = Self(std::array<W, N>{1}); // 1 in standard domain
571 auto b = Self(this->to_words()); // *this in standard domain
572
573 // First loop iteration
575
576 auto a = b.negate();
577 // y += x but y is zero at the outset
578 auto y = x;
579
580 // First half of second loop iteration
582
583 for(;;) {
584 // Conditional ok: this function is variable time
585 if(a.m_val == b.m_val) {
586 // At this point it should be that a == b == 1
587 auto r = y.negate();
588
589 // Convert back to Montgomery if required
590 r.m_val = Rep::to_rep(r.m_val);
591 return r;
592 }
593
594 auto nx = x + y;
595
596 /*
597 * Otherwise either b > a or a > b
598 *
599 * If b > a we want to set b to b - a
600 * Otherwise we want to set a to a - b
601 *
602 * Compute r = b - a and check if it underflowed
603 * If it did not then we are in the b > a path
604 */
605 std::array<W, N> r; // NOLINT(*-member-init)
606 word carry = bigint_sub3(r.data(), b.data(), N, a.data(), N);
607
608 // Conditional ok: this function is variable time
609 if(carry == 0) {
610 // b > a
611 b.m_val = r;
612 x = nx;
614 } else {
615 // We know this can't underflow because a > b
616 bigint_sub3(r.data(), a.data(), N, b.data(), N);
617 a.m_val = r;
618 y = nx;
620 }
621 }
622 }
constexpr CT::Choice is_zero() const
static constexpr void _invert_vartime_div2_helper(Self &a, Self &x)
constexpr std::array< W, Self::N > to_words() const
static constexpr Self zero()
constexpr auto bigint_sub3(W z[], const W x[], size_t x_size, const W y[], size_t y_size) -> W
Definition mp_core.h:194

◆ is_even()

template<typename Rep>
CT::Choice Botan::IntMod< Rep >::is_even ( ) const
inlineconstexpr

Check in constant time if this is an even integer

Definition at line 219 of file pcurves_impl.h.

219 {
220 auto v = Rep::from_rep(m_val);
221 return !CT::Choice::from_int(v[0] & 0x01);
222 }
static constexpr Choice from_int(T v)
Definition ct_utils.h:314

Referenced by Botan::IntMod< MontgomeryRep< ScalarParams > >::correct_sign().

◆ is_nonzero()

template<typename Rep>
CT::Choice Botan::IntMod< Rep >::is_nonzero ( ) const
inlineconstexpr

Check in constant time if this not equal to zero

Definition at line 209 of file pcurves_impl.h.

209{ return !is_zero(); }

◆ is_one()

template<typename Rep>
CT::Choice Botan::IntMod< Rep >::is_one ( ) const
inlineconstexpr

Check in constant time if this equal to one

Definition at line 214 of file pcurves_impl.h.

214{ return (*this == Self::one()); }
static constexpr Self one()

◆ is_zero()

template<typename Rep>
CT::Choice Botan::IntMod< Rep >::is_zero ( ) const
inlineconstexpr

Check in constant time if this is equal to zero

Definition at line 204 of file pcurves_impl.h.

204{ return CT::all_zeros(m_val.data(), m_val.size()).as_choice(); }
constexpr CT::Mask< T > all_zeros(const T elem[], size_t len)
Definition ct_utils.h:813

Referenced by Botan::IntMod< MontgomeryRep< ScalarParams > >::invert_vartime(), and Botan::IntMod< MontgomeryRep< ScalarParams > >::is_nonzero().

◆ mul2()

template<typename Rep>
Self Botan::IntMod< Rep >::mul2 ( ) const
inlineconstexpr

Return (*this) multiplied by 2.

Definition at line 291 of file pcurves_impl.h.

291 {
292 std::array<W, N> t = value();
293 W carry = shift_left<1>(t);
294
295 std::array<W, N> r; // NOLINT(*-member-init)
296 bigint_monty_maybe_sub<N>(r.data(), carry, t.data(), P.data());
297 return Self(r);
298 }
constexpr W shift_left(std::array< W, N > &x)
Definition mp_core.h:612
constexpr void bigint_monty_maybe_sub(size_t N, W z[], W x0, const W x[], const W p[])
Definition mp_core.h:227

Referenced by Botan::IntMod< MontgomeryRep< ScalarParams > >::mul3(), Botan::IntMod< MontgomeryRep< ScalarParams > >::mul4(), and Botan::IntMod< MontgomeryRep< ScalarParams > >::mul8().

◆ mul3()

template<typename Rep>
Self Botan::IntMod< Rep >::mul3 ( ) const
inlineconstexpr

Return (*this) multiplied by 3.

Definition at line 301 of file pcurves_impl.h.

301{ return mul2() + (*this); }
constexpr Self mul2() const
Return (*this) multiplied by 2.

◆ mul4()

template<typename Rep>
Self Botan::IntMod< Rep >::mul4 ( ) const
inlineconstexpr

Return (*this) multiplied by 4.

Definition at line 304 of file pcurves_impl.h.

304{ return mul2().mul2(); }

◆ mul8()

template<typename Rep>
Self Botan::IntMod< Rep >::mul8 ( ) const
inlineconstexpr

Return (*this) multiplied by 8.

Definition at line 307 of file pcurves_impl.h.

307{ return mul2().mul2().mul2(); }

◆ negate()

template<typename Rep>
Self Botan::IntMod< Rep >::negate ( ) const
inlineconstexpr

Modular negation

Returns the additive inverse of (*this)

Definition at line 418 of file pcurves_impl.h.

418 {
419 const W x_is_zero = ~CT::all_zeros(this->data(), N).value();
420
421 std::array<W, N> r; // NOLINT(*-member-init)
422 W carry = 0;
423 for(size_t i = 0; i != N; ++i) {
424 r[i] = word_sub(P[i] & x_is_zero, m_val[i], &carry);
425 }
426
427 return Self(r);
428 }
constexpr auto word_sub(W x, W y, W *carry) -> W
Definition mp_asmi.h:280

Referenced by Botan::IntMod< MontgomeryRep< ScalarParams > >::correct_sign(), and Botan::IntMod< MontgomeryRep< ScalarParams > >::invert_vartime().

◆ one()

template<typename Rep>
constexpr Self Botan::IntMod< Rep >::one ( )
inlinestaticconstexpr

Return integer one

Definition at line 179 of file pcurves_impl.h.

179{ return Self(Rep::one()); }

Referenced by Botan::IntMod< MontgomeryRep< ScalarParams > >::pow_vartime().

◆ operator!=()

template<typename Rep>
CT::Choice Botan::IntMod< Rep >::operator!= ( const Self & other) const
inlineconstexpr

Constant time integer inequality test

Definition at line 695 of file pcurves_impl.h.

695{ return !(*this == other); }

◆ operator*=()

template<typename Rep>
Self & Botan::IntMod< Rep >::operator*= ( const Self & other)
inlineconstexpr

Modular multiplication; set this to this * other

Definition at line 321 of file pcurves_impl.h.

321 {
322 std::array<W, 2 * N> z; // NOLINT(*-member-init)
323 comba_mul<N>(z.data(), data(), other.data());
324 m_val = Rep::redc(z);
325 return (*this);
326 }
constexpr void comba_mul(W z[2 *N], const W x[N], const W y[N])
Definition mp_core.h:699

◆ operator=() [1/2]

template<typename Rep>
IntMod & Botan::IntMod< Rep >::operator= ( const Self & other)
default

◆ operator=() [2/2]

template<typename Rep>
IntMod & Botan::IntMod< Rep >::operator= ( Self && other)
default

◆ operator==()

template<typename Rep>
CT::Choice Botan::IntMod< Rep >::operator== ( const Self & other) const
inlineconstexpr

Constant time integer equality test

Since both this and other are in Montgomery representation (if applicable), we can always compare the words directly, without having to convert out.

Definition at line 688 of file pcurves_impl.h.

688 {
689 return CT::is_equal(this->data(), other.data(), N).as_choice();
690 }
constexpr CT::Mask< T > is_equal(const T x[], const T y[], size_t len)
Definition ct_utils.h:826

◆ pow_vartime()

template<typename Rep>
Self Botan::IntMod< Rep >::pow_vartime ( const std::array< W, N > & exp) const
inlineconstexpr

Modular Exponentiation (Variable Time)

This function is variable time with respect to the exponent. It should only be used when exp is not secret. In the current code, exp is always a compile-time constant.

This function should not leak any information about this, since the value being operated on may be a secret.

TODO: this interface should be changed so that the exponent is always a compile-time constant; this should allow some interesting optimizations.

Definition at line 443 of file pcurves_impl.h.

443 {
444 constexpr size_t WindowBits = (Self::BITS <= 256) ? 4 : 5;
445 constexpr size_t WindowElements = (1 << WindowBits) - 1;
446
447 constexpr size_t Windows = (Self::BITS + WindowBits - 1) / WindowBits;
448
449 /*
450 A simple fixed width window modular multiplication.
451
452 TODO: investigate using sliding window here
453 */
454
456
457 tbl[0] = (*this);
458
459 for(size_t i = 1; i != WindowElements; ++i) {
460 // Conditional ok: table indexes are public here
461 if(i % 2 == 1) {
462 tbl[i] = tbl[i / 2].square();
463 } else {
464 tbl[i] = tbl[i - 1] * tbl[0];
465 }
466 }
467
468 auto r = Self::one();
469
471
472 // Conditional ok: this function is variable time
473 if(w0 > 0) {
474 r = tbl[w0 - 1];
475 }
476
477 for(size_t i = 1; i != Windows; ++i) {
479
480 const size_t w = read_window_bits<WindowBits>(std::span{exp}, (Windows - i - 1) * WindowBits);
481
482 // Conditional ok: this function is variable time
483 if(w > 0) {
484 r *= tbl[w - 1];
485 }
486 }
487
488 return r;
489 }
constexpr void square_n(size_t n)
constexpr Self square() const
constexpr size_t read_window_bits(std::span< const W, N > words, size_t offset)
Definition mp_core.h:952

Referenced by Botan::IntMod< MontgomeryRep< ScalarParams > >::invert(), and Botan::IntMod< MontgomeryRep< ScalarParams > >::sqrt().

◆ random()

template<typename Rep>
Self Botan::IntMod< Rep >::random ( RandomNumberGenerator & rng)
inlinestatic

Return a random integer value in [1,p)

This uses rejection sampling. This could have alternatively been implemented by oversampling the random number generator and then performing a wide reduction. The main reason that approach is avoided here is because it makes testing ECDSA-style known answer tests more difficult.

This function avoids returning zero since in almost all contexts where a random integer is desired we want a random integer in Z_p*

Definition at line 817 of file pcurves_impl.h.

817 {
818 constexpr size_t MAX_ATTEMPTS = 1000;
819
821
822 for(size_t i = 0; i != MAX_ATTEMPTS; ++i) {
823 rng.randomize(buf);
824
825 // Zero off high bits that if set would certainly cause us
826 // to be out of range
827 if constexpr(Self::BITS % 8 != 0) {
828 constexpr uint8_t mask = 0xFF >> (8 - (Self::BITS % 8));
829 buf[0] &= mask;
830 }
831
832 // Conditionals ok: rejection sampling reveals only values we didn't use
833 if(auto s = Self::deserialize(buf)) {
834 if(s.value().is_nonzero().as_bool()) {
835 return s.value();
836 }
837 }
838 }
839
840 throw Internal_Error("Failed to generate random Scalar within bounded number of attempts");
841 }
static std::optional< Self > deserialize(std::span< const uint8_t > bytes)

◆ serialize_to()

template<typename Rep>
void Botan::IntMod< Rep >::serialize_to ( std::span< uint8_t, Self::BYTES > bytes) const
inlineconstexpr

Serialize the integer to a bytestring

Definition at line 705 of file pcurves_impl.h.

705 {
706 auto v = Rep::from_rep(m_val);
707 std::reverse(v.begin(), v.end());
708
709 if constexpr(Self::BYTES == N * WordInfo<W>::bytes) {
710 store_be(bytes, v);
711 } else {
712 // Remove leading zero bytes
713 const auto padded_bytes = store_be(v);
714 constexpr size_t extra = N * WordInfo<W>::bytes - Self::BYTES;
716 }
717 }
constexpr auto store_be(ParamTs &&... params)
Definition loadstor.h:745

◆ sqrt()

template<typename Rep>
CT::Option< Self > Botan::IntMod< Rep >::sqrt ( ) const
inlineconstexpr

Return the modular square root if it exists

The CT::Option will be unset if the square root does not exist

Definition at line 629 of file pcurves_impl.h.

629 {
630 if constexpr(Self::P_MOD_4 == 3) {
631 // The easy case for square root is when p == 3 (mod 4)
632
633 constexpr auto P_PLUS_1_OVER_4 = p_plus_1_over_4(P);
635
636 // Zero out the return value if it would otherwise be incorrect
637 const CT::Choice correct = (z.square() == *this);
639 return CT::Option<Self>(z, correct);
640 } else {
641 // Shanks-Tonelli, following I.4 in RFC 9380
642
643 /*
644 Constants:
645 1. c1, the largest integer such that 2^c1 divides q - 1.
646 2. c2 = (q - 1) / (2^c1) # Integer arithmetic
647 3. c3 = (c2 - 1) / 2 # Integer arithmetic
648 4. c4, a non-square value in F
649 5. c5 = c4^c2 in F
650 */
651 constexpr auto C1_C2 = shanks_tonelli_c1c2(Self::P);
652 constexpr std::array<W, N> C3 = shanks_tonelli_c3(C1_C2.second);
655 constexpr Self C5 = C4.pow_vartime(C1_C2.second);
656
657 const Self& x = (*this);
658
659 auto z = x.pow_vartime(C3);
660 auto t = z.square();
661 t *= x;
662 z *= x;
663 auto b = t;
664 auto c = C5;
665
666 for(size_t i = C1_C2.first; i >= 2; i--) {
667 b.square_n(i - 2);
668 const CT::Choice e = b.is_one();
669 z.conditional_assign(!e, z * c);
670 c.square_n(1);
671 t.conditional_assign(!e, t * c);
672 b = t;
673 }
674
675 // Zero out the return value if it would otherwise be incorrect
676 const CT::Choice correct = (z.square() == *this);
678 return CT::Option<Self>(z, correct);
679 }
680 }
static constexpr auto P_MOD_4
constexpr CT::Choice is_one() const
consteval std::array< W, N > shanks_tonelli_c3(const std::array< W, N > &c2)
consteval std::array< W, N > p_plus_1_over_4(const std::array< W, N > &p)
consteval std::array< W, N > p_minus_1_over_2(const std::array< W, N > &p)
consteval auto shanks_tonelli_c4(const std::array< W, N > &p_minus_1_over_2) -> Z
consteval std::pair< size_t, std::array< W, N > > shanks_tonelli_c1c2(const std::array< W, N > &p)

◆ square()

template<typename Rep>
Self Botan::IntMod< Rep >::square ( ) const
inlineconstexpr

Modular squaring

Returns the square of this after modular reduction

Definition at line 392 of file pcurves_impl.h.

392 {
393 std::array<W, 2 * N> z; // NOLINT(*-member-init)
394 comba_sqr<N>(z.data(), this->data());
395 return Self(Rep::redc(z));
396 }
constexpr void comba_sqr(W z[2 *N], const W x[N])
Definition mp_core.h:735

Referenced by Botan::IntMod< MontgomeryRep< ScalarParams > >::sqrt(), and Botan::EllipticCurve< Params, FieldRep >::x3_ax_b().

◆ square_n()

template<typename Rep>
void Botan::IntMod< Rep >::square_n ( size_t n)
inlineconstexpr

Repeated modular squaring

Returns the nth square of this

(Alternate view, returns this raised to the 2^nth power)

Definition at line 405 of file pcurves_impl.h.

405 {
406 std::array<W, 2 * N> z; // NOLINT(*-member-init)
407 for(size_t i = 0; i != n; ++i) {
408 comba_sqr<N>(z.data(), this->data());
409 m_val = Rep::redc(z);
410 }
411 }

◆ stash_value()

template<typename Rep>
template<size_t L>
std::array< W, L > Botan::IntMod< Rep >::stash_value ( ) const
inline

Store the raw words to an array

See pcurves_wrap.h for why/where this is used

Definition at line 725 of file pcurves_impl.h.

725 {
726 static_assert(L >= N);
728 for(size_t i = 0; i != N; ++i) {
729 stash[i] = m_val[i];
730 }
731 return stash;
732 }

◆ to_words()

template<typename Rep>
std::array< W, Self::N > Botan::IntMod< Rep >::to_words ( ) const
inlineconstexpr

Convert the integer to standard representation and return the sequence of words

Definition at line 700 of file pcurves_impl.h.

700{ return Rep::from_rep(m_val); }

Referenced by Botan::IntMod< MontgomeryRep< ScalarParams > >::invert_vartime().

◆ zero()

template<typename Rep>
constexpr Self Botan::IntMod< Rep >::zero ( )
inlinestaticconstexpr

Return integer zero

Note this assumes that the representation of zero is an all zero sequence of words. This is true for both Montgomery and standard representations.

Definition at line 174 of file pcurves_impl.h.

174{ return Self(std::array<W, N>{0}); }

Referenced by Botan::IntMod< MontgomeryRep< ScalarParams > >::invert_vartime().

◆ operator*

template<typename Rep>
Self operator* ( const Self & a,
const Self & b )
friend

Modular multiplication; return c = a * b

Definition at line 312 of file pcurves_impl.h.

312 {
313 std::array<W, 2 * N> z; // NOLINT(*-member-init)
314 comba_mul<N>(z.data(), a.data(), b.data());
315 return Self(Rep::redc(z));
316 }

◆ operator+

template<typename Rep>
Self operator+ ( const Self & a,
const Self & b )
friend

Modular addition; return c = a + b

Definition at line 244 of file pcurves_impl.h.

244 {
245 std::array<W, N> t; // NOLINT(*-member-init)
246
247 W carry = 0;
248 for(size_t i = 0; i != N; ++i) {
249 t[i] = word_add(a.m_val[i], b.m_val[i], &carry);
250 }
251
252 std::array<W, N> r; // NOLINT(*-member-init)
253 bigint_monty_maybe_sub<N>(r.data(), carry, t.data(), P.data());
254 return Self(r);
255 }
constexpr auto word_add(W x, W y, W *carry) -> W
Definition mp_asmi.h:191

◆ operator-

template<typename Rep>
Self operator- ( const Self & a,
const Self & b )
friend

Modular subtraction; return c = a - b

Definition at line 260 of file pcurves_impl.h.

260 {
261 std::array<W, N> r; // NOLINT(*-member-init)
262 W carry = 0;
263 for(size_t i = 0; i != N; ++i) {
264 r[i] = word_sub(a.m_val[i], b.m_val[i], &carry);
265 }
266
267 bigint_cnd_add(carry, r.data(), P.data(), N);
268 return Self(r);
269 }

Member Data Documentation

◆ BITS

template<typename Rep>
size_t Botan::IntMod< Rep >::BITS = count_bits(P)
staticconstexpr

Definition at line 151 of file pcurves_impl.h.

◆ BYTES

template<typename Rep>
size_t Botan::IntMod< Rep >::BYTES = (BITS + 7) / 8
staticconstexpr

Definition at line 152 of file pcurves_impl.h.

◆ P_MOD_4

template<typename Rep>
auto Botan::IntMod< Rep >::P_MOD_4 = P[0] % 4
staticconstexpr

Definition at line 154 of file pcurves_impl.h.


The documentation for this class was generated from the following file: