2626#include < type_traits>
2727
2828#include " scl/math/bases.h"
29- #include " scl/math/fields .h"
29+ #include " scl/math/field_ops .h"
3030#include " scl/math/ring.h"
3131#include " scl/prg.h"
3232
3333namespace scl {
3434namespace details {
3535
3636/* *
37- * @brief Elements of the finite field \f$\mathbb{F}_p\f$ for prime \f$p \f$.
37+ * @brief Elements of the finite field \f$\mathbb{F}\f$.
3838 *
39- * <p>This class defines finite field element that behaves according to some
40- * finite field definition as specified by the \p Field template parameter. The
41- * \p Bits parameter is used to indicate the number of available bits of the
42- * field, but is otherwise ignored.</p>
39+ * <p>The FF class provides the high level interface for "finite field elements"
40+ * in SCL.</p>
4341 *
44- * <p>FF uses will call a number of static methods on \p Field, so these must be
45- * defined in order for FF to work. The interface of these methods can be seen
46- * in #DEFINE_FINITE_FIELD or by reading the documentation of the methods on
47- * FF.</p>
42+ * <p>An instantiation of this template consists of two parameters: A \p Bits
43+ * parameter, indicating the number of bits that the field supports, and a \p
44+ * Field type which determines the behaviour of the field. The \p Bits parameter
45+ * is purely for documenting purposes and can be used to indicate that a
46+ * particular field instantiation supports a particular number of bits for
47+ * computing.</p>
48+ *
49+ * <p>The \p Field parameter must be a class of the following form</p>
50+ *
51+ * \code
52+ * struct SomeField {
53+ * using ValueType = ... // the internal type of a field element
54+ * constexpr static const char* kName = ... // readable name of this field
55+ * constexpr static const std::size_t kByteSize = ... // size in bytes
56+ * constexpr static const std::size_t kBitSize = ... // size in bits
57+ * };
58+ * \endcode
59+ *
60+ * <p>The <code>kBitSize</code> does not need to have any relation to the \p
61+ * Bits parameter, although it's assumed that <code>Bits <= kBitSize</code>.</p>
62+ *
63+ * <p>In order to make a field definition useful, overloads must be defined for
64+ * some or all of the functions in field_ops.h. For example, to support addition
65+ * operations on the field (that is, the operators <code>+</code> and
66+ * <code>+=</code>) we would need to define</p>
67+ *
68+ * \code
69+ * template <>
70+ * void scl::details::FieldAdd<SomeField>(SomeField::ValueType& out,
71+ * const SomeField::ValueType& in) {
72+ * // definition of addition for SomeField
73+ * }
74+ * \endcode
75+ *
76+ * <p>Refer to the documentation for methods on FF to see which specializations
77+ * are needed where.</p>
4878 *
4979 * @tparam Bits the desired bit size of the field
50- * @tparam Field a class defining operations on field elements
51- * @see DEFINE_FINITE_FIELD
80+ * @tparam Field the field
5281 */
5382template <unsigned Bits, typename Field>
5483class FF final : details::RingBase<FF<Bits, Field>> {
@@ -92,16 +121,13 @@ class FF final : details::RingBase<FF<Bits, Field>> {
92121
93122 /* *
94123 * @brief Read a field element from a buffer.
95- *
96- * The de-serialization of field elements are defined by a static method
97- * <code>Field::FromBytes(ValueType&, const unsigned char*)</code>.
98- *
99124 * @param src the buffer
100125 * @return a field element.
126+ * @see scl::details::FieldFromBytes
101127 */
102128 static FF Read (const unsigned char * src) {
103129 FF e;
104- Field::FromBytes (e.mValue , src);
130+ details::FieldFromBytes<Field> (e.mValue , src);
105131 return e;
106132 }
107133
@@ -118,40 +144,34 @@ class FF final : details::RingBase<FF<Bits, Field>> {
118144
119145 /* *
120146 * @brief Create a field element from a string.
121- *
122- * De-stringification is determined by the static method
123- * <code>Field::FromString(ValueType&, const std::string&, enum
124- * NumberBase)</code>.
125- *
126147 * @param str the string
127148 * @param base the base of the string
128149 * @return a finite field element.
150+ * @see scl::details::FieldFromString
129151 */
130152 static FF FromString (const std::string& str, enum NumberBase base) {
131153 FF e;
132- Field::FromString (e.mValue , str, base);
154+ details::FieldFromString<Field> (e.mValue , str, base);
133155 return e;
134156 };
135157
136158 /* *
137159 * @brief Create a field element from a base 10 string.
138160 * @param str the string
139161 * @return a finite field element.
140- * @see FF::FromString
141162 */
142163 static FF FromString (const std::string& str) {
143164 return FF::FromString (str, NumberBase::DECIMAL);
144165 };
145166
146167 /* *
147168 * @brief Create a new element from an int.
148- *
149- * The resulting field element is created according to the static method
150- * <code>Field::FromInt(int)</code>.
151- *
152169 * @param value the value to interpret as a field element
170+ * @see scl::details::FieldConvertIn
153171 */
154- explicit constexpr FF (int value) : mValue(Field::FromInt(value)){};
172+ explicit constexpr FF (int value) {
173+ details::FieldConvertIn<Field>(mValue , value);
174+ };
155175
156176 /* *
157177 * @brief Create a new element equal to 0 in the field.
@@ -160,43 +180,34 @@ class FF final : details::RingBase<FF<Bits, Field>> {
160180
161181 /* *
162182 * @brief Add another field element to this.
163- *
164- * Field element addition is defined by the static method
165- * <code>Field::Add(ValueType&, const ValueType&)</code>.
166- *
167183 * @param other the other element
168184 * @return this set to this + \p other.
185+ * @see scl::details::FieldAdd
169186 */
170187 FF& operator +=(const FF& other) {
171- Field::Add (mValue , other.mValue );
188+ details::FieldAdd<Field> (mValue , other.mValue );
172189 return *this ;
173190 };
174191
175192 /* *
176193 * @brief Subtract another field element to this.
177- *
178- * Field element subtraction is defined by the static method
179- * <code>Field::Subtract(ValueType&, const ValueType&)</code>.
180- *
181194 * @param other the other element
182195 * @return this set to this - \p other.
196+ * @see scl::details::FieldSubtract
183197 */
184198 FF& operator -=(const FF& other) {
185- Field::Subtract (mValue , other.mValue );
199+ details::FieldSubtract<Field> (mValue , other.mValue );
186200 return *this ;
187201 };
188202
189203 /* *
190204 * @brief Multiply another field element to this.
191- *
192- * Field element multiplication is defined by the static method
193- * <code>Field::Multiply(ValueType&, const ValueType&)</code>.
194- *
195205 * @param other the other element
196206 * @return this set to this * \p other.
207+ * @see scl::details::FieldMultiply
197208 */
198209 FF& operator *=(const FF& other) {
199- Field::Multiply (mValue , other.mValue );
210+ details::FieldMultiply<Field> (mValue , other.mValue );
200211 return *this ;
201212 };
202213
@@ -213,14 +224,11 @@ class FF final : details::RingBase<FF<Bits, Field>> {
213224
214225 /* *
215226 * @brief Negates this element.
216- *
217- * Field element negation is defined by
218- * <code>Field::Negate(ValueType&)</code>.
219- *
220227 * @return this set to -this.
228+ * @see scl::details::FieldNegate
221229 */
222230 FF& Negate () {
223- Field::Negate (mValue );
231+ details::FieldNegate<Field> (mValue );
224232 return *this ;
225233 };
226234
@@ -232,21 +240,18 @@ class FF final : details::RingBase<FF<Bits, Field>> {
232240 FF Negated () {
233241 auto copy = mValue ;
234242 FF r;
235- Field::Negate (copy);
243+ details::FieldNegate<Field> (copy);
236244 r.mValue = copy;
237245 return r;
238246 };
239247
240248 /* *
241249 * @brief Inverts this element.
242- *
243- * Computation of field element inverses is defined by
244- * <code>Field::Invert(ValueType)</code>.
245- *
246250 * @return this set to its inverse.
251+ * @see scl::details::FieldInvert
247252 */
248253 FF& Invert () {
249- Field::Invert (mValue );
254+ details::FieldInvert<Field> (mValue );
250255 return *this ;
251256 };
252257
@@ -264,40 +269,113 @@ class FF final : details::RingBase<FF<Bits, Field>> {
264269 * @brief Checks if this element is equal to another.
265270 * @param other the other element
266271 * @return true if this is equal to \p other.
272+ * @see scl::details::FieldEqual
267273 */
268274 bool Equal (const FF& other) const {
269- return Field::Equal (mValue , other.mValue );
275+ return details::FieldEqual<Field> (mValue , other.mValue );
270276 };
271277
272278 /* *
273279 * @brief Returns a string representation of this element.
274- *
275- * Stringification of an element is defined by
276- * <code>Field::ToString(ValueType)</code>.
277- *
278280 * @return a string representation of this field element.
281+ * @see scl::details::FieldToString
279282 */
280- std::string ToString () const { return Field::ToString (mValue ); };
283+ std::string ToString () const {
284+ return details::FieldToString<Field>(mValue );
285+ };
281286
282287 /* *
283288 * @brief Write this element to a byte buffer.
284- *
285- * <p>Serializes this field element. Serialization is defined by
286- * <code>Field::ToBytes(unsigned char*, const ValueType&)</code>. In general,
287- * it should be the case that \p dest has space for \ref ByteSize() amount of
288- * bytes, although more may be needed depending on Field.</p>
289- *
290- * <p>For pre-defined fields in SCL, \p dest <i>must</i> have space for \ref
291- * ByteSize() amount of bytes.</p>
292- *
293289 * @param dest the buffer. Must have space for \ref ByteSize() bytes.
290+ * @see scl::details::FieldToBytes
294291 */
295- void Write (unsigned char * dest) const { Field::ToBytes (dest, mValue ); }
292+ void Write (unsigned char * dest) const {
293+ details::FieldToBytes<Field>(dest, mValue );
294+ };
296295
297296 private:
298297 ValueType mValue ;
299298};
300299
300+ /* *
301+ * @brief The field \f$\mathbb{F}_p\f$ with \f$p=2^{61}-1\f$.
302+ */
303+ struct Mersenne61 {
304+ /* *
305+ * @brief Internal type elements of this field.
306+ */
307+ using ValueType = std::uint64_t ;
308+
309+ /* *
310+ * @brief The name of this field.
311+ */
312+ constexpr static const char * kName = " Mersenne61" ;
313+
314+ /* *
315+ * @brief The size of field elements of this field in bytes.
316+ */
317+ constexpr static const std::size_t kByteSize = sizeof (ValueType);
318+
319+ /* *
320+ * @brief The size of field elements of this field in bits.
321+ */
322+ constexpr static const std::size_t kBitSize = 61 ;
323+ };
324+
325+ /* *
326+ * @brief The field \f$\mathbb{F}_p\f$ with \f$p=2^{127}-1\f$.
327+ */
328+ struct Mersenne127 {
329+ /* *
330+ * @brief Internal type elements of this field.
331+ */
332+ using ValueType = __uint128_t ;
333+
334+ /* *
335+ * @brief The name of this field.
336+ */
337+ constexpr static const char * kName = " Mersenne127" ;
338+
339+ /* *
340+ * @brief The size of field elements of this field in bytes.
341+ */
342+ constexpr static const std::size_t kByteSize = sizeof (ValueType);
343+
344+ /* *
345+ * @brief The size of field elements of this field in bits.
346+ */
347+ constexpr static const std::size_t kBitSize = 127 ;
348+ };
349+
350+ #define _SCL_LE (a, b ) ((a) <= (b))
351+ #define _SCL_GE (a, b ) ((a) >= (b))
352+
353+ /* *
354+ * @brief Select a suitable Finite Field based on a provided bitlevel.
355+ */
356+ template <unsigned Bits>
357+ struct FieldSelector {
358+ /* *
359+ * @brief The field.
360+ */
361+ // clang-format off
362+ using Field =
363+ std::conditional_t <
364+ _SCL_GE (Bits, 1 ) && _SCL_LE(Bits, 61 ),
365+ Mersenne61,
366+
367+ std::conditional_t <
368+ _SCL_GE (Bits, 62 ) && _SCL_LE(Bits, 127 ),
369+ Mersenne127,
370+
371+ void >>;
372+
373+ // clang-format on
374+ };
375+
376+ #undef _SCL_LE
377+ #undef _SCL_GE
378+
301379} // namespace details
302380
303381/* *
0 commit comments