progs/perftest.c: Use from Glibc syscall numbers.
[catacomb] / base / ct.c
CommitLineData
d4bb7fde
MW
1/* -*-c-*-
2 *
3 * Constant-time operations
4 *
5 * (c) 2013 Straylight/Edgeware
6 */
7
8/*----- Licensing notice --------------------------------------------------*
9 *
10 * This file is part of Catacomb.
11 *
12 * Catacomb is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as
14 * published by the Free Software Foundation; either version 2 of the
15 * License, or (at your option) any later version.
16 *
17 * Catacomb is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with Catacomb; if not, write to the Free
24 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25 * MA 02111-1307, USA.
26 */
27
28/*----- Header files ------------------------------------------------------*/
29
30#include <mLib/bits.h>
31
32#include "ct.h"
33
34/*----- Main code ---------------------------------------------------------*/
35
36#define MASK(a) (U32(~((a) - 1)))
37
38/* --- @ct_inteq@ --- *
39 *
40 * Arguments: @uint32 x, y@ = two 32-bit unsigned integers
41 *
42 * Returns: One if @x@ and @y@ are equal, zero if they differ.
43 *
44 * Use: Answers whether two integers are equal, in constant time.
45 */
46
47int ct_inteq(uint32 x, uint32 y)
48{
8f7fd6c0
MW
49 uint32 a = x ^ y;
50
51 /* --- How it works --- *
52 *
53 * Obviously, %$a$% is nonzero if and only if %$x \ne y$%. Let %$N > 0$%.
54 * Suppose that %$0 < a < N$%. Then:
55 *
56 * %$N/2 = N - N/2 \le N - (a + 1)/2 = N - a/2 - 1/2$%
57 * %${} = N - a + a/2 - 1/2 = N - a + (a - 1)/2$%
58 * %${} \le N - a + \lfloor a/2 \rfloor < N$%
59 *
60 * Consequently, if %$N = 2^{32}$% and %$a$% is nonzero, then
61 * %$a - \lfloor a/2 \rfloor$% has its top bit set. Of course, if
62 * %$a = 0$% then %$a - \lfloor a/2 \rfloor = 0$%.
63 */
64
65 a = (a >> 1) - a;
66 return (U32(~a) >> 31);
d4bb7fde
MW
67}
68
69/* --- @ct_intle@ --- *
70 *
71 * Arguments: @uint32 x, y@ = two 32-bit unsigned integers
72 *
c4377d0e 73 * Returns: One if %$x \le y$%, zero if @x@ is greater.
d4bb7fde
MW
74 *
75 * Use: Answers whether two integers are ordered, in constant time.
76 */
77
78int ct_intle(uint32 x, uint32 y)
79{
80 /* --- This bit's a little fiddly --- *
81 *
82 * If the top bits of @x@ and @y@ are the same then %$x \le y$% if and only
83 * if %$y - x$% has its top bit clear; otherwise, %$x \le y$% if and only
8f7fd6c0 84 * if (the top bit of @x@ is clear and) the top bit of @y@ is set.
d4bb7fde
MW
85 *
86 * This assumes we can do subtraction in constant time, which seems like a
87 * safe enough bet.
88 */
89
8f7fd6c0
MW
90 uint32 diff = x^y;
91 uint32 low = y - x;
92 uint32 a = (y&diff) | (~low&~diff);
93 return (U32(a) >> 31);
d4bb7fde
MW
94}
95
96/* --- @ct_pick@ --- *
97 *
98 * Arguments: @uint32 a@ = a switch, either zero or one
99 * @uint32 x0, x1@ = two 32-bit unsigned integers
100 *
101 * Returns: @x0@ if @a@ is zero; @x1@ if @a@ is one. Other values of @a@
102 * will give you unhelpful results.
103 *
104 * Use: Picks one of two results according to a switch variable, in
105 * constant time.
106 */
107
108int ct_pick(uint32 a, uint32 x0, uint32 x1)
109 { uint32 m = MASK(a); return (x0&~m) | (x1&m); }
110
111/* --- @ct_condcopy@ --- *
112 *
113 * Arguments: @uint32 a@ = a switch, either zero or one
114 * @void *d@ = destination pointer
115 * @const void *s@ = source pointer
116 * @size_t n@ amount to copy
117 *
118 * Returns: ---
119 *
120 * Use: If @a@ is one then copy the @n@ bytes starting at @s@ to
121 * @d@; if @a@ is zero then leave @d@ unchanged (but it will
122 * still be written). All of this is done in constant time.
123 */
124
125void ct_condcopy(uint32 a, void *d, const void *s, size_t n)
126{
127 octet *dd = d;
128 const octet *ss = s;
129 uint32 m = MASK(a);
130
131 while (n--) {
132 *dd = (*ss++&m) | (*dd&~m);
133 dd++;
134 }
135}
136
137/* --- @ct_memeq@ ---
138 *
139 * Arguments: @const void *p, *q@ = two pointers to buffers
140 * @size_t n@ = the (common) size of the buffers
141 *
142 * Returns: One if the two buffers are equal, zero if they aren't.
143 *
144 * Use: Compares two chunks of memory, in constant time.
145 */
146
147int ct_memeq(const void *p, const void *q, size_t n)
148{
149 const octet *pp = p, *qq = q;
150 octet a = 0;
151
152 while (n--) a |= *pp++ ^ *qq++;
153 return (ct_inteq(a, 0));
154}
155
156/*----- That's all, folks -------------------------------------------------*/