bulletproofs: reject points not in the main subgroup

This commit is contained in:
moneromooo-monero 2018-06-29 15:03:00 +01:00
parent 1569717718
commit c429176248
No known key found for this signature in database
GPG key ID: 686F07454D6CEFC3
6 changed files with 97 additions and 0 deletions

View file

@ -922,6 +922,19 @@ bool bulletproof_VERIFY(const std::vector<const Bulletproof*> &proofs)
for (const Bulletproof *p: proofs) for (const Bulletproof *p: proofs)
{ {
const Bulletproof &proof = *p; const Bulletproof &proof = *p;
// check subgroup
for (const rct::key &k: proof.V)
CHECK_AND_ASSERT_MES(rct::isInMainSubgroup(k), false, "Input point not in subgroup");
for (const rct::key &k: proof.L)
CHECK_AND_ASSERT_MES(rct::isInMainSubgroup(k), false, "Input point not in subgroup");
for (const rct::key &k: proof.R)
CHECK_AND_ASSERT_MES(rct::isInMainSubgroup(k), false, "Input point not in subgroup");
CHECK_AND_ASSERT_MES(rct::isInMainSubgroup(proof.A), false, "Input point not in subgroup");
CHECK_AND_ASSERT_MES(rct::isInMainSubgroup(proof.S), false, "Input point not in subgroup");
CHECK_AND_ASSERT_MES(rct::isInMainSubgroup(proof.T1), false, "Input point not in subgroup");
CHECK_AND_ASSERT_MES(rct::isInMainSubgroup(proof.T2), false, "Input point not in subgroup");
CHECK_AND_ASSERT_MES(proof.V.size() >= 1, false, "V does not have at least one element"); CHECK_AND_ASSERT_MES(proof.V.size() >= 1, false, "V does not have at least one element");
CHECK_AND_ASSERT_MES(proof.L.size() == proof.R.size(), false, "Mismatched L and R sizes"); CHECK_AND_ASSERT_MES(proof.L.size() == proof.R.size(), false, "Mismatched L and R sizes");
CHECK_AND_ASSERT_MES(proof.L.size() > 0, false, "Empty proof"); CHECK_AND_ASSERT_MES(proof.L.size() > 0, false, "Empty proof");

View file

@ -60,6 +60,17 @@ namespace rct {
//Various key generation functions //Various key generation functions
bool toPointCheckOrder(ge_p3 *P, const unsigned char *data)
{
if (ge_frombytes_vartime(P, data))
return false;
ge_p2 R;
ge_scalarmult(&R, curveOrder().bytes, P);
key tmp;
ge_tobytes(tmp.bytes, &R);
return tmp == identity();
}
//generates a random scalar which can be used as a secret key or mask //generates a random scalar which can be used as a secret key or mask
void skGen(key &sk) { void skGen(key &sk) {
random32_unbiased(sk.bytes); random32_unbiased(sk.bytes);
@ -200,6 +211,12 @@ namespace rct {
return aP; return aP;
} }
//Computes aL where L is the curve order
bool isInMainSubgroup(const key & a) {
ge_p3 p3;
return toPointCheckOrder(&p3, a.bytes);
}
//Curve addition / subtractions //Curve addition / subtractions
//for curve points: AB = A + B //for curve points: AB = A + B

View file

@ -83,6 +83,7 @@ namespace rct {
keyM keyMInit(size_t rows, size_t cols); keyM keyMInit(size_t rows, size_t cols);
//Various key generation functions //Various key generation functions
bool toPointCheckOrder(ge_p3 *P, const unsigned char *data);
//generates a random scalar which can be used as a secret key or mask //generates a random scalar which can be used as a secret key or mask
key skGen(); key skGen();
@ -119,6 +120,8 @@ namespace rct {
key scalarmultKey(const key &P, const key &a); key scalarmultKey(const key &P, const key &a);
//Computes aH where H= toPoint(cn_fast_hash(G)), G the basepoint //Computes aH where H= toPoint(cn_fast_hash(G)), G the basepoint
key scalarmultH(const key & a); key scalarmultH(const key & a);
// checks a is in the main subgroup (ie, not a small one)
bool isInMainSubgroup(const key & a);
//Curve addition / subtractions //Curve addition / subtractions

View file

@ -51,6 +51,7 @@ enum test_op
op_addKeys2, op_addKeys2,
op_addKeys3, op_addKeys3,
op_addKeys3_2, op_addKeys3_2,
op_isInMainSubgroup,
}; };
template<test_op op> template<test_op op>
@ -102,6 +103,7 @@ public:
case op_addKeys2: rct::addKeys2(key, scalar0, scalar1, point0); break; case op_addKeys2: rct::addKeys2(key, scalar0, scalar1, point0); break;
case op_addKeys3: rct::addKeys3(key, scalar0, point0, scalar1, precomp1); break; case op_addKeys3: rct::addKeys3(key, scalar0, point0, scalar1, precomp1); break;
case op_addKeys3_2: rct::addKeys3(key, scalar0, precomp0, scalar1, precomp1); break; case op_addKeys3_2: rct::addKeys3(key, scalar0, precomp0, scalar1, precomp1); break;
case op_isInMainSubgroup: rct::isInMainSubgroup(point0); break;
default: return false; default: return false;
} }
return true; return true;

View file

@ -237,6 +237,7 @@ int main(int argc, char** argv)
TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_addKeys2); TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_addKeys2);
TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_addKeys3); TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_addKeys3);
TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_addKeys3_2); TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_addKeys3_2);
TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_isInMainSubgroup);
TEST_PERFORMANCE2(filter, p, test_multiexp, multiexp_bos_coster, 2); TEST_PERFORMANCE2(filter, p, test_multiexp, multiexp_bos_coster, 2);
TEST_PERFORMANCE2(filter, p, test_multiexp, multiexp_bos_coster, 4); TEST_PERFORMANCE2(filter, p, test_multiexp, multiexp_bos_coster, 4);

View file

@ -30,6 +30,7 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "string_tools.h"
#include "ringct/rctOps.h" #include "ringct/rctOps.h"
#include "ringct/rctSigs.h" #include "ringct/rctSigs.h"
#include "ringct/bulletproofs.h" #include "ringct/bulletproofs.h"
@ -193,3 +194,63 @@ TEST(bulletproofs, invalid_gamma_ff)
rct::Bulletproof proof = bulletproof_PROVE(invalid_amount, gamma); rct::Bulletproof proof = bulletproof_PROVE(invalid_amount, gamma);
ASSERT_FALSE(rct::bulletproof_VERIFY(proof)); ASSERT_FALSE(rct::bulletproof_VERIFY(proof));
} }
static const char * const torsion_elements[] =
{
"c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa",
"0000000000000000000000000000000000000000000000000000000000000000",
"26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85",
"ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
"26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05",
"0000000000000000000000000000000000000000000000000000000000000080",
"c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a",
};
TEST(bulletproofs, invalid_torsion)
{
rct::Bulletproof proof = bulletproof_PROVE(7329838943733, rct::skGen());
ASSERT_TRUE(rct::bulletproof_VERIFY(proof));
for (const auto &xs: torsion_elements)
{
rct::key x;
ASSERT_TRUE(epee::string_tools::hex_to_pod(xs, x));
ASSERT_FALSE(rct::isInMainSubgroup(x));
for (auto &k: proof.V)
{
const rct::key org_k = k;
rct::addKeys(k, org_k, x);
ASSERT_FALSE(rct::bulletproof_VERIFY(proof));
k = org_k;
}
for (auto &k: proof.L)
{
const rct::key org_k = k;
rct::addKeys(k, org_k, x);
ASSERT_FALSE(rct::bulletproof_VERIFY(proof));
k = org_k;
}
for (auto &k: proof.R)
{
const rct::key org_k = k;
rct::addKeys(k, org_k, x);
ASSERT_FALSE(rct::bulletproof_VERIFY(proof));
k = org_k;
}
const rct::key org_A = proof.A;
rct::addKeys(proof.A, org_A, x);
ASSERT_FALSE(rct::bulletproof_VERIFY(proof));
proof.A = org_A;
const rct::key org_S = proof.S;
rct::addKeys(proof.S, org_S, x);
ASSERT_FALSE(rct::bulletproof_VERIFY(proof));
proof.S = org_S;
const rct::key org_T1 = proof.T1;
rct::addKeys(proof.T1, org_T1, x);
ASSERT_FALSE(rct::bulletproof_VERIFY(proof));
proof.T1 = org_T1;
const rct::key org_T2 = proof.T2;
rct::addKeys(proof.T2, org_T2, x);
ASSERT_FALSE(rct::bulletproof_VERIFY(proof));
proof.T2 = org_T2;
}
}