/src/botan/src/lib/math/pcurves/pcurves_secp224r1/pcurves_secp224r1.cpp
Line | Count | Source |
1 | | /* |
2 | | * (C) 2024 Jack Lloyd |
3 | | * |
4 | | * Botan is released under the Simplified BSD License (see license.txt) |
5 | | */ |
6 | | |
7 | | #include <botan/internal/pcurves_instance.h> |
8 | | |
9 | | #include <botan/internal/pcurves_solinas.h> |
10 | | #include <botan/internal/pcurves_wrap.h> |
11 | | |
12 | | namespace Botan::PCurve { |
13 | | |
14 | | namespace { |
15 | | |
16 | | namespace secp224r1 { |
17 | | |
18 | | template <typename Params> |
19 | | class Secp224r1Rep final { |
20 | | public: |
21 | | static constexpr auto P = Params::P; |
22 | | static constexpr size_t N = Params::N; |
23 | | typedef typename Params::W W; |
24 | | |
25 | 405k | constexpr static std::array<W, N> redc(const std::array<W, 2 * N>& z) { |
26 | 405k | const int64_t X00 = get_uint32(z.data(), 0); |
27 | 405k | const int64_t X01 = get_uint32(z.data(), 1); |
28 | 405k | const int64_t X02 = get_uint32(z.data(), 2); |
29 | 405k | const int64_t X03 = get_uint32(z.data(), 3); |
30 | 405k | const int64_t X04 = get_uint32(z.data(), 4); |
31 | 405k | const int64_t X05 = get_uint32(z.data(), 5); |
32 | 405k | const int64_t X06 = get_uint32(z.data(), 6); |
33 | 405k | const int64_t X07 = get_uint32(z.data(), 7); |
34 | 405k | const int64_t X08 = get_uint32(z.data(), 8); |
35 | 405k | const int64_t X09 = get_uint32(z.data(), 9); |
36 | 405k | const int64_t X10 = get_uint32(z.data(), 10); |
37 | 405k | const int64_t X11 = get_uint32(z.data(), 11); |
38 | 405k | const int64_t X12 = get_uint32(z.data(), 12); |
39 | 405k | const int64_t X13 = get_uint32(z.data(), 13); |
40 | | |
41 | 405k | const int64_t S0 = 0x00000001 + X00 - X07 - X11; |
42 | 405k | const int64_t S1 = 0x00000000 + X01 - X08 - X12; |
43 | 405k | const int64_t S2 = 0x00000000 + X02 - X09 - X13; |
44 | 405k | const int64_t S3 = 0xFFFFFFFF + X03 + X07 + X11 - X10; |
45 | 405k | const int64_t S4 = 0xFFFFFFFF + X04 + X08 + X12 - X11; |
46 | 405k | const int64_t S5 = 0xFFFFFFFF + X05 + X09 + X13 - X12; |
47 | 405k | const int64_t S6 = 0xFFFFFFFF + X06 + X10 - X13; |
48 | | |
49 | 405k | std::array<W, N> r = {}; |
50 | | |
51 | 405k | SolinasAccum sum(r); |
52 | | |
53 | 405k | sum.accum(S0); |
54 | 405k | sum.accum(S1); |
55 | 405k | sum.accum(S2); |
56 | 405k | sum.accum(S3); |
57 | 405k | sum.accum(S4); |
58 | 405k | sum.accum(S5); |
59 | 405k | sum.accum(S6); |
60 | 405k | const auto S = sum.final_carry(0); |
61 | | |
62 | 405k | BOTAN_DEBUG_ASSERT(S <= 2); |
63 | | |
64 | 405k | const auto correction = p224_mul_mod_224(S); |
65 | 405k | W borrow = bigint_sub2(r.data(), N, correction.data(), N); |
66 | | |
67 | 405k | bigint_cnd_add(borrow, r.data(), N, P.data(), N); |
68 | | |
69 | 405k | return r; |
70 | 405k | } |
71 | | |
72 | 1.59k | constexpr static std::array<W, N> one() { return std::array<W, N>{1}; } |
73 | | |
74 | 46 | constexpr static std::array<W, N> to_rep(const std::array<W, N>& x) { return x; } |
75 | | |
76 | | constexpr static std::array<W, N> wide_to_rep(const std::array<W, 2 * N>& x) { return redc(x); } |
77 | | |
78 | 80 | constexpr static std::array<W, N> from_rep(const std::array<W, N>& z) { return z; } |
79 | | |
80 | | private: |
81 | | // Return (i*P-224) % 2**224 |
82 | | // |
83 | | // Assumes i is small |
84 | 405k | constexpr static std::array<W, N> p224_mul_mod_224(W i) { |
85 | 405k | static_assert(WordInfo<W>::bits == 32 || WordInfo<W>::bits == 64); |
86 | | |
87 | | // For small i, multiples of P-224 have a simple structure so it's faster to |
88 | | // compute the value directly vs a (constant time) table lookup |
89 | | |
90 | 405k | auto r = P; |
91 | | |
92 | | if constexpr(WordInfo<W>::bits == 32) { |
93 | | r[3] -= i; |
94 | | r[0] += i; |
95 | 405k | } else { |
96 | 405k | const W i32 = i << 32; |
97 | 405k | r[1] -= i32; |
98 | 405k | r[0] += i; |
99 | 405k | } |
100 | 405k | return r; |
101 | 405k | } |
102 | | }; |
103 | | |
104 | | // clang-format off |
105 | | class Params final : public EllipticCurveParameters< |
106 | | "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001", |
107 | | "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE", |
108 | | "B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4", |
109 | | "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D", |
110 | | "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21", |
111 | | "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34"> { |
112 | | }; |
113 | | |
114 | | // clang-format on |
115 | | |
116 | | class Curve final : public EllipticCurve<Params, Secp224r1Rep> { |
117 | | public: |
118 | | // Return the square of the inverse of x |
119 | 850 | static FieldElement fe_invert2(const FieldElement& x) { |
120 | 850 | auto z = x.square(); |
121 | 850 | z *= x; |
122 | 850 | z = z.square(); |
123 | 850 | z *= x; |
124 | 850 | auto t0 = z; |
125 | 850 | t0.square_n(3); |
126 | 850 | t0 *= z; |
127 | 850 | auto t1 = t0; |
128 | 850 | t1.square_n(6); |
129 | 850 | t0 *= t1; |
130 | 850 | t0.square_n(3); |
131 | 850 | z *= t0; |
132 | 850 | t0 = z.square(); |
133 | 850 | t0 *= x; |
134 | 850 | t1 = t0; |
135 | 850 | t1.square_n(16); |
136 | 850 | t0 *= t1; |
137 | 850 | t1 = t0; |
138 | 850 | t1.square_n(15); |
139 | 850 | z *= t1; |
140 | 850 | t1 = z; |
141 | 850 | t1.square_n(47); |
142 | 850 | z *= t1; |
143 | 850 | z = z.square(); |
144 | 850 | z *= x; |
145 | 850 | t1 = z; |
146 | 850 | t1.square_n(32); |
147 | 850 | t0 *= t1; |
148 | 850 | t0.square_n(96); |
149 | 850 | z *= t0; |
150 | 850 | return z.square(); |
151 | 850 | } |
152 | | |
153 | 8 | static Scalar scalar_invert(const Scalar& x) { |
154 | | // Generated using https://github.com/mmcloughlin/addchain |
155 | 8 | auto t6 = x.square(); |
156 | 8 | auto z = t6.square(); |
157 | 8 | auto t3 = x * z; |
158 | 8 | auto t2 = t3 * t6; |
159 | 8 | auto t8 = t2 * z; |
160 | 8 | auto t7 = t8 * z; |
161 | 8 | auto t5 = t7 * z; |
162 | 8 | auto t0 = t5 * t6; |
163 | 8 | auto t1 = t0 * t6; |
164 | 8 | auto t4 = t1 * z; |
165 | 8 | z = t4 * t6; |
166 | 8 | t6 *= z; |
167 | 8 | auto t10 = t6.square(); |
168 | 8 | auto t9 = t10 * x; |
169 | 8 | t10.square_n(5); |
170 | 8 | t9 *= t10; |
171 | 8 | t10.square_n(5); |
172 | 8 | t9 *= t10; |
173 | 8 | t10 = t9; |
174 | 8 | t10.square_n(16); |
175 | 8 | t10 *= t9; |
176 | 8 | auto t11 = t10; |
177 | 8 | t11.square_n(32); |
178 | 8 | t11 *= t10; |
179 | 8 | t11.square_n(32); |
180 | 8 | t10 *= t11; |
181 | 8 | t10.square_n(16); |
182 | 8 | t9 *= t10; |
183 | 8 | t9.square_n(7); |
184 | 8 | t8 *= t9; |
185 | 8 | t8.square_n(4); |
186 | 8 | t8 *= t3; |
187 | 8 | t8.square_n(8); |
188 | 8 | t8 *= t1; |
189 | 8 | t8.square_n(10); |
190 | 8 | t8 *= t1; |
191 | 8 | t8.square_n(7); |
192 | 8 | t7 *= t8; |
193 | 8 | t7.square_n(11); |
194 | 8 | t6 *= t7; |
195 | 8 | t6.square_n(9); |
196 | 8 | t5 *= t6; |
197 | 8 | t5.square_n(5); |
198 | 8 | t4 *= t5; |
199 | 8 | t4.square_n(3); |
200 | 8 | t4 *= t3; |
201 | 8 | t4.square_n(5); |
202 | 8 | t4 *= t3; |
203 | 8 | t4.square_n(5); |
204 | 8 | t3 *= t4; |
205 | 8 | t3.square_n(8); |
206 | 8 | t3 *= t0; |
207 | 8 | t3.square_n(4); |
208 | 8 | t2 *= t3; |
209 | 8 | t2.square_n(8); |
210 | 8 | t1 *= t2; |
211 | 8 | t1.square_n(9); |
212 | 8 | t0 *= t1; |
213 | 8 | t0.square_n(8); |
214 | 8 | z *= t0; |
215 | 8 | z = z.square(); |
216 | 8 | z *= x; |
217 | 8 | return z; |
218 | 8 | } |
219 | | }; |
220 | | |
221 | | } // namespace secp224r1 |
222 | | |
223 | | } // namespace |
224 | | |
225 | 110 | std::shared_ptr<const PrimeOrderCurve> PCurveInstance::secp224r1() { |
226 | 110 | return PrimeOrderCurveImpl<secp224r1::Curve>::instance(); |
227 | 110 | } |
228 | | |
229 | | } // namespace Botan::PCurve |