mirror of
https://github.com/monero-project/monero.git
synced 2024-12-23 12:09:54 +00:00
bulletproofs: reject points not in the main subgroup
This commit is contained in:
parent
1569717718
commit
c429176248
6 changed files with 97 additions and 0 deletions
|
@ -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");
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue