X-Git-Url: https://git.distorted.org.uk/~mdw/secnet/blobdiff_plain/8a7654a695e8ecdc8c14dced445839a7a7e6a8ca..refs/heads/mdw/xdh:/fgoldi.c diff --git a/fgoldi.c b/fgoldi.c index 14b98ed..08e6592 100644 --- a/fgoldi.c +++ b/fgoldi.c @@ -54,20 +54,20 @@ * (hence the name). */ +typedef fgoldi_piece piece; + /* We represent an element of GF(p) as 16 28-bit signed integer pieces x_i: * x = SUM_{0<=i<16} x_i 2^(28i). */ -typedef int32 piece; typedef int64 dblpiece; + typedef int64 dblpiece; typedef uint32 upiece; typedef uint64 udblpiece; #define PIECEWD(i) 28 #define NPIECE 16 #define P p28 -#define B28 0x10000000u #define B27 0x08000000u #define M28 0x0fffffffu -#define M27 0x07ffffffu #define M32 0xffffffffu /*----- Debugging machinery -----------------------------------------------*/ @@ -285,8 +285,72 @@ void fgoldi_sub(fgoldi *z, const fgoldi *x, const fgoldi *y) for (i = 0; i < NPIECE; i++) z->P[i] = x->P[i] - y->P[i]; } +/* --- @fgoldi_neg@ --- * + * + * Arguments: @fgoldi *z@ = where to put the result (may alias @x@) + * @const fgoldi *x@ = an operand + * + * Returns: --- + * + * Use: Set @z = -x@. + */ + +void fgoldi_neg(fgoldi *z, const fgoldi *x) +{ + unsigned i; + for (i = 0; i < NPIECE; i++) z->P[i] = -x->P[i]; +} + /*----- Constant-time utilities -------------------------------------------*/ +/* --- @fgoldi_pick2@ --- * + * + * Arguments: @fgoldi *z@ = where to put the result (may alias @x@ or @y@) + * @const fgoldi *x, *y@ = two operands + * @uint32 m@ = a mask + * + * Returns: --- + * + * Use: If @m@ is zero, set @z = y@; if @m@ is all-bits-set, then set + * @z = x@. If @m@ has some other value, then scramble @z@ in + * an unhelpful way. + */ + +void fgoldi_pick2(fgoldi *z, const fgoldi *x, const fgoldi *y, uint32 m) +{ + mask32 mm = FIX_MASK32(m); + unsigned i; + for (i = 0; i < NPIECE; i++) z->P[i] = PICK2(x->P[i], y->P[i], mm); +} + +/* --- @fgoldi_pickn@ --- * + * + * Arguments: @fgoldi *z@ = where to put the result + * @const fgoldi *v@ = a table of entries + * @size_t n@ = the number of entries in @v@ + * @size_t i@ = an index + * + * Returns: --- + * + * Use: If @0 <= i < n < 32@ then set @z = v[i]@. If @n >= 32@ then + * do something unhelpful; otherwise, if @i >= n@ then set @z@ + * to zero. + */ + +void fgoldi_pickn(fgoldi *z, const fgoldi *v, size_t n, size_t i) +{ + uint32 b = (uint32)1 << (31 - i); + mask32 m; + unsigned j; + + for (j = 0; j < NPIECE; j++) z->P[j] = 0; + while (n--) { + m = SIGN(b); + for (j = 0; j < NPIECE; j++) CONDPICK(z->P[j], v->P[j], m); + v++; b <<= 1; + } +} + /* --- @fgoldi_condswap@ --- * * * Arguments: @fgoldi *x, *y@ = two operands @@ -307,6 +371,31 @@ void fgoldi_condswap(fgoldi *x, fgoldi *y, uint32 m) for (i = 0; i < NPIECE; i++) CONDSWAP(x->P[i], y->P[i], mm); } +/* --- @fgoldi_condneg@ --- * + * + * Arguments: @fgoldi *z@ = where to put the result (may alias @x@) + * @const fgoldi *x@ = an operand + * @uint32 m@ = a mask + * + * Returns: --- + * + * Use: If @m@ is zero, set @z = x@; if @m@ is all-bits-set, then set + * @z = -x@. If @m@ has some other value then scramble @z@ in + * an unhelpful way. + */ + +void fgoldi_condneg(fgoldi *z, const fgoldi *x, uint32 m) +{ + mask32 m_xor = FIX_MASK32(m); + piece m_add = m&1; +# define CONDNEG(x) (((x) ^ m_xor) + m_add) + + unsigned i; + for (i = 0; i < NPIECE; i++) z->P[i] = CONDNEG(x->P[i]); + +#undef CONDNEG +} + /*----- Multiplication ----------------------------------------------------*/ /* Let B = 2^63 - 1 be the largest value such that +B and -B can be @@ -586,4 +675,86 @@ void fgoldi_inv(fgoldi *z, const fgoldi *x) #undef SQRN } +/* --- @fgoldi_quosqrt@ --- * + * + * Arguments: @fgoldi *z@ = where to put the result (may alias @x@ or @y@) + * @const fgoldi *x, *y@ = two operands + * + * Returns: Zero if successful, @-1@ if %$x/y$% is not a square. + * + * Use: Stores in @z@ the one of the square roots %$\pm\sqrt{x/y}$%. + * If %$x = y = 0% then the result is zero; if %$y = 0$% but %$x + * \ne 0$% then the operation fails. If you wanted a specific + * square root then you'll have to pick it yourself. + */ + +int fgoldi_quosqrt(fgoldi *z, const fgoldi *x, const fgoldi *y) +{ + fgoldi t, u, v; + octet xb[56], b0[56]; + int32 rc = -1; + mask32 m; + unsigned i; + +#define SQRN(z, x, n) do { \ + fgoldi_sqr((z), (x)); \ + for (i = 1; i < (n); i++) fgoldi_sqr((z), (z)); \ +} while (0) + + /* This is, fortunately, significantly easier than the equivalent problem + * in GF(2^255 - 19), since p == 3 (mod 4). + * + * If x/y is square, then so is v = y^2 x/y = x y, and therefore u has + * order r = (p - 1)/2. Let w = v^{(p-3)/4}. Then w^2 = v^{(p-3)/2} = + * u^{r-1} = 1/v = 1/x y. Clearly, then, (x w)^2 = x^2/x y = x/y, so x w + * is one of the square roots we seek. + * + * The addition chain, then, is a prefix of the previous one. + */ + fgoldi_mul(&v, x, y); + + fgoldi_sqr(&u, &v); /* 1 | 2 */ + fgoldi_mul(&t, &u, &v); /* 2 | 3 */ + SQRN(&u, &t, 2); /* 4 | 12 */ + fgoldi_mul(&t, &u, &t); /* 5 | 15 */ + SQRN(&u, &t, 4); /* 9 | 240 */ + fgoldi_mul(&u, &u, &t); /* 10 | 255 = 2^8 - 1 */ + SQRN(&u, &u, 4); /* 14 | 2^12 - 16 */ + fgoldi_mul(&t, &u, &t); /* 15 | 2^12 - 1 */ + SQRN(&u, &t, 12); /* 27 | 2^24 - 2^12 */ + fgoldi_mul(&u, &u, &t); /* 28 | 2^24 - 1 */ + SQRN(&u, &u, 12); /* 40 | 2^36 - 2^12 */ + fgoldi_mul(&t, &u, &t); /* 41 | 2^36 - 1 */ + fgoldi_sqr(&t, &t); /* 42 | 2^37 - 2 */ + fgoldi_mul(&t, &t, &v); /* 43 | 2^37 - 1 */ + SQRN(&u, &t, 37); /* 80 | 2^74 - 2^37 */ + fgoldi_mul(&u, &u, &t); /* 81 | 2^74 - 1 */ + SQRN(&u, &u, 37); /* 118 | 2^111 - 2^37 */ + fgoldi_mul(&t, &u, &t); /* 119 | 2^111 - 1 */ + SQRN(&u, &t, 111); /* 230 | 2^222 - 2^111 */ + fgoldi_mul(&t, &u, &t); /* 231 | 2^222 - 1 */ + fgoldi_sqr(&u, &t); /* 232 | 2^223 - 2 */ + fgoldi_mul(&u, &u, &v); /* 233 | 2^223 - 1 */ + SQRN(&u, &u, 223); /* 456 | 2^446 - 2^223 */ + fgoldi_mul(&t, &u, &t); /* 457 | 2^446 - 2^222 - 1 */ + +#undef SQRN + + /* Now we must decide whether the answer was right. We should have z^2 = + * x/y, so y z^2 = x. + * + * The easiest way to compare is to encode. This isn't as wasteful as it + * sounds: the hard part is normalizing the representations, which we have + * to do anyway. + */ + fgoldi_mul(z, x, &t); + fgoldi_sqr(&t, z); + fgoldi_mul(&t, &t, y); + fgoldi_store(xb, x); + fgoldi_store(b0, &t); + m = -consttime_memeq(xb, b0, 56); + rc = PICK2(0, rc, m); + return (rc); +} + /*----- That's all, folks -------------------------------------------------*/