-
m-relay
<rbrunner7:monero.social> Meeting in 1 hour
-
m-relay
<rbrunner7:monero.social> Meeting time. Hello!
monero-project/meta #1319
-
m-relay
<jberman:monero.social> *waves*
-
m-relay
<sneedlewoods_xmr:matrix.org> hello and happy new year
-
m-relay
<rbrunner7:monero.social> Good, some people are still here, not everybody exit-scammed with the turn of the year :)
-
m-relay
<rbrunner7:monero.social> Likewise, happy new year
-
m-relay
<jberman:monero.social> happy new year :)
-
m-relay
<jbabb:cypherstack.com> Happy new year all
-
m-relay
<rbrunner7:monero.social> Let's start already with the reports. I could finish a first review of SNeedlewoods 's magnum opus, moving the CLI wallet to the Wallet API:
monero-project/monero #10233
-
m-relay
<rbrunner7:monero.social> Overall, looks pretty good, I would say
-
m-relay
<jeffro256:monero.social> Howdy
-
m-relay
<vtnerd:monero.social> hi
-
m-relay
<jeffro256:monero.social> Happy New Year!
-
m-relay
<sneedlewoods_xmr:matrix.org> thanks to rbrunner and vtnerd I have lots of valuable review comments to work on
-
m-relay
<sneedlewoods_xmr:matrix.org> currently focusing on vtnerds review of #9464 / #10232
-
m-relay
<jberman:monero.social> thank you guys for reviewing
-
m-relay
<jeffro256:monero.social> Thanks for taking on that first review
-
m-relay
<rbrunner7:monero.social> Fun fact: With that merged, git blame will say for more than half of all CLI wallet code that it's from sneedlewoods :)
-
m-relay
<jberman:monero.social> me: completed changes to tx relay v2 (
0xFFFC0000/monero #62) and ofrnxmr has been testing. The only thing noted there so far is a potential issue with "refill" logic (refilling the pool on restart), but I don't believe that's an issue with txs relay v2, so that seems to be holding up well
-
m-relay
<jberman:monero.social> I then dug into a segfault
seraphis-migration/monero #258 and have narrowed in on what looks like a likely cause. It seems to be an upstream issue to me and unrelated to FCMP++
-
m-relay
<rbrunner7:monero.social> Any more reports?
-
m-relay
<jeffro256:monero.social> Me: I'm thinking about breaking the `wallet2` reserve proof API and I wanted to bring up the idea here.
-
m-relay
<rbrunner7:monero.social> You mean introduce a breaking change how that works?
-
m-relay
<vtnerd:monero.social> I got lwsf to construct fcmp++ txes with a custom ZMQ function in monerod
-
m-relay
<jeffro256:monero.social> The reason is that the reserve proof API in `wallet2` is sort of broken right now in that it doesn't do a good job at checking non-collusion across entities, even though the crypto code itself tries to check this. The fundamental reason why it is broken is because it A) takes 1 proof at a time, B) uses current chain state to "pin" Monero addresses to one-time address, and C) doesn<clipped mess
-
m-relay
<jeffro256:monero.social> 't check chain state differences across reserve proofs
-
m-relay
<vtnerd:monero.social> *custom rpc method. That rpc method is going to be tweaked such that it only accepts the new global output indexes
-
m-relay
<rbrunner7:monero.social> Sounds like a nice milestone reached, vtnerd
-
m-relay
<vtnerd:monero.social> yes, hopefully the lwsf based wallets will not be left behind (couldn’t resist)
-
m-relay
<rbrunner7:monero.social> Lol
-
m-relay
<rbrunner7:monero.social> jeffro256: I am afraid I don't yet understand the fundamentals here. What entities are you speaking of that may collude? Isn't a reserve proof something for just a single wallet, and that's it?
-
m-relay
<jeffro256:monero.social> This leads to a scenario where entities A and B are trying to prove reserves, and are supposed to be separate. Entity V is validating reserves. Entity A could make a reserve proof, Entity V could validate the proof with `wallet2::check_reserve_proof()`, Entity A could then send XMR to entity B, Entity B could make a reserve proof with shared funds, then Entity V could validate B's<clipped mess
-
m-relay
<jeffro256:monero.social> proof with `waller2::check_reserve_proof()` . It would look like A and B hold reserves separately, but in reality, they are "double dipping"
-
m-relay
<jeffro256:monero.social> Nice!
-
m-relay
<ofrnxmr:monero.social> Yeah, seems to be working well enough
-
m-relay
<rbrunner7:monero.social> Hmm. Doesn't sending *any* funds *after* a reserve proof make that proof moot already? ELI5 :)
-
m-relay
<kayabanerve:matrix.org> 👋
-
m-relay
<jeffro256:monero.social> What needs to be done is that `wallet2` must understand that reserve proofs need to be validated in some sort of explicit shared context, or the `wallet2` must pin some blockchain state (e.g. lowest used block hash) between validations of reserve proofs
-
m-relay
<jeffro256:monero.social> Yes, exactly, but the API doesn't really have a way to handle this.
-
m-relay
<jeffro256:monero.social> Which is why I think it merits breaking it
-
m-relay
<kayabanerve:matrix.org> I've reported some issues with wallet2 to jeffro256, specifically around size limits on transactions and the methodology of construction. Some of it is stupidly over-complicated (add a payment ID if it's not a blood moon, unless the user is a virgin in the eyes of Cthulhu), and some of it could be argued fingerprints in edge cases.
-
m-relay
<kayabanerve:matrix.org> While _some_ of these should disappear with CARROT, I think there may be a couple explicit lines of code which need to be whacked for this to properly move forward.
-
m-relay
<rbrunner7:monero.social> There is nothing like a "timestamp" in that proof? Like "done at this and this state of the blockchain, and/or the wallet"?
-
m-relay
<sneedlewoods_xmr:matrix.org> breaking something that's broken to fix it sounds good to me
-
m-relay
<kayabanerve:matrix.org> Also, isn't multisig TX construction completely independent, having been rebuilt by koe? That implies the two have fingerprints due to the absurd amount of bug-for-bug compatibility you'd need. Very silly, very messy. Thankfully, that's under an experimental flag.
-
m-relay
<kayabanerve:matrix.org> I think I can give you an address that Monero will send to, but won't realize is an address when determining how many people were sent to, with weird as hell effects from there.
-
m-relay
<rbrunner7:monero.social> You should trademark that expression, "bug-for-bug compatibility"
-
m-relay
<kayabanerve:matrix.org> Nothing breaking, just very stupid edge cases.
-
m-relay
<rucknium:monero.social> Would it make sense to discuss implementing another reserve proof?, e.g. Thakore, V., & Vijayakumaran, S. (2025). MProve-Nova: A Privacy-Preserving Proof of Reserves Protocol for Monero. Proceedings on Privacy Enhancing Technologies, 2025(2), 582–606.
moneroresearch.info/266
-
m-relay
<rucknium:monero.social> Or the one before that
-
m-relay
<kayabanerve:matrix.org> It's the same issues discussed with Bitcoin, lacking a formal spec, as the code is the spec. I think one of their opcodes immediately begins by throwing away the first value.
-
m-relay
<kayabanerve:matrix.org> Not because that's reasonable. They just loaded the first argument twice in their evaluator, from a stack, so the top of the stack gets yeeted.
-
m-relay
<rbrunner7:monero.social> Seems to be a constant: "There is always a paper" :)
-
m-relay
<kayabanerve:matrix.org> every observable effect of a system, even if unintentional, will become someone's requirement for the behavior of the system
-
m-relay
<jeffro256:monero.social> The reserve specifies references to one-time addresses, and its associated Monero receive addresses and key images. The verifier then deferences these one-time addresses, does the Monero address -> one-time address derivation, validates the one-time address -> key image association, then checks that the key images are not yet spent. There's no "timestamp" in the proof per se. You <clipped mess
-
m-relay
<jeffro256:monero.social> could calculate the block index when the reserve proof stops being valid by the first occurrence of a key image on-chain in the given set inside the reserve proof. However, the daemon doesn't store when key images first appeared in the chain, so you'd have to do a full-chain scan for key images to find this block index, unfortunately
-
m-relay
<rucknium:monero.social> Regular MProve
moneroresearch.info/256 and MProve+ exist too
moneroresearch.info/35
-
m-relay
<rucknium:monero.social> rbrunner7: So it's actually three papers :P
-
m-relay
<rbrunner7:monero.social> Ok ok
-
m-relay
<jeffro256:monero.social> Disclaimer: I wrote a new type of reserve proofs which use FCMP++ to get full-chain privacy ;)
-
m-relay
<jeffro256:monero.social> That would also cause a breaking of the API
-
m-relay
<rucknium:monero.social> The only instance of a Monero reserve proof I have seen was a wrapped coin implementation IIRC.
-
m-relay
<rbrunner7:monero.social> Just curious: Do such proofs play a large role "out there in the wild"? Or would we at least very much make them more popular, and more widely used?
-
m-relay
<rbrunner7:monero.social> *like to make them more popular
-
m-relay
<rucknium:monero.social> IIRC, Thakore & Vijayakumaran (2025) uses an auxiliary Merkle tree to get "full privacy" with RingCT.
-
m-relay
<rbrunner7:monero.social> So the 3 proofs in the 3 papers may not translate cleanly to FCMP++?
-
m-relay
<kayabanerve:matrix.org>
xkcd.com/1172 as my final comment on wallet2 bs as reported on above :p
-
m-relay
<jeffro256:monero.social> They're in `wallet2` right now, but they have 0 sender privacy, 0 receive privacy, and 0 amount privacy. And the API is broken like I mentioned
-
m-relay
<kayabanerve:matrix.org> jeffro256: The FCMP codebase is obviously internally modular, so you should be able to run with it :)
-
m-relay
<rbrunner7:monero.social> kayabanerve: That's a good XKCD. Classic
-
m-relay
<rbrunner7:monero.social> Isn't "amount privacy" a bit difficult with a proof of reserves?
-
m-relay
<rbrunner7:monero.social> Or do you mean that not only the sum, but the individual enotes become known?
-
m-relay
<kayabanerve:matrix.org> The idea is you prove reserves equal to or in excess of, without revealing the exact outputs.
-
m-relay
<kayabanerve:matrix.org> So it's, on a naïve level, a batch FCMP + Proof of Ownership that _doesn't_ reveal the key images (but does assert they're distinct and unspent within the current blockchain), plus a final proof over the sum of their value.
-
m-relay
<rbrunner7:monero.social> I think the proof string contains a version, so we could continue to support the old proofs after introducing any new one, and nobody will be left out in the cold?
-
m-relay
<rbrunner7:monero.social> But hey, do they work with FCMP++ at all, as they are now, or are we *forced* to move?
-
m-relay
<jeffro256:monero.social> The way I currently have written the new ones reveals the key image , just not the input output pubkey -> key image associations
-
m-relay
<jeffro256:monero.social> For simplicity and so that provers don't have to remake reserve proofs every block
-
m-relay
<jeffro256:monero.social> Validating would work , but only on pre-FCMP++ outputs
-
m-relay
<jeffro256:monero.social> So yeah we are effectively forced to update anyways
-
m-relay
<jeffro256:monero.social> But the wallet2 API itself would also have to change
-
m-relay
<rbrunner7:monero.social> Well, if our hands are forced, that's just living with and developping for a currency that moves forward with a high speed
-
m-relay
<rbrunner7:monero.social> Did you already actually implement your new proof, jeffro256?
-
m-relay
<jeffro256:monero.social> Cryptographically, yes. Haven't integrated it yet b/c of the API issue
-
m-relay
<jberman:monero.social> personally I think reserve proofs are a pretty niche feature / not many wallets support it AFAIK, and so breaking the API for an improved reserve proof with FCMP++/Carrot is a fairly reasonable / sane decision
-
m-relay
<jberman:monero.social> considering the break is isolated to just the reserve proof API
-
m-relay
<rbrunner7:monero.social> I tend to agree
-
m-relay
<kayabanerve:matrix.org> jeffro256: Why do you hate privacy and why do you want to break a critical part of the Monero ecosystem, with 0-5 users?
-
m-relay
<kayabanerve:matrix.org> Your solution should either be perfectly private, and post-quantum, and backwards-compatible, or I don't actually think you support Monero
-
m-relay
<rbrunner7:monero.social> Suuure
-
m-relay
<kayabanerve:matrix.org> /s :p
-
m-relay
<kayabanerve:matrix.org> It sounds like the reserve proof should be _versioned_ but yes, new protocol, new proof, and the rest sounds straightforward from there.
-
m-relay
<kayabanerve:matrix.org> I don't support publishing key images (by far), but that's the hardest problem _and_ it's fine in a post-FCMP++ world.
-
m-relay
<jeffro256:monero.social> sorry my bad i will also integrate a proof of liabilities protocol next week
-
m-relay
<rbrunner7:monero.social> We seem to have now:
-
m-relay
<rbrunner7:monero.social> static constexpr char header_v1[] = "ReserveProofV1";
-
m-relay
<rbrunner7:monero.social> static constexpr char header_v2[] = "ReserveProofV2"; // assumes same length as header_v1
-
m-relay
<kayabanerve:matrix.org> Prove reserves, provw liabilities, why don't you prove you're not a federal agent? Huh? Huh???
-
m-relay
<kayabanerve:matrix.org> /s :p I'll stop, my actual comment is above, thank you jeffro256: for all your hard work on this transition and a proper future ♥
-
m-relay
<rbrunner7:monero.social> If not FEDs, certainly Mossad. I learned that today on Reddit.
-
m-relay
<rbrunner7:monero.social> So it seems we have loose consensus that a breaking wallet2 API change has merit, and is acceptable.
-
m-relay
<jeffro256:monero.social> Yeah I'm not sure how we would do this. I know how to do exclusion proof by revealing the value (or at least a range that the value could be in), but not how to do exclusion proofs using FCMPs on a value which you don't reveal, and on which there must also be some sort of composition proof
-
m-relay
<rbrunner7:monero.social> For reserve proofs.
-
m-relay
<rbrunner7:monero.social> Alright. Some additional topic that we have to discuss today? We are nearing the full hour, for once :)
-
m-relay
<rbrunner7:monero.social> Doesn't look like it. Nice meeting, good start into the new year. Thanks everybody for attending, read you again in 1 week!
-
m-relay
<jeffro256:monero.social> Yeah spend proofs, tx proofs, and output decoding are pretty much unaffected and have a direct Carrot/FCMP++ analogues
-
m-relay
<jeffro256:monero.social> Thanks everyone!
-
m-relay
<sneedlewoods_xmr:matrix.org> thanks everyone
-
m-relay
<jeffro256:monero.social> Thanks everyone!
-
m-relay
<datahoarder:monero.social> ^ so analogue I already added them to my libraries & block explorer, generation and verification (ready for beta stressnet!)
-
m-relay
<jeffro256:monero.social> yay! Awesome to hear that
-
m-relay
<jberman:monero.social> nice DataHoarder :)
-
m-relay
<jeffro256:monero.social> Sorry, I saw your message last week and meant to respond. Did you make the generation for the tx proofs constant time by making the verification do all 4 combos of point negation ?
-
m-relay
<kayabanerve:matrix.org> jeffro256:
-
m-relay
<kayabanerve:matrix.org> Prove the key image in the FCMP. This is feasible. We don't do it because HWWs are small _and_ we need backwards compatibility.
-
m-relay
<kayabanerve:matrix.org> Build a sparse merkle tree of all key images on-chain, which offers exclusion proofs.
-
m-relay
<kayabanerve:matrix.org> Prove each key image isn't in the sparse tree.
-
m-relay
<kayabanerve:matrix.org> Prove each key image is distinct. This is O(n), or O(n**2) naïvely.
-
m-relay
<kayabanerve:matrix.org> The most difficult part is we'd need to prove the key image, which also requires a proof of the opening of the xG term. This requires the private spend key go hot for the reserve proof OR
-
m-relay
<kayabanerve:matrix.org> The private spend key does a Schnorr signature.
-
m-relay
<kayabanerve:matrix.org> Said signature is verified inside the reserve proof's BP.
-
m-relay
<kayabanerve:matrix.org> That requires implementing a hash fn inside the BP _OR_
-
m-relay
<kayabanerve:matrix.org> It requires an arithmetic hash, as seen with Ed25519 -> Selene <-> Helios, but in a distinct path: Ed25519 -> X -> Ed25519
-
m-relay
<kayabanerve:matrix.org> Proving key images are distinct can be done proving they're sorted, which isn't a pleasant gadget to write, but allows comparing (0, 1), then (1, 2), while never comparing (0, 2).
-
m-relay
<kayabanerve:matrix.org> So:
-
m-relay
<kayabanerve:matrix.org> Sparse Merkle Tree of Key Images
-
m-relay
<kayabanerve:matrix.org> Exclusion proofs
-
m-relay
<kayabanerve:matrix.org> Sorted
-
m-relay
<kayabanerve:matrix.org> Require a hot wallet
-
m-relay
<kayabanerve:matrix.org> OR
-
m-relay
<kayabanerve:matrix.org> Verify Schnorr signatures in-proof to assert the view key term is correctly defined
-
m-relay
<kayabanerve:matrix.org> OR
-
m-relay
<kayabanerve:matrix.org> Compose with a Schnorr signature externally, as we currently do, which somehow does that despite not _proving_ the key image itself.
-
m-relay
<kayabanerve:matrix.org> ... that's actually feasible. Just transform from xG yT to xG rZ and require an opening over G, Z. Either the y term was correctly defined, and the key image is valid, or the additional proof will fail.
-
m-relay
<kayabanerve:matrix.org> That only reveals the amount of outputs, but you could pad it to defend there.
-
m-relay
<kayabanerve:matrix.org> *transform from xG yT to yT rZ and require an opening over T, Z
-
m-relay
<kayabanerve:matrix.org> This, of course, only works for new wallets as it requires `x` in BP, unless one accepts that.
-
m-relay
<kayabanerve:matrix.org> TL;DR it's an additional tree and either O(n**2) complexity or a new annoying gadget which achieves O(n) complexity, and it only works for new wallets unless you accept loading the private spend key into the BP.
-
m-relay
<jeffro256:monero.social> Yikes :). I think I understand the O(N^2) approach, but why does that need a sparse tree ? (N is the number of on-chain key images, correct?)
-
m-relay
<kayabanerve:matrix.org> The N^2 approach is for the amount of outputs proven in reserves, where you prove there aren't duplicated by comparing each output to every other.
-
m-relay
<kayabanerve:matrix.org> The additional tree is for an sparse merkle tree of all key images on-chain to prove the n key images for your n outputs haven't appeared on-chain.
-
m-relay
<kayabanerve:matrix.org> It's of n log(k) complexity, where k is the amount of key images on-chain.
-
m-relay
<kayabanerve:matrix.org> The O(n) approach for outputs is to prove each next output is greater than the prior, therefore proving they're distinct.
-
m-relay
<kayabanerve:matrix.org> That's annoying as it requires a bit decomposition. Ordinality isn't a property inherently exposed via field arithmetic.