Update crypto code from Catacomb 2.5.0.
[secnet] / fgoldi.c
index 14b98ed..08e6592 100644 (file)
--- a/fgoldi.c
+++ b/fgoldi.c
  * (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 -------------------------------------------------*/