const m_root_check: FieldElement = fe()
const p_root_check: FieldElement = fe()
/**
- * @returns -1 if bytes fail to decode to a point, 0 if decoding is successful
+ * Variable-time point negation converted from byte representation.
+ *
+ * Compiler optimization of vartime function is OK.
+ *
+ * @returns {i32} 0 if `s` decodes to a valid point, else -1
*/
export function ge_frombytes_negate_vartime (h: ge_p3, s: StaticArray<u8>): i32 {
- fe_frombytes(h.Y, s)
fe_1(h.Z)
+ fe_frombytes(h.Y, s)
+
+ // u = y²-1
+ // v = dy²+1
fe_sq(u, h.Y)
fe_mul(v, u, ed25519_d)
- fe_sub(u, u, h.Z) /* u = y^2-1 */
- fe_add(v, v, h.Z) /* v = dy^2+1 */
+ u[0] -= 1
+ v[0] += 1
+ // v3 = v³
fe_sq(v3, v)
- fe_mul(v3, v3, v) /* v3 = v^3 */
+ fe_mul(v3, v3, v)
+
+ // x = uv⁷
fe_sq(h.X, v3)
fe_mul(h.X, h.X, v)
- fe_mul(h.X, h.X, u) /* x = uv^7 */
+ fe_mul(h.X, h.X, u)
+
+ // x = (uv⁷)^((q-5)/8)
+ fe_pow22523(h.X, h.X)
- fe_pow22523(h.X, h.X) /* x = (uv^7)^((q-5)/8) */
+ // x = uv³((uv⁷)^((q-5)/8))
fe_mul(h.X, h.X, v3)
- fe_mul(h.X, h.X, u) /* x = uv^3(uv^7)^((q-5)/8) */
+ fe_mul(h.X, h.X, u)
+ // vxx = vx²
fe_sq(vxx, h.X)
fe_mul(vxx, vxx, v)
- fe_sub(m_root_check, vxx, u) /* vx^2-u */
+
+ // m = vx²-u
+ fe_sub(m_root_check, vxx, u)
if (fe_iszero(m_root_check) == 0) {
- fe_add(p_root_check, vxx, u) /* vx^2+u */
+ // p = vx²+u
+ fe_add(p_root_check, vxx, u)
if (fe_iszero(p_root_check) == 0) {
return -1
}
fe_mul(h.X, h.X, fe_sqrtm1)
}
- if (fe_isnegative(h.X) == (s[31] >> 7)) { /* vartime function - compiler optimization is fine */
+ if (fe_isnegative(h.X) == (s[31] >> 7)) {
fe_neg(h.X, h.X)
}
fe_mul(h.T, h.X, h.Y)