Skip to content

Commit

Permalink
Check that E' points are actually in G2 by ensuring they are of order r.
Browse files Browse the repository at this point in the history
  • Loading branch information
ebfull committed Dec 13, 2016
1 parent 9f7bc6c commit c4fce3f
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 0 deletions.
61 changes: 61 additions & 0 deletions src/gtest/test_proofs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,67 @@ typedef libsnark::default_r1cs_ppzksnark_pp::Fqe_type curve_Fq2;
#include "version.h"
#include "utilstrencodings.h"

TEST(proofs, g2_subgroup_check)
{
// all G2 elements are order r
ASSERT_TRUE(libsnark::alt_bn128_modulus_r * curve_G2::random_element() == curve_G2::zero());

// but that doesn't mean all elements that satisfy the curve equation are in G2...
curve_G2 p = curve_G2::one();

while (1) {
// This will construct an order r(2q-r) point with high probability
p.X = curve_Fq2::random_element();
try {
p.Y = ((p.X.squared() * p.X) + libsnark::alt_bn128_twist_coeff_b).sqrt();
break;
} catch(...) {}
}

ASSERT_TRUE(p.is_well_formed()); // it's on the curve
ASSERT_TRUE(libsnark::alt_bn128_modulus_r * p != curve_G2::zero()); // but not the order r subgroup..

{
// libsnark unfortunately doesn't check, and the pairing will complete
auto e = curve_Fr("149");
auto a = curve_pp::reduced_pairing(curve_G1::one(), p);
auto b = curve_pp::reduced_pairing(e * curve_G1::one(), p);

// though it will not preserve bilinearity
ASSERT_TRUE((a^e) != b);
}

{
// so, our decompression API should not allow you to decompress G2 elements of that form!
CompressedG2 badp(p);
try {
auto newp = badp.to_libsnark_g2<curve_G2>();
FAIL() << "Expected std::runtime_error";
} catch (std::runtime_error const & err) {
EXPECT_EQ(err.what(), std::string("point is not in G2"));
} catch(...) {
FAIL() << "Expected std::runtime_error";
}
}

// educational purposes: showing that E'(Fp2) is of order r(2q-r),
// by multiplying our random point in E' by (2q-r) = (q + q - r) to
// get an element in G2
{
auto p1 = libsnark::alt_bn128_modulus_q * p;
p1 = p1 + p1;
p1 = p1 - (libsnark::alt_bn128_modulus_r * p);

ASSERT_TRUE(p1.is_well_formed());
ASSERT_TRUE(libsnark::alt_bn128_modulus_r * p1 == curve_G2::zero());

CompressedG2 goodp(p1);
auto newp = goodp.to_libsnark_g2<curve_G2>();

ASSERT_TRUE(newp == p1);
}
}

TEST(proofs, sqrt_zero)
{
ASSERT_TRUE(curve_Fq::zero() == curve_Fq::zero().sqrt());
Expand Down
4 changes: 4 additions & 0 deletions src/zcash/Proof.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,10 @@ curve_G2 CompressedG2::to_libsnark_g2() const

assert(r.is_well_formed());

if (alt_bn128_modulus_r * r != curve_G2::zero()) {
throw std::runtime_error("point is not in G2");
}

return r;
}

Expand Down

0 comments on commit c4fce3f

Please sign in to comment.