Skip to content

carrot+fcmp: complete hot/cold wallet implementation [BETA] - #358

Draft
jeffro256 wants to merge 1 commit into
seraphis-migration:fcmp++-beta-stressnetfrom
jeffro256:fcmp++-beta-hotcold
Draft

carrot+fcmp: complete hot/cold wallet implementation [BETA]#358
jeffro256 wants to merge 1 commit into
seraphis-migration:fcmp++-beta-stressnetfrom
jeffro256:fcmp++-beta-hotcold

Conversation

@jeffro256

Copy link
Copy Markdown
Collaborator

#52

@jeffro256
jeffro256 marked this pull request as draft May 7, 2026 15:23
@UkoeHB

UkoeHB commented May 17, 2026

Copy link
Copy Markdown

The code has this

/**
 * brief: CarrotTransactionProposalV1 - A specification on how to construct a Carrot transaction, minus key material
 *
 * The fields in `CarrotTransactionProposalV1` are chosen as what is the absolute minimum amount of
 * information required to verifiably, in a human-meaningful way, reconstruct the "signable
 * transaction hash". The signable transaction hash, (usually written `signable_tx_hash` in code),
 * is the actual 32-byte message that the FCMP++ Spend-Authorization & Linkability (SA/L) proofs
 * sign and verify against. In situations where the signing device may be separate from the device
 * formulating the transaction (e.g. cold signing, hardware devices, multisig, etc), this struct
 * can be passed amongst signers so that the signers can actually verifying what they are signing.
 *
 * For exact details on what goes into the signable transaction hash, see `rct::get_pre_mlsag_hash`.
 */

The InputProposalV1 values do not point to specific enotes in the ledger. You need ledger enote indices at minimum (I don't think block ids are enough, afaik Ko uniqueness is only enforced within txs). Multisig is a big pain without this, since I need to collect multisig info from transfer_details in the wallet, but can't actually use input proposals to look for them securely. It also means membership proofs could end up proving the wrong inputs as members, although this is less of a problem so long as the key image and amount commitments are correctly passed to the SAL proof.

In seraphis_lib this info is passed along in parallel, but there is no corresponding data flow in carrot_impl. See the membership proof preps here: https://github.com/UkoeHB/monero/blob/83331b6aea0b01add566c4b75d939ec48a84c877/src/seraphis_main/txtype_squashed_v1.cpp#L412

To fix this I will change InputProposalV1 into a struct that includes the block index and enote ledger index. Here: UkoeHB@3d03d70

@jeffro256

jeffro256 commented May 18, 2026

Copy link
Copy Markdown
Collaborator Author

The InputProposalV1 values do not point to specific enotes in the ledger.

This is specifically by design. CARROT enotes have burning bug protection by binding to input_context and $C_a$. Both of these protect signers who do not have on-chain context. For legacy enotes, the signer needs to know the chain state to do burning bug protection correctly. Not referencing specific enotes forces someone using this struct for legacy enotes to do a local enote lookup before transaction construction. For FCMP++ txs, you still need to do a burning bug lookup for legacy enotes, but proving membership doesn't care about the indices of the output on-chain, given a signed transaction, it is irrelevant. Yes, the membership prover has to do decide on one specific duplicated of $(K_o, C_a)$ to prove membership for, but it can decide to do either if it knows the re-randomizations.

@jeffro256

Copy link
Copy Markdown
Collaborator Author

Multisig is a big pain without this, since I need to collect multisig info from transfer_details in the wallet, but can't actually use input proposals to look for them securely.

What do you mean by this? If you know $K_o$ (provided by the input proposal), you can simply do a lookup in wallet2::m_pub_keys. You do a lookup in the result of tools::wallet::collect_non_burned_transfers_by_onetime_address(), which is a function I provided specifically designed to do this outside of wallet2.

@jeffro256

jeffro256 commented May 18, 2026

Copy link
Copy Markdown
Collaborator Author

It also means membership proofs could end up proving the wrong inputs as members, although this is less of a problem so long as the key image and amount commitments are correctly passed to the SAL proof.

This is an "issue" (or feature) that still exists if you add ledger indices to InputProposalV1 (which you shouldn't). It is a core design feature of FCMP++ that a SA/L proof can do "transaction chaining", which means proving on an input without regard to chain context.

@UkoeHB

UkoeHB commented May 18, 2026

Copy link
Copy Markdown

collect_non_burned_transfers_by_onetime_address()

Ok this should work.

@UkoeHB

UkoeHB commented May 20, 2026

Copy link
Copy Markdown

Can you add comments to CarrotOutputOpeningHintV1 and CarrotOutputOpeningHintV2 clarifying why they exist as different versions?

@UkoeHB

UkoeHB commented May 22, 2026

Copy link
Copy Markdown

Can you rebase so I can rebase on this? Need the multisig_attempt_ignore_sets that was merged to master.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants