2 * qfarith.h: utilities for quick field arithmetic
5 * This file is Free Software. It has been modified to as part of its
6 * incorporation into secnet.
8 * Copyright 2017 Mark Wooding
10 * You may redistribute this file and/or modify it under the terms of
11 * the permissive licence shown below.
13 * You may redistribute secnet as a whole and/or modify it under the
14 * terms of the GNU General Public License as published by the Free
15 * Software Foundation; either version 3, or (at your option) any
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, see
25 * https://www.gnu.org/licenses/gpl.html.
28 * Imported from Catacomb, and modified for Secnet (2017-04-30):
30 * * Use `fake-mLib-bits.h' in place of the real <mLib/bits.h>.
32 * * Use C99 signed integer types instead of our own local probing.
34 * * Remove the support for non-two's-complement targets.
36 * The file's original comment headers are preserved below.
40 * Utilities for quick field arithmetic
42 * (c) 2017 Straylight/Edgeware
45 /*----- Licensing notice --------------------------------------------------*
47 * This file is part of Catacomb.
49 * Catacomb is free software; you can redistribute it and/or modify
50 * it under the terms of the GNU Library General Public License as
51 * published by the Free Software Foundation; either version 2 of the
52 * License, or (at your option) any later version.
54 * Catacomb is distributed in the hope that it will be useful,
55 * but WITHOUT ANY WARRANTY; without even the implied warranty of
56 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
57 * GNU Library General Public License for more details.
59 * You should have received a copy of the GNU Library General Public
60 * License along with Catacomb; if not, write to the Free
61 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
65 #ifndef CATACOMB_QFARITH_H
66 #define CATACOMB_QFARITH_H
72 /*----- Header files ------------------------------------------------------*/
77 #include "fake-mLib-bits.h"
79 /*----- Signed integer types ----------------------------------------------*/
81 typedef int_fast32_t int32;
82 typedef int_fast64_t int64;
85 /*----- General bit-hacking utilities -------------------------------------*/
87 /* Individual bits, and masks for low bits. */
88 #define BIT(n) (1ul << (n))
89 #define MASK(n) (BIT(n) - 1)
91 /* Arithmetic right shift. If X is a value of type TY, and N is a
92 * nonnegative integer, then return the value of X shifted right by N bits;
93 * alternatively, this is floor(X/2^N).
95 * GCC manages to compile this into a simple shift operation if one is
96 * available, but it's correct for all C targets.
98 #define ASR(ty, x, n) (((x) - (ty)((u##ty)(x)&MASK(n)))/(ty)BIT(n))
100 /*----- Constant-time utilities -------------------------------------------*/
102 /* The following have better implementations on a two's complement target. */
105 /* If we have two's complement arithmetic then masks are signed; this
106 * avoids a switch to unsigned representation, with the consequent problem
107 * of overflow when we convert back.
109 typedef int32 mask32;
111 /* Convert an unsigned mask M into a `mask32'. This is a hairy-looking
112 * no-op on many targets, but, given that we have two's complement
113 * integers, it is free of arithmetic overflow.
115 # define FIX_MASK32(m) \
116 ((mask32)((m)&0x7fffffffu) + (-(mask32)0x7fffffff - 1)*(((m) >> 31)&1u))
118 /* If Z is zero and M has its low 32 bits set, then copy (at least) the low
119 * 32 bits of X to Z; if M is zero, do nothing. Otherwise, scramble Z
122 # define CONDPICK(z, x, m) do { (z) |= (x)&(m); } while (0)
124 /* If M has its low 32 bits set, then return (at least) the low 32 bits of
125 * X in Z; if M is zero, then return (at least) the low 32 bits of Y in Z.
126 * Otherwise, return an unhelful result.
128 # define PICK2(x, y, m) (((x)&(m)) | ((y)&~(m)))
130 /* If M has its low 32 bits set then swap (at least) the low 32 bits of X
131 * and Y; if M is zero, then do nothing. Otherwise, scramble X and Y
134 # define CONDSWAP(x, y, m) \
135 do { mask32 t_ = ((x) ^ (y))&(m); (x) ^= t_; (y) ^= t_; } while (0)
137 # error "Targets without two's complement arithmetic aren't supported"
140 /* Return zero if bit 31 of X is clear, or a mask with (at least) the low 32
141 * bits set if bit 31 of X is set.
143 #define SIGN(x) (-(mask32)(((uint32)(x) >> 31)&1))
145 /* Return zero if X is zero, or a mask with (at least) the low 32 bits set if
148 #define NONZEROP(x) SIGN((U32(x) >> 1) - U32(x))
150 /*----- Debugging utilities -----------------------------------------------*/
152 /* Define a debugging function DUMPFN, which will dump an integer represented
153 * modulo M. The integer is represented as a vector of NPIECE pieces of type
154 * PIECETY. The pieces are assembled at possibly irregular offsets: piece i
155 * logically has width PIECEWD(i), but may overhang the next piece. The
156 * pieces may be signed. GETMOD is an expression which calculates and
157 * returns the value of M, as an `mp *'.
159 * The generated function writes the value of such an integer X to the stream
160 * FP, labelled with the string WHAT.
162 * The definition assumes that <stdio.h>, <catacomb/mp.h>, and
163 * <catacomb/mptext.h> have been included.
165 #define DEF_FDUMP(dumpfn, piecety, piecewd, npiece, noctet, getmod) \
166 static void dumpfn(FILE *fp, const char *what, const piecety *x) \
169 mp m, *y = MP_ZERO, *t = MP_NEW, *p; \
174 mp_build(&m, &w, &w + 1); \
175 for (i = o = 0; i < npiece; i++) { \
176 if (x[i] >= 0) { w = x[i]; m.f &= ~MP_NEG; } \
177 else { w = -x[i]; m.f |= MP_NEG; } \
178 t = mp_lsl(t, &m, o); \
179 y = mp_add(y, y, t); \
183 fprintf(fp, "%s = <", what); \
184 for (i = 0; i < npiece; i++) { \
185 if (i) fputs(", ", fp); \
186 fprintf(fp, "%ld", (long)x[i]); \
188 fputs(">\n\t= ", fp); \
189 mp_writefile(y, fp, 10); \
190 fputs("\n\t== ", fp); \
191 mp_div(0, &y, y, p); \
192 mp_writefile(y, fp, 10); \
193 fputs("\n\t= 0x", fp); \
194 mp_writefile(y, fp, 16); \
195 fputs(" (mod 2^255 - 19)\n\t= [", fp); \
196 mp_storel(y, b, sizeof(b)); \
197 for (i = 0; i < 32; i++) { \
198 if (i && !(i%4)) fputc(':', fp); \
199 fprintf(fp, "%02x", b[i]); \
202 mp_drop(y); mp_drop(p); mp_drop(t); \
205 /*----- That's all, folks -------------------------------------------------*/