mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-18 13:17:55 +02:00
Merge #491: Use proper parsing API for generator comparison
15371c3Refactor UnblindConfidentialPair, and use proper generator serialization comparison (Gregory Sanders)67fa949Use proper secp API to compare generators in issuance validation (Gregory Sanders) Pull request description: Shouldn't be an issue, but just as a precaution to protect against non-guaranteed conditions changing. Tree-SHA512: 2bc983c36abd6157852b1f38636612ebde7519adb7c210b39a4b3dd9f36f497b7e80861223f4d582f6c35abdc669847126b246a0418f7d8d24455c841566f145
This commit is contained in:
commit
43f6cdbd31
2 changed files with 66 additions and 30 deletions
|
|
@ -51,50 +51,77 @@ bool UnblindConfidentialPair(const CKey &key, const CConfidentialValue& confValu
|
|||
|
||||
// ECDH or not depending on if nonce commitment is non-empty
|
||||
uint256 nonce;
|
||||
bool fBlankNonce = false;
|
||||
bool blank_nonce = false;
|
||||
if (nNonce.vchCommitment.size() > 0) {
|
||||
nonce = key.ECDH(ephemeral_key);
|
||||
CSHA256().Write(nonce.begin(), 32).Finalize(nonce.begin());
|
||||
} else {
|
||||
// Use blinding key directly, and don't commit to a scriptpubkey
|
||||
fBlankNonce = true;
|
||||
// This is used for issuance inputs.
|
||||
blank_nonce = true;
|
||||
nonce = uint256(std::vector<unsigned char>(key.begin(), key.end()));
|
||||
}
|
||||
unsigned char msg[4096];
|
||||
|
||||
// API-prescribed sidechannel maximum size, though we only use 64 bytes
|
||||
unsigned char msg[4096] = {0};
|
||||
// 32 bytes of asset type, 32 bytes of asset blinding factor in sidechannel
|
||||
size_t msg_size = 64;
|
||||
uint64_t min_value, max_value, amount;
|
||||
secp256k1_pedersen_commitment commit;
|
||||
|
||||
// If value is unblinded, we don't support unblinding just the asset
|
||||
if (!confValue.IsCommitment()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
secp256k1_generator gen;
|
||||
// Valid asset commitment?
|
||||
secp256k1_generator observed_gen;
|
||||
if (confAsset.IsCommitment()) {
|
||||
if (secp256k1_generator_parse(secp256k1_blind_context, &gen, &confAsset.vchCommitment[0]) != 1)
|
||||
if (secp256k1_generator_parse(secp256k1_blind_context, &observed_gen, &confAsset.vchCommitment[0]) != 1)
|
||||
return false;
|
||||
}
|
||||
else if (confAsset.IsExplicit()) {
|
||||
if (secp256k1_generator_generate(secp256k1_blind_context, &gen, confAsset.GetAsset().begin()) != 1)
|
||||
} else if (confAsset.IsExplicit()) {
|
||||
if (secp256k1_generator_generate(secp256k1_blind_context, &observed_gen, confAsset.GetAsset().begin()) != 1)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (secp256k1_pedersen_commitment_parse(secp256k1_blind_context, &commit, &confValue.vchCommitment[0]) != 1)
|
||||
// Valid value commitment?
|
||||
secp256k1_pedersen_commitment commit;
|
||||
if (secp256k1_pedersen_commitment_parse(secp256k1_blind_context, &commit, &confValue.vchCommitment[0]) != 1) {
|
||||
return false;
|
||||
int res = secp256k1_rangeproof_rewind(secp256k1_blind_context, blinding_factor_out.begin(), &amount, msg, &msg_size, nonce.begin(), &min_value, &max_value, &commit, &vchRangeproof[0], vchRangeproof.size(), (committedScript.size() && !fBlankNonce)? &committedScript.front(): NULL, fBlankNonce ? 0 : committedScript.size(), &gen);
|
||||
secp256k1_generator recoveredGen;
|
||||
|
||||
if (!res || amount > (uint64_t)MAX_MONEY || !MoneyRange((CAmount)amount) || msg_size != 64 || secp256k1_generator_generate_blinded(secp256k1_blind_context, &recoveredGen, msg+32, msg+64) != 1 || !memcmp(&gen, &recoveredGen, 33)) {
|
||||
amount_out = 0;
|
||||
blinding_factor_out = uint256();
|
||||
asset_out.SetNull();
|
||||
asset_blinding_factor_out = uint256();
|
||||
return false;
|
||||
} else {
|
||||
amount_out = (CAmount)amount;
|
||||
asset_out = CAsset(std::vector<unsigned char>(msg, msg+32));
|
||||
asset_blinding_factor_out = uint256(std::vector<unsigned char>(msg+32, msg+64));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Rewind rangeproof
|
||||
uint64_t min_value, max_value, amount;
|
||||
if (!secp256k1_rangeproof_rewind(secp256k1_blind_context, blinding_factor_out.begin(), &amount, msg, &msg_size, nonce.begin(), &min_value, &max_value, &commit, &vchRangeproof[0], vchRangeproof.size(), (committedScript.size() && !blank_nonce)? &committedScript.front(): NULL, blank_nonce ? 0 : committedScript.size(), &observed_gen)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Value sidechannel must be a transaction-valid amount (should be belt-and-suspenders check)
|
||||
if (!MoneyRange((CAmount)amount)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Convienience pointers to starting point of each recovered 32 byte message
|
||||
unsigned char *asset_type = msg;
|
||||
unsigned char *asset_blinder = msg+32;
|
||||
|
||||
// Asset sidechannel of asset type + asset blinder
|
||||
secp256k1_generator recalculated_gen;
|
||||
if (msg_size != 64 || secp256k1_generator_generate_blinded(secp256k1_blind_context, &recalculated_gen, asset_type, asset_blinder) != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Serialize both generators then compare
|
||||
unsigned char observed_generator[33];
|
||||
unsigned char derived_generator[33];
|
||||
secp256k1_generator_serialize(secp256k1_blind_context, observed_generator, &observed_gen);
|
||||
secp256k1_generator_serialize(secp256k1_blind_context, derived_generator, &recalculated_gen);
|
||||
if (memcmp(observed_generator, derived_generator, sizeof(observed_generator))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
amount_out = (CAmount)amount;
|
||||
asset_out = CAsset(std::vector<unsigned char>(asset_type, asset_type+32));
|
||||
asset_blinding_factor_out = uint256(std::vector<unsigned char>(asset_blinder, asset_blinder+32));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Create surjection proof
|
||||
|
|
|
|||
|
|
@ -757,7 +757,7 @@ bool VerifyAmounts(const CCoinsViewCache& cache, const CTransaction& tx, std::ve
|
|||
vData.reserve((tx.vin.size() + tx.vout.size() + GetNumIssuances(tx)));
|
||||
secp256k1_pedersen_commitment *p = vData.data();
|
||||
secp256k1_pedersen_commitment commit;
|
||||
secp256k1_generator gen, gencmp;
|
||||
secp256k1_generator gen;
|
||||
// This is used to add in the explicit values
|
||||
unsigned char explBlinds[32];
|
||||
memset(explBlinds, 0, sizeof(explBlinds));
|
||||
|
|
@ -847,13 +847,22 @@ bool VerifyAmounts(const CCoinsViewCache& cache, const CTransaction& tx, std::ve
|
|||
|
||||
// Must check that prevout is the blinded issuance token
|
||||
// prevout's asset tag = assetTokenID + assetBlindingNonce
|
||||
if (secp256k1_generator_generate_blinded(secp256k1_ctx_verify_amounts, &gen, assetTokenID.begin(), issuance.assetBlindingNonce.begin()) != 1) {
|
||||
return false;
|
||||
}
|
||||
// Serialize the generator for direct comparison
|
||||
unsigned char derived_generator[33];
|
||||
secp256k1_generator_serialize(secp256k1_ctx_verify_amounts, derived_generator, &gen);
|
||||
|
||||
if (secp256k1_generator_generate_blinded(secp256k1_ctx_verify_amounts, &gen, assetTokenID.begin(), issuance.assetBlindingNonce.begin()) != 1)
|
||||
// Belt-and-suspenders: Check that asset commitment from issuance input is correct size
|
||||
if (asset.vchCommitment.size() != sizeof(derived_generator)) {
|
||||
return false;
|
||||
if (secp256k1_generator_parse(secp256k1_ctx_verify_amounts, &gencmp, &asset.vchCommitment[0]) != 1)
|
||||
return false;
|
||||
if (memcmp(&gen, &gencmp, 33))
|
||||
}
|
||||
|
||||
// We have already checked the outputs' generator commitment for general validity, so directly compare serialized bytes
|
||||
if (memcmp(asset.vchCommitment.data(), derived_generator, sizeof(derived_generator))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Process issuance of asset
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue