Botan 3.11.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 BOTAN_FORCE_INLINE 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 BOTAN_FORCE_INLINE 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 BOTAN_FORCE_INLINE 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 BOTAN_FORCE_INLINE Self operator* (const Self &a, const Self &b)
constexpr BOTAN_FORCE_INLINE Self operator+ (const Self &a, const Self &b)
constexpr BOTAN_FORCE_INLINE 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 163 of file pcurves_impl.h.

Member Typedef Documentation

◆ Self

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

Definition at line 177 of file pcurves_impl.h.

Constructor & Destructor Documentation

◆ IntMod() [1/3]

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

Definition at line 180 of file pcurves_impl.h.

180: 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 889 of file pcurves_impl.h.

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

◆ _const_time_unpoison()

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

Definition at line 891 of file pcurves_impl.h.

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

◆ _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 547 of file pcurves_impl.h.

547 {
548 constexpr auto INV_2 = p_div_2_plus_1(Rep::P);
549
550 // Conditional ok: this function is variable time
551 while((a.m_val[0] & 1) != 1) {
552 shift_right<1>(a.m_val);
553
554 const W borrow = shift_right<1>(x.m_val);
555
556 // Conditional ok: this function is variable time
557 if(borrow) {
558 bigint_add2(x.m_val.data(), N, INV_2.data(), N);
559 }
560 }
561 }
constexpr auto bigint_add2(W x[], size_t x_size, const W y[], size_t y_size) -> W
Definition mp_core.h:94
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:727

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 256 of file pcurves_impl.h.

256 {
257 auto r = y;
259 return r;
260 }
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 367 of file pcurves_impl.h.

367 {
368 const W mask = cond.into_bitmask<W>();
369
370 for(size_t i = 0; i != N; ++i) {
371 m_val[i] = Botan::choose(mask, nx.m_val[i], m_val[i]);
372 }
373 }
BOTAN_FORCE_INLINE constexpr T choose(T mask, T a, T b)
Definition bit_ops.h:216

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 380 of file pcurves_impl.h.

380 {
381 const W mask = cond.into_bitmask<W>();
382
383 for(size_t i = 0; i != N; ++i) {
384 x.m_val[i] = Botan::choose(mask, nx.m_val[i], x.m_val[i]);
385 y.m_val[i] = Botan::choose(mask, ny.m_val[i], y.m_val[i]);
386 }
387 }

◆ 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 394 of file pcurves_impl.h.

395 {
396 const W mask = cond.into_bitmask<W>();
397
398 for(size_t i = 0; i != N; ++i) {
399 x.m_val[i] = Botan::choose(mask, nx.m_val[i], x.m_val[i]);
400 y.m_val[i] = Botan::choose(mask, ny.m_val[i], y.m_val[i]);
401 z.m_val[i] = Botan::choose(mask, nz.m_val[i], z.m_val[i]);
402 }
403 }

◆ 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 410 of file pcurves_impl.h.

410 {
411 const W mask = cond.into_bitmask<W>();
412
413 for(size_t i = 0; i != N; ++i) {
414 auto nx = Botan::choose(mask, y.m_val[i], x.m_val[i]);
415 auto ny = Botan::choose(mask, x.m_val[i], y.m_val[i]);
416 x.m_val[i] = nx;
417 y.m_val[i] = ny;
418 }
419 }

◆ 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 882 of file pcurves_impl.h.

882 {
884 v[0] = (x >= 0) ? x : -x;
885 auto s = Self::from_words(v);
886 return (x >= 0) ? s : s.negate();
887 }
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 248 of file pcurves_impl.h.

248 {
249 const auto flip = (even != this->is_even());
250 return Self::choose(flip, this->negate(), *this);
251 }
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 792 of file pcurves_impl.h.

792 {
793 // Conditional ok: input length is public
794 if(bytes.size() != Self::BYTES) {
795 return {};
796 }
797
798 const auto words = bytes_to_words<W, N, BYTES>(bytes.first<Self::BYTES>());
799
800 // Conditional acceptable: std::optional is implicitly not constant time
801 if(!bigint_ct_is_lt(words.data(), N, P.data(), N).as_bool()) {
802 return {};
803 }
804
805 // Safe because we checked above that words is an integer < P
806 return Self::from_words(words);
807 }
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:473

◆ div2()

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

Return the value of this divided by 2

Definition at line 302 of file pcurves_impl.h.

302 {
303 // The inverse of 2 modulo P is (P/2)+1; this avoids a constexpr time
304 // general inversion, which some compilers can't handle
305 constexpr auto INV_2 = p_div_2_plus_1(Rep::P);
306
307 // We could multiply by INV_2 but there is a better way ...
308
309 std::array<W, N> t = value();
310 const W borrow = shift_right<1>(t);
311
312 // If value was odd, add (P/2)+1
313 const auto mask = CT::Mask<W>::expand(borrow).value();
314
315 W carry = 0;
316
317 for(size_t i = 0; i != N; ++i) {
318 t[i] = word_add(t[i], INV_2[i] & mask, &carry);
319 }
320
321 return Self(t);
322 }
static constexpr Mask< T > expand(T v)
Definition ct_utils.h:392
IntMod< Rep > Self
constexpr auto word_add(W x, W y, W *carry) -> W
Definition mp_asmi.h:231

◆ 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 774 of file pcurves_impl.h.

774 {
775 static_assert(L >= N);
777 for(size_t i = 0; i != N; ++i) {
778 val[i] = stash[i];
779 }
780 return Self(val);
781 }

◆ 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 816 of file pcurves_impl.h.

816 {
817 static_assert(8 * L <= 2 * Self::BITS);
821 }
static constexpr size_t BITS
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition mem_ops.h:144

◆ 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 829 of file pcurves_impl.h.

829 {
830 // Conditional ok: input length is public
831 if(bytes.size() > 2 * Self::BYTES) {
832 return {};
833 }
834
836 copy_mem(std::span{padded_bytes}.last(bytes.size()), bytes);
838 }

◆ 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 211 of file pcurves_impl.h.

211 {
212 if constexpr(L == N) {
213 return Self(Rep::to_rep(w));
214 } else {
215 static_assert(L < N);
216 std::array<W, N> ew = {};
217 copy_mem(std::span{ew}.template first<L>(), w);
218 return Self(Rep::to_rep(ew));
219 }
220 }

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 538 of file pcurves_impl.h.

538{ 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 598 of file pcurves_impl.h.

598 {
599 // Conditional ok: this function is variable time
600 if(this->is_zero().as_bool()) {
601 return Self::zero();
602 }
603
604 auto x = Self(std::array<W, N>{1}); // 1 in standard domain
605 auto b = Self(this->to_words()); // *this in standard domain
606
607 // First loop iteration
609
610 auto a = b.negate();
611 // y += x but y is zero at the outset
612 auto y = x;
613
614 // First half of second loop iteration
616
617 for(;;) {
618 // Conditional ok: this function is variable time
619 if(a.m_val == b.m_val) {
620 // At this point it should be that a == b == 1
621 auto r = y.negate();
622
623 // Convert back to Montgomery if required
624 r.m_val = Rep::to_rep(r.m_val);
625 return r;
626 }
627
628 auto nx = x + y;
629
630 /*
631 * Otherwise either b > a or a > b
632 *
633 * If b > a we want to set b to b - a
634 * Otherwise we want to set a to a - b
635 *
636 * Compute r = b - a and check if it underflowed
637 * If it did not then we are in the b > a path
638 */
639 std::array<W, N> r; // NOLINT(*-member-init)
640 const word carry = bigint_sub3(r.data(), b.data(), N, a.data(), N);
641
642 // Conditional ok: this function is variable time
643 if(carry == 0) {
644 // b > a
645 b.m_val = r;
646 x = nx;
648 } else {
649 // We know this can't underflow because a > b
650 bigint_sub3(r.data(), a.data(), N, b.data(), N);
651 a.m_val = r;
652 y = nx;
654 }
655 }
656 }
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:192

◆ 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 240 of file pcurves_impl.h.

240 {
241 auto v = Rep::from_rep(m_val);
242 return !CT::Choice::from_int(v[0] & 0x01);
243 }
static constexpr Choice from_int(T v)
Definition ct_utils.h:268

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 230 of file pcurves_impl.h.

230{ 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 235 of file pcurves_impl.h.

235{ 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 225 of file pcurves_impl.h.

225{ 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:785

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

◆ mul2()

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

Return (*this) multiplied by 2.

Definition at line 325 of file pcurves_impl.h.

325 {
326 std::array<W, N> t = value();
327 const W carry = shift_left<1>(t);
328
329 std::array<W, N> r; // NOLINT(*-member-init)
330 bigint_monty_maybe_sub<N>(r.data(), carry, t.data(), P.data());
331 return Self(r);
332 }
constexpr W shift_left(std::array< W, N > &x)
Definition mp_core.h:712
constexpr void bigint_monty_maybe_sub(size_t N, W z[], W x0, const W x[], const W p[])
Definition mp_core.h:225

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 335 of file pcurves_impl.h.

335{ return mul2() + (*this); }
constexpr BOTAN_FORCE_INLINE 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 338 of file pcurves_impl.h.

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

◆ mul8()

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

Return (*this) multiplied by 8.

Definition at line 341 of file pcurves_impl.h.

341{ 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 452 of file pcurves_impl.h.

452 {
453 const W x_is_zero = ~CT::all_zeros(this->data(), N).value();
454
455 std::array<W, N> r; // NOLINT(*-member-init)
456 W carry = 0;
457 for(size_t i = 0; i != N; ++i) {
458 r[i] = word_sub(P[i] & x_is_zero, m_val[i], &carry);
459 }
460
461 return Self(r);
462 }
constexpr auto word_sub(W x, W y, W *carry) -> W
Definition mp_asmi.h:320

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 200 of file pcurves_impl.h.

200{ 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 729 of file pcurves_impl.h.

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

◆ operator*=()

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

Modular multiplication; set this to this * other

Definition at line 355 of file pcurves_impl.h.

355 {
356 std::array<W, 2 * N> z; // NOLINT(*-member-init)
357 comba_mul<N>(z.data(), data(), other.data());
358 m_val = Rep::redc(z);
359 return (*this);
360 }
constexpr void comba_mul(W z[2 *N], const W x[N], const W y[N])
Definition mp_core.h:801

◆ 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 722 of file pcurves_impl.h.

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

◆ 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 477 of file pcurves_impl.h.

477 {
478 constexpr size_t WindowBits = (Self::BITS <= 256) ? 4 : 5;
479 constexpr size_t WindowElements = (1 << WindowBits) - 1;
480
481 constexpr size_t Windows = (Self::BITS + WindowBits - 1) / WindowBits;
482
483 /*
484 A simple fixed width window modular multiplication.
485
486 TODO: investigate using sliding window here
487 */
488
490
491 tbl[0] = (*this);
492
493 for(size_t i = 1; i != WindowElements; ++i) {
494 // Conditional ok: table indexes are public here
495 if(i % 2 == 1) {
496 tbl[i] = tbl[i / 2].square();
497 } else {
498 tbl[i] = tbl[i - 1] * tbl[0];
499 }
500 }
501
502 auto r = Self::one();
503
505
506 // Conditional ok: this function is variable time
507 if(w0 > 0) {
508 r = tbl[w0 - 1];
509 }
510
511 for(size_t i = 1; i != Windows; ++i) {
513
514 const size_t w = read_window_bits<WindowBits>(std::span{exp}, (Windows - i - 1) * WindowBits);
515
516 // Conditional ok: this function is variable time
517 if(w > 0) {
518 r *= tbl[w - 1];
519 }
520 }
521
522 return r;
523 }
constexpr void square_n(size_t n)
constexpr BOTAN_FORCE_INLINE Self square() const
constexpr size_t read_window_bits(std::span< const W, N > words, size_t offset)
Definition mp_core.h:1054

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 851 of file pcurves_impl.h.

851 {
852 constexpr size_t MAX_ATTEMPTS = 1000;
853
855
856 for(size_t i = 0; i != MAX_ATTEMPTS; ++i) {
857 rng.randomize(buf);
858
859 // Zero off high bits that if set would certainly cause us
860 // to be out of range
861 if constexpr(Self::BITS % 8 != 0) {
862 constexpr uint8_t mask = 0xFF >> (8 - (Self::BITS % 8));
863 buf[0] &= mask;
864 }
865
866 // Conditionals ok: rejection sampling reveals only values we didn't use
867 if(auto s = Self::deserialize(buf)) {
868 if(s.value().is_nonzero().as_bool()) {
869 return s.value();
870 }
871 }
872 }
873
874 throw Internal_Error("Failed to generate random Scalar within bounded number of attempts");
875 }
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 739 of file pcurves_impl.h.

739 {
740 auto v = Rep::from_rep(m_val);
741 std::reverse(v.begin(), v.end());
742
743 if constexpr(Self::BYTES == N * WordInfo<W>::bytes) {
744 store_be(bytes, v);
745 } else {
746 // Remove leading zero bytes
747 const auto padded_bytes = store_be(v);
748 constexpr size_t extra = N * WordInfo<W>::bytes - Self::BYTES;
750 }
751 }
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 663 of file pcurves_impl.h.

663 {
664 if constexpr(Self::P_MOD_4 == 3) {
665 // The easy case for square root is when p == 3 (mod 4)
666
667 constexpr auto P_PLUS_1_OVER_4 = p_plus_1_over_4(P);
669
670 // Zero out the return value if it would otherwise be incorrect
671 const CT::Choice correct = (z.square() == *this);
673 return CT::Option<Self>(z, correct);
674 } else {
675 // Shanks-Tonelli, following I.4 in RFC 9380
676
677 /*
678 Constants:
679 1. c1, the largest integer such that 2^c1 divides q - 1.
680 2. c2 = (q - 1) / (2^c1) # Integer arithmetic
681 3. c3 = (c2 - 1) / 2 # Integer arithmetic
682 4. c4, a non-square value in F
683 5. c5 = c4^c2 in F
684 */
685 constexpr auto C1_C2 = shanks_tonelli_c1c2(Self::P);
686 constexpr std::array<W, N> C3 = shanks_tonelli_c3(C1_C2.second);
689 constexpr Self C5 = C4.pow_vartime(C1_C2.second);
690
691 const Self& x = (*this);
692
693 auto z = x.pow_vartime(C3);
694 auto t = z.square();
695 t *= x;
696 z *= x;
697 auto b = t;
698 auto c = C5;
699
700 for(size_t i = C1_C2.first; i >= 2; i--) {
701 b.square_n(i - 2);
702 const CT::Choice e = b.is_one();
703 z.conditional_assign(!e, z * c);
704 c.square_n(1);
705 t.conditional_assign(!e, t * c);
706 b = t;
707 }
708
709 // Zero out the return value if it would otherwise be incorrect
710 const CT::Choice correct = (z.square() == *this);
712 return CT::Option<Self>(z, correct);
713 }
714 }
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>
BOTAN_FORCE_INLINE Self Botan::IntMod< Rep >::square ( ) const
inlineconstexpr

Modular squaring

Returns the square of this after modular reduction

Definition at line 426 of file pcurves_impl.h.

426 {
427 std::array<W, 2 * N> z; // NOLINT(*-member-init)
428 comba_sqr<N>(z.data(), this->data());
429 return Self(Rep::redc(z));
430 }
constexpr void comba_sqr(W z[2 *N], const W x[N])
Definition mp_core.h:837

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 439 of file pcurves_impl.h.

439 {
440 std::array<W, 2 * N> z; // NOLINT(*-member-init)
441 for(size_t i = 0; i != n; ++i) {
442 comba_sqr<N>(z.data(), this->data());
443 m_val = Rep::redc(z);
444 }
445 }

◆ 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 759 of file pcurves_impl.h.

759 {
760 static_assert(L >= N);
762 for(size_t i = 0; i != N; ++i) {
763 stash[i] = m_val[i];
764 }
765 return stash;
766 }

◆ 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 734 of file pcurves_impl.h.

734{ 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 195 of file pcurves_impl.h.

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

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

◆ operator*

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

Modular multiplication; return c = a * b

Definition at line 346 of file pcurves_impl.h.

346 {
347 std::array<W, 2 * N> z; // NOLINT(*-member-init)
348 comba_mul<N>(z.data(), a.data(), b.data());
349 return Self(Rep::redc(z));
350 }

◆ operator+

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

Modular addition; return c = a + b

Definition at line 265 of file pcurves_impl.h.

265 {
266 std::array<W, N> t; // NOLINT(*-member-init)
267
268 W carry = 0;
269 for(size_t i = 0; i != N; ++i) {
270 t[i] = word_add(a.m_val[i], b.m_val[i], &carry);
271 }
272
273 std::array<W, N> r; // NOLINT(*-member-init)
274 bigint_monty_maybe_sub<N>(r.data(), carry, t.data(), P.data());
275 return Self(r);
276 }

◆ operator-

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

Modular subtraction; return c = a - b

Definition at line 281 of file pcurves_impl.h.

281 {
282 std::array<W, N> r; // NOLINT(*-member-init)
283 W carry = 0;
284 for(size_t i = 0; i != N; ++i) {
285 r[i] = word_sub(a.m_val[i], b.m_val[i], &carry);
286 }
287
288 const auto mask = CT::Mask<W>::expand(carry).value();
289
290 carry = 0;
291
292 for(size_t i = 0; i != N; ++i) {
293 r[i] = word_add(r[i], P[i] & mask, &carry);
294 }
295
296 return Self(r);
297 }

Member Data Documentation

◆ BITS

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

Definition at line 172 of file pcurves_impl.h.

◆ BYTES

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

Definition at line 173 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 175 of file pcurves_impl.h.


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