fixed unit tests; fixed core tests; fixed performance tests; added fix to prevent change in block reward split (thanks Akil); added prelim code for spend authority proof - not complete / working

This commit is contained in:
Some Random Crypto Guy
2024-12-15 11:09:46 +00:00
parent 49fd907073
commit b87c243da1
46 changed files with 631 additions and 268 deletions
+81 -9
View File
@@ -521,7 +521,73 @@ namespace rct {
sc_sub(c.bytes, c_old.bytes, rv.cc.bytes);
return sc_isnonzero(c.bytes) == 0;
}
// Optimized function to hash a vector of keys into a scalar
rct::key my_hash_to_scalar(std::vector<rct::key>& keys) {
// Create a fixed-size buffer large enough to hold all keys and a domain separator
size_t total_size = keys.size() * sizeof(rct::key) + sizeof("ZKP") - 1;
std::vector<uint8_t> data(total_size);
// Copy the keys into the buffer
size_t offset = 0;
for (const auto& key : keys) {
std::memcpy(data.data() + offset, key.bytes, sizeof(rct::key));
offset += sizeof(rct::key);
}
// Add the domain separator "ZKP" at the end of the buffer
const char* domain_separator = "ZKP";
std::memcpy(data.data() + offset, domain_separator, sizeof("ZKP") - 1);
// Hash the concatenated data into a fixed-size hash
rct::key hash_output;
keccak((const uint8_t *)data.data(), total_size, hash_output.bytes, sizeof(rct::key));
sc_reduce32(hash_output.bytes); // Reduce to valid scalar
return hash_output;
}
zk_proof PRProof_Gen(const rct::key &difference) {
zk_proof proof;
// Generate a random scalar for blinding
rct::key r = rct::skGen();
// Compute R = r * G
proof.R = rct::scalarmultBase(r);
// Compute the commitment to the difference
rct::key comm_diff;
genC(comm_diff, difference, 0);
// Calculate challenge c = H_p(R)
std::vector<rct::key> keys{proof.R, comm_diff};
rct::key c = rct::hash_to_scalar(keys);
sc_reduce32(c.bytes);
// Calculate response z = r + c * difference
sc_muladd(proof.z1.bytes, difference.bytes, c.bytes, r.bytes);
proof.z2 = rct::zero();
return proof;
}
bool PRProof_Ver(const rct::key &C, const zk_proof &proof) {
// Compute challenge c = H_p(R)
std::vector<rct::key> keys{proof.R, C};
rct::key c = rct::hash_to_scalar(keys);
// Recalculate R' = z * G - c * C (where C is the commitment rv.p_r)
rct::key zG = rct::scalarmultBase(proof.z1);
rct::key cC = rct::scalarmultKey(C, c);
rct::key R_prime;
rct::subKeys(R_prime, zG, cC);
// Verify R' ?= R
return rct::equalKeys(R_prime, proof.R);
}
//proveRange and verRange
@@ -639,7 +705,7 @@ namespace rct {
kv.push_back(p.t);
}
}
else if (rv.type == RCTTypeBulletproofPlus)
else if (rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs)
{
kv.reserve((6*2+6) * rv.p.bulletproofs_plus.size());
for (const auto &p: rv.p.bulletproofs_plus)
@@ -1074,7 +1140,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);
hwdev.ecdhEncode(rv.ecdhInfo[i], amount_keys[i], rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs);
}
//set txn fee
@@ -1141,6 +1207,9 @@ namespace rct {
case 4:
rv.type = RCTTypeBulletproofPlus;
break;
case 5:
rv.type = RCTTypeFullProofs;
break;
default:
ASSERT_MES_AND_THROW("Unsupported BP version: " << rct_config.bp_version);
}
@@ -1257,7 +1326,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);
hwdev.ecdhEncode(rv.ecdhInfo[i], amount_keys[i], rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs);
}
//set txn fee
@@ -1282,7 +1351,8 @@ 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.pr_proof = PRProof_Gen(difference);
key full_message = get_pre_mlsag_hash(rv,hwdev);
for (i = 0 ; i < inamounts.size(); i++)
@@ -1416,8 +1486,10 @@ namespace rct {
std::vector<const BulletproofPlus*> 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,
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs,
false, "verRctSemanticsSimple called on non simple rctSig");
if (rv.type == RCTTypeFullProofs)
CHECK_AND_ASSERT_MES(PRProof_Ver(rv.p_r, rv.pr_proof), false, "Invalid p_r commitment to difference");
const bool bulletproof = is_rct_bulletproof(rv.type);
const bool bulletproof_plus = is_rct_bulletproof_plus(rv.type);
if (bulletproof || bulletproof_plus)
@@ -1540,7 +1612,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,
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs,
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);
@@ -1612,7 +1684,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);
hwdev.ecdhDecode(ecdh_info, sk, rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs);
mask = ecdh_info.mask;
key amount = ecdh_info.amount;
key C = rv.outPk[i].mask;
@@ -1636,14 +1708,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,
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs,
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);
hwdev.ecdhDecode(ecdh_info, sk, rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeFullProofs);
mask = ecdh_info.mask;
key amount = ecdh_info.amount;
key C = rv.outPk[i].mask;
+3
View File
@@ -85,6 +85,9 @@ 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 &);
zk_proof PRProof_Gen(const rct::key &difference);
bool PRProof_Ver(const rct::key &C, const zk_proof &proof);
//proveRange and verRange
//proveRange gives C, and mask such that \sumCi = C
// c.f. https://eprint.iacr.org/2015/1098 section 5.1
+34 -9
View File
@@ -90,6 +90,19 @@ namespace rct {
typedef std::vector<key> keyV; //vector of keys
typedef std::vector<keyV> keyM; //matrix of keys (indexed by column first)
struct zk_proof {
key R; // Commitment
key z1; // Response
key z2; // Response
BEGIN_SERIALIZE_OBJECT()
FIELD(R)
FIELD(z1)
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
// while "mask" contains a where C = aG + bH is CT pedersen commitment and b is the amount
@@ -304,6 +317,7 @@ namespace rct {
RCTTypeBulletproof2 = 4,
RCTTypeCLSAG = 5,
RCTTypeBulletproofPlus = 6,
RCTTypeFullProofs = 7
};
enum RangeProofType { RangeProofBorromean, RangeProofBulletproof, RangeProofMultiOutputBulletproof, RangeProofPaddedBulletproof };
struct RCTConfig {
@@ -326,9 +340,11 @@ namespace rct {
ctkeyV outPk;
xmr_amount txnFee; // contains b
key p_r;
zk_proof pr_proof; // p_r
proofV sa_proof;
rctSigBase() :
type(RCTTypeNull), message{}, mixRing{}, pseudoOuts{}, ecdhInfo{}, outPk{}, txnFee(0)
type(RCTTypeNull), message{}, mixRing{}, pseudoOuts{}, ecdhInfo{}, outPk{}, txnFee(0), p_r{}, pr_proof{}, sa_proof{}
{}
template<bool W, template <bool> class Archive>
@@ -337,7 +353,7 @@ namespace rct {
FIELD(type)
if (type == RCTTypeNull)
return ar.good();
if (type != RCTTypeFull && type != RCTTypeSimple && type != RCTTypeBulletproof && type != RCTTypeBulletproof2 && type != RCTTypeCLSAG && type != RCTTypeBulletproofPlus)
if (type != RCTTypeFull && type != RCTTypeSimple && type != RCTTypeBulletproof && type != RCTTypeBulletproof2 && type != RCTTypeCLSAG && type != RCTTypeBulletproofPlus && type != RCTTypeFullProofs)
return false;
VARINT_FIELD(txnFee)
// inputs/outputs not saved, only here for serialization help
@@ -366,7 +382,7 @@ namespace rct {
return false;
for (size_t i = 0; i < outputs; ++i)
{
if (type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus)
if (type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus || type == RCTTypeFullProofs)
{
// Since RCTTypeBulletproof2 enote types, we don't serialize the blinding factor, and only serialize the
// first 8 bytes of ecdhInfo[i].amount
@@ -403,6 +419,11 @@ namespace rct {
}
ar.end_array();
FIELD(p_r)
if (type == RCTTypeFullProofs)
{
FIELD(pr_proof)
FIELD(sa_proof)
}
return ar.good();
}
@@ -415,6 +436,10 @@ namespace rct {
FIELD(outPk)
VARINT_FIELD(txnFee)
FIELD(p_r)
if (type == RCTTypeFullProofs) {
FIELD(pr_proof)
FIELD(sa_proof)
}
END_SERIALIZE()
};
struct rctSigPrunable {
@@ -437,9 +462,9 @@ namespace rct {
return false;
if (type == RCTTypeNull)
return ar.good();
if (type != RCTTypeFull && type != RCTTypeSimple && type != RCTTypeBulletproof && type != RCTTypeBulletproof2 && type != RCTTypeCLSAG && type != RCTTypeBulletproofPlus)
if (type != RCTTypeFull && type != RCTTypeSimple && type != RCTTypeBulletproof && type != RCTTypeBulletproof2 && type != RCTTypeCLSAG && type != RCTTypeBulletproofPlus && type != RCTTypeFullProofs)
return false;
if (type == RCTTypeBulletproofPlus)
if (type == RCTTypeBulletproofPlus || type == RCTTypeFullProofs)
{
uint32_t nbp = bulletproofs_plus.size();
VARINT_FIELD(nbp)
@@ -496,7 +521,7 @@ namespace rct {
ar.end_array();
}
if (type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus)
if (type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus || type == RCTTypeFullProofs)
{
ar.tag("CLSAGs");
ar.begin_array();
@@ -587,7 +612,7 @@ namespace rct {
}
ar.end_array();
}
if (type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus)
if (type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus || type == RCTTypeFullProofs)
{
ar.tag("pseudoOuts");
ar.begin_array();
@@ -619,12 +644,12 @@ namespace rct {
keyV& get_pseudo_outs()
{
return type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus ? p.pseudoOuts : pseudoOuts;
return type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus || type == RCTTypeFullProofs ? p.pseudoOuts : pseudoOuts;
}
keyV const& get_pseudo_outs() const
{
return type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus ? p.pseudoOuts : pseudoOuts;
return type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus || type == RCTTypeFullProofs ? p.pseudoOuts : pseudoOuts;
}
BEGIN_SERIALIZE_OBJECT()