diff --git a/src/cryptonote_basic/cryptonote_boost_serialization.h b/src/cryptonote_basic/cryptonote_boost_serialization.h index 31bc3265e..794ac4b97 100644 --- a/src/cryptonote_basic/cryptonote_boost_serialization.h +++ b/src/cryptonote_basic/cryptonote_boost_serialization.h @@ -355,6 +355,16 @@ namespace boost a & x.D; } + template + inline void serialize(Archive &a, rct::tclsag &x, const boost::serialization::version_type ver) + { + a & x.sx; + a & x.sy; + a & x.c1; + // a & x.I; // not serialized, we can recover it from the tx vin + a & x.D; + } + template inline void serialize(Archive &a, rct::zk_proof &x, const boost::serialization::version_type ver) { @@ -376,7 +386,7 @@ namespace boost a & x.salvium_data_type; a & x.pr_proof; a & x.sa_proof; - if (x.salvium_data_type == rct::SalviumAudit) + if (x.salvium_data_type == rct::SalviumZeroAudit) { a & x.cz_proof; a & x.input_verification_data; @@ -438,7 +448,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 && x.type != rct::RCTTypeCLSAG && x.type != rct::RCTTypeBulletproofPlus && x.type != rct::RCTTypeFullProofs && x.type != rct::RCTTypeSalviumOne) + if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeBulletproofPlus && x.type != rct::RCTTypeFullProofs && x.type != rct::RCTTypeSalviumZero && x.type != rct::RCTTypeSalviumOne) 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 @@ -448,7 +458,7 @@ namespace boost serializeOutPk(a, x.outPk, ver); a & x.txnFee; a & x.p_r; - if (x.type == rct::RCTTypeSalviumOne) { + if (x.type == rct::RCTTypeSalviumZero || x.type == rct::RCTTypeSalviumOne) { a & x.salvium_data; } else if (x.type == rct::RCTTypeFullProofs) { a & x.salvium_data.pr_proof; @@ -467,6 +477,8 @@ namespace boost a & x.bulletproofs_plus; } a & x.MGs; + if (ver >= 3u) + a & x.TCLSAGs; if (ver >= 1u) a & x.CLSAGs; if (x.rangeSigs.empty()) @@ -479,7 +491,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 && x.type != rct::RCTTypeCLSAG && x.type != rct::RCTTypeBulletproofPlus && x.type != rct::RCTTypeFullProofs && x.type != rct::RCTTypeSalviumOne) + if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeBulletproofPlus && x.type != rct::RCTTypeFullProofs && x.type != rct::RCTTypeSalviumZero && x.type != rct::RCTTypeSalviumOne) 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 @@ -489,7 +501,7 @@ namespace boost serializeOutPk(a, x.outPk, ver); a & x.txnFee; a & x.p_r; - if (x.type == rct::RCTTypeSalviumOne) { + if (x.type == rct::RCTTypeSalviumZero || x.type == rct::RCTTypeSalviumOne) { a & x.salvium_data; } else if (x.type == rct::RCTTypeFullProofs) { a & x.salvium_data.pr_proof; @@ -504,9 +516,11 @@ namespace boost a & x.p.bulletproofs_plus; } a & x.p.MGs; + if (ver >= 5u) + a & x.p.TCLSAGs; if (ver >= 1u) a & x.p.CLSAGs; - if (x.type == rct::RCTTypeBulletproof || x.type == rct::RCTTypeBulletproof2 || x.type == rct::RCTTypeCLSAG || x.type == rct::RCTTypeBulletproofPlus || x.type == rct::RCTTypeFullProofs || x.type == rct::RCTTypeSalviumOne) + if (x.type == rct::RCTTypeBulletproofPlus || x.type == rct::RCTTypeFullProofs || x.type == rct::RCTTypeSalviumZero || x.type == rct::RCTTypeSalviumOne) a & x.p.pseudoOuts; } @@ -547,6 +561,6 @@ namespace boost } } -BOOST_CLASS_VERSION(rct::rctSigPrunable, 2) -BOOST_CLASS_VERSION(rct::rctSig, 4) +BOOST_CLASS_VERSION(rct::rctSigPrunable, 3) +BOOST_CLASS_VERSION(rct::rctSig, 5) BOOST_CLASS_VERSION(rct::multisig_out, 1) diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp index 9141065d0..0904c3523 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.cpp +++ b/src/cryptonote_core/cryptonote_tx_utils.cpp @@ -834,12 +834,12 @@ namespace cryptonote salvium_data.enc_view_privkey_str = encrypt_pvk(sender_account_keys.m_view_secret_key, PK); // And now the rest of the structure - salvium_data.salvium_data_type = rct::SalviumAudit; + salvium_data.salvium_data_type = rct::SalviumZeroAudit; salvium_data.input_verification_data.reserve(sources.size()); salvium_data.spend_pubkey = sender_account_keys.m_account_address.m_spend_public_key; } else { - salvium_data.salvium_data_type = rct::SalviumNormal; + salvium_data.salvium_data_type = rct::SalviumZero; } uint64_t summary_inputs_money = 0; //fill inputs diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index d52f51769..f10e0056d 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -119,6 +119,13 @@ namespace const size_t n_scalars = ring_size; return rct::clsag{rct::keyV(n_scalars, I), I, I, I}; } + + rct::tclsag make_dummy_tclsag(size_t ring_size) + { + const rct::key I = rct::identity(); + const size_t n_scalars = ring_size; + return rct::tclsag{rct::keyV(n_scalars, I), rct::keyV(n_scalars, I), I, I, I}; + } } namespace rct { @@ -365,7 +372,7 @@ namespace rct { return sig; } - clsagCarrot CLSAG_Gen_Carrot( + tclsag TCLSAG_Gen( const key &message, const keyV & P, const key & x, // x term of P @@ -377,7 +384,7 @@ namespace rct { const unsigned int l, hw::device &hwdev) { - clsagCarrot sig; + tclsag sig; size_t n = P.size(); // ring size CHECK_AND_ASSERT_THROW_MES(n == C.size(), "Signing and commitment key vector sizes must match!"); CHECK_AND_ASSERT_THROW_MES(n == C_nonzero.size(), "Signing and commitment key vector sizes must match!"); @@ -803,7 +810,7 @@ namespace rct { hashes.push_back(hash2rct(h)); keyV kv; - if (rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG) + if (is_rct_bulletproof(rv.type)) { kv.reserve((6*2+9) * rv.p.bulletproofs.size()); for (const auto &p: rv.p.bulletproofs) @@ -825,7 +832,7 @@ namespace rct { kv.push_back(p.t); } } - else if (rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs || rv.type == RCTTypeSalviumOne) + else if (is_rct_bulletproof_plus(rv.type)) { kv.reserve((6*2+6) * rv.p.bulletproofs_plus.size()); for (const auto &p: rv.p.bulletproofs_plus) @@ -977,7 +984,7 @@ namespace rct { return result; } - clsagCarrot proveRctCLSAGSimpleCarrot(const key &message, const ctkeyV &pubs, const key &x, const key &y, const key &mask, const key &a, const key &Cout, unsigned int index, hw::device &hwdev) { + tclsag proveRctTCLSAGSimple(const key &message, const ctkeyV &pubs, const key &x, const key &y, const key &mask, const key &a, const key &Cout, unsigned int index, hw::device &hwdev) { //setup vars size_t rows = 1; size_t cols = pubs.size(); @@ -1000,7 +1007,7 @@ namespace rct { key sk; sc_sub(sk.bytes, mask.bytes, a.bytes); // private key of the output commitment - clsagCarrot result = CLSAG_Gen_Carrot(message, P, x, y, C, sk, C_nonzero, Cout, index, hwdev); + tclsag result = TCLSAG_Gen(message, P, x, y, C, sk, C_nonzero, Cout, index, hwdev); memwipe(&sk, sizeof(key)); return result; } @@ -1197,7 +1204,7 @@ namespace rct { catch (...) { return false; } } - bool verRctCLSAGSimpleCarrot(const key &message, const clsagCarrot &sig, const ctkeyV & pubs, const key & C_offset) { + bool verRctTCLSAGSimple(const key &message, const tclsag &sig, const ctkeyV & pubs, const key & C_offset) { try { PERF_TIMER(verRctCLSAGSimpleCarrot); @@ -1366,55 +1373,60 @@ namespace rct { } return index; } + + zk_proof SAProof_Gen(const key &P, const key &x_change, const key &y_change, const key &key_yF) { - zk_proof SAProof_Gen(const key &P, const key &x_change, const key &key_yF) { - - // Sanity checks for inputs - CHECK_AND_ASSERT_THROW_MES(!rct::equalKeys(P, rct::zero()), "SAProof_Gen() failed - invalid public key provided"); - CHECK_AND_ASSERT_THROW_MES(!rct::equalKeys(x_change, rct::zero()), "SAProof_Gen() failed - invalid x_change key provided"); - CHECK_AND_ASSERT_THROW_MES(!rct::equalKeys(key_yF, rct::zero()), "SAProof_Gen() failed - invalid shared secret key provided"); - - // Declare a return structure - zk_proof proof{}; - proof.z2 = rct::zero(); - - // Calculate a random r value and calculate a commitment R for it - rct::key r = rct::skGen(); - proof.R = rct::scalarmultBase(r); - - // Calculate the challenge hash from the commitment plus the pubkey plus the shared secret - keyV challenge_keys{proof.R, P, key_yF}; - rct::key c = rct::hash_to_scalar(challenge_keys); - - rct::key z_x; - sc_muladd(z_x.bytes, x_change.bytes, c.bytes, r.bytes); - proof.z1 = z_x; - - // Return the proof to the caller - return proof; - } - - bool SAProof_Ver(const zk_proof &proof, const key &P, const key &key_yF) { - - // Sanity checks for inputs - CHECK_AND_ASSERT_THROW_MES(!rct::equalKeys(P, rct::zero()), "SAProof_Ver() failed - invalid public key provided"); - CHECK_AND_ASSERT_THROW_MES(!rct::equalKeys(key_yF, rct::zero()), "SAProof_Ver() failed - invalid shared secret key provided"); - - // Recompute the challenge hash - keyV challenge_keys{proof.R, P, key_yF}; - rct::key c = rct::hash_to_scalar(challenge_keys); - - // Recalculate the expected commitment using the formula: z_x * G = R + c * P - rct::key expected_commitment = rct::addKeys(proof.R, rct::scalarmultKey(P, c)); - - // Verify z_x * G matches the expected commitment - if (!rct::equalKeys(rct::scalarmultBase(proof.z1), expected_commitment)) { - return false; // Verification failed + // Sanity checks for inputs + CHECK_AND_ASSERT_THROW_MES(!rct::equalKeys(P, rct::zero()), "SAProof_Gen() failed - invalid public key provided"); + CHECK_AND_ASSERT_THROW_MES(!rct::equalKeys(x_change, rct::zero()), "SAProof_Gen() failed - invalid x_change key provided"); + CHECK_AND_ASSERT_THROW_MES(!rct::equalKeys(y_change, rct::zero()), "SAProof_Gen() failed - invalid y_change key provided"); + CHECK_AND_ASSERT_THROW_MES(!rct::equalKeys(key_yF, rct::zero()), "SAProof_Gen() failed - invalid shared secret key provided"); + + // Declare a return structure + zk_proof proof{}; + + // Calculate a random r_x and r_y values and calculate a commitment R for it + rct::key r_x = rct::skGen(); + rct::key r_y = rct::skGen(); + rct::addKeys2(proof.R, r_x, r_y, rct::pk2rct(crypto::get_T())); + + // Calculate the challenge hash from the commitment plus the pubkey plus the shared secret + keyV challenge_keys{proof.R, P, key_yF}; + rct::key c = rct::hash_to_scalar(challenge_keys); + + rct::key z_x,z_y; + sc_muladd(z_x.bytes, x_change.bytes, c.bytes, r_x.bytes); + sc_muladd(z_y.bytes, y_change.bytes, c.bytes, r_y.bytes); + proof.z1 = z_x; + proof.z2 = z_y; + + // Return the proof to the caller + return proof; } - // All checks passed - return true; - } + bool SAProof_Ver(const zk_proof &proof, const key &P, const key &key_yF) { + + // Sanity checks for inputs + CHECK_AND_ASSERT_THROW_MES(!rct::equalKeys(P, rct::zero()), "SAProof_Ver() failed - invalid public key provided"); + CHECK_AND_ASSERT_THROW_MES(!rct::equalKeys(key_yF, rct::zero()), "SAProof_Ver() failed - invalid shared secret key provided"); + + // Recompute the challenge hash + keyV challenge_keys{proof.R, P, key_yF}; + rct::key c = rct::hash_to_scalar(challenge_keys); + + // Recalculate the expected commitment using the formula: R + c * P + rct::key expected_result = rct::addKeys(proof.R, rct::scalarmultKey(P, c)); + + // Verify z_x * G + z_y * T matches the expected commitment + rct::key actual_result; + rct::addKeys2(actual_result, proof.z1, proof.z2, rct::pk2rct(crypto::get_T())); + if (!rct::equalKeys(actual_result, expected_result)) { + return false; // Verification failed + } + + // All checks passed + return true; + } //RingCT protocol //genRct: @@ -1458,7 +1470,7 @@ namespace rct { //mask amount and mask rv.ecdhInfo[i].mask = copy(outSk[i].mask); rv.ecdhInfo[i].amount = d2h(amounts[i]); - hwdev.ecdhEncode(rv.ecdhInfo[i], amount_keys[i], rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs || rv.type == RCTTypeSalviumOne); + hwdev.ecdhEncode(rv.ecdhInfo[i], amount_keys[i], is_rct_bulletproof_plus(rv.type)); } //set txn fee @@ -1485,6 +1497,172 @@ namespace rct { return genRct(message, inSk, destinations, amounts, mixRing, amount_keys, index, outSk, rct_config, hwdev); } + //RCT simple + //for post-rct only + rctSig genRctSimpleCarrot( + const key &message, + const carrot_ctkeyV & inSk, + const keyV & destinations, + const cryptonote::transaction_type tx_type, + const std::string& in_asset_type, + const std::vector & destination_asset_types, + const std::vector &inamounts, + const std::vector &outamounts, + xmr_amount txnFee, + const ctkeyM & mixRing, + const keyV &amount_keys, + const std::vector & index, + ctkeyV &outSk, + const RCTConfig &rct_config, + hw::device &hwdev, + const rct::salvium_data_t &salvium_data, + const key &x_change, + const key &y_change, + const size_t change_index, + const key &key_yF + ) + { + CHECK_AND_ASSERT_THROW_MES(rct_config.range_proof_type == RangeProofPaddedBulletproof, "Borromean range proofs no longer supported"); + CHECK_AND_ASSERT_THROW_MES(destination_asset_types.size() == destinations.size(), "Different number of amount_keys/destinations"); + CHECK_AND_ASSERT_THROW_MES(inamounts.size() > 0, "Empty inamounts"); + CHECK_AND_ASSERT_THROW_MES(inamounts.size() == inSk.size(), "Different number of inamounts/inSk"); + CHECK_AND_ASSERT_THROW_MES(outamounts.size() == destinations.size(), "Different number of amounts/destinations"); + CHECK_AND_ASSERT_THROW_MES(amount_keys.size() == destinations.size(), "Different number of amount_keys/destinations"); + CHECK_AND_ASSERT_THROW_MES(index.size() == inSk.size(), "Different number of index/inSk"); + CHECK_AND_ASSERT_THROW_MES(mixRing.size() == inSk.size(), "Different number of mixRing/inSk"); + for (size_t n = 0; n < mixRing.size(); ++n) { + CHECK_AND_ASSERT_THROW_MES(index[n] < mixRing[n].size(), "Bad index into mixRing"); + } + + rctSig rv; + switch (rct_config.bp_version) + { + case 0: + case 6: + rv.type = RCTTypeSalviumOne; + break; + default: + ASSERT_MES_AND_THROW("Unsupported BP version: " << rct_config.bp_version); + } + + rv.message = message; + rv.outPk.resize(destinations.size()); + rv.ecdhInfo.resize(destinations.size()); + + size_t i; + keyV masks(destinations.size()); //sk mask.. + outSk.resize(destinations.size()); + for (i = 0; i < destinations.size(); i++) { + + //add destination to sig + rv.outPk[i].dest = copy(destinations[i]); + } + + rv.p.bulletproofs.clear(); + rv.p.bulletproofs_plus.clear(); + CHECK_AND_ASSERT_THROW_MES(rct_config.range_proof_type == rct::RangeProofPaddedBulletproof, + "Unsupported range proof type: " << rct_config.range_proof_type); + { + rct::keyV C, masks; + if (hwdev.get_mode() == hw::device::TRANSACTION_CREATE_FAKE) + { + // use a fake bulletproof for speed + rv.p.bulletproofs_plus.push_back(make_dummy_bulletproof_plus(outamounts, C, masks)); + } + else + { + const epee::span keys{&amount_keys[0], amount_keys.size()}; + rv.p.bulletproofs_plus.push_back(proveRangeBulletproofPlus(C, masks, outamounts, keys, hwdev)); + +#ifdef DBG + CHECK_AND_ASSERT_THROW_MES(verBulletproofPlus(rv.p.bulletproofs_plus.back()), "verBulletproofPlus failed on newly created proof"); +#endif + } + for (i = 0; i < outamounts.size(); ++i) + { + rv.outPk[i].mask = rct::scalarmult8(C[i]); + outSk[i].mask = masks[i]; + } + } + + key sumout = zero(); + for (i = 0; i < outSk.size(); ++i) + { + sc_add(sumout.bytes, outSk[i].mask.bytes, sumout.bytes); + + //mask amount and mask + rv.ecdhInfo[i].mask = copy(outSk[i].mask); + rv.ecdhInfo[i].amount = d2h(outamounts[i]); + hwdev.ecdhEncode(rv.ecdhInfo[i], amount_keys[i], is_rct_bulletproof_plus(rv.type)); + } + + //set txn fee + rv.txnFee = txnFee; +// TODO: unused ?? +// key txnFeeKey = scalarmultH(d2h(rv.txnFee)); + rv.mixRing = mixRing; + keyV &pseudoOuts = is_rct_bulletproof_plus(rv.type) ? rv.p.pseudoOuts : rv.pseudoOuts; + pseudoOuts.resize(inamounts.size()); + if (is_rct_tclsag(rv.type)) + rv.p.TCLSAGs.resize(inamounts.size()); + else if (is_rct_clsag(rv.type)) + rv.p.CLSAGs.resize(inamounts.size()); + else + rv.p.MGs.resize(inamounts.size()); + key sumpouts = zero(); //sum pseudoOut masks + keyV a(inamounts.size()); + bool audit = (tx_type == cryptonote::transaction_type::AUDIT && rv.type == RCTTypeSalviumZero && salvium_data.salvium_data_type == rct::SalviumZeroAudit); + for (i = 0 ; i < inamounts.size(); i++) { + if (audit) + a[i] = rct::zero(); + else + skGen(a[i]); + sc_add(sumpouts.bytes, a[i].bytes, sumpouts.bytes); + genC(pseudoOuts[i], a[i], inamounts[i]); + } + key difference; + sc_sub(difference.bytes, sumpouts.bytes, sumout.bytes); + genC(rv.p_r, difference, 0); + DP(rv.p_r); + if (rv.type == RCTTypeFullProofs || rv.type == RCTTypeSalviumZero || rv.type == RCTTypeSalviumOne) { + rv.salvium_data.pr_proof = PRProof_Gen(difference); +#ifdef DBG + CHECK_AND_ASSERT_THROW_MES(PRProof_Ver(rv.p_r, rv.salvium_data.pr_proof), "PRProof_Ver() failed on recently created proof"); +#endif + rv.salvium_data.salvium_data_type = salvium_data.salvium_data_type; + if (audit) { + // SRCG: populate the audit proof here + rv.salvium_data.input_verification_data = salvium_data.input_verification_data; + rv.salvium_data.spend_pubkey = salvium_data.spend_pubkey; + rv.salvium_data.enc_view_privkey_str = salvium_data.enc_view_privkey_str; + rv.salvium_data.cz_proof = PRProof_Gen(outSk[0].mask); +#ifdef DBG + CHECK_AND_ASSERT_THROW_MES(PRProof_Ver(rv.outPk[0].mask, rv.salvium_data.cz_proof), "PRProof_Ver() failed on recently created change proof"); +#endif + } + } + + // Check if spend authority proof is needed (only for TRANSFER TXs) + if (tx_type == cryptonote::transaction_type::TRANSFER && rv.type == rct::RCTTypeSalviumOne) { + rv.salvium_data.sa_proof = SAProof_Gen(destinations[change_index], x_change, y_change, key_yF); +#ifdef DBG + CHECK_AND_ASSERT_THROW_MES(SAProof_Ver(rv.salvium_data.sa_proof, destinations[change_index], key_yF), "SAProof_Ver() failed on recently created proof"); +#endif + } + + key full_message = get_pre_mlsag_hash(rv,hwdev); + + for (i = 0 ; i < inamounts.size(); i++) + { + if (hwdev.get_mode() == hw::device::TRANSACTION_CREATE_FAKE) + rv.p.TCLSAGs[i] = make_dummy_tclsag(rv.mixRing[i].size()); + else + rv.p.TCLSAGs[i] = proveRctTCLSAGSimple(full_message, rv.mixRing[i], inSk[i].x, inSk[i].y, inSk[i].mask, a[i], pseudoOuts[i], index[i], hwdev); + } + + return rv; + } + //RCT simple //for post-rct only rctSig genRctSimple( @@ -1534,7 +1712,7 @@ namespace rct { rv.type = RCTTypeFullProofs; break; case 6: - rv.type = RCTTypeSalviumOne; + rv.type = RCTTypeSalviumZero; break; default: ASSERT_MES_AND_THROW("Unsupported BP version: " << rct_config.bp_version); @@ -1653,7 +1831,7 @@ namespace rct { //mask amount and mask rv.ecdhInfo[i].mask = copy(outSk[i].mask); rv.ecdhInfo[i].amount = d2h(outamounts[i]); - hwdev.ecdhEncode(rv.ecdhInfo[i], amount_keys[i], rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs || rv.type == RCTTypeSalviumOne); + hwdev.ecdhEncode(rv.ecdhInfo[i], amount_keys[i], rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs || rv.type == RCTTypeSalviumZero); } //set txn fee @@ -1669,7 +1847,7 @@ namespace rct { rv.p.MGs.resize(inamounts.size()); key sumpouts = zero(); //sum pseudoOut masks keyV a(inamounts.size()); - bool audit = (tx_type == cryptonote::transaction_type::AUDIT && rv.type == RCTTypeSalviumOne && salvium_data.salvium_data_type == rct::SalviumAudit); + bool audit = (tx_type == cryptonote::transaction_type::AUDIT && rv.type == RCTTypeSalviumZero && salvium_data.salvium_data_type == rct::SalviumZeroAudit); for (i = 0 ; i < inamounts.size(); i++) { if (audit) a[i] = rct::zero(); @@ -1682,7 +1860,7 @@ namespace rct { sc_sub(difference.bytes, sumpouts.bytes, sumout.bytes); genC(rv.p_r, difference, 0); DP(rv.p_r); - if (rv.type == RCTTypeFullProofs || rv.type == RCTTypeSalviumOne) { + if (rv.type == RCTTypeFullProofs || rv.type == RCTTypeSalviumZero) { rv.salvium_data.pr_proof = PRProof_Gen(difference); #ifdef DBG CHECK_AND_ASSERT_THROW_MES(PRProof_Ver(rv.p_r, rv.salvium_data.pr_proof), "PRProof_Ver() failed on recently created proof"); @@ -1700,16 +1878,6 @@ namespace rct { } } - /* - // Check if spend authority proof is needed (only for TRANSFER TXs) - if (tx_type == cryptonote::transaction_type::TRANSFER && rv.type == rct::RCTTypeSalviumOne) { - rv.salvium_data.sa_proof = SAProof_Gen(destinations[change_index], x_change, key_yF); -#ifdef DBG - CHECK_AND_ASSERT_THROW_MES(SAProof_Ver(rv.salvium_data.sa_proof, destinations[change_index], key_yF), "SAProof_Ver() failed on recently created proof"); -#endif - } - */ - key full_message = get_pre_mlsag_hash(rv,hwdev); for (i = 0 ; i < inamounts.size(); i++) @@ -1719,9 +1887,6 @@ namespace rct { if (hwdev.get_mode() == hw::device::TRANSACTION_CREATE_FAKE) rv.p.CLSAGs[i] = make_dummy_clsag(rv.mixRing[i].size()); else { - if (rv.type == RCTTypeSalviumOne) - rv.p.CLSAGs[i] = proveRctCLSAGSimpleCarrot(full_message, rv.mixRing[i], inSk[i].x, inSk[i].y, inSk[i].dest, a[i], pseudoOuts[i], index[i], hwdev); - else rv.p.CLSAGs[i] = proveRctCLSAGSimple(full_message, rv.mixRing[i], inSk[i], a[i], pseudoOuts[i], index[i], hwdev); } } @@ -1852,9 +2017,9 @@ namespace rct { std::vector bpp_proofs; size_t max_non_bp_proofs = 0, offset = 0; - CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs || rv.type == RCTTypeSalviumOne, + CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs || rv.type == RCTTypeSalviumZero || rv.type == RCTTypeSalviumOne, false, "verRctSemanticsSimple called on non simple rctSig"); - if (rv.type == RCTTypeFullProofs || rv.type == RCTTypeSalviumOne) + if (rv.type == RCTTypeFullProofs || rv.type == RCTTypeSalviumZero || rv.type == RCTTypeSalviumOne) CHECK_AND_ASSERT_MES(PRProof_Ver(rv.p_r, rv.salvium_data.pr_proof), false, "Invalid p_r commitment to difference"); const bool bulletproof = is_rct_bulletproof(rv.type); @@ -1865,8 +2030,15 @@ namespace rct { CHECK_AND_ASSERT_MES(rv.outPk.size() == n_bulletproof_plus_amounts(rv.p.bulletproofs_plus), false, "Mismatched sizes of outPk and bulletproofs_plus"); else CHECK_AND_ASSERT_MES(rv.outPk.size() == n_bulletproof_amounts(rv.p.bulletproofs), false, "Mismatched sizes of outPk and bulletproofs"); - if (is_rct_clsag(rv.type)) + if (is_rct_tclsag(rv.type)) { + CHECK_AND_ASSERT_MES(rv.p.CLSAGs.empty(), false, "CLSAGs are not empty for TCLSAG"); + CHECK_AND_ASSERT_MES(rv.p.MGs.empty(), false, "MGs are not empty for TCLSAG"); + CHECK_AND_ASSERT_MES(rv.p.pseudoOuts.size() == rv.p.TCLSAGs.size(), false, "Mismatched sizes of rv.p.pseudoOuts and rv.p.TCLSAGs"); + } + else if (is_rct_clsag(rv.type)) + { + CHECK_AND_ASSERT_MES(rv.p.TCLSAGs.empty(), false, "TCLSAGs are not empty for CLSAG"); CHECK_AND_ASSERT_MES(rv.p.MGs.empty(), false, "MGs are not empty for CLSAG"); CHECK_AND_ASSERT_MES(rv.p.pseudoOuts.size() == rv.p.CLSAGs.size(), false, "Mismatched sizes of rv.p.pseudoOuts and rv.p.CLSAGs"); } @@ -1979,7 +2151,7 @@ namespace rct { { PERF_TIMER(verRctNonSemanticsSimple); - CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs || rv.type == RCTTypeSalviumOne, + CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs || rv.type == RCTTypeSalviumZero || rv.type == RCTTypeSalviumOne, false, "verRctNonSemanticsSimple called on non simple rctSig"); const bool bulletproof = is_rct_bulletproof(rv.type); const bool bulletproof_plus = is_rct_bulletproof_plus(rv.type); @@ -2003,7 +2175,9 @@ namespace rct { results.resize(rv.mixRing.size()); for (size_t i = 0 ; i < rv.mixRing.size() ; i++) { tpool.submit(&waiter, [&, i] { - if (is_rct_clsag(rv.type)) + if (is_rct_tclsag(rv.type)) + results[i] = verRctTCLSAGSimple(message, rv.p.TCLSAGs[i], rv.mixRing[i], pseudoOuts[i]); + else if (is_rct_clsag(rv.type)) results[i] = verRctCLSAGSimple(message, rv.p.CLSAGs[i], rv.mixRing[i], pseudoOuts[i]); else results[i] = verRctMGSimple(message, rv.p.MGs[i], rv.mixRing[i], pseudoOuts[i]); @@ -2019,7 +2193,7 @@ namespace rct { } } - bool audit = (rv.type == RCTTypeSalviumOne && rv.salvium_data.salvium_data_type == rct::SalviumAudit); + bool audit = (rv.type == RCTTypeSalviumZero && rv.salvium_data.salvium_data_type == rct::SalviumZeroAudit); if (audit) { // Validate the Salvium audit data CHECK_AND_ASSERT_THROW_MES(PRProof_Ver(rv.outPk[0].mask, rv.salvium_data.cz_proof), "PRProof_Ver() failed on change proof"); @@ -2087,7 +2261,7 @@ namespace rct { //mask amount and mask ecdhTuple ecdh_info = rv.ecdhInfo[i]; - hwdev.ecdhDecode(ecdh_info, sk, rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs || rv.type == RCTTypeSalviumOne); + hwdev.ecdhDecode(ecdh_info, sk, is_rct_bulletproof_plus(rv.type)); mask = ecdh_info.mask; key amount = ecdh_info.amount; key C = rv.outPk[i].mask; @@ -2111,14 +2285,14 @@ namespace rct { } xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key &mask, hw::device &hwdev) { - CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs || rv.type == RCTTypeSalviumOne, + CHECK_AND_ASSERT_MES(is_rct_bulletproof_plus(rv.type), false, "decodeRct called on non simple rctSig"); CHECK_AND_ASSERT_THROW_MES(i < rv.ecdhInfo.size(), "Bad index"); 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]; - hwdev.ecdhDecode(ecdh_info, sk, rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs || rv.type == RCTTypeSalviumOne); + hwdev.ecdhDecode(ecdh_info, sk, is_rct_bulletproof_plus(rv.type)); mask = ecdh_info.mask; key amount = ecdh_info.amount; key C = rv.outPk[i].mask; diff --git a/src/ringct/rctSigs.h b/src/ringct/rctSigs.h index f755ce012..d6833ad25 100644 --- a/src/ringct/rctSigs.h +++ b/src/ringct/rctSigs.h @@ -85,14 +85,14 @@ namespace rct { clsag proveRctCLSAGSimple(const key &, const ctkeyV &, const ctkey &, const key &, const key &, unsigned int, hw::device &); bool verRctCLSAGSimple(const key &, const clsag &, const ctkeyV &, const key &); - clsagCarrot CLSAG_Gen_Carrot(const key &message, const keyV & P, const key & x, const key & y, const keyV & C, const key & z, const keyV & C_nonzero, const key & C_offset, const unsigned int l, hw::device &hwdev); - clsagCarrot proveRctCLSAGSimpleCarrot(const key &message, const ctkeyV &pubs, const key &x, const key &y, const key &mask, const key &a, const key &Cout, unsigned int index, hw::device &hwdev); - bool verRctCLSAGSimpleCarrot(const key &message, const clsagCarrot &sig, const ctkeyV & pubs, const key & C_offset); + tclsag TCLSAG_Gen(const key &message, const keyV & P, const key & x, const key & y, const keyV & C, const key & z, const keyV & C_nonzero, const key & C_offset, const unsigned int l, hw::device &hwdev); + tclsag proveRctTCLSAGSimple(const key &message, const ctkeyV &pubs, const key &x, const key &y, const key &mask, const key &a, const key &Cout, unsigned int index, hw::device &hwdev); + bool verRctTCLSAGSimple(const key &message, const tclsag &sig, const ctkeyV & pubs, const key & C_offset); zk_proof PRProof_Gen(const rct::key &difference); bool PRProof_Ver(const rct::key &C, const zk_proof &proof); - zk_proof SAProof_Gen(const key &P, const key &x_change, const key &key_yF); + zk_proof SAProof_Gen(const key &P, const key &x_change, const key &y_change, const key &key_yF); bool SAProof_Ver(const zk_proof &proof, const key &P, const key &key_yF); //proveRange and verRange @@ -138,6 +138,27 @@ namespace rct { // must know the destination private key to find the correct amount, else will return a random number rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const std::vector & amounts, const ctkeyM &mixRing, const keyV &amount_keys, unsigned int index, ctkeyV &outSk, const RCTConfig &rct_config, hw::device &hwdev); rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const std::vector & amounts, const keyV &amount_keys, const int mixin, const RCTConfig &rct_config, hw::device &hwdev); + rctSig genRctSimpleCarrot( + const key & message, + const carrot_ctkeyV & inSk, + const ctkeyV & inPk, + const keyV & destinations, + const cryptonote::transaction_type tx_type, + const std::string& in_asset_type, + const std::vector & destination_asset_types, + const std::vector & inamounts, + const std::vector & outamounts, + const keyV &amount_keys, + xmr_amount txnFee, + unsigned int mixin, + const RCTConfig &rct_config, + hw::device &hwdev, + const rct::salvium_data_t &salvium_data, + const key &x_change = rct::zero(), + const key &y_change = rct::zero(), + const size_t change_index = 0, + const key &key_yF = rct::zero() + ); rctSig genRctSimple( const key & message, const ctkeyV & inSk, diff --git a/src/ringct/rctTypes.cpp b/src/ringct/rctTypes.cpp index 4d0829145..e235c418a 100644 --- a/src/ringct/rctTypes.cpp +++ b/src/ringct/rctTypes.cpp @@ -198,6 +198,7 @@ namespace rct { case RCTTypeCLSAG: case RCTTypeBulletproofPlus: case RCTTypeFullProofs: + case RCTTypeSalviumZero: case RCTTypeSalviumOne: return true; default: @@ -224,6 +225,7 @@ namespace rct { { case RCTTypeBulletproofPlus: case RCTTypeFullProofs: + case RCTTypeSalviumZero: case RCTTypeSalviumOne: return true; default: @@ -250,6 +252,18 @@ namespace rct { case RCTTypeCLSAG: case RCTTypeBulletproofPlus: case RCTTypeFullProofs: + case RCTTypeSalviumZero: + return true; + case RCTTypeSalviumOne: + default: + return false; + } + } + + bool is_rct_tclsag(int type) + { + switch (type) + { case RCTTypeSalviumOne: return true; default: @@ -265,6 +279,7 @@ namespace rct { case RCTTypeCLSAG: case RCTTypeBulletproofPlus: case RCTTypeFullProofs: + case RCTTypeSalviumZero: case RCTTypeSalviumOne: return true; case RCTTypeNull: diff --git a/src/ringct/rctTypes.h b/src/ringct/rctTypes.h index 3f84d5f37..314dd27b5 100644 --- a/src/ringct/rctTypes.h +++ b/src/ringct/rctTypes.h @@ -223,8 +223,8 @@ namespace rct { END_SERIALIZE() }; - // CLSAG signature - struct clsagCarrot { + // TCLSAG signature + struct tclsag { keyV sx; // x scalars(responses) keyV sy; // y scalars(responses) key c1; @@ -352,7 +352,8 @@ namespace rct { RCTTypeCLSAG = 5, RCTTypeBulletproofPlus = 6, RCTTypeFullProofs = 7, - RCTTypeSalviumOne = 8 + RCTTypeSalviumZero = 8, + RCTTypeSalviumOne = 9 }; enum RangeProofType { RangeProofBorromean, RangeProofBulletproof, RangeProofMultiOutputBulletproof, RangeProofPaddedBulletproof }; struct RCTConfig { @@ -366,7 +367,7 @@ namespace rct { END_SERIALIZE() }; - enum SalviumDataType { SalviumNormal=0, SalviumAudit=1 }; + enum SalviumDataType { SalviumZero=0, SalviumZeroAudit=1, SalviumOne=2 }; struct salvium_input_data_t { crypto::key_derivation aR; xmr_amount amount; @@ -400,7 +401,7 @@ namespace rct { VARINT_FIELD(salvium_data_type) FIELD(pr_proof) FIELD(sa_proof) - if (salvium_data_type == SalviumAudit) + if (salvium_data_type == SalviumZeroAudit) { FIELD(cz_proof) FIELD(input_verification_data) @@ -431,27 +432,12 @@ namespace rct { FIELD(type) if (type == RCTTypeNull) return ar.good(); - if (type != RCTTypeFull && type != RCTTypeSimple && type != RCTTypeBulletproof && type != RCTTypeBulletproof2 && type != RCTTypeCLSAG && type != RCTTypeBulletproofPlus && type != RCTTypeFullProofs && type != RCTTypeSalviumOne) + if (type != RCTTypeBulletproofPlus && type != RCTTypeFullProofs && type != RCTTypeSalviumZero && type != RCTTypeSalviumOne) 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) // moved to prunable with bulletproofs - { - ar.tag("pseudoOuts"); - ar.begin_array(); - PREPARE_CUSTOM_VECTOR_SERIALIZATION(inputs, pseudoOuts); - if (pseudoOuts.size() != inputs) - return false; - for (size_t i = 0; i < inputs; ++i) - { - FIELDS(pseudoOuts[i]) - if (inputs - i > 1) - ar.delimit_array(); - } - ar.end_array(); - } ar.tag("ecdhInfo"); ar.begin_array(); @@ -460,7 +446,7 @@ namespace rct { return false; for (size_t i = 0; i < outputs; ++i) { - if (type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus || type == RCTTypeFullProofs || type == RCTTypeSalviumOne) + if (type == RCTTypeBulletproofPlus || type == RCTTypeFullProofs || type == RCTTypeSalviumZero) { // Since RCTTypeBulletproof2 enote types, we don't serialize the blinding factor, and only serialize the // first 8 bytes of ecdhInfo[i].amount @@ -497,7 +483,7 @@ namespace rct { } ar.end_array(); FIELD(p_r) - if (type == RCTTypeSalviumOne) + if (type == RCTTypeSalviumZero) { FIELD(salvium_data) } @@ -518,7 +504,7 @@ namespace rct { FIELD(outPk) VARINT_FIELD(txnFee) FIELD(p_r) - if (type == RCTTypeSalviumOne) + if (type == RCTTypeSalviumZero) { FIELD(salvium_data) } @@ -535,6 +521,7 @@ namespace rct { std::vector bulletproofs_plus; std::vector MGs; // simple rct has N, full has 1 std::vector CLSAGs; + std::vector TCLSAGs; keyV pseudoOuts; //C - for simple rct // when changing this function, update cryptonote::get_pruned_transaction_weight @@ -549,9 +536,8 @@ namespace rct { return false; if (type == RCTTypeNull) return ar.good(); - if (type != RCTTypeFull && type != RCTTypeSimple && type != RCTTypeBulletproof && type != RCTTypeBulletproof2 && type != RCTTypeCLSAG && type != RCTTypeBulletproofPlus && type != RCTTypeFullProofs && type != RCTTypeSalviumOne) + if (type != RCTTypeBulletproofPlus && type != RCTTypeFullProofs && type != RCTTypeSalviumZero && type != RCTTypeSalviumOne) return false; - if (type == RCTTypeBulletproofPlus || type == RCTTypeFullProofs || type == RCTTypeSalviumOne) { uint32_t nbp = bulletproofs_plus.size(); VARINT_FIELD(nbp) @@ -570,45 +556,61 @@ namespace rct { return false; ar.end_array(); } - else if (type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeCLSAG) + + if (type == RCTTypeSalviumOne) { - uint32_t nbp = bulletproofs.size(); - if (type == RCTTypeBulletproof2 || type == RCTTypeCLSAG) - VARINT_FIELD(nbp) - else - FIELD(nbp) - ar.tag("bp"); + ar.tag("TCLSAGs"); ar.begin_array(); - if (nbp > outputs) + PREPARE_CUSTOM_VECTOR_SERIALIZATION(inputs, TCLSAGs); + if (TCLSAGs.size() != inputs) return false; - PREPARE_CUSTOM_VECTOR_SERIALIZATION(nbp, bulletproofs); - for (size_t i = 0; i < nbp; ++i) + for (size_t i = 0; i < inputs; ++i) { - FIELDS(bulletproofs[i]) - if (nbp - i > 1) - ar.delimit_array(); + // we save the TCLSAGs contents directly, because we want it to save its + // arrays without the size prefixes, and the load can't know what size + // to expect if it's not in the data + ar.begin_object(); + ar.tag("sx"); + ar.begin_array(); + PREPARE_CUSTOM_VECTOR_SERIALIZATION(mixin + 1, TCLSAGs[i].sx); + if (TCLSAGs[i].sx.size() != mixin + 1) + return false; + for (size_t j = 0; j <= mixin; ++j) + { + FIELDS(TCLSAGs[i].sx[j]) + if (mixin + 1 - j > 1) + ar.delimit_array(); + } + ar.end_array(); + + ar.tag("sy"); + ar.begin_array(); + PREPARE_CUSTOM_VECTOR_SERIALIZATION(mixin + 1, TCLSAGs[i].sy); + if (TCLSAGs[i].sy.size() != mixin + 1) + return false; + for (size_t j = 0; j <= mixin; ++j) + { + FIELDS(TCLSAGs[i].sy[j]) + if (mixin + 1 - j > 1) + ar.delimit_array(); + } + ar.end_array(); + + ar.tag("c1"); + FIELDS(CLSAGs[i].c1) + + // CLSAGs[i].I not saved, it can be reconstructed + ar.tag("D"); + FIELDS(CLSAGs[i].D) + ar.end_object(); + + if (inputs - i > 1) + ar.delimit_array(); } - if (n_bulletproof_max_amounts(bulletproofs) < outputs) - return false; + 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(); - } - - if (type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus || type == RCTTypeFullProofs || type == RCTTypeSalviumOne) { ar.tag("CLSAGs"); ar.begin_array(); @@ -648,58 +650,6 @@ namespace rct { ar.end_array(); } - else - { - 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 || type == RCTTypeBulletproof || type == RCTTypeBulletproof2) ? inputs : 1; - PREPARE_CUSTOM_VECTOR_SERIALIZATION(mg_elements, MGs); - if (MGs.size() != mg_elements) - return false; - for (size_t i = 0; i < mg_elements; ++i) - { - // we save the MGs contents directly, because we want it to save its - // arrays and matrices without the size prefixes, and the load can't - // know what size to expect if it's not in the data - ar.begin_object(); - ar.tag("ss"); - ar.begin_array(); - PREPARE_CUSTOM_VECTOR_SERIALIZATION(mixin + 1, MGs[i].ss); - if (MGs[i].ss.size() != mixin + 1) - return false; - for (size_t j = 0; j < mixin + 1; ++j) - { - ar.begin_array(); - size_t mg_ss2_elements = ((type == RCTTypeSimple || type == RCTTypeBulletproof || type == RCTTypeBulletproof2) ? 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; - for (size_t k = 0; k < mg_ss2_elements; ++k) - { - FIELDS(MGs[i].ss[j][k]) - if (mg_ss2_elements - k > 1) - ar.delimit_array(); - } - ar.end_array(); - - if (mixin + 1 - j > 1) - ar.delimit_array(); - } - ar.end_array(); - - ar.tag("cc"); - FIELDS(MGs[i].cc) - // MGs[i].II not saved, it can be reconstructed - ar.end_object(); - - if (mg_elements - i > 1) - ar.delimit_array(); - } - ar.end_array(); - } - if (type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus || type == RCTTypeFullProofs || type == RCTTypeSalviumOne) { ar.tag("pseudoOuts"); ar.begin_array(); @@ -731,12 +681,12 @@ namespace rct { keyV& get_pseudo_outs() { - return type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus || type == RCTTypeFullProofs || type == RCTTypeSalviumOne ? p.pseudoOuts : pseudoOuts; + return type == RCTTypeBulletproofPlus || type == RCTTypeFullProofs || type == RCTTypeSalviumZero || type == RCTTypeSalviumOne ? p.pseudoOuts : pseudoOuts; } keyV const& get_pseudo_outs() const { - return type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus || type == RCTTypeFullProofs || type == RCTTypeSalviumOne ? p.pseudoOuts : pseudoOuts; + return type == RCTTypeBulletproofPlus || type == RCTTypeFullProofs || type == RCTTypeSalviumZero || type == RCTTypeSalviumOne ? p.pseudoOuts : pseudoOuts; } BEGIN_SERIALIZE_OBJECT() @@ -851,6 +801,7 @@ namespace rct { bool is_rct_bulletproof_plus(int type); bool is_rct_borromean(int type); bool is_rct_clsag(int type); + bool is_rct_tclsag(int type); bool is_rct_short_amount(int type); static inline const rct::key &pk2rct(const crypto::public_key &pk) { return (const rct::key&)pk; } @@ -908,6 +859,7 @@ VARIANT_TAG(debug_archive, rct::Bulletproof, "rct::bulletproof"); VARIANT_TAG(debug_archive, rct::multisig_kLRki, "rct::multisig_kLRki"); VARIANT_TAG(debug_archive, rct::multisig_out, "rct::multisig_out"); VARIANT_TAG(debug_archive, rct::clsag, "rct::clsag"); +VARIANT_TAG(debug_archive, rct::tclsag, "rct::tclsag"); VARIANT_TAG(debug_archive, rct::BulletproofPlus, "rct::bulletproof_plus"); VARIANT_TAG(debug_archive, rct::zk_proof, "rct::zk_proof"); VARIANT_TAG(debug_archive, rct::salvium_input_data_t, "rct::salvium_input_data"); @@ -933,6 +885,7 @@ VARIANT_TAG(binary_archive, rct::BulletproofPlus, 0xa0); VARIANT_TAG(binary_archive, rct::zk_proof, 0xa1); VARIANT_TAG(binary_archive, rct::salvium_input_data_t, 0xa2); VARIANT_TAG(binary_archive, rct::salvium_data_t, 0xa3); +VARIANT_TAG(binary_archive, rct::tclsag, 0xa4); VARIANT_TAG(json_archive, rct::key, "rct_key"); VARIANT_TAG(json_archive, rct::key64, "rct_key64"); @@ -950,6 +903,7 @@ VARIANT_TAG(json_archive, rct::Bulletproof, "rct_bulletproof"); VARIANT_TAG(json_archive, rct::multisig_kLRki, "rct_multisig_kLR"); VARIANT_TAG(json_archive, rct::multisig_out, "rct_multisig_out"); VARIANT_TAG(json_archive, rct::clsag, "rct_clsag"); +VARIANT_TAG(json_archive, rct::tclsag, "rct_tclsag"); VARIANT_TAG(json_archive, rct::BulletproofPlus, "rct_bulletproof_plus"); VARIANT_TAG(json_archive, rct::zk_proof, "rct_zk_proof"); VARIANT_TAG(json_archive, rct::salvium_input_data_t, "rct_salvium_input_data"); diff --git a/src/serialization/json_object.cpp b/src/serialization/json_object.cpp index db7e6cd87..286f7eddd 100644 --- a/src/serialization/json_object.cpp +++ b/src/serialization/json_object.cpp @@ -1220,6 +1220,7 @@ void toJsonValue(rapidjson::Writer& dest, const rct::rctSig& INSERT_INTO_JSON_OBJECT(dest, bulletproofs_plus, sig.p.bulletproofs_plus); INSERT_INTO_JSON_OBJECT(dest, mlsags, sig.p.MGs); INSERT_INTO_JSON_OBJECT(dest, clsags, sig.p.CLSAGs); + INSERT_INTO_JSON_OBJECT(dest, tclsags, sig.p.TCLSAGs); INSERT_INTO_JSON_OBJECT(dest, pseudo_outs, sig.get_pseudo_outs()); dest.EndObject(); @@ -1263,6 +1264,7 @@ void fromJsonValue(const rapidjson::Value& val, rct::rctSig& sig) GET_FROM_JSON_OBJECT(prunable->value, sig.p.bulletproofs_plus, bulletproofs_plus); GET_FROM_JSON_OBJECT(prunable->value, sig.p.MGs, mlsags); GET_FROM_JSON_OBJECT(prunable->value, sig.p.CLSAGs, clsags); + GET_FROM_JSON_OBJECT(prunable->value, sig.p.TCLSAGs, tclsags); GET_FROM_JSON_OBJECT(prunable->value, pseudo_outs, pseudo_outs); sig.get_pseudo_outs() = std::move(pseudo_outs); @@ -1274,6 +1276,7 @@ void fromJsonValue(const rapidjson::Value& val, rct::rctSig& sig) sig.p.bulletproofs_plus.clear(); sig.p.MGs.clear(); sig.p.CLSAGs.clear(); + sig.p.TCLSAGs.clear(); sig.get_pseudo_outs().clear(); } } @@ -1505,6 +1508,31 @@ void fromJsonValue(const rapidjson::Value& val, rct::clsag& sig) GET_FROM_JSON_OBJECT(val, sig.D, D); } +void toJsonValue(rapidjson::Writer& dest, const rct::tclsag& sig) +{ + dest.StartObject(); + + INSERT_INTO_JSON_OBJECT(dest, sx, sig.sx); + INSERT_INTO_JSON_OBJECT(dest, sy, sig.sy); + INSERT_INTO_JSON_OBJECT(dest, c1, sig.c1); + INSERT_INTO_JSON_OBJECT(dest, D, sig.D); + + dest.EndObject(); +} + +void fromJsonValue(const rapidjson::Value& val, rct::tclsag& sig) +{ + if (!val.IsObject()) + { + throw WRONG_TYPE("key64 (rct::key[64])"); + } + + GET_FROM_JSON_OBJECT(val, sig.sx, sx); + GET_FROM_JSON_OBJECT(val, sig.sy, sy); + GET_FROM_JSON_OBJECT(val, sig.c1, c1); + GET_FROM_JSON_OBJECT(val, sig.D, D); +} + void toJsonValue(rapidjson::Writer& dest, const rct::zk_proof& proof) { dest.StartObject(); @@ -1567,7 +1595,7 @@ void toJsonValue(rapidjson::Writer& dest, const rct::salvium_ INSERT_INTO_JSON_OBJECT(dest, salvium_data_type, salvium_data.salvium_data_type); INSERT_INTO_JSON_OBJECT(dest, pr_proof, salvium_data.pr_proof); INSERT_INTO_JSON_OBJECT(dest, sa_proof, salvium_data.sa_proof); - if (salvium_data.salvium_data_type == rct::SalviumAudit) { + if (salvium_data.salvium_data_type == rct::SalviumZeroAudit) { INSERT_INTO_JSON_OBJECT(dest, cz_proof, salvium_data.cz_proof); INSERT_INTO_JSON_OBJECT(dest, input_verification_data, salvium_data.input_verification_data); INSERT_INTO_JSON_OBJECT(dest, spend_pubkey, salvium_data.spend_pubkey); @@ -1587,7 +1615,7 @@ void fromJsonValue(const rapidjson::Value& val, rct::salvium_data_t& salvium_dat GET_FROM_JSON_OBJECT(val, salvium_data.salvium_data_type, salvium_data_type); GET_FROM_JSON_OBJECT(val, salvium_data.pr_proof, pr_proof); GET_FROM_JSON_OBJECT(val, salvium_data.sa_proof, sa_proof); - if (salvium_data.salvium_data_type == rct::SalviumAudit) { + if (salvium_data.salvium_data_type == rct::SalviumZeroAudit) { GET_FROM_JSON_OBJECT(val, salvium_data.cz_proof, cz_proof); GET_FROM_JSON_OBJECT(val, salvium_data.input_verification_data, input_verification_data); GET_FROM_JSON_OBJECT(val, salvium_data.spend_pubkey, spend_pubkey); diff --git a/src/serialization/json_object.h b/src/serialization/json_object.h index 73d46b4ea..df2323289 100644 --- a/src/serialization/json_object.h +++ b/src/serialization/json_object.h @@ -310,6 +310,9 @@ void fromJsonValue(const rapidjson::Value& val, rct::mgSig& sig); void toJsonValue(rapidjson::Writer& dest, const rct::clsag& sig); void fromJsonValue(const rapidjson::Value& val, rct::clsag& sig); +void toJsonValue(rapidjson::Writer& dest, const rct::tclsag& sig); +void fromJsonValue(const rapidjson::Value& val, rct::tclsag& sig); + void toJsonValue(rapidjson::Writer& dest, const rct::zk_proof& p); void fromJsonValue(const rapidjson::Value& val, rct::zk_proof& p); diff --git a/src/wallet/tx_builder.cpp b/src/wallet/tx_builder.cpp index 8bbfd97b6..b543f1680 100644 --- a/src/wallet/tx_builder.cpp +++ b/src/wallet/tx_builder.cpp @@ -969,7 +969,7 @@ cryptonote::transaction finalize_all_proofs_from_transfer_details( crypto::hash tx_prefix_hash; get_transaction_prefix_hash(tx, tx_prefix_hash, hwdev); rct::ctkeyV outSk; - tx.rct_signatures = rct::genRctSimple( + tx.rct_signatures = rct::genRctSimpleCarrot( rct::hash2rct(tx_prefix_hash), inSk, destinations, @@ -986,6 +986,7 @@ cryptonote::transaction finalize_all_proofs_from_transfer_details( hwdev, salvium_data, rct::sk2rct(x_change), + rct::sk2rct(y_change), change_index, key_yF ); diff --git a/tests/unit_tests/ringct.cpp b/tests/unit_tests/ringct.cpp index 96b8524dc..2f2e00452 100644 --- a/tests/unit_tests/ringct.cpp +++ b/tests/unit_tests/ringct.cpp @@ -300,7 +300,7 @@ TEST(ringct, CLSAG) ASSERT_TRUE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout)); } -TEST(ringct, CLSAG_CARROT) +TEST(ringct, TCLSAG) { const size_t N = 16; const size_t idx = 5; @@ -308,7 +308,7 @@ TEST(ringct, CLSAG_CARROT) key x, y, t, t2, u; const key message = identity(); ctkey backup; - clsagCarrot clsag; + tclsag tclsag; key backup_key; for (size_t i = 0; i < N; ++i) @@ -338,14 +338,14 @@ TEST(ringct, CLSAG_CARROT) addKeys2(Cout,t2,u,H); // bad message - clsag = rct::proveRctCLSAGSimpleCarrot(zero(), pubs, x, y, t, t2, Cout, idx, hw::get_device("default")); - ASSERT_FALSE(rct::verRctCLSAGSimpleCarrot(message,clsag,pubs,Cout)); + tclsag = rct::proveRctTCLSAGSimple(zero(), pubs, x, y, t, t2, Cout, idx, hw::get_device("default")); + ASSERT_FALSE(rct::verRctTCLSAGSimple(message,tclsag,pubs,Cout)); // bad index at creation try { - clsag = rct::proveRctCLSAGSimpleCarrot(message, pubs, x, y, t, t2, Cout, (idx + 1) % N, hw::get_device("default")); - ASSERT_FALSE(rct::verRctCLSAGSimpleCarrot(message,clsag,pubs,Cout)); + tclsag = rct::proveRctTCLSAGSimple(message, pubs, x, y, t, t2, Cout, (idx + 1) % N, hw::get_device("default")); + ASSERT_FALSE(rct::verRctTCLSAGSimple(message,tclsag,pubs,Cout)); } catch (...) { /* either exception, or failure to verify above */ } @@ -354,8 +354,8 @@ TEST(ringct, CLSAG_CARROT) pubs[idx].mask = scalarmultBase(skGen()); try { - clsag = rct::proveRctCLSAGSimpleCarrot(message, pubs, x, y, t, t2, Cout, idx, hw::get_device("default")); - ASSERT_FALSE(rct::verRctCLSAGSimpleCarrot(message,clsag,pubs,Cout)); + tclsag = rct::proveRctTCLSAGSimple(message, pubs, x, y, t, t2, Cout, idx, hw::get_device("default")); + ASSERT_FALSE(rct::verRctTCLSAGSimple(message,tclsag,pubs,Cout)); } catch (...) { /* either exception, or failure to verify above */ } pubs[idx] = backup; @@ -365,8 +365,8 @@ TEST(ringct, CLSAG_CARROT) skGen(x); try { - clsag = rct::proveRctCLSAGSimpleCarrot(message, pubs, x, y, t, t2, Cout, idx, hw::get_device("default")); - ASSERT_FALSE(rct::verRctCLSAGSimpleCarrot(message,clsag,pubs,Cout)); + tclsag = rct::proveRctTCLSAGSimple(message, pubs, x, y, t, t2, Cout, idx, hw::get_device("default")); + ASSERT_FALSE(rct::verRctTCLSAGSimple(message,tclsag,pubs,Cout)); } catch (...) { /* either exception, or failure to verify above */ } x = backup_key; @@ -376,8 +376,8 @@ TEST(ringct, CLSAG_CARROT) skGen(y); try { - clsag = rct::proveRctCLSAGSimpleCarrot(message, pubs, x, y, t, t2, Cout, idx, hw::get_device("default")); - ASSERT_FALSE(rct::verRctCLSAGSimpleCarrot(message,clsag,pubs,Cout)); + tclsag = rct::proveRctTCLSAGSimple(message, pubs, x, y, t, t2, Cout, idx, hw::get_device("default")); + ASSERT_FALSE(rct::verRctTCLSAGSimple(message,tclsag,pubs,Cout)); } catch (...) { /* either exception, or failure to verify above */ } y = backup_key; @@ -387,101 +387,101 @@ TEST(ringct, CLSAG_CARROT) pubs[idx].dest = scalarmultBase(skGen()); try { - clsag = rct::proveRctCLSAGSimpleCarrot(message, pubs, x, y, t, t2, Cout, idx, hw::get_device("default")); - ASSERT_FALSE(rct::verRctCLSAGSimpleCarrot(message,clsag,pubs,Cout)); + tclsag = rct::proveRctTCLSAGSimple(message, pubs, x, y, t, t2, Cout, idx, hw::get_device("default")); + ASSERT_FALSE(rct::verRctTCLSAGSimple(message,tclsag,pubs,Cout)); } catch (...) { /* either exception, or failure to verify above */ } pubs[idx] = backup; // generate the signature - clsag = rct::proveRctCLSAGSimpleCarrot(message, pubs, x, y, t, t2, Cout, idx, hw::get_device("default")); - ASSERT_TRUE(rct::verRctCLSAGSimpleCarrot(message,clsag,pubs,Cout)); + tclsag = rct::proveRctTCLSAGSimple(message, pubs, x, y, t, t2, Cout, idx, hw::get_device("default")); + ASSERT_TRUE(rct::verRctTCLSAGSimple(message,tclsag,pubs,Cout)); // empty sx - auto sbackup = clsag.sx; - clsag.sx.clear(); - ASSERT_FALSE(rct::verRctCLSAGSimpleCarrot(message,clsag,pubs,Cout)); - clsag.sx = sbackup; + auto sbackup = tclsag.sx; + tclsag.sx.clear(); + ASSERT_FALSE(rct::verRctTCLSAGSimple(message,tclsag,pubs,Cout)); + tclsag.sx = sbackup; // too few sx elements - backup_key = clsag.sx.back(); - clsag.sx.pop_back(); - ASSERT_FALSE(rct::verRctCLSAGSimpleCarrot(message,clsag,pubs,Cout)); - clsag.sx.push_back(backup_key); + backup_key = tclsag.sx.back(); + tclsag.sx.pop_back(); + ASSERT_FALSE(rct::verRctTCLSAGSimple(message,tclsag,pubs,Cout)); + tclsag.sx.push_back(backup_key); // too many sx elements - clsag.sx.push_back(skGen()); - ASSERT_FALSE(rct::verRctCLSAGSimpleCarrot(message,clsag,pubs,Cout)); - clsag.sx.pop_back(); + tclsag.sx.push_back(skGen()); + ASSERT_FALSE(rct::verRctTCLSAGSimple(message,tclsag,pubs,Cout)); + tclsag.sx.pop_back(); - // bad sx in clsag at verification - for (auto &sx: clsag.sx) + // bad sx in tclsag at verification + for (auto &sx: tclsag.sx) { backup_key = sx; sx = skGen(); - ASSERT_FALSE(rct::verRctCLSAGSimpleCarrot(message,clsag,pubs,Cout)); + ASSERT_FALSE(rct::verRctTCLSAGSimple(message,tclsag,pubs,Cout)); sx = backup_key; } // empty sy - sbackup = clsag.sy; - clsag.sy.clear(); - ASSERT_FALSE(rct::verRctCLSAGSimpleCarrot(message,clsag,pubs,Cout)); - clsag.sy = sbackup; + sbackup = tclsag.sy; + tclsag.sy.clear(); + ASSERT_FALSE(rct::verRctTCLSAGSimple(message,tclsag,pubs,Cout)); + tclsag.sy = sbackup; // too few sy elements - backup_key = clsag.sy.back(); - clsag.sy.pop_back(); - ASSERT_FALSE(rct::verRctCLSAGSimpleCarrot(message,clsag,pubs,Cout)); - clsag.sy.push_back(backup_key); + backup_key = tclsag.sy.back(); + tclsag.sy.pop_back(); + ASSERT_FALSE(rct::verRctTCLSAGSimple(message,tclsag,pubs,Cout)); + tclsag.sy.push_back(backup_key); // too many sy elements - clsag.sy.push_back(skGen()); - ASSERT_FALSE(rct::verRctCLSAGSimpleCarrot(message,clsag,pubs,Cout)); - clsag.sy.pop_back(); + tclsag.sy.push_back(skGen()); + ASSERT_FALSE(rct::verRctTCLSAGSimple(message,tclsag,pubs,Cout)); + tclsag.sy.pop_back(); - // bad sy in clsag at verification - for (auto &sy: clsag.sy) + // bad sy in tclsag at verification + for (auto &sy: tclsag.sy) { backup_key = sy; sy = skGen(); - ASSERT_FALSE(rct::verRctCLSAGSimpleCarrot(message,clsag,pubs,Cout)); + ASSERT_FALSE(rct::verRctTCLSAGSimple(message,tclsag,pubs,Cout)); sy = backup_key; } - // bad c1 in clsag at verification - backup_key = clsag.c1; - clsag.c1 = skGen(); - ASSERT_FALSE(rct::verRctCLSAGSimpleCarrot(message,clsag,pubs,Cout)); - clsag.c1 = backup_key; + // bad c1 in tclsag at verification + backup_key = tclsag.c1; + tclsag.c1 = skGen(); + ASSERT_FALSE(rct::verRctTCLSAGSimple(message,tclsag,pubs,Cout)); + tclsag.c1 = backup_key; - // bad I in clsag at verification - backup_key = clsag.I; - clsag.I = scalarmultBase(skGen()); - ASSERT_FALSE(rct::verRctCLSAGSimpleCarrot(message,clsag,pubs,Cout)); - clsag.I = backup_key; + // bad I in tclsag at verification + backup_key = tclsag.I; + tclsag.I = scalarmultBase(skGen()); + ASSERT_FALSE(rct::verRctTCLSAGSimple(message,tclsag,pubs,Cout)); + tclsag.I = backup_key; - // bad D in clsag at verification - backup_key = clsag.D; - clsag.D = scalarmultBase(skGen()); - ASSERT_FALSE(rct::verRctCLSAGSimpleCarrot(message,clsag,pubs,Cout)); - clsag.D = backup_key; + // bad D in tclsag at verification + backup_key = tclsag.D; + tclsag.D = scalarmultBase(skGen()); + ASSERT_FALSE(rct::verRctTCLSAGSimple(message,tclsag,pubs,Cout)); + tclsag.D = backup_key; - // D not in main subgroup in clsag at verification - backup_key = clsag.D; + // D not in main subgroup in tclsag at verification + backup_key = tclsag.D; rct::key foo; ASSERT_TRUE(epee::string_tools::hex_to_pod("c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", foo)); - clsag.D = rct::addKeys(clsag.D, foo); - ASSERT_FALSE(rct::verRctCLSAGSimpleCarrot(message,clsag,pubs,Cout)); - clsag.D = backup_key; + tclsag.D = rct::addKeys(tclsag.D, foo); + ASSERT_FALSE(rct::verRctTCLSAGSimple(message,tclsag,pubs,Cout)); + tclsag.D = backup_key; - // swapped I and D in clsag at verification - std::swap(clsag.I, clsag.D); - ASSERT_FALSE(rct::verRctCLSAGSimpleCarrot(message,clsag,pubs,Cout)); - std::swap(clsag.I, clsag.D); + // swapped I and D in tclsag at verification + std::swap(tclsag.I, tclsag.D); + ASSERT_FALSE(rct::verRctTCLSAGSimple(message,tclsag,pubs,Cout)); + std::swap(tclsag.I, tclsag.D); // check it's still good, in case we failed to restore - ASSERT_TRUE(rct::verRctCLSAGSimpleCarrot(message,clsag,pubs,Cout)); + ASSERT_TRUE(rct::verRctTCLSAGSimple(message,tclsag,pubs,Cout)); } TEST(ringct, range_proofs)