Snooping attacks on joinmarket - mitigation ideas

in #bitcoin8 years ago

With the ongoing attack on Joinmarket privacy, the developers are discussing responses and will code and test once there is some agreement. These ideas are from

<h3>Basic background: <p dir="auto">See sequence of messages in canonical joinmarket in <p dir="auto"><span><a href="https://github.com/JoinMarket-Org/JoinMarket-Docs/blob/master/encryption_protocol.txt" target="_blank" rel="nofollow noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">https://github.com/JoinMarket-Org/JoinMarket-Docs/blob/master/encryption_protocol.txt <h3>Attack description: <p dir="auto"><span>See <a href="https://github.com/chris-belcher/joinmarket/issues/156" target="_blank" rel="nofollow noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">https://github.com/chris-belcher/joinmarket/issues/156. <h3>Requirements of a solution: <ol> <li>some cost imposed on gaining access to maker's utxos. <li>Allow joinmarket to remain usable without a lot of initial setup for the taker. <li>Allow it to be feasible to integrate at least taker (and ideally maker) functionality<br /> into an existing Bitcoin wallet software. <h3>Background on the current status: <p dir="auto">Maker's utxos are passed in the <code>!ioauth message<br /> (under E2E encryption with the taker), after the taker has sent one utxo pubkey, and a signature of his<br /> encryption pubkey with that btc pubkey (but note currently: the utxo is <em>not sent at this step, so the<br /> utxo's status is not queried by the maker at this step). <p dir="auto">The current design is an attempt to prevent trivial MITM attacks -<br /> since the maker will not sign transactions <em>not using a utxo which corresponds to the btc pubkey used for signing,<br /> it will not be possible for a MITM to receive btc signatures from a taker for the transaction.<br /> But the current design does <em>not prevent using a fictitious btc pubkey, with no attempt to to receive signatures,<br /> but only with the goal of receiving knowledge of the maker's current utxos. <h3>Defence #1 : Require taker to send the actual utxo to the maker, and prevent (too many) repeats. <p dir="auto">This allows the maker to check that the taker utxo is real before sending any information (his own utxos) to the taker<br /> (technically this is already possible, but computationally impractical). <p dir="auto">Further, the maker can keep a local database of already-used utxos and prevent re-use after a certain number<br /> of retries. Even further, additional limits can be placed on the utxo (the most obvious being the coin age).<br /> A simple implementation (briefly tested but still needs some work) can be found in <a href="https://github.com/chris-belcher/joinmarket/pull/328" target="_blank" rel="nofollow noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">this PR. <h3>Defence #2: Committing to a utxo in public/plaintext at the start of the handshake. <p dir="auto">An idea due to gmaxwell on how to do this: use ``proof of discrete log equivalence''. In brief:<br /> starting from an owned utxo U with keypair (pub=P, priv=x), using another basepoint on the curve J (as opposed<br /> to secp256k1's G), construct: P2 = x*J, and publish H(P2) (H=sha256, say). <p dir="auto">Thus <code>!fill becomes <pre><code>!fill <oid> <amount> <H(P2)> <p dir="auto">Once encryption is established, in !auth, append a zero knowledge proof that P2->J and P->G have<br /> the same discrete log (i.e. same secret key x). <ol> <li>Taker chooses a nonce value k <li>Taker computes K_G = k*G, K_J = k*J <li>Taker computes hash e= H(K_G || K_J || P || P2) <li>Taker computes signature s = k + x*e <p dir="auto">Taker then sends: <pre><code>!auth <P> <txid:N> <btc sig of encryption pubkey using P> <P2> <s> <e> <p dir="auto">Maker verifies in these steps, before revealing his own utxos: <ol> <li>Verify H(P2) = value previously committed in <code>!fill. <li>Check that H(P2) is not repeated (too often). <li>As in Defence #1, verify that utxo <code>txid:N is real, and check that P matches it. <li>Compute K_G = s*G - e*P <li>Compute K_J = s*J - e*P2 <li>Finally, verify that H(K_G || K_J || P || P2) = e. <p dir="auto">At this point, the maker has verified that the previously committed to utxo in the <code>!fill (with commitment H(P2))<br /> is the same as the one received in the auth, and that it is real, and that its private key is owned by the taker. <p dir="auto">(Notes: J will be have to be a NUMS, see Confidential Transactions for an example (can be reused here presumably).<br /> Also, note the brief description of this idea <a href="http://crypto.stackexchange.com/questions/15758/how-can-we-prove-that-two-discrete-logarithms-are-equal" target="_blank" rel="nofollow noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">here. <p dir="auto">This more complex procedure in Defence #2 compared with Defence #1 allows additional flexibility: if<br /> the commitment values H(P2) are publicised (they are in any case in the clear in this proposal, but not broadcast<br /> by default), then attempts to re-use utxos across makers may be blocked, but without sacrificing privacy for takers<br /> (since there is no way to derive H(P2) from P for those who don't know x - this would be the weakness if one just<br /> used H( P) instead). <h3>Defence #3 Pay-to-contract (hash). <p dir="auto">In this proposal, the taker is required to create a utxo specifically for the purpose of doing a transaction.<br /> The utxo is created in such a way that he can prove ownership, <em>and can prove that it was created specifically<br /> in connection with a certain 'message' (wich could be the hash of a contract), <em>and can still spend this output<br /> after it has been used for proof purposes. See some discussion <a href="https://bitcointalk.org/index.php?topic=318279.0" target="_blank" rel="nofollow noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">here. <p dir="auto">In the simplest iteration we would<br /> have this message be simply the amount of the proposed coinjoin. <p dir="auto">Taker follows these steps: <ol> <li><p dir="auto">Generates a new privkey=x, whose pubkey is P = x*G <li><p dir="auto">Constructs a derived spending key = x+H(P||m), and thus a derived spending pubkey Q = P + H(P||m)*G (m is the coinjoin amount) <li><p dir="auto">Constructs the bitcoin address of Q and spends amount A to Q, with utxo reference txid:N <li><p dir="auto">Sends new <code>!auth message as follows: <pre><code>!auth <input utxo> <btc sig of encryption pubkey> <P> <txid:N> <p dir="auto">Maker performs these checks, before revealing his own utxos: <ol> <li>Check that input utxo is real and check btc signature (as usual)<br /> (these parts are not part of Defence #3 but discussed at the start of this doc) <li>Construct Q = P + H(P||m)*G, and corresponding address. <li>Check that txid:N is real (utxo on the network), corresponds to Q and (optionally)<br /> check that A is an acceptable amount, (optionally) check that this transaction has confirmations. <li>Check Q against a list to disallow too many repeats. <h3>Final comments. <p dir="auto">The first element is outside any of the 3 proposals, which is just ensuring<br /> that the taker's initial utxo proposal is real by querying the blockchain.<br /> This seems clearly necessary and should have been done already. Defence #1 is just<br /> an addition / completion of that; checking repeats, and I believe should be done. <p dir="auto">W.r.t. Defence #2 and #3, I feel that #3 affects the workflow of the taker too much<br /> (see the comments at the start of the doc). #2 isn't hugely different from #1, but<br /> can require takers to commit early to utxos, and in public (while keeping privacy).<br /> I'm also interested to think about whether the mechanism in #2 can be applied to<br /> makers too (can they commit to utxos in public like this also?).