Botan 3.11.0
Crypto and TLS for C&
mp_monty.cpp
Go to the documentation of this file.
1/*
2* Montgomery Reduction
3* (C) 1999-2011,2025 Jack Lloyd
4* 2006 Luca Piccarreta
5* 2016 Matthias Gierlings
6*
7* Botan is released under the Simplified BSD License (see license.txt)
8*/
9
10#include <botan/internal/mp_core.h>
11
12#include <botan/assert.h>
13
14namespace Botan {
15
16namespace {
17
18BOTAN_FORCE_INLINE void mul_rev_range(word3<word>& accum, const word ws[], const word p[], size_t bound) {
19 /*
20 Unrolled version of:
21
22 for(size_t i = 0; i < bound; ++i) {
23 accum.mul(ws[i], p[bound - i]);
24 }
25 */
26
27 size_t lower = 0;
28 while(lower < bound) {
29 const size_t upper = bound - lower;
30
31 if(upper >= 16) {
32 accum.mul(ws[lower], p[upper]);
33 accum.mul(ws[lower + 1], p[upper - 1]);
34 accum.mul(ws[lower + 2], p[upper - 2]);
35 accum.mul(ws[lower + 3], p[upper - 3]);
36 accum.mul(ws[lower + 4], p[upper - 4]);
37 accum.mul(ws[lower + 5], p[upper - 5]);
38 accum.mul(ws[lower + 6], p[upper - 6]);
39 accum.mul(ws[lower + 7], p[upper - 7]);
40 accum.mul(ws[lower + 8], p[upper - 8]);
41 accum.mul(ws[lower + 9], p[upper - 9]);
42 accum.mul(ws[lower + 10], p[upper - 10]);
43 accum.mul(ws[lower + 11], p[upper - 11]);
44 accum.mul(ws[lower + 12], p[upper - 12]);
45 accum.mul(ws[lower + 13], p[upper - 13]);
46 accum.mul(ws[lower + 14], p[upper - 14]);
47 accum.mul(ws[lower + 15], p[upper - 15]);
48 lower += 16;
49 } else if(upper >= 8) {
50 accum.mul(ws[lower], p[upper]);
51 accum.mul(ws[lower + 1], p[upper - 1]);
52 accum.mul(ws[lower + 2], p[upper - 2]);
53 accum.mul(ws[lower + 3], p[upper - 3]);
54 accum.mul(ws[lower + 4], p[upper - 4]);
55 accum.mul(ws[lower + 5], p[upper - 5]);
56 accum.mul(ws[lower + 6], p[upper - 6]);
57 accum.mul(ws[lower + 7], p[upper - 7]);
58 lower += 8;
59 } else if(upper >= 4) {
60 accum.mul(ws[lower], p[upper]);
61 accum.mul(ws[lower + 1], p[upper - 1]);
62 accum.mul(ws[lower + 2], p[upper - 2]);
63 accum.mul(ws[lower + 3], p[upper - 3]);
64 lower += 4;
65 } else if(upper >= 2) {
66 accum.mul(ws[lower], p[upper]);
67 accum.mul(ws[lower + 1], p[upper - 1]);
68 lower += 2;
69 } else {
70 accum.mul(ws[lower], p[upper]);
71 lower += 1;
72 }
73 }
74}
75
76} // namespace
77
78/*
79* Montgomery reduction - product scanning form
80*
81* Algorithm 5 from "Energy-Efficient Software Implementation of Long
82* Integer Modular Arithmetic"
83* (https://www.iacr.org/archive/ches2005/006.pdf)
84*
85* See also
86*
87* https://eprint.iacr.org/2013/882.pdf
88* https://www.microsoft.com/en-us/research/wp-content/uploads/1996/01/j37acmon.pdf
89*/
91 word r[], const word z[], size_t z_size, const word p[], size_t p_size, word p_dash, word ws[]) {
92 BOTAN_ARG_CHECK(z_size >= 2 * p_size && p_size > 0, "Invalid sizes for bigint_monty_redc_generic");
93
94 word3<word> accum;
95
96 accum.add(z[0]);
97
98 ws[0] = accum.monty_step(p[0], p_dash);
99
100 for(size_t i = 1; i != p_size; ++i) {
101 mul_rev_range(accum, ws, p, i);
102 accum.add(z[i]);
103 ws[i] = accum.monty_step(p[0], p_dash);
104 }
105
106 for(size_t i = 0; i != p_size - 1; ++i) {
107 mul_rev_range(accum, &ws[i + 1], &p[i], p_size - (i + 1));
108 accum.add(z[p_size + i]);
109 ws[i] = accum.extract();
110 }
111
112 accum.add(z[2 * p_size - 1]);
113
114 ws[p_size - 1] = accum.extract();
115 // w1 is the final part, which is not stored in the workspace
116 const word w1 = accum.extract();
117
118 /*
119 * The result might need to be reduced mod p. To avoid a timing
120 * channel, always perform the subtraction. If in the computation
121 * of x - p a borrow is required then x was already < p.
122 *
123 * x starts at ws[0] and is p_size bytes long plus a possible high
124 * digit left over in w1.
125 *
126 * x - p starts at z[0] and is also p_size bytes long
127 *
128 * If borrow was set after the subtraction, then x was already less
129 * than p and the subtraction was not needed. In that case overwrite
130 * z[0:p_size] with the original x in ws[0:p_size].
131 *
132 * We only copy out p_size in the final step because we know
133 * the Montgomery result is < P
134 */
135
136 bigint_monty_maybe_sub(p_size, r, w1, ws, p);
137}
138
139} // namespace Botan
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:33
constexpr void add(W x)
Definition mp_asmi.h:601
constexpr W monty_step(W p0, W p_dash)
Definition mp_asmi.h:618
constexpr W extract()
Definition mp_asmi.h:610
#define BOTAN_FORCE_INLINE
Definition compiler.h:87
BOTAN_FUZZER_API void bigint_monty_redc_generic(word r[], const word z[], size_t z_size, const word p[], size_t p_size, word p_dash, word ws[])
Definition mp_monty.cpp:90
constexpr void bigint_monty_maybe_sub(size_t N, W z[], W x0, const W x[], const W p[])
Definition mp_core.h:225
std::conditional_t< HasNative64BitRegisters, std::uint64_t, uint32_t > word
Definition types.h:119