17:00:02 Meeting in 1 hour 18:00:03 Meeting time. Hello! https://github.com/monero-project/meta/issues/1319 18:00:27 *waves* 18:00:31 hello and happy new year 18:00:59 Good, some people are still here, not everybody exit-scammed with the turn of the year :) 18:01:10 Likewise, happy new year 18:01:22 happy new year :) 18:02:01 Happy new year all 18:03:09 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: https://github.com/monero-project/monero/pull/10233/ 18:03:21 Overall, looks pretty good, I would say 18:03:29 Howdy 18:03:32 hi 18:03:40 Happy New Year! 18:03:42 thanks to rbrunner and vtnerd I have lots of valuable review comments to work on 18:03:44 currently focusing on vtnerds review of #9464 / #10232 18:03:59 thank you guys for reviewing 18:04:53 Thanks for taking on that first review 18:05:27 Fun fact: With that merged, git blame will say for more than half of all CLI wallet code that it's from sneedlewoods :) 18:07:46 me: completed changes to tx relay v2 (https://github.com/0xFFFC0000/monero/pull/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 18:07:46 I then dug into a segfault https://github.com/seraphis-migration/monero/issues/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++ 18:09:39 Any more reports? 18:09:51 Me: I'm thinking about breaking the `wallet2` reserve proof API and I wanted to bring up the idea here. 18:10:33 You mean introduce a breaking change how that works? 18:11:43 I got lwsf to construct fcmp++ txes with a custom ZMQ function in monerod 18:12:02 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 't check chain state differences across reserve proofs 18:12:07 *custom rpc method. That rpc method is going to be tweaked such that it only accepts the new global output indexes 18:12:30 Sounds like a nice milestone reached, vtnerd 18:13:09 yes, hopefully the lwsf based wallets will not be left behind (couldn’t resist) 18:13:16 Lol 18:14:29 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? 18:14:34 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 proof with `waller2::check_reserve_proof()` . It would look like A and B hold reserves separately, but in reality, they are "double dipping" 18:15:11 Nice! 18:15:20 Yeah, seems to be working well enough 18:16:20 Hmm. Doesn't sending *any* funds *after* a reserve proof make that proof moot already? ELI5 :) 18:16:31 👋 18:16:43 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 18:17:35 Yes, exactly, but the API doesn't really have a way to handle this. 18:18:13 Which is why I think it merits breaking it 18:18:18 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. 18:18:20 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. 18:18:51 There is nothing like a "timestamp" in that proof? Like "done at this and this state of the blockchain, and/or the wallet"? 18:18:59 breaking something that's broken to fix it sounds good to me 18:19:18 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. 18:20:34 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. 18:20:35 You should trademark that expression, "bug-for-bug compatibility" 18:20:43 Nothing breaking, just very stupid edge cases. 18:21:51 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. https://moneroresearch.info/266 18:22:04 Or the one before that 18:22:31 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. 18:22:32 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. 18:22:34 Seems to be a constant: "There is always a paper" :) 18:22:52 every observable effect of a system, even if unintentional, will become someone's requirement for the behavior of the system 18:23:09 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 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 18:24:21 Regular MProve https://moneroresearch.info/256 and MProve+ exist too https://moneroresearch.info/35 18:24:34 rbrunner7: So it's actually three papers :P 18:24:43 Ok ok 18:25:10 Disclaimer: I wrote a new type of reserve proofs which use FCMP++ to get full-chain privacy ;) 18:25:23 That would also cause a breaking of the API 18:25:35 The only instance of a Monero reserve proof I have seen was a wrapped coin implementation IIRC. 18:25:39 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? 18:26:19 *like to make them more popular 18:27:04 IIRC, Thakore & Vijayakumaran (2025) uses an auxiliary Merkle tree to get "full privacy" with RingCT. 18:27:42 So the 3 proofs in the 3 papers may not translate cleanly to FCMP++? 18:27:56 https://xkcd.com/1172/ as my final comment on wallet2 bs as reported on above :p 18:28:05 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 18:28:51 jeffro256: The FCMP codebase is obviously internally modular, so you should be able to run with it :) 18:29:36 kayabanerve: That's a good XKCD. Classic 18:30:19 Isn't "amount privacy" a bit difficult with a proof of reserves? 18:31:29 Or do you mean that not only the sum, but the individual enotes become known? 18:31:47 The idea is you prove reserves equal to or in excess of, without revealing the exact outputs. 18:32:43 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. 18:33:53 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? 18:35:34 But hey, do they work with FCMP++ at all, as they are now, or are we *forced* to move? 18:36:25 The way I currently have written the new ones reveals the key image , just not the input output pubkey -> key image associations 18:37:13 For simplicity and so that provers don't have to remake reserve proofs every block 18:38:52 Validating would work , but only on pre-FCMP++ outputs 18:39:08 So yeah we are effectively forced to update anyways 18:39:28 But the wallet2 API itself would also have to change 18:40:51 Well, if our hands are forced, that's just living with and developping for a currency that moves forward with a high speed 18:42:34 Did you already actually implement your new proof, jeffro256? 18:43:46 Cryptographically, yes. Haven't integrated it yet b/c of the API issue 18:44:04 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 18:44:41 considering the break is isolated to just the reserve proof API 18:44:55 I tend to agree 18:45:19 jeffro256: Why do you hate privacy and why do you want to break a critical part of the Monero ecosystem, with 0-5 users? 18:45:51 Your solution should either be perfectly private, and post-quantum, and backwards-compatible, or I don't actually think you support Monero 18:46:13 Suuure 18:46:15 /s :p 18:46:16 It sounds like the reserve proof should be _versioned_ but yes, new protocol, new proof, and the rest sounds straightforward from there. 18:46:49 I don't support publishing key images (by far), but that's the hardest problem _and_ it's fine in a post-FCMP++ world. 18:47:00 sorry my bad i will also integrate a proof of liabilities protocol next week 18:47:08 We seem to have now: 18:47:09 static constexpr char header_v1[] = "ReserveProofV1"; 18:47:10 static constexpr char header_v2[] = "ReserveProofV2"; // assumes same length as header_v1 18:47:39 Prove reserves, provw liabilities, why don't you prove you're not a federal agent? Huh? Huh??? 18:48:05 /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 ♥ 18:48:19 If not FEDs, certainly Mossad. I learned that today on Reddit. 18:49:08 So it seems we have loose consensus that a breaking wallet2 API change has merit, and is acceptable. 18:49:15 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 18:49:20 For reserve proofs. 18:51:00 Alright. Some additional topic that we have to discuss today? We are nearing the full hour, for once :) 18:52:34 Doesn't look like it. Nice meeting, good start into the new year. Thanks everybody for attending, read you again in 1 week! 18:52:40 Yeah spend proofs, tx proofs, and output decoding are pretty much unaffected and have a direct Carrot/FCMP++ analogues 18:53:20 Thanks everyone! 18:53:21 thanks everyone 18:57:14 Thanks everyone! 18:57:18 ^ so analogue I already added them to my libraries & block explorer, generation and verification (ready for beta stressnet!) 18:57:34 yay! Awesome to hear that 18:57:52 nice DataHoarder :) 18:58:37 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 ? 18:59:29 jeffro256: 18:59:30 Prove the key image in the FCMP. This is feasible. We don't do it because HWWs are small _and_ we need backwards compatibility. 18:59:32 Build a sparse merkle tree of all key images on-chain, which offers exclusion proofs. 18:59:34 Prove each key image isn't in the sparse tree. 18:59:36 Prove each key image is distinct. This is O(n), or O(n**2) naïvely. 19:02:11 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 19:02:12 The private spend key does a Schnorr signature. 19:02:14 Said signature is verified inside the reserve proof's BP. 19:02:16 That requires implementing a hash fn inside the BP _OR_ 19:02:18 It requires an arithmetic hash, as seen with Ed25519 -> Selene <-> Helios, but in a distinct path: Ed25519 -> X -> Ed25519 19:03:57 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). 19:06:47 So: 19:06:48 Sparse Merkle Tree of Key Images 19:06:50 Exclusion proofs 19:06:52 Sorted 19:06:54 Require a hot wallet 19:06:56 OR 19:06:58 Verify Schnorr signatures in-proof to assert the view key term is correctly defined 19:07:00 OR 19:07:02 Compose with a Schnorr signature externally, as we currently do, which somehow does that despite not _proving_ the key image itself. 19:07:04 ... 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. 19:07:06 That only reveals the amount of outputs, but you could pad it to defend there. 19:08:25 *transform from xG yT to yT rZ and require an opening over T, Z 19:08:26 This, of course, only works for new wallets as it requires `x` in BP, unless one accepts that. 19:09:58 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. 19:15:00 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?) 19:29:48 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. 19:30:12 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. 19:30:35 It's of n log(k) complexity, where k is the amount of key images on-chain. 19:31:09 The O(n) approach for outputs is to prove each next output is greater than the prior, therefore proving they're distinct. 19:31:47 That's annoying as it requires a bit decomposition. Ordinality isn't a property inherently exposed via field arithmetic.