Skip to content

Commit

Permalink
Integrate CLSAGs into monero
Browse files Browse the repository at this point in the history
They are allowed from v12, and MLSAGs are rejected from v13.
  • Loading branch information
moneromooo-monero committed Jun 19, 2019
1 parent 9d048a2 commit 52c6585
Show file tree
Hide file tree
Showing 25 changed files with 985 additions and 144 deletions.
27 changes: 22 additions & 5 deletions src/cryptonote_basic/cryptonote_boost_serialization.h
Expand Up @@ -46,7 +46,6 @@
#include "ringct/rctTypes.h"
#include "ringct/rctOps.h"

//namespace cryptonote {
namespace boost
{
namespace serialization
Expand Down Expand Up @@ -245,6 +244,15 @@ namespace boost
// a & x.II; // not serialized, we can recover it from the tx vin
}

template <class Archive>
inline void serialize(Archive &a, rct::clsag &x, const boost::serialization::version_type ver)
{
a & x.s;
a & x.c1;
// a & x.I; // not serialized, we can recover it from the tx vin
a & x.D;
}

template <class Archive>
inline void serialize(Archive &a, rct::ecdhTuple &x, const boost::serialization::version_type ver)
{
Expand All @@ -265,6 +273,9 @@ namespace boost
inline void serialize(Archive &a, rct::multisig_out &x, const boost::serialization::version_type ver)
{
a & x.c;
if (ver < 1)
return;
a & x.mu_p;
}

template <class Archive>
Expand Down Expand Up @@ -295,7 +306,7 @@ namespace boost
a & x.type;
if (x.type == rct::RCTTypeNull)
return;
if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeBulletproof && x.type != rct::RCTTypeBulletproof2)
if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeBulletproof && x.type != rct::RCTTypeBulletproof2 && x.type != rct::RCTTypeCLSAG)
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
Expand All @@ -313,6 +324,8 @@ namespace boost
if (x.rangeSigs.empty())
a & x.bulletproofs;
a & x.MGs;
if (ver >= 1)
a & x.CLSAGs;
if (x.rangeSigs.empty())
a & x.pseudoOuts;
}
Expand All @@ -323,7 +336,7 @@ namespace boost
a & x.type;
if (x.type == rct::RCTTypeNull)
return;
if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeBulletproof && x.type != rct::RCTTypeBulletproof2)
if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeBulletproof && x.type != rct::RCTTypeBulletproof2 && x.type != rct::RCTTypeCLSAG)
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
Expand All @@ -337,7 +350,9 @@ namespace boost
if (x.p.rangeSigs.empty())
a & x.p.bulletproofs;
a & x.p.MGs;
if (x.type == rct::RCTTypeBulletproof || x.type == rct::RCTTypeBulletproof2)
if (ver >= 1)
a & x.p.CLSAGs;
if (x.type == rct::RCTTypeBulletproof || x.type == rct::RCTTypeBulletproof2 || x.type == rct::RCTTypeCLSAG)
a & x.p.pseudoOuts;
}

Expand Down Expand Up @@ -378,4 +393,6 @@ namespace boost
}
}

//}
BOOST_CLASS_VERSION(rct::rctSigPrunable, 1)
BOOST_CLASS_VERSION(rct::rctSig, 1)
BOOST_CLASS_VERSION(rct::multisig_out, 1)
1 change: 1 addition & 0 deletions src/cryptonote_config.h
Expand Up @@ -150,6 +150,7 @@
#define HF_VERSION_SAME_MIXIN 12
#define HF_VERSION_MIN_2_OUTPUTS 12
#define HF_VERSION_MIN_V2_COINBASE_TX 12
#define HF_VERSION_CLSAG 12

#define PER_KB_FEE_QUANTIZATION_DECIMALS 8

Expand Down
45 changes: 42 additions & 3 deletions src/cryptonote_core/blockchain.cpp
Expand Up @@ -2745,6 +2745,30 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
}
}

// from v12, allow CLSAGs
if (hf_version < HF_VERSION_CLSAG) {
if (tx.version >= 2) {
if (tx.rct_signatures.type == rct::RCTTypeCLSAG)
{
MERROR_VER("Ringct type " << (unsigned)rct::RCTTypeCLSAG << " is not allowed before v" << HF_VERSION_CLSAG);
tvc.m_invalid_output = true;
return false;
}
}
}

// from v13, allow only CLSAGs
if (hf_version > HF_VERSION_CLSAG) {
if (tx.version >= 2) {
if (tx.rct_signatures.type <= rct::RCTTypeBulletproof2)
{
MERROR_VER("Ringct type " << (unsigned)tx.rct_signatures.type << " is not allowed from v" << (HF_VERSION_CLSAG + 1));
tvc.m_invalid_output = true;
return false;
}
}
}

return true;
}
//------------------------------------------------------------------
Expand Down Expand Up @@ -2785,7 +2809,7 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr
}
}
}
else if (rv.type == rct::RCTTypeSimple || rv.type == rct::RCTTypeBulletproof || rv.type == rct::RCTTypeBulletproof2)
else if (rv.type == rct::RCTTypeSimple || rv.type == rct::RCTTypeBulletproof || rv.type == rct::RCTTypeBulletproof2 || rv.type == rct::RCTTypeCLSAG)
{
CHECK_AND_ASSERT_MES(!pubkeys.empty() && !pubkeys[0].empty(), false, "empty pubkeys");
rv.mixRing.resize(pubkeys.size());
Expand Down Expand Up @@ -2826,6 +2850,14 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr
}
}
}
else if (rv.type == rct::RCTTypeCLSAG)
{
CHECK_AND_ASSERT_MES(rv.p.CLSAGs.size() == tx.vin.size(), false, "Bad CLSAGs size");
for (size_t n = 0; n < tx.vin.size(); ++n)
{
rv.p.CLSAGs[n].I = rct::ki2rct(boost::get<txin_to_key>(tx.vin[n]).k_image);
}
}
else
{
CHECK_AND_ASSERT_MES(false, false, "Unsupported rct tx type: " + boost::lexical_cast<std::string>(rv.type));
Expand Down Expand Up @@ -3120,6 +3152,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
case rct::RCTTypeSimple:
case rct::RCTTypeBulletproof:
case rct::RCTTypeBulletproof2:
case rct::RCTTypeCLSAG:
{
// check all this, either reconstructed (so should really pass), or not
{
Expand Down Expand Up @@ -3155,14 +3188,20 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
}
}

if (rv.p.MGs.size() != tx.vin.size())
const size_t n_sigs = rv.type == rct::RCTTypeCLSAG ? rv.p.CLSAGs.size() : rv.p.MGs.size();
if (n_sigs != tx.vin.size())
{
MERROR_VER("Failed to check ringct signatures: mismatched MGs/vin sizes");
return false;
}
for (size_t n = 0; n < tx.vin.size(); ++n)
{
if (rv.p.MGs[n].II.empty() || memcmp(&boost::get<txin_to_key>(tx.vin[n]).k_image, &rv.p.MGs[n].II[0], 32))
bool error;
if (rv.type == rct::RCTTypeCLSAG)
error = memcmp(&boost::get<txin_to_key>(tx.vin[n]).k_image, &rv.p.CLSAGs[n].I, 32);
else
error = rv.p.MGs[n].II.empty() || memcmp(&boost::get<txin_to_key>(tx.vin[n]).k_image, &rv.p.MGs[n].II[0], 32);
if (error)
{
MERROR_VER("Failed to check ringct signatures: mismatched key image");
return false;
Expand Down
3 changes: 2 additions & 1 deletion src/cryptonote_core/cryptonote_core.cpp
Expand Up @@ -912,6 +912,7 @@ namespace cryptonote
break;
case rct::RCTTypeBulletproof:
case rct::RCTTypeBulletproof2:
case rct::RCTTypeCLSAG:
if (!is_canonical_bulletproof_layout(rv.p.bulletproofs))
{
MERROR_VER("Bulletproof does not have canonical form");
Expand Down Expand Up @@ -939,7 +940,7 @@ namespace cryptonote
{
if (!tx_info[n].result)
continue;
if (tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproof && tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproof2)
if (tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproof && tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproof2 && tx_info[n].tx->rct_signatures.type != rct::RCTTypeCLSAG)
continue;
if (assumed_bad || !rct::verRctSemanticsSimple(tx_info[n].tx->rct_signatures))
{
Expand Down
6 changes: 3 additions & 3 deletions src/device/device_ledger.cpp
Expand Up @@ -1628,7 +1628,7 @@ namespace hw {

// ====== Aout, Bout, AKout, C, v, k ======
kv_offset = data_offset;
if (type==rct::RCTTypeBulletproof2) {
if (type==rct::RCTTypeBulletproof2 || type==rct::RCTTypeCLSAG) {
C_offset = kv_offset+ (8)*outputs_size;
} else {
C_offset = kv_offset+ (32+32)*outputs_size;
Expand All @@ -1645,7 +1645,7 @@ namespace hw {
offset = set_command_header(INS_VALIDATE, 0x02, i+1);
//options
this->buffer_send[offset] = (i==outputs_size-1)? 0x00:0x80 ;
this->buffer_send[offset] |= (type==rct::RCTTypeBulletproof2)?0x02:0x00;
this->buffer_send[offset] |= (type==rct::RCTTypeBulletproof2 || type==rct::RCTTypeCLSAG)?0x02:0x00;
offset += 1;
if (found) {
//is_subaddress
Expand All @@ -1671,7 +1671,7 @@ namespace hw {
memmove(this->buffer_send+offset, data+C_offset,32);
offset += 32;
C_offset += 32;
if (type==rct::RCTTypeBulletproof2) {
if (type==rct::RCTTypeBulletproof2 || type==rct::RCTTypeCLSAG) {
//k
memset(this->buffer_send+offset, 0, 32);
offset += 32;
Expand Down
2 changes: 1 addition & 1 deletion src/device_trezor/trezor/protocol.hpp
Expand Up @@ -289,7 +289,7 @@ namespace tx {
throw std::invalid_argument("RV not initialized");
}
auto tp = m_ct.rv->type;
return tp == rct::RCTTypeBulletproof || tp == rct::RCTTypeBulletproof2;
return tp == rct::RCTTypeBulletproof || tp == rct::RCTTypeBulletproof2 || tp == rct::RCTTypeCLSAG;
}

bool is_offloading() const {
Expand Down
3 changes: 3 additions & 0 deletions src/hardforks/hardforks.cpp
Expand Up @@ -64,6 +64,9 @@ const hardfork_t mainnet_hard_forks[] = {

// version 11 starts from block 1788720, which is on or around the 10th of March, 2019. Fork time finalised on 2019-02-15.
{ 11, 1788720, 0, 1550225678 },

{ 12, 1788721, 0, 1550225679 },
{ 13, 1788722, 0, 1550225680 },
};
const size_t num_mainnet_hard_forks = sizeof(mainnet_hard_forks) / sizeof(mainnet_hard_forks[0]);
const uint64_t mainnet_hard_fork_version_1_till = 1009826;
Expand Down

0 comments on commit 52c6585

Please sign in to comment.