elements: align unblinding with the elements impl
What changed, and why it matters
This commit tightens the unblinding process for confidential asset transactions in the Elements/Liquid sidechain. Previously, the code blindly trusted the decrypted message and did not verify that the extracted asset ID and blinding factor actually match the original cryptographic commitments. The patch adds verification steps: after decryption it re-derives the asset generator and value commitment and compares them to the inputs. If they do not match, it clears the sensitive outputs and returns an error. This prevents a class of attacks where a malicious or malformed blinded output could make the wallet accept an incorrect asset ID or amount.
Treat this as a security-hardening fix and include it in the next release. Users handling confidential assets should upgrade. Review whether any other unblinding entry points (e.g., wally_asset_unblind) share the same validation pattern and ensure they are also covered. No immediate incident response is indicated unless a specific exploit has been reported.
Security signals we found
Adds cryptographic verification of decrypted unblinding results against original commitments
Replaces a FIXME comment indicating an incomplete security check
Uses secure clearing (wally_clear_4) of extracted secrets on validation failure
Returns explicit error instead of silently accepting unverified decrypted values
Aligns implementation with reference 'elements impl' (blind.cpp)
Evidence from the diff
The change is in wally_asset_unblind_with_nonce() in src/elements.c. The old code had a ‘FIXME: check results per blind.cpp’ and simply memcpy’d the first 32 bytes of the decrypted message to asset_out and the next 32 bytes to abf_out without validating them against the supplied generator and commitment. The new code checks message_len, then re-derives the asset generator from asset_out+abf_out and compares it to the input generator, and re-derives the value commitment from value_out+vbf_out+generator and compares it to the input commitment. On mismatch it securely clears the extracted values and returns WALLY_ERROR. This aligns unblinding with the reference elements implementation and closes a cryptographic validation gap.
Changed components
src/elements.cwally_asset_unblind_with_nonce()Confidential asset unblinding for Elements/Liquid transactionsInspect captured patch +29 / −6
diff --git a/src/elements.c b/src/elements.c
index 0756633..b615f9d 100644
--- a/src/elements.c
+++ b/src/elements.c
@@ -433,12 +433,35 @@ int wally_asset_unblind_with_nonce(const unsigned char *nonce_hash, size_t nonce
&gen))
goto cleanup;
- /* FIXME: check results per blind.cpp */
-
- /* Extract the asset id and asset blinding factor from the message */
- memcpy(asset_out, message, ASSET_TAG_LEN);
- memcpy(abf_out, message + ASSET_TAG_LEN, ASSET_TAG_LEN);
- ret = WALLY_OK;
+ if (message_len != sizeof(message)) {
+ ret = WALLY_ERROR;
+ goto cleanup;
+ } else {
+ unsigned char msg_generator[ASSET_GENERATOR_LEN];
+ unsigned char msg_commitment[ASSET_COMMITMENT_LEN];
+ /* Extract the asset id and asset blinding factor from the message */
+ memcpy(asset_out, message, ASSET_TAG_LEN);
+ memcpy(abf_out, message + ASSET_TAG_LEN, ASSET_TAG_LEN);
+ /* Verify extracted asset */
+ ret = wally_asset_generator_from_bytes(asset_out, asset_out_len,
+ abf_out, abf_out_len,
+ msg_generator, sizeof(msg_generator));
+ if (ret != WALLY_OK || memcmp(generator, msg_generator, generator_len)) {
+ goto mismatch;
+ }
+ /* Verify unwound value */
+ ret = wally_asset_value_commitment(*value_out, vbf_out, vbf_out_len,
+ generator, generator_len,
+ msg_commitment, sizeof(msg_commitment));
+ if (ret != WALLY_OK || memcmp(commitment, msg_commitment, commitment_len)) {
+mismatch:
+ wally_clear_4(msg_commitment, sizeof(msg_commitment),
+ msg_generator, sizeof(msg_generator),
+ asset_out, asset_out_len, abf_out, abf_out_len);
+ ret = WALLY_ERROR;
+ goto cleanup;
+ }
+ }
cleanup:
wally_clear_3(&gen, sizeof(gen), &commit, sizeof(commit),
Why this scored 59/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.