mirror of
https://github.com/monero-project/monero.git
synced 2024-12-23 12:09:54 +00:00
add bulletproofs from v7 on testnet
This commit is contained in:
parent
8620ef0a0d
commit
c83d0b3ee2
11 changed files with 201 additions and 70 deletions
|
@ -280,11 +280,11 @@ namespace boost
|
|||
a & x.type;
|
||||
if (x.type == rct::RCTTypeNull)
|
||||
return;
|
||||
if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple)
|
||||
if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeFullBulletproof && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeSimpleBulletproof)
|
||||
throw boost::archive::archive_exception(boost::archive::archive_exception::other_exception, "Unsupported rct type");
|
||||
// a & x.message; message is not serialized, as it can be reconstructed from the tx data
|
||||
// a & x.mixRing; mixRing is not serialized, as it can be reconstructed from the offsets
|
||||
if (x.type == rct::RCTTypeSimple)
|
||||
if (x.type == rct::RCTTypeSimple || x.type == rct::RCTTypeSimpleBulletproof)
|
||||
a & x.pseudoOuts;
|
||||
a & x.ecdhInfo;
|
||||
serializeOutPk(a, x.outPk, ver);
|
||||
|
@ -306,11 +306,11 @@ namespace boost
|
|||
a & x.type;
|
||||
if (x.type == rct::RCTTypeNull)
|
||||
return;
|
||||
if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple)
|
||||
if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeFullBulletproof && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeSimpleBulletproof)
|
||||
throw boost::archive::archive_exception(boost::archive::archive_exception::other_exception, "Unsupported rct type");
|
||||
// a & x.message; message is not serialized, as it can be reconstructed from the tx data
|
||||
// a & x.mixRing; mixRing is not serialized, as it can be reconstructed from the offsets
|
||||
if (x.type == rct::RCTTypeSimple)
|
||||
if (x.type == rct::RCTTypeSimple || x.type == rct::RCTTypeSimpleBulletproof)
|
||||
a & x.pseudoOuts;
|
||||
a & x.ecdhInfo;
|
||||
serializeOutPk(a, x.outPk, ver);
|
||||
|
|
|
@ -127,6 +127,7 @@ static const struct {
|
|||
{ 5, 802660, 0, 1472415036 + 86400*180 }, // add 5 months on testnet to shut the update warning up since there's a large gap to v6
|
||||
|
||||
{ 6, 971400, 0, 1501709789 },
|
||||
{ 7, 1057028, 0, 1512211236 },
|
||||
};
|
||||
static const uint64_t testnet_hard_fork_version_1_till = 624633;
|
||||
|
||||
|
@ -2387,8 +2388,10 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
|
|||
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||
CRITICAL_REGION_LOCAL(m_blockchain_lock);
|
||||
|
||||
const uint8_t hf_version = m_hardfork->get_current_version();
|
||||
|
||||
// from hard fork 2, we forbid dust and compound outputs
|
||||
if (m_hardfork->get_current_version() >= 2) {
|
||||
if (hf_version >= 2) {
|
||||
for (auto &o: tx.vout) {
|
||||
if (tx.version == 1)
|
||||
{
|
||||
|
@ -2401,7 +2404,7 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
|
|||
}
|
||||
|
||||
// in a v2 tx, all outputs must have 0 amount
|
||||
if (m_hardfork->get_current_version() >= 3) {
|
||||
if (hf_version >= 3) {
|
||||
if (tx.version >= 2) {
|
||||
for (auto &o: tx.vout) {
|
||||
if (o.amount != 0) {
|
||||
|
@ -2413,7 +2416,7 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
|
|||
}
|
||||
|
||||
// from v4, forbid invalid pubkeys
|
||||
if (m_hardfork->get_current_version() >= 4) {
|
||||
if (hf_version >= 4) {
|
||||
for (const auto &o: tx.vout) {
|
||||
if (o.target.type() == typeid(txout_to_key)) {
|
||||
const txout_to_key& out_to_key = boost::get<txout_to_key>(o.target);
|
||||
|
@ -2425,6 +2428,16 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
|
|||
}
|
||||
}
|
||||
|
||||
// from v7, allow bulletproofs
|
||||
if (hf_version < 7 || !m_testnet) {
|
||||
if (!tx.rct_signatures.p.bulletproofs.empty())
|
||||
{
|
||||
MERROR("Bulletproofs are not allowed before v7 or on mainnet");
|
||||
tvc.m_invalid_output = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
|
@ -2450,7 +2463,7 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr
|
|||
rv.message = rct::hash2rct(tx_prefix_hash);
|
||||
|
||||
// mixRing - full and simple store it in opposite ways
|
||||
if (rv.type == rct::RCTTypeFull)
|
||||
if (rv.type == rct::RCTTypeFull || rv.type == rct::RCTTypeFullBulletproof)
|
||||
{
|
||||
rv.mixRing.resize(pubkeys[0].size());
|
||||
for (size_t m = 0; m < pubkeys[0].size(); ++m)
|
||||
|
@ -2464,7 +2477,7 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (rv.type == rct::RCTTypeSimple)
|
||||
else if (rv.type == rct::RCTTypeSimple || rv.type == rct::RCTTypeSimpleBulletproof)
|
||||
{
|
||||
rv.mixRing.resize(pubkeys.size());
|
||||
for (size_t n = 0; n < pubkeys.size(); ++n)
|
||||
|
@ -2482,14 +2495,14 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr
|
|||
}
|
||||
|
||||
// II
|
||||
if (rv.type == rct::RCTTypeFull)
|
||||
if (rv.type == rct::RCTTypeFull || rv.type == rct::RCTTypeFullBulletproof)
|
||||
{
|
||||
rv.p.MGs.resize(1);
|
||||
rv.p.MGs[0].II.resize(tx.vin.size());
|
||||
for (size_t n = 0; n < tx.vin.size(); ++n)
|
||||
rv.p.MGs[0].II[n] = rct::ki2rct(boost::get<txin_to_key>(tx.vin[n]).k_image);
|
||||
}
|
||||
else if (rv.type == rct::RCTTypeSimple)
|
||||
else if (rv.type == rct::RCTTypeSimple || rv.type == rct::RCTTypeSimpleBulletproof)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(rv.p.MGs.size() == tx.vin.size(), false, "Bad MGs size");
|
||||
for (size_t n = 0; n < tx.vin.size(); ++n)
|
||||
|
@ -2753,7 +2766,9 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
|
|||
MERROR_VER("Null rct signature on non-coinbase tx");
|
||||
return false;
|
||||
}
|
||||
case rct::RCTTypeSimple: {
|
||||
case rct::RCTTypeSimple:
|
||||
case rct::RCTTypeSimpleBulletproof:
|
||||
{
|
||||
// check all this, either recontructed (so should really pass), or not
|
||||
{
|
||||
if (pubkeys.size() != rv.mixRing.size())
|
||||
|
@ -2809,7 +2824,9 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
|
|||
}
|
||||
break;
|
||||
}
|
||||
case rct::RCTTypeFull: {
|
||||
case rct::RCTTypeFull:
|
||||
case rct::RCTTypeFullBulletproof:
|
||||
{
|
||||
// check all this, either recontructed (so should really pass), or not
|
||||
{
|
||||
bool size_matches = true;
|
||||
|
|
|
@ -625,6 +625,22 @@ namespace cryptonote
|
|||
}
|
||||
for (size_t n = 0; n < tx.rct_signatures.outPk.size(); ++n)
|
||||
rv.outPk[n].dest = rct::pk2rct(boost::get<txout_to_key>(tx.vout[n].target).key);
|
||||
|
||||
const bool bulletproof = rv.type == rct::RCTTypeFullBulletproof || rv.type == rct::RCTTypeSimpleBulletproof;
|
||||
if (bulletproof)
|
||||
{
|
||||
if (rv.p.bulletproofs.size() != tx.vout.size())
|
||||
{
|
||||
LOG_PRINT_L1("WRONG TRANSACTION BLOB, Bad bulletproofs size in tx " << tx_hash << ", rejected");
|
||||
tvc.m_verifivation_failed = true;
|
||||
return false;
|
||||
}
|
||||
for (size_t n = 0; n < rv.outPk.size(); ++n)
|
||||
{
|
||||
rv.p.bulletproofs[n].V.resize(1);
|
||||
rv.p.bulletproofs[n].V[0] = rv.outPk[n].mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (keeped_by_block && get_blockchain_storage().is_within_compiled_block_hash_area())
|
||||
|
@ -828,6 +844,7 @@ namespace cryptonote
|
|||
MERROR_VER("Unexpected Null rctSig type");
|
||||
return false;
|
||||
case rct::RCTTypeSimple:
|
||||
case rct::RCTTypeSimpleBulletproof:
|
||||
if (!rct::verRctSimple(rv, true))
|
||||
{
|
||||
MERROR_VER("rct signature semantics check failed");
|
||||
|
@ -835,6 +852,7 @@ namespace cryptonote
|
|||
}
|
||||
break;
|
||||
case rct::RCTTypeFull:
|
||||
case rct::RCTTypeFullBulletproof:
|
||||
if (!rct::verRct(rv, true))
|
||||
{
|
||||
MERROR_VER("rct signature semantics check failed");
|
||||
|
|
|
@ -47,7 +47,8 @@ namespace rct {
|
|||
{
|
||||
mask = rct::skGen();
|
||||
Bulletproof proof = bulletproof_PROVE(amount, mask);
|
||||
C = proof.V;
|
||||
CHECK_AND_ASSERT_THROW_MES(proof.V.size() == 1, "V has not exactly one element");
|
||||
C = proof.V[0];
|
||||
return proof;
|
||||
}
|
||||
|
||||
|
@ -344,16 +345,41 @@ namespace rct {
|
|||
hashes.push_back(hash2rct(h));
|
||||
|
||||
keyV kv;
|
||||
kv.reserve((64*3+1) * rv.p.rangeSigs.size());
|
||||
for (auto r: rv.p.rangeSigs)
|
||||
if (rv.type == RCTTypeSimpleBulletproof || rv.type == RCTTypeFullBulletproof)
|
||||
{
|
||||
for (size_t n = 0; n < 64; ++n)
|
||||
kv.push_back(r.asig.s0[n]);
|
||||
for (size_t n = 0; n < 64; ++n)
|
||||
kv.push_back(r.asig.s1[n]);
|
||||
kv.push_back(r.asig.ee);
|
||||
for (size_t n = 0; n < 64; ++n)
|
||||
kv.push_back(r.Ci[n]);
|
||||
kv.reserve((6*2+10) * rv.p.bulletproofs.size());
|
||||
for (const auto &p: rv.p.bulletproofs)
|
||||
{
|
||||
for (size_t n = 0; n < p.V.size(); ++n)
|
||||
kv.push_back(p.V[n]);
|
||||
kv.push_back(p.A);
|
||||
kv.push_back(p.S);
|
||||
kv.push_back(p.T1);
|
||||
kv.push_back(p.T2);
|
||||
kv.push_back(p.taux);
|
||||
kv.push_back(p.mu);
|
||||
for (size_t n = 0; n < p.L.size(); ++n)
|
||||
kv.push_back(p.L[n]);
|
||||
for (size_t n = 0; n < p.R.size(); ++n)
|
||||
kv.push_back(p.R[n]);
|
||||
kv.push_back(p.a);
|
||||
kv.push_back(p.b);
|
||||
kv.push_back(p.t);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
kv.reserve((64*3+1) * rv.p.rangeSigs.size());
|
||||
for (const auto &r: rv.p.rangeSigs)
|
||||
{
|
||||
for (size_t n = 0; n < 64; ++n)
|
||||
kv.push_back(r.asig.s0[n]);
|
||||
for (size_t n = 0; n < 64; ++n)
|
||||
kv.push_back(r.asig.s1[n]);
|
||||
kv.push_back(r.asig.ee);
|
||||
for (size_t n = 0; n < 64; ++n)
|
||||
kv.push_back(r.Ci[n]);
|
||||
}
|
||||
}
|
||||
hashes.push_back(cn_fast_hash(kv));
|
||||
return cn_fast_hash(hashes);
|
||||
|
@ -581,10 +607,13 @@ namespace rct {
|
|||
}
|
||||
|
||||
rctSig rv;
|
||||
rv.type = RCTTypeFull;
|
||||
rv.type = bulletproof ? RCTTypeFullBulletproof : RCTTypeFull;
|
||||
rv.message = message;
|
||||
rv.outPk.resize(destinations.size());
|
||||
rv.p.rangeSigs.resize(destinations.size());
|
||||
if (bulletproof)
|
||||
rv.p.bulletproofs.resize(destinations.size());
|
||||
else
|
||||
rv.p.rangeSigs.resize(destinations.size());
|
||||
rv.ecdhInfo.resize(destinations.size());
|
||||
|
||||
size_t i = 0;
|
||||
|
@ -650,7 +679,7 @@ namespace rct {
|
|||
}
|
||||
|
||||
rctSig rv;
|
||||
rv.type = RCTTypeSimple;
|
||||
rv.type = bulletproof ? RCTTypeSimpleBulletproof : RCTTypeSimple;
|
||||
rv.message = message;
|
||||
rv.outPk.resize(destinations.size());
|
||||
if (bulletproof)
|
||||
|
@ -738,10 +767,10 @@ namespace rct {
|
|||
// must know the destination private key to find the correct amount, else will return a random number
|
||||
bool verRct(const rctSig & rv, bool semantics) {
|
||||
PERF_TIMER(verRct);
|
||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull, false, "verRct called on non-full rctSig");
|
||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull || rv.type == RCTTypeFullBulletproof, false, "verRct called on non-full rctSig");
|
||||
if (semantics)
|
||||
{
|
||||
if (rv.p.rangeSigs.empty())
|
||||
if (rv.type == RCTTypeFullBulletproof)
|
||||
CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.p.bulletproofs.size(), false, "Mismatched sizes of outPk and rv.p.bulletproofs");
|
||||
else
|
||||
CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.p.rangeSigs.size(), false, "Mismatched sizes of outPk and rv.p.rangeSigs");
|
||||
|
@ -764,7 +793,7 @@ namespace rct {
|
|||
for (size_t i = 0; i < rv.outPk.size(); i++) {
|
||||
tpool.submit(&waiter, [&, i] {
|
||||
if (rv.p.rangeSigs.empty())
|
||||
results[i] = bulletproof_VERIFY(rv.p.bulletproofs[i]); // TODO
|
||||
results[i] = bulletproof_VERIFY(rv.p.bulletproofs[i]);
|
||||
else
|
||||
results[i] = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]);
|
||||
});
|
||||
|
@ -806,10 +835,10 @@ namespace rct {
|
|||
{
|
||||
PERF_TIMER(verRctSimple);
|
||||
|
||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple, false, "verRctSimple called on non simple rctSig");
|
||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeSimpleBulletproof, false, "verRctSimple called on non simple rctSig");
|
||||
if (semantics)
|
||||
{
|
||||
if (rv.p.rangeSigs.empty())
|
||||
if (rv.type == RCTTypeSimpleBulletproof)
|
||||
CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.p.bulletproofs.size(), false, "Mismatched sizes of outPk and rv.p.bulletproofs");
|
||||
else
|
||||
CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.p.rangeSigs.size(), false, "Mismatched sizes of outPk and rv.p.rangeSigs");
|
||||
|
@ -905,9 +934,17 @@ namespace rct {
|
|||
// uses the attached ecdh info to find the amounts represented by each output commitment
|
||||
// must know the destination private key to find the correct amount, else will return a random number
|
||||
xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, key & mask) {
|
||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull, false, "decodeRct called on non-full rctSig");
|
||||
CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.ecdhInfo.size(), "Mismatched sizes of rv.outPk and rv.ecdhInfo");
|
||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull || rv.type == RCTTypeFullBulletproof, false, "decodeRct called on non-full rctSig");
|
||||
CHECK_AND_ASSERT_THROW_MES(i < rv.ecdhInfo.size(), "Bad index");
|
||||
if (rv.type == RCTTypeFullBulletproof)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(rv.p.bulletproofs.size() == rv.ecdhInfo.size(), "Mismatched sizes of rv.p.bulletproofs and rv.ecdhInfo");
|
||||
CHECK_AND_ASSERT_THROW_MES(rv.p.bulletproofs[i].V.size() == 1, "Unexpected sizes of rv.p.bulletproofs[i].V");
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.ecdhInfo.size(), "Mismatched sizes of rv.outPk and rv.ecdhInfo");
|
||||
}
|
||||
|
||||
//mask amount and mask
|
||||
ecdhTuple ecdh_info = rv.ecdhInfo[i];
|
||||
|
@ -933,16 +970,24 @@ namespace rct {
|
|||
}
|
||||
|
||||
xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key &mask) {
|
||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple, false, "decodeRct called on non simple rctSig");
|
||||
CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.ecdhInfo.size(), "Mismatched sizes of rv.outPk and rv.ecdhInfo");
|
||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeSimpleBulletproof, false, "decodeRct called on non simple rctSig");
|
||||
CHECK_AND_ASSERT_THROW_MES(i < rv.ecdhInfo.size(), "Bad index");
|
||||
if (rv.type == RCTTypeSimpleBulletproof)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(rv.p.bulletproofs.size() == rv.ecdhInfo.size(), "Mismatched sizes of rv.p.bulletproofs and rv.ecdhInfo");
|
||||
CHECK_AND_ASSERT_THROW_MES(rv.p.bulletproofs[i].V.size() == 1, "Unexpected sizes of rv.p.bulletproofs[i].V");
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.ecdhInfo.size(), "Mismatched sizes of rv.outPk and rv.ecdhInfo");
|
||||
}
|
||||
|
||||
//mask amount and mask
|
||||
ecdhTuple ecdh_info = rv.ecdhInfo[i];
|
||||
ecdhDecode(ecdh_info, sk);
|
||||
mask = ecdh_info.mask;
|
||||
key amount = ecdh_info.amount;
|
||||
key C = rv.outPk[i].mask;
|
||||
key C = (rv.type == RCTTypeSimpleBulletproof) ? rv.p.bulletproofs[i].V.front() : rv.outPk[i].mask;
|
||||
DP("C");
|
||||
DP(C);
|
||||
key Ctmp;
|
||||
|
|
|
@ -164,17 +164,19 @@ namespace rct {
|
|||
|
||||
struct Bulletproof
|
||||
{
|
||||
rct::key V, A, S, T1, T2;
|
||||
rct::keyV V;
|
||||
rct::key A, S, T1, T2;
|
||||
rct::key taux, mu;
|
||||
rct::keyV L, R;
|
||||
rct::key a, b, t;
|
||||
|
||||
Bulletproof() {}
|
||||
Bulletproof(const rct::key &V, const rct::key &A, const rct::key &S, const rct::key &T1, const rct::key &T2, const rct::key &taux, const rct::key &mu, const rct::keyV &L, const rct::keyV &R, const rct::key &a, const rct::key &b, const rct::key &t):
|
||||
V(V), A(A), S(S), T1(T1), T2(T2), taux(taux), mu(mu), L(L), R(R), a(a), b(b), t(t) {}
|
||||
V({V}), A(A), S(S), T1(T1), T2(T2), taux(taux), mu(mu), L(L), R(R), a(a), b(b), t(t) {}
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(V)
|
||||
// Commitments aren't saved, they're restored via outPk
|
||||
// FIELD(V)
|
||||
FIELD(A)
|
||||
FIELD(S)
|
||||
FIELD(T1)
|
||||
|
@ -203,6 +205,8 @@ namespace rct {
|
|||
RCTTypeNull = 0,
|
||||
RCTTypeFull = 1,
|
||||
RCTTypeSimple = 2,
|
||||
RCTTypeFullBulletproof = 3,
|
||||
RCTTypeSimpleBulletproof = 4,
|
||||
};
|
||||
struct rctSigBase {
|
||||
uint8_t type;
|
||||
|
@ -220,13 +224,13 @@ namespace rct {
|
|||
FIELD(type)
|
||||
if (type == RCTTypeNull)
|
||||
return true;
|
||||
if (type != RCTTypeFull && type != RCTTypeSimple)
|
||||
if (type != RCTTypeFull && type != RCTTypeFullBulletproof && type != RCTTypeSimple && type != RCTTypeSimpleBulletproof)
|
||||
return false;
|
||||
VARINT_FIELD(txnFee)
|
||||
// inputs/outputs not saved, only here for serialization help
|
||||
// FIELD(message) - not serialized, it can be reconstructed
|
||||
// FIELD(mixRing) - not serialized, it can be reconstructed
|
||||
if (type == RCTTypeSimple)
|
||||
if (type == RCTTypeSimple || type == RCTTypeSimpleBulletproof)
|
||||
{
|
||||
ar.tag("pseudoOuts");
|
||||
ar.begin_array();
|
||||
|
@ -280,24 +284,9 @@ namespace rct {
|
|||
{
|
||||
if (type == RCTTypeNull)
|
||||
return true;
|
||||
if (type != RCTTypeFull && type != RCTTypeSimple)
|
||||
if (type != RCTTypeFull && type != RCTTypeFullBulletproof && type != RCTTypeSimple && type != RCTTypeSimpleBulletproof)
|
||||
return false;
|
||||
ar.tag("rangeSigs");
|
||||
ar.begin_array();
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(outputs, rangeSigs);
|
||||
if (!rangeSigs.empty())
|
||||
{
|
||||
if (rangeSigs.size() != outputs)
|
||||
return false;
|
||||
for (size_t i = 0; i < outputs; ++i)
|
||||
{
|
||||
FIELDS(rangeSigs[i])
|
||||
if (outputs - i > 1)
|
||||
ar.delimit_array();
|
||||
}
|
||||
ar.end_array();
|
||||
}
|
||||
else
|
||||
if (type == RCTTypeSimpleBulletproof || type == RCTTypeFullBulletproof)
|
||||
{
|
||||
ar.tag("bp");
|
||||
ar.begin_array();
|
||||
|
@ -312,12 +301,27 @@ namespace rct {
|
|||
}
|
||||
ar.end_array();
|
||||
}
|
||||
else
|
||||
{
|
||||
ar.tag("rangeSigs");
|
||||
ar.begin_array();
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(outputs, rangeSigs);
|
||||
if (rangeSigs.size() != outputs)
|
||||
return false;
|
||||
for (size_t i = 0; i < outputs; ++i)
|
||||
{
|
||||
FIELDS(rangeSigs[i])
|
||||
if (outputs - i > 1)
|
||||
ar.delimit_array();
|
||||
}
|
||||
ar.end_array();
|
||||
}
|
||||
|
||||
ar.tag("MGs");
|
||||
ar.begin_array();
|
||||
// we keep a byte for size of MGs, because we don't know whether this is
|
||||
// a simple or full rct signature, and it's starting to annoy the hell out of me
|
||||
size_t mg_elements = type == RCTTypeSimple ? inputs : 1;
|
||||
size_t mg_elements = (type == RCTTypeSimple || type == RCTTypeSimpleBulletproof) ? inputs : 1;
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(mg_elements, MGs);
|
||||
if (MGs.size() != mg_elements)
|
||||
return false;
|
||||
|
@ -335,7 +339,7 @@ namespace rct {
|
|||
for (size_t j = 0; j < mixin + 1; ++j)
|
||||
{
|
||||
ar.begin_array();
|
||||
size_t mg_ss2_elements = (type == RCTTypeSimple ? 1 : inputs) + 1;
|
||||
size_t mg_ss2_elements = ((type == RCTTypeSimple || type == RCTTypeSimpleBulletproof) ? 1 : inputs) + 1;
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(mg_ss2_elements, MGs[i].ss[j]);
|
||||
if (MGs[i].ss[j].size() != mg_ss2_elements)
|
||||
return false;
|
||||
|
|
|
@ -1007,6 +1007,7 @@ void toJsonValue(rapidjson::Document& doc, const rct::rctSigPrunable& sig, rapid
|
|||
val.SetObject();
|
||||
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, rangeSigs, sig.rangeSigs);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, bulletproofs, sig.bulletproofs);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, MGs, sig.MGs);
|
||||
}
|
||||
|
||||
|
@ -1018,6 +1019,7 @@ void fromJsonValue(const rapidjson::Value& val, rct::rctSigPrunable& sig)
|
|||
}
|
||||
|
||||
GET_FROM_JSON_OBJECT(val, sig.rangeSigs, rangeSigs);
|
||||
GET_FROM_JSON_OBJECT(val, sig.bulletproofs, bulletproofs);
|
||||
GET_FROM_JSON_OBJECT(val, sig.MGs, MGs);
|
||||
}
|
||||
|
||||
|
@ -1052,6 +1054,45 @@ void fromJsonValue(const rapidjson::Value& val, rct::rangeSig& sig)
|
|||
}
|
||||
}
|
||||
|
||||
void toJsonValue(rapidjson::Document& doc, const rct::Bulletproof& p, rapidjson::Value& val)
|
||||
{
|
||||
val.SetObject();
|
||||
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, V, p.V);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, A, p.A);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, S, p.S);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, T1, p.T1);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, T2, p.T2);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, taux, p.taux);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, mu, p.mu);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, L, p.L);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, R, p.R);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, a, p.a);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, b, p.b);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, t, p.t);
|
||||
}
|
||||
|
||||
void fromJsonValue(const rapidjson::Value& val, rct::Bulletproof& p)
|
||||
{
|
||||
if (!val.IsObject())
|
||||
{
|
||||
throw WRONG_TYPE("json object");
|
||||
}
|
||||
|
||||
GET_FROM_JSON_OBJECT(val, p.V, V);
|
||||
GET_FROM_JSON_OBJECT(val, p.A, A);
|
||||
GET_FROM_JSON_OBJECT(val, p.S, S);
|
||||
GET_FROM_JSON_OBJECT(val, p.T1, T1);
|
||||
GET_FROM_JSON_OBJECT(val, p.T2, T2);
|
||||
GET_FROM_JSON_OBJECT(val, p.taux, taux);
|
||||
GET_FROM_JSON_OBJECT(val, p.mu, mu);
|
||||
GET_FROM_JSON_OBJECT(val, p.L, L);
|
||||
GET_FROM_JSON_OBJECT(val, p.R, R);
|
||||
GET_FROM_JSON_OBJECT(val, p.a, a);
|
||||
GET_FROM_JSON_OBJECT(val, p.b, b);
|
||||
GET_FROM_JSON_OBJECT(val, p.t, t);
|
||||
}
|
||||
|
||||
void toJsonValue(rapidjson::Document& doc, const rct::boroSig& sig, rapidjson::Value& val)
|
||||
{
|
||||
val.SetObject();
|
||||
|
|
|
@ -274,6 +274,9 @@ void fromJsonValue(const rapidjson::Value& val, rct::rctSigPrunable& sig);
|
|||
void toJsonValue(rapidjson::Document& doc, const rct::rangeSig& sig, rapidjson::Value& val);
|
||||
void fromJsonValue(const rapidjson::Value& val, rct::rangeSig& sig);
|
||||
|
||||
void toJsonValue(rapidjson::Document& doc, const rct::Bulletproof& p, rapidjson::Value& val);
|
||||
void fromJsonValue(const rapidjson::Value& val, rct::Bulletproof& p);
|
||||
|
||||
void toJsonValue(rapidjson::Document& doc, const rct::boroSig& sig, rapidjson::Value& val);
|
||||
void fromJsonValue(const rapidjson::Value& val, rct::boroSig& sig);
|
||||
|
||||
|
|
|
@ -823,8 +823,10 @@ static uint64_t decodeRct(const rct::rctSig & rv, const crypto::key_derivation &
|
|||
switch (rv.type)
|
||||
{
|
||||
case rct::RCTTypeSimple:
|
||||
case rct::RCTTypeSimpleBulletproof:
|
||||
return rct::decodeRctSimple(rv, rct::sk2rct(scalar1), i, mask);
|
||||
case rct::RCTTypeFull:
|
||||
case rct::RCTTypeFullBulletproof:
|
||||
return rct::decodeRct(rv, rct::sk2rct(scalar1), i, mask);
|
||||
default:
|
||||
LOG_ERROR("Unsupported rct type: " << rv.type);
|
||||
|
@ -3774,9 +3776,10 @@ bool wallet2::sign_tx(unsigned_tx_set &exported_txs, const std::string &signed_f
|
|||
LOG_PRINT_L1(" " << (n+1) << ": " << sd.sources.size() << " inputs, ring size " << sd.sources[0].outputs.size());
|
||||
signed_txes.ptx.push_back(pending_tx());
|
||||
tools::wallet2::pending_tx &ptx = signed_txes.ptx.back();
|
||||
bool bulletproof = sd.use_rct && !ptx.tx.rct_signatures.p.bulletproofs.empty();
|
||||
crypto::secret_key tx_key;
|
||||
std::vector<crypto::secret_key> additional_tx_keys;
|
||||
bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sd.sources, sd.splitted_dsts, sd.change_dts.addr, sd.extra, ptx.tx, sd.unlock_time, tx_key, additional_tx_keys, sd.use_rct);
|
||||
bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sd.sources, sd.splitted_dsts, sd.change_dts.addr, sd.extra, ptx.tx, sd.unlock_time, tx_key, additional_tx_keys, sd.use_rct, bulletproof);
|
||||
THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sd.sources, sd.splitted_dsts, sd.unlock_time, m_testnet);
|
||||
// we don't test tx size, because we don't know the current limit, due to not having a blockchain,
|
||||
// and it's a bit pointless to fail there anyway, since it'd be a (good) guess only. We sign anyway,
|
||||
|
@ -4659,7 +4662,7 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent
|
|||
|
||||
void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry> dsts, const std::vector<size_t>& selected_transfers, size_t fake_outputs_count,
|
||||
std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs,
|
||||
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx, pending_tx &ptx)
|
||||
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx, pending_tx &ptx, bool bulletproof)
|
||||
{
|
||||
using namespace cryptonote;
|
||||
// throw if attempting a transaction with no destinations
|
||||
|
@ -4775,7 +4778,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
|
|||
crypto::secret_key tx_key;
|
||||
std::vector<crypto::secret_key> additional_tx_keys;
|
||||
LOG_PRINT_L2("constructing tx");
|
||||
bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sources, splitted_dsts, change_dts.addr, extra, tx, unlock_time, tx_key, additional_tx_keys, true);
|
||||
bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sources, splitted_dsts, change_dts.addr, extra, tx, unlock_time, tx_key, additional_tx_keys, true, bulletproof);
|
||||
LOG_PRINT_L2("constructed tx, r="<<r);
|
||||
THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, dsts, unlock_time, m_testnet);
|
||||
THROW_WALLET_EXCEPTION_IF(upper_transaction_size_limit <= get_object_blobsize(tx), error::tx_too_big, tx, upper_transaction_size_limit);
|
||||
|
@ -5734,7 +5737,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
|
|||
tx.selected_transfers.size() << " inputs");
|
||||
if (use_rct)
|
||||
transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
|
||||
test_tx, test_ptx);
|
||||
test_tx, test_ptx, bulletproof);
|
||||
else
|
||||
transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
|
||||
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx);
|
||||
|
@ -5777,7 +5780,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
|
|||
while (needed_fee > test_ptx.fee) {
|
||||
if (use_rct)
|
||||
transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
|
||||
test_tx, test_ptx);
|
||||
test_tx, test_ptx, bulletproof);
|
||||
else
|
||||
transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
|
||||
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx);
|
||||
|
@ -5984,7 +5987,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
|
|||
tx.selected_transfers.size() << " outputs");
|
||||
if (use_rct)
|
||||
transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
|
||||
test_tx, test_ptx);
|
||||
test_tx, test_ptx, bulletproof);
|
||||
else
|
||||
transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
|
||||
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx);
|
||||
|
@ -6001,7 +6004,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
|
|||
tx.dsts[0].amount = available_for_fee - needed_fee;
|
||||
if (use_rct)
|
||||
transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
|
||||
test_tx, test_ptx);
|
||||
test_tx, test_ptx, bulletproof);
|
||||
else
|
||||
transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
|
||||
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx);
|
||||
|
|
|
@ -536,7 +536,7 @@ namespace tools
|
|||
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction& tx, pending_tx &ptx);
|
||||
void transfer_selected_rct(std::vector<cryptonote::tx_destination_entry> dsts, const std::vector<size_t>& selected_transfers, size_t fake_outputs_count,
|
||||
std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs,
|
||||
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx, pending_tx &ptx);
|
||||
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx, pending_tx &ptx, bool bulletproof);
|
||||
|
||||
void commit_tx(pending_tx& ptx_vector);
|
||||
void commit_tx(std::vector<pending_tx>& ptx_vector);
|
||||
|
|
|
@ -132,7 +132,7 @@ bool gen_rct_tx_validation_base::generate_with(std::vector<test_event_entry>& ev
|
|||
CHECK_AND_ASSERT_MES(r, false, "Failed to generate key derivation");
|
||||
crypto::secret_key amount_key;
|
||||
crypto::derivation_to_scalar(derivation, o, amount_key);
|
||||
if (rct_txes[n].rct_signatures.type == rct::RCTTypeSimple)
|
||||
if (rct_txes[n].rct_signatures.type == rct::RCTTypeSimple || rct_txes[n].rct_signatures.type == rct::RCTTypeSimpleBulletproof)
|
||||
rct::decodeRctSimple(rct_txes[n].rct_signatures, rct::sk2rct(amount_key), o, rct_tx_masks[o+n*4]);
|
||||
else
|
||||
rct::decodeRct(rct_txes[n].rct_signatures, rct::sk2rct(amount_key), o, rct_tx_masks[o+n*4]);
|
||||
|
|
|
@ -80,7 +80,7 @@ public:
|
|||
{
|
||||
if (rct)
|
||||
{
|
||||
if (m_tx.rct_signatures.type == rct::RCTTypeFull)
|
||||
if (m_tx.rct_signatures.type == rct::RCTTypeFull || m_tx.rct_signatures.type == rct::RCTTypeFullBulletproof)
|
||||
return rct::verRct(m_tx.rct_signatures);
|
||||
else
|
||||
return rct::verRctSimple(m_tx.rct_signatures);
|
||||
|
|
Loading…
Reference in a new issue