diff --git a/src/crypto/crypto-sugar.h b/src/crypto/crypto-sugar.h index 6ecdf713..7e0d881f 100644 --- a/src/crypto/crypto-sugar.h +++ b/src/crypto/crypto-sugar.h @@ -612,9 +612,13 @@ namespace crypto bool is_zero() const { - // (0, 1) ~ (0, z, z, 0) + // (0, 1) ~ (0, z, z, 0) for any non-zero z https://www.rfc-editor.org/rfc/rfc8032#page-17 if (fe_isnonzero(m_p3.X) != 0) - return false; + return false; // x != 0 + if (fe_isnonzero(m_p3.Z) == 0) + return false; // z == 0 + if (fe_isnonzero(m_p3.T) != 0) + return false; // t != 0 fe y_minus_z; fe_sub(y_minus_z, m_p3.Y, m_p3.Z); return fe_isnonzero(y_minus_z) == 0; diff --git a/tests/functional_tests/crypto_tests.cpp b/tests/functional_tests/crypto_tests.cpp index 41ea0a03..efa4aab0 100644 --- a/tests/functional_tests/crypto_tests.cpp +++ b/tests/functional_tests/crypto_tests.cpp @@ -1466,6 +1466,37 @@ TEST(crypto, point_is_zero) ASSERT_TRUE(p.is_zero()); + + memset(&p.m_p3, 0, sizeof p.m_p3); + memcpy(&p.m_p3.Y, f_x, sizeof p.m_p3.Y); + memcpy(&p.m_p3.Z, f_x, sizeof p.m_p3.Z); + memcpy(&p.m_p3.T, fancy_p, sizeof p.m_p3.T); + // {0, x, x, P} == {0, 1} (still the identity point) + + ASSERT_TRUE(p.is_zero()); + + // + // negative tests + // + + memset(&p.m_p3, 0, sizeof p.m_p3); + // {0, 0, 0, 0} is not a point at all + + ASSERT_FALSE(p.is_zero()); + + + memset(&p.m_p3, 0, sizeof p.m_p3); + memcpy(&p.m_p3.Y, f_x, sizeof p.m_p3.Y); + memcpy(&p.m_p3.Z, f_x, sizeof p.m_p3.Z); + memcpy(&p.m_p3.T, fancy_p_plus_1, sizeof p.m_p3.T); + // {0, x, x, !0} is not a valid point (incorrect non-zero T) + + ASSERT_FALSE(p.is_zero()); + + memcpy(&p.m_p3.T, f_x, sizeof p.m_p3.T); + // {0, x, x, x}, while x != 0 is still incorrect point representation + ASSERT_FALSE(p.is_zero()); + return true; }