I’m truly sorry to have disappeared without giving notice. I’ve been dealing with personal issues that have consumed much of my time.
I have made good progress on this task, though. It was identified by phyro that my initial API allowed collusion between the initial and final nodes. I went back to the drawing board and came up with a new API.
The current draft of the API now just requires
ephemeral_key: secp::PublicKey
hmac: hmac::Hmac<Sha512>
commitment: secp::Commitment
payloads: Vec<EncPayload>
where EncPayload is a byte array that, once decrypted, contains the excess and either the routing_info for the next node or the rangeproof if the payload is for the final node.
After each hop, the current node will unwrap each payload, transform the commitment, ephemeral_key, and hmac, then forward the remaining payloads onto the next node.
I actually had to code this new API and the onion encryption components to convince myself that it worked. So I do have some working code that is nearly ready to share. It’s the language I had the least experience with, but since the community consensus was that Rust would be the easiest to support, that’s what I chose to use.
I’ll write up the API more formally and clean up the code this week. As soon as it’s ready, I’ll share links to everything here. Once again, I’m truly sorry for the lack of communication. I’ll do better.
That’s not the onion encryption that the design calls for.
The payload for node i should be encrypted so only node i can decrypt it, which should result in the data for node i + the payload for node i+1.
With your vector of payloads, the first and last nodes could collude to correlate their data.
Given 3 nodes n1, n2, and n3, each with known pubkeys n1.K = n1.k*G, n2.K = n2.k*g, and n3.K = n3.k*G, the caller provides
* ephemeral_key: The initial ephemeral pubkey, R1
* commitment: The real input commitment C0
* payloads:
1. E1(p1)
2. E1(E2(p2))
3. E1(E2(E3(p3)))
n1 then computes shared secret s1 = ECDH(n1.k, R1). Using s1, the node decrypts the 3 payloads to get p1, E2(p2), and E2(E3(p3)). It reads the excess x1 from p1.
It seems like you have n*(n+1)/2 decryptions in total which is of order n^2 instead of exactly n. Couldn’t n1 decrypt only the 3rd option and get p1 along with the next encrypted message? The encrypted payload would need a recursive form:
It doesn’t actually involve more decryption. It’s a stream cipher, so whether we perform the decryption on the whole chunk at once, or decrypt each payload individually, the same amount of processing is required. You can think of the payloads as being one contiguous block of data instead of separate blocks in a list, and you’ll see that, in practice, it’s exactly the same as what you’re proposing.
The commitment should not be separate, but there should be one in every payload, so the node knows which excess to apply to which commitment. This looks like a major oversight.
Ok, so that is essentially equivalent to using the intended
Each node receives a sorted column, not knowing the i indices shown,
transforms each commitment by some excess specified for that commitment,
sorts the results, and passes on the new column to the next node.
To prevent correlations, node j must not know which commitment belongs to which user. That’s why the payloads are permuted by each node.
It’s a little worrying that you missed the essence of the design:-(
If there’s any aspect of the coinswap protocol that’s not entirely clear to you, then please ask for clarification, so we don’t have such misunderstandings.
Node j still won’t. For each i, a Ci,j-1 is computed by node j-1. The tuples (Ci,j-1, payloadsi,j) are then sorted by commitment (Ci,j-1), and the sorted matrix of tuples is then sent to node j. Node j+1 wouldn’t see Ci,j-1.
The design is clear to me. I believe we’re just speaking on different wavelengths . I’ll finish writing the RPC layer and then take a break to more formally document the flow of data. That should clear up any misunderstandings.
I’m sorry for mistaking your deviation from the proposal as a misunderstanding. I now see that it’s a useful optimization.
My apologies, and good job on spotting the redundancy!
Milestone 1 is just about complete. I just have a bit of error handling left and some documentation to write. If someone could create a mwixnet repo in the mimblewimble github org, I’ll be able to create a pull request for everyone to review.
First I need to familiarize myself with the protocol we are trying to implement. Is Mimblewimble CoinSwap proposal the completed specification or is there an updated one somewhere else?
communicates with a GRIN node’s API using jsonrpc calls
validates input signatures using the new Commitment Signature scheme
verifies input commitments are in the UTXO set
executes round every DAY_HEIGHT (1440) blocks
verifies generated output commitments are not in the UTXO set
builds the kernel and assembles the transaction
submits the transaction to the node
For milestone 2, I still need to
add reorg support
improve fee handling & wallet support (could fall under milestone 3)
add better e2e tests
Trying to add support for handling reorgs efficiently has been the main challenge so far. I’m getting frustrated by the lack of progress, so may skip this and come back to it after the rest of milestone 2 is finished and merged.
My original time estimates were apparently too optimistic. Estimating software is hard. But don’t worry, I’m not going anywhere. I’ll try to give more frequent updates so everyone knows I’m still here.