X-Git-Url: https://git.distorted.org.uk/u/mdw/catacomb/blobdiff_plain/ba6e6b64033b1f9de49feccb5c9cd438354481f7..0f00dc4c8eb47e67bc0f148c2dd109f73a451e0a:/base/ct.c diff --git a/base/ct.c b/base/ct.c new file mode 100644 index 0000000..ef2adeb --- /dev/null +++ b/base/ct.c @@ -0,0 +1,144 @@ +/* -*-c-*- + * + * Constant-time operations + * + * (c) 2013 Straylight/Edgeware + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of Catacomb. + * + * Catacomb is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * Catacomb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with Catacomb; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +/*----- Header files ------------------------------------------------------*/ + +#include + +#include "ct.h" + +/*----- Main code ---------------------------------------------------------*/ + +#define MASK(a) (U32(~((a) - 1))) + +/* --- @ct_inteq@ --- * + * + * Arguments: @uint32 x, y@ = two 32-bit unsigned integers + * + * Returns: One if @x@ and @y@ are equal, zero if they differ. + * + * Use: Answers whether two integers are equal, in constant time. + */ + +int ct_inteq(uint32 x, uint32 y) +{ + uint32 a = U32(~(x ^ y)); + + a &= a >> 16; + a &= a >> 8; + a &= a >> 4; + a &= a >> 2; + a &= a >> 1; + return (a & 1); +} + +/* --- @ct_intle@ --- * + * + * Arguments: @uint32 x, y@ = two 32-bit unsigned integers + * + * Returns: One if %$x \le y$% are equal, zero if @x@ is greater. + * + * Use: Answers whether two integers are ordered, in constant time. + */ + +int ct_intle(uint32 x, uint32 y) +{ + /* --- This bit's a little fiddly --- * + * + * If the top bits of @x@ and @y@ are the same then %$x \le y$% if and only + * if %$y - x$% has its top bit clear; otherwise, %$x \le y$% if and only + * if the top bit of @x@ is clear and the top bit of @y@ is set. + * + * This assumes we can do subtraction in constant time, which seems like a + * safe enough bet. + */ + + uint32 xx = x >> 31, yy = y >> 31, zz = (y - x) >> 31; + return ((~xx&yy) | (~(xx^yy)&~zz)) & 1; +} + +/* --- @ct_pick@ --- * + * + * Arguments: @uint32 a@ = a switch, either zero or one + * @uint32 x0, x1@ = two 32-bit unsigned integers + * + * Returns: @x0@ if @a@ is zero; @x1@ if @a@ is one. Other values of @a@ + * will give you unhelpful results. + * + * Use: Picks one of two results according to a switch variable, in + * constant time. + */ + +int ct_pick(uint32 a, uint32 x0, uint32 x1) + { uint32 m = MASK(a); return (x0&~m) | (x1&m); } + +/* --- @ct_condcopy@ --- * + * + * Arguments: @uint32 a@ = a switch, either zero or one + * @void *d@ = destination pointer + * @const void *s@ = source pointer + * @size_t n@ amount to copy + * + * Returns: --- + * + * Use: If @a@ is one then copy the @n@ bytes starting at @s@ to + * @d@; if @a@ is zero then leave @d@ unchanged (but it will + * still be written). All of this is done in constant time. + */ + +void ct_condcopy(uint32 a, void *d, const void *s, size_t n) +{ + octet *dd = d; + const octet *ss = s; + uint32 m = MASK(a); + + while (n--) { + *dd = (*ss++&m) | (*dd&~m); + dd++; + } +} + +/* --- @ct_memeq@ --- + * + * Arguments: @const void *p, *q@ = two pointers to buffers + * @size_t n@ = the (common) size of the buffers + * + * Returns: One if the two buffers are equal, zero if they aren't. + * + * Use: Compares two chunks of memory, in constant time. + */ + +int ct_memeq(const void *p, const void *q, size_t n) +{ + const octet *pp = p, *qq = q; + octet a = 0; + + while (n--) a |= *pp++ ^ *qq++; + return (ct_inteq(a, 0)); +} + +/*----- That's all, folks -------------------------------------------------*/