partial working serialisation

This commit is contained in:
Some Random Crypto Guy
2024-12-15 22:28:14 +00:00
parent 1334bac45a
commit 2ce22c2508
18 changed files with 303 additions and 208 deletions
@@ -350,6 +350,14 @@ namespace boost
a & x.D;
}
template <class Archive>
inline void serialize(Archive &a, rct::zk_proof &x, const boost::serialization::version_type ver)
{
a & x.R;
a & x.z1;
a & x.z2;
}
template <class Archive>
inline void serialize(Archive &a, rct::ecdhTuple &x, const boost::serialization::version_type ver)
{
@@ -403,7 +411,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)
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)
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
@@ -413,6 +421,10 @@ namespace boost
serializeOutPk(a, x.outPk, ver);
a & x.txnFee;
a & x.p_r;
if (x.type == rct::RCTTypeFullProofs) {
a & x.pr_proof;
//a & x.sa_proofs;
}
}
template <class Archive>
@@ -438,7 +450,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)
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)
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,6 +460,10 @@ namespace boost
serializeOutPk(a, x.outPk, ver);
a & x.txnFee;
a & x.p_r;
if (x.type == rct::RCTTypeFullProofs) {
a & x.pr_proof;
//a & x.sa_proofs;
}
//--------------
a & x.p.rangeSigs;
if (x.p.rangeSigs.empty())
@@ -459,7 +475,7 @@ namespace boost
a & x.p.MGs;
if (ver >= 1u)
a & x.p.CLSAGs;
if (x.type == rct::RCTTypeBulletproof || x.type == rct::RCTTypeBulletproof2 || x.type == rct::RCTTypeCLSAG || x.type == rct::RCTTypeBulletproofPlus)
if (x.type == rct::RCTTypeBulletproof || x.type == rct::RCTTypeBulletproof2 || x.type == rct::RCTTypeCLSAG || x.type == rct::RCTTypeBulletproofPlus || x.type == rct::RCTTypeFullProofs)
a & x.p.pseudoOuts;
}
@@ -501,5 +517,5 @@ namespace boost
}
BOOST_CLASS_VERSION(rct::rctSigPrunable, 2)
BOOST_CLASS_VERSION(rct::rctSig, 2)
BOOST_CLASS_VERSION(rct::rctSig, 3)
BOOST_CLASS_VERSION(rct::multisig_out, 1)
@@ -110,7 +110,7 @@ namespace cryptonote
uint64_t get_transaction_weight_clawback(const transaction &tx, size_t n_padded_outputs)
{
const rct::rctSig &rv = tx.rct_signatures;
const bool plus = rv.type == rct::RCTTypeBulletproofPlus;
const bool plus = (rv.type == rct::RCTTypeBulletproofPlus || rv.type == rct::RCTTypeFullProofs);
const uint64_t bp_base = (32 * ((plus ? 6 : 9) + 7 * 2)) / 2; // notional size of a 2 output proof, normalized to 1 proof (ie, divided by 2)
const size_t n_outputs = tx.vout.size();
if (n_padded_outputs <= 2)
@@ -517,7 +517,7 @@ namespace cryptonote
{
CHECK_AND_ASSERT_MES(tx.pruned, std::numeric_limits<uint64_t>::max(), "get_pruned_transaction_weight does not support non pruned txes");
CHECK_AND_ASSERT_MES(tx.version >= 2, std::numeric_limits<uint64_t>::max(), "get_pruned_transaction_weight does not support v1 txes");
CHECK_AND_ASSERT_MES(tx.rct_signatures.type == rct::RCTTypeBulletproof2 || tx.rct_signatures.type == rct::RCTTypeCLSAG || tx.rct_signatures.type == rct::RCTTypeBulletproofPlus,
CHECK_AND_ASSERT_MES(tx.rct_signatures.type == rct::RCTTypeBulletproof2 || tx.rct_signatures.type == rct::RCTTypeCLSAG || tx.rct_signatures.type == rct::RCTTypeBulletproofPlus || tx.rct_signatures.type == rct::RCTTypeFullProofs,
std::numeric_limits<uint64_t>::max(), "Unsupported rct_signatures type in get_pruned_transaction_weight");
CHECK_AND_ASSERT_MES(!tx.vin.empty(), std::numeric_limits<uint64_t>::max(), "empty vin");
CHECK_AND_ASSERT_MES(tx.vin[0].type() == typeid(cryptonote::txin_to_key), std::numeric_limits<uint64_t>::max(), "empty vin");
+5 -3
View File
@@ -1497,6 +1497,7 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl
switch (version) {
case HF_VERSION_BULLETPROOF_PLUS:
case HF_VERSION_ENABLE_N_OUTS:
case HF_VERSION_FULL_PROOFS:
if (b.miner_tx.amount_burnt > 0) {
CHECK_AND_ASSERT_MES(money_in_use + b.miner_tx.amount_burnt > money_in_use, false, "miner transaction is overflowed by amount_burnt");
money_in_use += b.miner_tx.amount_burnt;
@@ -3709,7 +3710,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 || rv.type == rct::RCTTypeCLSAG || rv.type == rct::RCTTypeBulletproofPlus)
else if (rv.type == rct::RCTTypeSimple || rv.type == rct::RCTTypeBulletproof || rv.type == rct::RCTTypeBulletproof2 || rv.type == rct::RCTTypeCLSAG || rv.type == rct::RCTTypeBulletproofPlus || rv.type == rct::RCTTypeFullProofs)
{
CHECK_AND_ASSERT_MES(!pubkeys.empty() && !pubkeys[0].empty(), false, "empty pubkeys");
rv.mixRing.resize(pubkeys.size());
@@ -3750,7 +3751,7 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr
}
}
}
else if (rv.type == rct::RCTTypeCLSAG || rv.type == rct::RCTTypeBulletproofPlus)
else if (rv.type == rct::RCTTypeCLSAG || rv.type == rct::RCTTypeBulletproofPlus || rv.type == rct::RCTTypeFullProofs)
{
if (!tx.pruned)
{
@@ -3997,7 +3998,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
false, "Transaction spends at least one output which is too young");
// Warn that new RCT types are present, and thus the cache is not being used effectively
static constexpr const std::uint8_t RCT_CACHE_TYPE = rct::RCTTypeBulletproofPlus;
static constexpr const std::uint8_t RCT_CACHE_TYPE = rct::RCTTypeFullProofs;
if (tx.rct_signatures.type > RCT_CACHE_TYPE)
{
MWARNING("RCT cache is not caching new verification results. Please update RCT_CACHE_TYPE!");
@@ -4040,6 +4041,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
case rct::RCTTypeBulletproof2:
case rct::RCTTypeCLSAG:
case rct::RCTTypeBulletproofPlus:
case rct::RCTTypeFullProofs:
{
if (!ver_rct_non_semantics_simple_cached(tx, pubkeys, m_rct_ver_cache, RCT_CACHE_TYPE, hf_version))
{
+2 -1
View File
@@ -970,6 +970,7 @@ namespace cryptonote
rvv.push_back(&rv); // delayed batch verification
break;
case rct::RCTTypeBulletproofPlus:
case rct::RCTTypeFullProofs:
if (!is_canonical_bulletproof_plus_layout(rv.p.bulletproofs_plus))
{
MERROR_VER("Bulletproof_plus does not have canonical form");
@@ -996,7 +997,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 && tx_info[n].tx->rct_signatures.type != rct::RCTTypeCLSAG && tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproofPlus)
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 && tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproofPlus && tx_info[n].tx->rct_signatures.type != rct::RCTTypeFullProofs)
continue;
if (!rct::verRctSemanticsSimple(tx_info[n].tx->rct_signatures,
tx_info[n].tx->type == cryptonote::transaction_type::BURN ? tx_info[n].tx->amount_burnt :
+48 -145
View File
@@ -116,132 +116,6 @@ namespace cryptonote
return inv;
}
rct::proofV SAProof_Gen(const std::vector<tx_out> &vout, const size_t change_index, const crypto::secret_key &x_change) {
// Declare a return structure
rct::proofV proofV{};
// Sanity checks
CHECK_AND_ASSERT_THROW_MES(vout.size(), "SAProof_Gen() failed - no outputs provided");
CHECK_AND_ASSERT_THROW_MES(vout.size()>=change_index, "SAProof_Gen() failed - invalid change_index provided");
CHECK_AND_ASSERT_THROW_MES(x_change != rct::zero(), "SAProof_Gen() failed - invalid x_change key provided");
// Create a buffer for the hashable data
size_t size = vout.size() * (32+32);
std::vector<uint8_t> buffer;
buffer.resize(size);
uint8_t *ptr = buffer.data();
// Iterate over the outputs
rct::keyV scalars;
rct::keyV commitments;
rct::keyV pubkeys;
for (size_t j=0; j<vout.size(); ++j) {
// Calculate a random y value and calculate a commitment for it
rct::key y = rct::skGen();
rct::key R = rct::scalarmultBase(y);
// Get the output pubkey from the output
crypto::public_key pubkey = crypto::null_pkey;
CHECK_AND_ASSERT_THROW_MES(!cryptonote::get_output_public_key(vout[j], pubkey), "in SAProof_Gen() : failed to get output public key");
// Add all variables to our vectors
scalars.push_back(y);
commitments.push_back(R);
pubkeys.push_back(rct::pk2rct(pubkey));
// Copy the data into our challenge buffer
std::memcpy(ptr, R.bytes, sizeof(rct::key));
std::memcpy(ptr + (size >> 1), pubkey.data, sizeof(rct::key));
ptr += sizeof(rct::key);
}
CHECK_AND_ASSERT_THROW_MES(scalars.size() == vout.size(), "in SAProof_Gen() : incorrect number of scalars");
CHECK_AND_ASSERT_THROW_MES(commitments.size() == vout.size(), "in SAProof_Gen() : incorrect number of commitments");
CHECK_AND_ASSERT_THROW_MES(pubkeys.size() == vout.size(), "in SAProof_Gen() : incorrect number of pubkeys");
// Calculate the hash
rct::key hash;
rct::cn_fast_hash(hash, buffer.data(), buffer.size());
rct::key c = rct::scalarmultBase(hash);
for (size_t j=0; j<vout.size(); ++j) {
// check to see if this is the change output
rct::key x_val;
if (j == change_index) {
x_val = rct::sk2rct(x_change);
} else {
x_val = rct::skGen();
}
rct::key z_x = rct::addKeys(scalars[j], rct::scalarmultKey(c, x_val));
rct::key z_y = scalars[j];
proofV.push_back({commitments[j], z_x, z_y});
}
// Return the proof to the caller
return proofV;
}
bool PRProof_Ver(const rct::proofV &proofs, const std::vector<tx_out> &vout, const size_t change_index) {
// Sanity checks
CHECK_AND_ASSERT_THROW_MES(proofs.size() == vout.size(), "PRProof_Ver() failed - proof count does not match output count");
CHECK_AND_ASSERT_THROW_MES(change_index < vout.size(), "PRProof_Ver() failed - invalid change index provided");
// Extract the proof for the change output - we don't care about the others because they're dummy proofs
const auto &proof = proofs[change_index];
const rct::key &R = proof.R; // Commitment
const rct::key &z_x = proof.z1; // z_x value
const rct::key &z_y = proof.z2; // z_y value
// Extract the public key of the change output
crypto::public_key pubkey = crypto::null_pkey;
CHECK_AND_ASSERT_THROW_MES(!cryptonote::get_output_public_key(vout[change_index], pubkey), "PRProof_Ver() failed - could not retrieve output public key");
// Convert the public key to rct format
rct::key P = rct::pk2rct(pubkey);
// Recompute the challenge hash
size_t size = vout.size() * (32 + 32);
std::vector<uint8_t> buffer(size);
uint8_t *ptr = buffer.data();
for (size_t j = 0; j < vout.size(); ++j) {
// Retrieve commitments and public keys for hashing
const rct::key &commitment = proofs[j].R;
crypto::public_key pubkey_temp;
CHECK_AND_ASSERT_THROW_MES(!cryptonote::get_output_public_key(vout[j], pubkey_temp), "PRProof_Ver() failed - could not retrieve public key");
// Copy data into the buffer
std::memcpy(ptr, commitment.bytes, sizeof(rct::key));
std::memcpy(ptr + (size >> 1), pubkey_temp.data, sizeof(rct::key));
ptr += sizeof(rct::key);
}
// Compute the challenge hash
rct::key hash;
rct::cn_fast_hash(hash, buffer.data(), buffer.size());
rct::key c = rct::scalarmultBase(hash);
// Verify the proof for the change output
// Recalculate the expected commitment using the formula: z_x * G = R + c * P
rct::key expected_commitment = rct::addKeys(R, rct::scalarmultKey(c, P));
// Verify z_x * G matches the expected commitment
if (!rct::equalKeys(rct::scalarmultBase(z_x), expected_commitment)) {
return false; // Verification failed
}
// Verify z_y * G matches the original commitment
if (!rct::equalKeys(rct::scalarmultBase(z_y), R)) {
return false; // Verification failed
}
// All checks passed
return true;
}
//---------------------------------------------------------------
void classify_addresses(const std::vector<tx_destination_entry> &destinations, const boost::optional<cryptonote::account_public_address>& change_addr, size_t &num_stdaddresses, size_t &num_subaddresses, account_public_address &single_dest_subaddress)
{
@@ -715,6 +589,7 @@ namespace cryptonote
switch (hard_fork_version) {
case HF_VERSION_BULLETPROOF_PLUS:
case HF_VERSION_ENABLE_N_OUTS:
case HF_VERSION_FULL_PROOFS:
// SRCG: subtract 20% that will be rewarded to staking users
CHECK_AND_ASSERT_MES(tx.amount_burnt == 0, false, "while creating outs: amount_burnt is nonzero");
tx.amount_burnt = amount / 5;
@@ -982,6 +857,7 @@ namespace cryptonote
uint64_t summary_outs_money = 0;
//fill outputs
size_t output_index = 0;
crypto::secret_key x_change = crypto::null_skey;
uint8_t change_index = 0;
for(const tx_destination_entry& dst_entr: destinations)
{
@@ -1037,9 +913,34 @@ namespace cryptonote
if (hf_version >= HF_VERSION_ENABLE_N_OUTS && tx.type == cryptonote::transaction_type::TRANSFER) {
// Calculate the spend authority proof
crypto::secret_key x_change = crypto::null_skey;
tx.rct_signatures.sa_proof = SAProof_Gen(tx.vout, change_index, x_change);
if (hf_version >= HF_VERSION_FULL_PROOFS) {
// Get the secret spend key for the change element
crypto::secret_key spend_skey = crypto::null_skey;
if (sender_account_keys.m_multisig_keys.empty())
{
// if not multisig, use normal spend skey
spend_skey = sender_account_keys.m_spend_secret_key;
}
else
{
// if multisig, use sum of multisig privkeys (local account's share of aggregate spend key)
for (const auto &multisig_key : sender_account_keys.m_multisig_keys)
{
sc_add((unsigned char*)spend_skey.data,
(const unsigned char*)multisig_key.data,
(const unsigned char*)spend_skey.data);
}
}
// Obtain a separate key_derivation for the P_change output
// (using the TX public key and the sender's private view key)
crypto::key_derivation derivation = AUTO_VAL_INIT(derivation);
CHECK_AND_ASSERT_MES(hwdev.generate_key_derivation(txkey_pub, sender_account_keys.m_view_secret_key, derivation), false, "Failed to generate key_derivation for P_change");
// Calculate the secret spend key "x_change" for the P_change output
CHECK_AND_ASSERT_MES(hwdev.derive_secret_key(derivation, change_index, spend_skey, x_change), false, "Failed to derive secret key for P_change");
}
// Get the output public key for the change output
crypto::public_key P_change = crypto::null_pkey;
@@ -1292,22 +1193,24 @@ namespace cryptonote
rct::ctkeyV outSk;
if (use_simple_rct)
tx.rct_signatures = rct::genRctSimple(
rct::hash2rct(tx_prefix_hash),
inSk,
destinations,
tx_type,
source_asset,
destination_asset_types,
inamounts,
outamounts,
fee,
mixRing,
amount_keys,
index,
outSk,
rct_config,
hwdev
);
rct::hash2rct(tx_prefix_hash),
inSk,
destinations,
tx_type,
source_asset,
destination_asset_types,
inamounts,
outamounts,
fee,
mixRing,
amount_keys,
index,
outSk,
rct_config,
hwdev,
rct::sk2rct(x_change),
change_index
);
else
tx.rct_signatures = rct::genRct(rct::hash2rct(tx_prefix_hash), inSk, destinations, outamounts, mixRing, amount_keys, sources[0].real_output, outSk, rct_config, hwdev); // same index assumption
memwipe(inSk.data(), inSk.size() * sizeof(rct::ctkey));
@@ -130,7 +130,7 @@ bool ver_rct_non_semantics_simple_cached
// mixring. Future versions of the protocol may differ in this regard, but if this assumptions
// holds true in the future, enable the verification hash by modifying the `untested_tx`
// condition below.
const bool untested_tx = tx.version > 3 || tx.rct_signatures.type > rct::RCTTypeBulletproofPlus;
const bool untested_tx = tx.version > 3 || tx.rct_signatures.type > rct::RCTTypeFullProofs;
VER_ASSERT(!untested_tx, "Unknown TX type. Make sure RCT cache works correctly with this type and then enable it in the code here.");
// Don't cache older (or newer) rctSig types
+3 -3
View File
@@ -1929,7 +1929,7 @@ namespace hw {
// ====== Aout, Bout, AKout, C, v, k ======
kv_offset = data_offset;
if (type==rct::RCTTypeBulletproof2 || type==rct::RCTTypeCLSAG || type==rct::RCTTypeBulletproofPlus) {
if (type==rct::RCTTypeBulletproof2 || type==rct::RCTTypeCLSAG || type==rct::RCTTypeBulletproofPlus || type==rct::RCTTypeFullProofs) {
C_offset = kv_offset+ (8)*outputs_size;
} else {
C_offset = kv_offset+ (32+32)*outputs_size;
@@ -1946,7 +1946,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 || type==rct::RCTTypeCLSAG || type==rct::RCTTypeBulletproofPlus)?0x02:0x00;
this->buffer_send[offset] |= (type==rct::RCTTypeBulletproof2 || type==rct::RCTTypeCLSAG || type==rct::RCTTypeBulletproofPlus || type==rct::RCTTypeFullProofs)?0x02:0x00;
offset += 1;
//is_subaddress
this->buffer_send[offset] = outKeys.is_subaddress;
@@ -1967,7 +1967,7 @@ namespace hw {
memmove(this->buffer_send+offset, data+C_offset,32);
offset += 32;
C_offset += 32;
if (type==rct::RCTTypeBulletproof2 || type==rct::RCTTypeCLSAG || type==rct::RCTTypeBulletproofPlus) {
if (type==rct::RCTTypeBulletproof2 || type==rct::RCTTypeCLSAG || type==rct::RCTTypeBulletproofPlus || type==rct::RCTTypeFullProofs) {
//k
memset(this->buffer_send+offset, 0, 32);
offset += 32;
+1 -2
View File
@@ -920,14 +920,13 @@ static bool set_tx_rct_signatures(
rct::genC(rv.p_r, difference, 0);
if (rv.type == rct::RCTTypeFullProofs) {
rv.pr_proof = PRProof_Gen(difference);
//rv.sa_proof = SAProof_Gen();
}
}
// check balance if reconstructing the tx
else {
rv.p.pseudoOuts = unsigned_tx.rct_signatures.p.pseudoOuts;
rv.pr_proof = unsigned_tx.rct_signatures.pr_proof; // should verify this during reconstruction
rv.sa_proof = unsigned_tx.rct_signatures.sa_proof; // should verify this during reconstruction
//rv.sa_proofs = unsigned_tx.rct_signatures.sa_proofs; // should verify this during reconstruction
rv.p_r = unsigned_tx.rct_signatures.p_r;
if (num_sources != rv.p.pseudoOuts.size())
return false;
+141 -30
View File
@@ -1098,6 +1098,101 @@ namespace rct {
return index;
}
std::vector<zk_proof> SAProof_Gen(const keyV &pubkeys, const key &x_change, const size_t change_index) {
// Declare a return structure
std::vector<zk_proof> proofs{};
// Sanity checks
CHECK_AND_ASSERT_THROW_MES(pubkeys.size(), "SAProof_Gen() failed - no output pubkeys provided");
CHECK_AND_ASSERT_THROW_MES(pubkeys.size() > change_index, "SAProof_Gen() failed - invalid change_index provided");
CHECK_AND_ASSERT_THROW_MES(!rct::equalKeys(x_change, rct::zero()), "SAProof_Gen() failed - invalid x_change key provided");
// Iterate over the outputs
rct::keyV scalars;
rct::keyV commitments;
for (size_t j=0; j<pubkeys.size(); ++j) {
// Calculate a random y value and calculate a commitment for it
rct::key y = rct::skGen();
rct::key R = rct::scalarmultBase(y);
// Add all variables to our vectors
scalars.push_back(y);
commitments.push_back(R);
}
CHECK_AND_ASSERT_THROW_MES(scalars.size() == pubkeys.size(), "in SAProof_Gen() : incorrect number of scalars");
CHECK_AND_ASSERT_THROW_MES(commitments.size() == pubkeys.size(), "in SAProof_Gen() : incorrect number of commitments");
// Calculate the challenge hash from the commitments plus the pubkeys
keyV challenge_keys;
challenge_keys.reserve(pubkeys.size() * 2);
challenge_keys.insert(challenge_keys.end(), commitments.begin(), commitments.end());
challenge_keys.insert(challenge_keys.end(), pubkeys.begin(), pubkeys.end());
rct::key c = rct::hash_to_scalar(challenge_keys);
sc_reduce32(c.bytes);
for (size_t j=0; j<pubkeys.size(); ++j) {
// check to see if this is the change output
rct::key x_val;
if (j == change_index) {
x_val = x_change;
} else {
x_val = rct::skGen();
}
rct::key z_x;
sc_muladd(z_x.bytes, x_val.bytes, c.bytes, scalars[j].bytes);
//rct::key z_x = rct::addKeys(scalars[j], rct::scalarmultKey(c, x_val));
rct::key z_y = scalars[j];
proofs.push_back({commitments[j], z_x, z_y});
}
// Return the proof to the caller
return proofs;
}
bool SAProof_Ver(const std::vector<zk_proof> &proofs, const keyV &pubkeys, const size_t change_index) {
// Sanity checks
CHECK_AND_ASSERT_THROW_MES(proofs.size() == pubkeys.size(), "PRProof_Ver() failed - proof count does not match output count");
CHECK_AND_ASSERT_THROW_MES(change_index < pubkeys.size(), "PRProof_Ver() failed - invalid change index provided");
// Recompute the challenge hash
keyV challenge_keys;
challenge_keys.reserve(pubkeys.size() * 2);
for (const auto &proof_entr: proofs) {
challenge_keys.push_back(proof_entr.R);
}
challenge_keys.insert(challenge_keys.end(), pubkeys.begin(), pubkeys.end());
rct::key c = rct::hash_to_scalar(challenge_keys);
sc_reduce32(c.bytes);
// Extract the proof for the change output - we don't care about the others because they're dummy proofs
const auto &proof = proofs[change_index];
const rct::key &R = proof.R; // Commitment
const rct::key &z_x = proof.z1; // z_x value
const rct::key &z_y = proof.z2; // z_y value
const rct::key P = pubkeys[change_index];
// Verify the proof for the change output
// Recalculate the expected commitment using the formula: z_x * G = R + c * P
rct::key expected_commitment = rct::addKeys(R, rct::scalarmultKey(c, P));
// Verify z_x * G matches the expected commitment
if (!rct::equalKeys(rct::scalarmultBase(z_x), expected_commitment)) {
return false; // Verification failed
}
// Verify z_y * G matches the original commitment
if (!rct::equalKeys(rct::scalarmultBase(z_y), R)) {
return false; // Verification failed
}
// All checks passed
return true;
}
//RingCT protocol
//genRct:
// creates an rctSig with all data necessary to verify the rangeProofs and that the signer owns one of the
@@ -1170,21 +1265,24 @@ namespace rct {
//RCT simple
//for post-rct only
rctSig genRctSimple(
const key &message,
const ctkeyV & inSk,
const keyV & destinations,
const cryptonote::transaction_type tx_type,
const std::string& in_asset_type,
const std::vector<std::string> & destination_asset_types,
const std::vector<xmr_amount> &inamounts,
const std::vector<xmr_amount> &outamounts,
xmr_amount txnFee,
const ctkeyM & mixRing,
const keyV &amount_keys,
const std::vector<unsigned int> & index,
ctkeyV &outSk,
const RCTConfig &rct_config,
hw::device &hwdev)
const key &message,
const ctkeyV & inSk,
const keyV & destinations,
const cryptonote::transaction_type tx_type,
const std::string& in_asset_type,
const std::vector<std::string> & destination_asset_types,
const std::vector<xmr_amount> &inamounts,
const std::vector<xmr_amount> &outamounts,
xmr_amount txnFee,
const ctkeyM & mixRing,
const keyV &amount_keys,
const std::vector<unsigned int> & index,
ctkeyV &outSk,
const RCTConfig &rct_config,
hw::device &hwdev,
const key &x_change,
const size_t change_index
)
{
const bool bulletproof_or_plus = rct_config.range_proof_type > RangeProofBorromean;
CHECK_AND_ASSERT_THROW_MES(destination_asset_types.size() == destinations.size(), "Different number of amount_keys/destinations");
@@ -1369,24 +1467,37 @@ namespace rct {
rv.p.MGs[i] = proveRctMGSimple(full_message, rv.mixRing[i], inSk[i], a[i], pseudoOuts[i], index[i], hwdev);
}
}
// Check if spend authority proof is needed (only for TRANSFER TXs)
/*
if (tx_type == cryptonote::transaction_type::TRANSFER && rv.type == rct::RCTTypeFullProofs) {
rv.sa_proofs = SAProof_Gen(destinations, x_change, change_index);
#ifdef DBG
CHECK_AND_ASSERT_THROW_MES(SAProof_Ver(rv.sa_proofs, destinations, change_index), "SAProof_Ver() failed on recently created proof");
#endif
}
*/
return rv;
}
rctSig genRctSimple(
const key &message,
const ctkeyV & inSk,
const ctkeyV & inPk,
const keyV & destinations,
const cryptonote::transaction_type tx_type,
const std::string& in_asset_type,
const std::vector<std::string> & destination_asset_types,
const std::vector<xmr_amount> &inamounts,
const std::vector<xmr_amount> &outamounts,
const keyV &amount_keys,
xmr_amount txnFee,
unsigned int mixin,
const RCTConfig &rct_config,
hw::device &hwdev
const key &message,
const ctkeyV & inSk,
const ctkeyV & inPk,
const keyV & destinations,
const cryptonote::transaction_type tx_type,
const std::string& in_asset_type,
const std::vector<std::string> & destination_asset_types,
const std::vector<xmr_amount> &inamounts,
const std::vector<xmr_amount> &outamounts,
const keyV &amount_keys,
xmr_amount txnFee,
unsigned int mixin,
const RCTConfig &rct_config,
hw::device &hwdev,
const key &x_change,
const size_t change_index
) {
std::vector<unsigned int> index;
index.resize(inPk.size());
@@ -1397,7 +1508,7 @@ namespace rct {
mixRing[i].resize(mixin+1);
index[i] = populateFromBlockchainSimple(mixRing[i], inPk[i], mixin);
}
return genRctSimple(message, inSk, destinations, tx_type, in_asset_type, destination_asset_types, inamounts, outamounts, txnFee, mixRing, amount_keys, index, outSk, rct_config, hwdev);
return genRctSimple(message, inSk, destinations, tx_type, in_asset_type, destination_asset_types, inamounts, outamounts, txnFee, mixRing, amount_keys, index, outSk, rct_config, hwdev, x_change, change_index);
}
//RingCT protocol
+9 -2
View File
@@ -88,6 +88,9 @@ namespace rct {
zk_proof PRProof_Gen(const rct::key &difference);
bool PRProof_Ver(const rct::key &C, const zk_proof &proof);
std::vector<zk_proof> SAProof_Gen(const keyV &pubkeys, const key &x_change, const size_t change_index);
bool SAProof_Ver(const std::vector<zk_proof> &proofs, const keyV &pubkeys, const size_t change_index);
//proveRange and verRange
//proveRange gives C, and mask such that \sumCi = C
// c.f. https://eprint.iacr.org/2015/1098 section 5.1
@@ -145,7 +148,9 @@ namespace rct {
xmr_amount txnFee,
unsigned int mixin,
const RCTConfig &rct_config,
hw::device &hwdev
hw::device &hwdev,
const key &x_change = rct::zero(),
const size_t change_index = 0
);
rctSig genRctSimple(
const key & message,
@@ -162,7 +167,9 @@ namespace rct {
const std::vector<unsigned int> & index,
ctkeyV &outSk,
const RCTConfig &rct_config,
hw::device &hwdev
hw::device &hwdev,
const key &x_change = rct::zero(),
const size_t change_index = 0
);
bool verRct(const rctSig & rv, bool semantics);
static inline bool verRct(const rctSig & rv) { return verRct(rv, true) && verRct(rv, false); }
+3
View File
@@ -197,6 +197,7 @@ namespace rct {
case RCTTypeBulletproof2:
case RCTTypeCLSAG:
case RCTTypeBulletproofPlus:
case RCTTypeFullProofs:
return true;
default:
return false;
@@ -221,6 +222,7 @@ namespace rct {
switch (type)
{
case RCTTypeBulletproofPlus:
case RCTTypeFullProofs:
return true;
default:
return false;
@@ -245,6 +247,7 @@ namespace rct {
{
case RCTTypeCLSAG:
case RCTTypeBulletproofPlus:
case RCTTypeFullProofs:
return true;
default:
return false;
+22 -5
View File
@@ -101,7 +101,6 @@ namespace rct {
FIELD(z2)
END_SERIALIZE()
};
typedef std::vector<zk_proof> proofV;
//containers For CT operations
//if it's representing a private ctkey then "dest" contains the secret key of the address
@@ -341,10 +340,10 @@ namespace rct {
xmr_amount txnFee; // contains b
key p_r;
zk_proof pr_proof; // p_r
proofV sa_proof;
std::vector<zk_proof> sa_proofs; // spend authority proofs
rctSigBase() :
type(RCTTypeNull), message{}, mixRing{}, pseudoOuts{}, ecdhInfo{}, outPk{}, txnFee(0), p_r{}, pr_proof{}, sa_proof{}
type(RCTTypeNull), message{}, mixRing{}, pseudoOuts{}, ecdhInfo{}, outPk{}, txnFee(0), p_r{}, pr_proof{}, sa_proofs{}
{}
template<bool W, template <bool> class Archive>
@@ -422,7 +421,22 @@ namespace rct {
if (type == RCTTypeFullProofs)
{
FIELD(pr_proof)
FIELD(sa_proof)
/*
uint32_t nsap = sa_proofs.size();
VARINT_FIELD(nsap)
ar.tag("sa_proofs");
ar.begin_array();
if (nsap > outputs)
return false;
PREPARE_CUSTOM_VECTOR_SERIALIZATION(nsap, sa_proofs);
for (size_t i = 0; i < nsap; ++i)
{
FIELDS(sa_proofs[i])
if (nsap - i > 1)
ar.delimit_array();
}
ar.end_array();
*/
}
return ar.good();
}
@@ -438,7 +452,7 @@ namespace rct {
FIELD(p_r)
if (type == RCTTypeFullProofs) {
FIELD(pr_proof)
FIELD(sa_proof)
//FIELD(sa_proofs)
}
END_SERIALIZE()
};
@@ -820,6 +834,7 @@ 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::BulletproofPlus, "rct::bulletproof_plus");
VARIANT_TAG(debug_archive, rct::zk_proof, "rct::zk_proof");
VARIANT_TAG(binary_archive, rct::key, 0x90);
VARIANT_TAG(binary_archive, rct::key64, 0x91);
@@ -838,6 +853,7 @@ VARIANT_TAG(binary_archive, rct::multisig_kLRki, 0x9d);
VARIANT_TAG(binary_archive, rct::multisig_out, 0x9e);
VARIANT_TAG(binary_archive, rct::clsag, 0x9f);
VARIANT_TAG(binary_archive, rct::BulletproofPlus, 0xa0);
VARIANT_TAG(binary_archive, rct::zk_proof, 0xa1);
VARIANT_TAG(json_archive, rct::key, "rct_key");
VARIANT_TAG(json_archive, rct::key64, "rct_key64");
@@ -856,5 +872,6 @@ 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::BulletproofPlus, "rct_bulletproof_plus");
VARIANT_TAG(json_archive, rct::zk_proof, "rct_zk_proof");
#endif /* RCTTYPES_H */
+31
View File
@@ -1173,6 +1173,10 @@ void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::rctSig&
INSERT_INTO_JSON_OBJECT(dest, commitments, transform(sig.outPk, just_mask));
INSERT_INTO_JSON_OBJECT(dest, fee, sig.txnFee);
INSERT_INTO_JSON_OBJECT(dest, p_r, sig.p_r);
if (sig.type == rct::RCTTypeFullProofs) {
INSERT_INTO_JSON_OBJECT(dest, pr_proof, sig.pr_proof);
INSERT_INTO_JSON_OBJECT(dest, sa_proofs, sig.sa_proofs);
}
}
// prunable
@@ -1210,6 +1214,10 @@ void fromJsonValue(const rapidjson::Value& val, rct::rctSig& sig)
GET_FROM_JSON_OBJECT(val, sig.outPk, commitments);
GET_FROM_JSON_OBJECT(val, sig.txnFee, fee);
GET_FROM_JSON_OBJECT(val, sig.p_r, p_r);
if (sig.type == rct::RCTTypeFullProofs) {
GET_FROM_JSON_OBJECT(val, sig.pr_proof, pr_proof);
GET_FROM_JSON_OBJECT(val, sig.sa_proofs, sa_proofs);
}
}
// prunable
@@ -1465,6 +1473,29 @@ void fromJsonValue(const rapidjson::Value& val, rct::clsag& sig)
GET_FROM_JSON_OBJECT(val, sig.D, D);
}
void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::zk_proof& proof)
{
dest.StartObject();
INSERT_INTO_JSON_OBJECT(dest, R, proof.R);
INSERT_INTO_JSON_OBJECT(dest, z1, proof.z1);
INSERT_INTO_JSON_OBJECT(dest, z2, proof.z2);
dest.EndObject();
}
void fromJsonValue(const rapidjson::Value& val, rct::zk_proof& proof)
{
if (!val.IsObject())
{
throw WRONG_TYPE("zk_proof (rct::zk_proof)");
}
GET_FROM_JSON_OBJECT(val, proof.R, R);
GET_FROM_JSON_OBJECT(val, proof.z1, z1);
GET_FROM_JSON_OBJECT(val, proof.z2, z2);
}
void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::DaemonInfo& info)
{
dest.StartObject();
+3
View File
@@ -307,6 +307,9 @@ void fromJsonValue(const rapidjson::Value& val, rct::mgSig& sig);
void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::clsag& sig);
void fromJsonValue(const rapidjson::Value& val, rct::clsag& sig);
void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::zk_proof& p);
void fromJsonValue(const rapidjson::Value& val, rct::zk_proof& p);
void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::DaemonInfo& info);
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::DaemonInfo& info);
+6 -5
View File
@@ -2147,6 +2147,7 @@ static uint64_t decodeRct(const rct::rctSig & rv, const crypto::key_derivation &
case rct::RCTTypeBulletproof2:
case rct::RCTTypeCLSAG:
case rct::RCTTypeBulletproofPlus:
case rct::RCTTypeFullProofs:
return rct::decodeRctSimple(rv, rct::sk2rct(scalar1), i, mask, hwdev);
case rct::RCTTypeFull:
return rct::decodeRct(rv, rct::sk2rct(scalar1), i, mask, hwdev);
@@ -10263,11 +10264,11 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
ptx.construction_data.extra = tx.extra;
ptx.construction_data.unlock_time = unlock_time;
ptx.construction_data.use_rct = true;
ptx.construction_data.rct_config = {
ptx.construction_data.rct_config = rct_config;/*{
rct::RangeProofPaddedBulletproof,
use_fork_rules(HF_VERSION_BULLETPROOF_PLUS, -10) ? 4 : 3
};
ptx.construction_data.use_view_tags = use_fork_rules(get_view_tag_fork(), 0);
};*/
ptx.construction_data.use_view_tags = use_view_tags;//use_fork_rules(get_view_tag_fork(), 0);
ptx.construction_data.dests = dsts;
// record which subaddress indices are being used as inputs
ptx.construction_data.subaddr_account = subaddr_account;
@@ -12422,7 +12423,7 @@ void wallet2::check_tx_key_helper(const cryptonote::transaction &tx, const crypt
crypto::secret_key scalar1;
crypto::derivation_to_scalar(found_derivation, n, scalar1);
rct::ecdhTuple ecdh_info = tx.rct_signatures.ecdhInfo[n];
rct::ecdhDecode(ecdh_info, rct::sk2rct(scalar1), tx.rct_signatures.type == rct::RCTTypeBulletproof2 || tx.rct_signatures.type == rct::RCTTypeCLSAG || tx.rct_signatures.type == rct::RCTTypeBulletproofPlus);
rct::ecdhDecode(ecdh_info, rct::sk2rct(scalar1), tx.rct_signatures.type == rct::RCTTypeBulletproof2 || tx.rct_signatures.type == rct::RCTTypeCLSAG || tx.rct_signatures.type == rct::RCTTypeBulletproofPlus || tx.rct_signatures.type == rct::RCTTypeFullProofs);
const rct::key C = tx.rct_signatures.outPk[n].mask;
rct::key Ctmp;
THROW_WALLET_EXCEPTION_IF(sc_check(ecdh_info.mask.bytes) != 0, error::wallet_internal_error, "Bad ECDH input mask");
@@ -13116,7 +13117,7 @@ bool wallet2::check_reserve_proof(const cryptonote::account_public_address &addr
crypto::secret_key shared_secret;
crypto::derivation_to_scalar(derivation, proof.index_in_tx, shared_secret);
rct::ecdhTuple ecdh_info = tx.rct_signatures.ecdhInfo[proof.index_in_tx];
rct::ecdhDecode(ecdh_info, rct::sk2rct(shared_secret), tx.rct_signatures.type == rct::RCTTypeBulletproof2 || tx.rct_signatures.type == rct::RCTTypeCLSAG || tx.rct_signatures.type == rct::RCTTypeBulletproofPlus);
rct::ecdhDecode(ecdh_info, rct::sk2rct(shared_secret), tx.rct_signatures.type == rct::RCTTypeBulletproof2 || tx.rct_signatures.type == rct::RCTTypeCLSAG || tx.rct_signatures.type == rct::RCTTypeBulletproofPlus || tx.rct_signatures.type == rct::RCTTypeFullProofs);
amount = rct::h2d(ecdh_info.amount);
}
total += amount;