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:
+81
-9
@@ -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;
|
||||
|
||||
@@ -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
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user