[WIP] Confidential transfers - #233
Conversation
… type definitions
…TokenIssuance ledger entries
…nfidential-transfers
…t/confidential-transfers
…ential-transfers-transactions
…ential-transfers-new-transactions
…nfidential-transfers
…t/confidential-transfers
…ential-transfers-transactions
…ential-transfers-transactions
…l/feat/confidential-transfers-new-transactions
…on and add MPTokenIssuanceSet test
… regression tests
…l/feat/confidential-transfers-new-transactions
…alidation failures
feat(confidential): add ElGamal encrypt/decrypt with hex-string API
feat(confidential): add ZK proof, commitment, and context-hash CGo bindings with hex-string API
chore: update vendored mpt-crypto to 0.3.0-rc1
feat(confidential): update vendored mpt-crypto to 0.3.0-rc1
…ransfers # Conflicts: # CHANGELOG.md # Makefile # README.md # xrpl/hash/ledger.go # xrpl/transaction/validations_xrpl_objects.go
| run: | | ||
| VERSION="${{ needs.check.outputs.version }}" | ||
| BRANCH="chore/update-mpt-crypto-${VERSION}" | ||
|
|
||
| git config user.name "github-actions[bot]" | ||
| git config user.email "github-actions[bot]@users.noreply.github.com" | ||
| git checkout -b "$BRANCH" | ||
| git add -f confidential/deps/ | ||
| git commit -m "chore(confidential): update vendored mpt-crypto to $VERSION" | ||
| git push -u origin "$BRANCH" | ||
|
|
||
| gh pr create \ | ||
| --base "${{ github.ref_name }}" \ | ||
| --title "Update vendored mpt-crypto to $VERSION" \ | ||
| --body "$(cat <<EOF | ||
| Automated update of vendored mpt-crypto static libraries. | ||
|
|
||
| **${{ needs.check.outputs.current }} → $VERSION** | ||
|
|
||
| Platforms built: | ||
| - linux-amd64 | ||
| - linux-arm64 | ||
| - darwin-arm64 | ||
| - darwin-amd64 | ||
| EOF | ||
| )" |
There was a problem hiding this comment.
Using variable interpolation ${{...}} with github context data in a run: step could allow an attacker to inject their own code into the runner. This would allow them to steal secrets and code. github context data can have arbitrary user input and should be treated as untrusted. Instead, use an intermediate environment variable with env: to store the data and use the environment variable in the run: script. Be sure to use double-quotes the environment variable, like this: "$ENVVAR".
🧹 Fixed in commit a386a3a 🧹
| run: | | ||
| CURRENT=$(cat confidential/deps/VERSION 2>/dev/null || echo "") | ||
| echo "current=$CURRENT" >> "$GITHUB_OUTPUT" | ||
|
|
||
| if [ -n "${{ inputs.version }}" ]; then | ||
| VERSION="${{ inputs.version }}" | ||
| else | ||
| VERSION=$(conan list 'mpt-crypto/*' -r xrplf 2>/dev/null \ | ||
| | grep 'mpt-crypto/' \ | ||
| | sed 's/.*mpt-crypto\///' \ | ||
| | sort -V \ | ||
| | tail -1) | ||
| fi | ||
| echo "version=$VERSION" >> "$GITHUB_OUTPUT" | ||
|
|
||
| if [ "$CURRENT" = "$VERSION" ]; then | ||
| echo "needed=false" >> "$GITHUB_OUTPUT" | ||
| echo "Already at mpt-crypto/$VERSION — skipping build." | ||
| elif git ls-remote --exit-code --heads origin "chore/update-mpt-crypto-${VERSION}" >/dev/null 2>&1; then | ||
| echo "needed=false" >> "$GITHUB_OUTPUT" | ||
| echo "::warning::Branch 'chore/update-mpt-crypto-${VERSION}' already exists. Delete it before re-running." | ||
| else | ||
| echo "needed=true" >> "$GITHUB_OUTPUT" | ||
| echo "Update needed: $CURRENT -> $VERSION" | ||
| fi | ||
|
|
There was a problem hiding this comment.
Using variable interpolation ${{...}} with github context data in a run: step could allow an attacker to inject their own code into the runner. This would allow them to steal secrets and code. github context data can have arbitrary user input and should be treated as untrusted. Instead, use an intermediate environment variable with env: to store the data and use the environment variable in the run: script. Be sure to use double-quotes the environment variable, like this: "$ENVVAR".
🎉 Fixed in commit a386a3a 🎉
Confidential transfers
Description
This pull request introduces comprehensive support for XLS-96 confidential transfer features in the codebase, particularly for Multi-Party Token (MPT) ledger entries and transactions. The changes add confidential transfer fields, flags, transaction types, and validation helpers to enable confidential amounts, encrypted balances, and related cryptographic operations for tokens. The update also extends test coverage to include these new features.
Type of change
Checklist:
Notes (optional)
Pre-merge checklist - XLS-96 Confidential MPT
Must fix
BlindingFactortype and nth changed in rippled: Ourdefinitions.jsonhasBlindingFactorasBlob, nth 45,isVLEncoded: true. Rippled now defines it asUINT256, nth 39,isVLEncoded: false(commita43cf94ff7). This is a serialization-breaking change - the field will encode/decode incorrectly.AmountCommitmentnth changed: Ourdefinitions.jsonhas nth 46. Rippled now has nth 45. Serialization will break.BalanceCommitmentnth changed: Ourdefinitions.jsonhas nth 47. Rippled now has nth 46. Serialization will break.HolderEncryptionKeysize validation:confidential_mpt_convert.go:106validates 64 bytes (uncompressed). Rippled enforces 33 bytes (compressed,0x02/0x03prefix viaisValidCompressedECPoint). Every valid key is rejected and every invalid key is accepted.Updated field comparison -
definitions.jsonvs rippledThe following table shows all fields that differ between our
definitions.jsonand the latest rippledsfields.macro:BlindingFactorAmountCommitmentBalanceCommitmentShould fix ?
ZKProoflength: CurrentlyIsValidHexBlob(any non-empty hex). Rippled requires exactly 98 bytes (196 hex) —ecEqualityProofLength.ZKProoflength: CurrentlyIsValidHexBlob. Rippled requires exactly 883 bytes (1766 hex) —ecPedersenProofLength + ecSingleBulletproofLength.ZKProoflength: CurrentlyIsValidHexBlob. Rippled requires 1503 bytes (3006 hex) without auditor, 1601 bytes (3202 hex) with auditor.IsValidCompressedEncryptionKeyshould verify02/03prefix to match rippled'sisValidCompressedECPoint. Same forIsValidCommitment(Pedersen commitments are compressed EC points).UncompressedPointLenandIsValidUncompressedEncryptionKeybecome unused after theHolderEncryptionKeyfix.BlindingFactorvalidation: After updating the type toUINT256indefinitions.json, theIsValidBlindingFactorfunction (64 hex = 32 bytes) is still correct for transaction-level validation since UINT256 is always 32 bytes. But the Go struct field type in the transaction structs should be reviewed - it may need to change fromstringto a fixed-size type if the binary codec handles UINT256 differently from Blob.Missing server-side validations
MPTokenIssuanceIDfor Convert (ConfidentialMPTConvert.cpp:19), ConvertBack (ConfidentialMPTConvertBack.cpp:22), and Send (ConfidentialMPTSend.cpp:25). Clawback has the inverse check (only issuer can submit). The Go code does not validate any of these. Implementing it client-side requires parsing the issuer account out of theMPTokenIssuanceIDhex encoding. Server rejects withtemMALFORMED. Spec references: section 8.3.1 item 2, section 10.4.1 item 2, section 7 ("self-conversion only").Spec divergences
HolderEncryptionKeyis 64 bytes (XLS-96 section 7.3.1, item 4). Rippled enforces 33 bytes compressed. We follow rippled. To be reported upstream.ZKProofsizes for Clawback, ConvertBack, and Send. Only says "length is incorrect". Exact byte lengths sourced from rippled'sProtocol.h. To be reported upstream.BlindingFactoras Blob (nth 45). Rippled changed it toUINT256(nth 39). Spec not yet updated.