+/* --- @f25519_quosqrt@ --- *
+ *
+ * Arguments: @f25519 *z@ = where to put the result (may alias @x@ or @y@)
+ * @const f25519 *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.
+ */
+
+static const piece sqrtm1_pieces[NPIECE] = {
+#if F25519_IMPL == 26
+ -32595792, -7943725, 9377950, 3500415, 12389472,
+ -272473, -25146209, -2005654, 326686, 11406482
+#elif F25519_IMPL == 10
+ 176, -88, 161, 157, -485, -196, -231, -220, -416,
+ -169, -255, 50, 189, -89, -266, -32, 202, -511,
+ 423, 357, 248, -249, 80, 288, 50, 174
+#endif
+};
+#define SQRTM1 ((const f25519 *)sqrtm1_pieces)
+
+int f25519_quosqrt(f25519 *z, const f25519 *x, const f25519 *y)
+{
+ f25519 t, u, w, beta, xy3, t2p50m1;
+ octet xb[32], b0[32], b1[32];
+ int32 rc = -1;
+ mask32 m;
+ unsigned i;
+
+#define SQRN(z, x, n) do { \
+ f25519_sqr((z), (x)); \
+ for (i = 1; i < (n); i++) f25519_sqr((z), (z)); \
+} while (0)
+
+ /* This is a bit tricky; the algorithm is from Bernstein, Duif, Lange,
+ * Schwabe, and Yang, `High-speed high-security signatures', 2011-09-26,
+ * https://ed25519.cr.yp.to/ed25519-20110926.pdf.
+ *
+ * First of all, a complicated exponentation. The addition chain here is
+ * mine. We start with some preliminary values.
+ */ /* step | value */
+ SQRN(&u, y, 1); /* 1 | 0, 2 */
+ f25519_mul(&t, &u, y); /* 2 | 0, 3 */
+ f25519_mul(&xy3, &t, x); /* 3 | 1, 3 */
+ SQRN(&u, &u, 1); /* 4 | 0, 4 */
+ f25519_mul(&w, &u, &xy3); /* 5 | 1, 7 */
+
+ /* And now we calculate w^((p - 5)/8) = w^(252 - 3). */
+ SQRN(&u, &w, 1); /* 6 | 2 */
+ f25519_mul(&t, &w, &u); /* 7 | 3 */
+ SQRN(&u, &t, 1); /* 8 | 6 */
+ f25519_mul(&t, &u, &w); /* 9 | 7 */
+ SQRN(&u, &t, 3); /* 12 | 56 */
+ f25519_mul(&t, &t, &u); /* 13 | 63 = 2^6 - 1 */
+ SQRN(&u, &t, 6); /* 19 | 2^12 - 2^6 */
+ f25519_mul(&t, &t, &u); /* 20 | 2^12 - 1 */
+ SQRN(&u, &t, 12); /* 32 | 2^24 - 2^12 */
+ f25519_mul(&t, &t, &u); /* 33 | 2^24 - 1 */
+ SQRN(&u, &t, 1); /* 34 | 2^25 - 2 */
+ f25519_mul(&t, &u, &w); /* 35 | 2^25 - 1 */
+ SQRN(&u, &t, 25); /* 60 | 2^50 - 2^25 */
+ f25519_mul(&t2p50m1, &t, &u); /* 61 | 2^50 - 1 */
+ SQRN(&u, &t2p50m1, 50); /* 111 | 2^100 - 2^50 */
+ f25519_mul(&t, &t2p50m1, &u); /* 112 | 2^100 - 1 */
+ SQRN(&u, &t, 100); /* 212 | 2^200 - 2^100 */
+ f25519_mul(&t, &t, &u); /* 213 | 2^200 - 1 */
+ SQRN(&u, &t, 50); /* 263 | 2^250 - 2^50 */
+ f25519_mul(&t, &t2p50m1, &u); /* 264 | 2^250 - 1 */
+ SQRN(&u, &t, 2); /* 266 | 2^252 - 4 */
+ f25519_mul(&t, &u, &w); /* 267 | 2^252 - 3 */
+
+ /* And finally... */
+ f25519_mul(&beta, &t, &xy3); /* 268 | ... */
+
+ /* Now we have beta = (x y^3) (x y^7)^((p - 5)/8) = (x/y)^((p + 3)/8), and
+ * we're ready to finish the computation. Suppose that alpha^2 = u/w.
+ * Then beta^4 = (x/y)^((p + 3)/2) = alpha^(p + 3) = alpha^4 = (x/y)^2, so
+ * we have beta^2 = ±x/y. If y beta^2 = x then beta is the one we wanted;
+ * if -y beta^2 = x, then we want beta sqrt(-1), which we already know. Of
+ * course, it might not match either, in which case we fail.
+ *
+ * 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.
+ */
+ f25519_sqr(&t, &beta);
+ f25519_mul(&t, &t, y);
+ f25519_neg(&u, &t);
+ f25519_store(xb, x);
+ f25519_store(b0, &t);
+ f25519_store(b1, &u);
+ f25519_mul(&u, &beta, SQRTM1);
+
+ m = -ct_memeq(b0, xb, 32);
+ rc = PICK2(0, rc, m);
+ f25519_pick2(z, &beta, &u, m);
+ m = -ct_memeq(b1, xb, 32);
+ rc = PICK2(0, rc, m);
+
+ /* And we're done. */
+ return (rc);
+}
+