Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

payment disclosure #2036

Open
nathan-at-least opened this issue Jan 23, 2017 · 43 comments
Open

payment disclosure #2036

nathan-at-least opened this issue Jan 23, 2017 · 43 comments
Labels
External Encoding F-memo-field Feature: Memo field F-selective-disclosure Feature: Selective disclosure of shielded transaction details. special to Zooko

Comments

@nathan-at-least
Copy link
Contributor

nathan-at-least commented Jan 23, 2017

Ticket #737 has a broader scope that allows changes to the protocol to implement a strong proof-of-payment protocol. This ticket is about a much more limited feature that can be implemented with the current protocol.

@nathan-at-least nathan-at-least added the F-selective-disclosure Feature: Selective disclosure of shielded transaction details. label Jan 23, 2017
@nathan-at-least nathan-at-least changed the title bilateral-only "proof" of payment that's compatible w/ current protocol payment disclosure Jan 23, 2017
@zmanian
Copy link

zmanian commented Jan 24, 2017

What if instead of revealing ephemeral secret key, you did a XEDDSA signature with the Esk of (jsouput, recipient address, challenge)? https://whispersystems.org/docs/specifications/xeddsa/#xeddsa

This solves your replayability problem inside the proof?

@arielgabizon
Copy link
Contributor

Maybe.. I'm slightly confused about what we need to defend against.
If it's a replay attack where some time later after I have sent my proof of payment, someone else replays that proof..can't the receiver just assume whomever sent the proof was the first time is the legitimate payment sender?
On the other hand, if it's a man-in-the-middle attack where someone is online between sender and receiver, he could still show that he payed even when there's an interactive signing challenge.
But I wonder, if for a first implementation, it's enough to just have what @nathan-at-least suggested above, and have the receiver assume whomever sent the proof of payment first is the legitimate one.

@zookozcash
Copy link

zookozcash commented Jan 26, 2017

@arielgabizon: a good defense against those sorts of replay/MITM attacks is to include identifiers (e.g. public keys or addresses) of the prover and the verifier into the proof.

In this case, it might not be the identifier (address) of the original address that paid, but instead a "reply/receipt/refund address", chosen by the prover (the original payer). The verifier would know that the proof proves not that whoever emailed him the proof paid, but that the person who controls the included refund address paid.

@arielgabizon
Copy link
Contributor

arielgabizon commented Jan 26, 2017

That's a nice idea. It can partially be implemented just with the memo field. Though a payer would have to know in advance he'll want to do such a proof of payment later so that he would include this receipt in the encrypted memo. Though still I'm wondering in practice, how bad it would be if the receiver would just assume the first person to send him the proof of payment is the real sender

@daira
Copy link
Contributor

daira commented Jan 26, 2017

@arielgabizon wrote:

On the other hand, if it's a man-in-the-middle attack where someone is online between sender and receiver, he could still show that he payed even when there's an interactive signing challenge.

If you have a secure channel with a purported (potentially anonymous) sender, and they perform an interactive proof with you over that channel, then you know that subsequent communications on the channel are with the actual sender (or someone who knows the sender's secrets).

@jackgavigan
Copy link
Contributor

@nathan-at-least wrote:

A 'payment disclosure' includes: (jsoutput, recipient address (pk_enc, a_pk), ephemeral secret key)

Am I correct in thinking that the 'payment disclosure' consists of data that the Recipient will possess, so therefore a 'payment disclosure' can be created and shared by either the Sender or the Recipient?

@daira
Copy link
Contributor

daira commented Jan 30, 2017

@jackgavigan The recipient doesn't initially know the ephemeral secret key (esk). It does know its own viewing key skenc which would be sufficient to decrypt the ciphertext, but that is also sufficient to decrypt all other ciphertexts sent to the recipient address.

@bitcartel
Copy link
Contributor

Could the following help increase the level of confidence that a presenter of the payment disclosure is indeed the sender (where the sender did not include anything in the memo field) ?

  • Sender retains the ephemeral JoinSplitSig Private Key.
  • Sender uses this private key to sign a payment disclosure / refund address / message.
  • Recipient verifies signed data using the JoinSplitSig Public Key.

@daira
Copy link
Contributor

daira commented Feb 24, 2017

There's a problem I hadn't thought of (documented in the draft zip here): in some cases (such as for t -> multiple z transactions), both outputs of each JoinSplit will be used as non-change outputs. In that case the "KDF Tweak" approach won't work, because that relies on the sender of a change output knowing skenc.

There are several possible resolutions:

  1. Make sure that each JoinSplit has at most one non-change output, at the expense of doubling the number of JoinSplits in the problematic case. E.g. for a transaction sending transparent input to two z-addresses, now two JoinSplits are needed instead of one.
  2. Only reveal the symmetric key Kenci (which is different for each output). The verifier decrypts and checks the commitment cmnewi. This has the disadvantage that it is possible to provide a "valid" proof of payment, even though the recipient could not have decrypted the payment: The attacker does this by creating a transaction in which the shared secret - out of which Kenci will be computed - is generated from recipient's public address together with e'sk not corresponding to the published epk; thus, the recipient will not manage to decrypt this note while scanning the blockchain. Note that the attacker needs to burn money to carry this out.
  3. A payment disclosure contains the inputs to the KDF, i.e. (i, hSig, sharedSecreti, epk, pknewenc,i), and a proof (e.g. Chaum-Pedersen) that (g, epk, pknewenc,i, sharedSecreti) is a DH tuple. Note that to avoid an information leak, we need that pknewenc,0 and pknewenc,1 are distinct (because if they are equal, then sharedSecret0 = sharedSecret1). But it is easy to avoid this case.

(edited by Ariel)

@bitcartel
Copy link
Contributor

bitcartel commented Feb 24, 2017

In 2. an independent judge/arbiter would require the recipient to provide a viewing key, if the recipient continues to claim they did not receive funds. So there could be a situation where an attacker burns funds, opens a dispute and provides a "valid" proof of payment, where the intent is to get the recipient to reveal their viewing key.

@daira
Copy link
Contributor

daira commented Feb 24, 2017

Actually in case 2., revealing Kenci would then allow the recipient to spend the funds (provided that the commitment is correct). So the issue is that the recipient would not previously have been able to spend them, and the payment might have been time-sensitive.

@daira
Copy link
Contributor

daira commented Feb 24, 2017

Here's the original paper on Chaum-Pedersen: http://www.cs.elte.hu/~rfid/chaum_pedersen.pdf (see section 3.2). It adapts straightforwardly to Curve25519.

It's presented as a signature scheme, but one that is constructed from a proof-of-DH-tuple. There are other possible ways to prove a DH tuple based on pairings, but Curve25519 isn't pairing-friendly.

@daira
Copy link
Contributor

daira commented Feb 24, 2017

A possible refinement of 3. is to use a Chaum-Pedersen signature to sign the information that should be nonmalleable (e.g. refund address). This is similar to @zmanian's idea of using XEdDSA.

Edit: it is easier-said-than-done to combine the proof-of-DH-tuple with a signature. A single instance of Chaum-Pedersen won't do it because the group element that depends on the message representative (z in the Chaum-Pedersen paper) is different than the ones (epk and pknewenc,i) involved in the proof that the note encryption was done correctly.

@zmanian
Copy link

zmanian commented Feb 25, 2017

Mike Hamburg has an x25519 signatures scheme in Strobe.
https://www.reddit.com/r/crypto/comments/5u7i3z/signature_with_a_montgomery_curve/ddu8or0/?context=3 See @Bascule's comment and Mike's response

@daira
Copy link
Contributor

daira commented Feb 25, 2017

In #1360 (comment) I point out that using both outputs of a JoinSplit entails an information leak. So there is a privacy-performance trade-off which, if we resolved it in favour of privacy at the cost of sometimes using more JoinSplits, would also allow us to use the simpler KDF Tweak approach (#2102) for payment disclosures.

@daira
Copy link
Contributor

daira commented Feb 25, 2017

In the next circuit change, we can eliminate this privacy-performance tension by implementing #647, as I pointed out in #647 (comment) .

@daira
Copy link
Contributor

daira commented Feb 25, 2017

I think we should exclude using an unconventional signature scheme. We have the joinSplitSig private Ed25519 key available to sign the associated nonmalleable information. Ed25519 is pleasantly boring, and this means we do not have to consider the joint security of the note encryption and the disclosure protocol with the same keys. (It is straightforward to ensure that inputs to the Ed25519 signature scheme for the disclosure protocol are not valid as dataToBeSigned for JoinSplit signatures, and vice versa.)

@nathan-at-least
Copy link
Contributor Author

Let's implement the new multi-joinsplit algorithm as an opt-in 'experimental feature', and point out it has better privacy and worse performance in the specific cases of many recipients (and many input notes). Then we'll get feedback from the wild-and-wooly about this.

@daira
Copy link
Contributor

daira commented Feb 28, 2017

The worse performance is only when there are many output notes (and fewer than twice as many input notes than output notes). The better privacy is whenever either vpubin or vpubout is nonzero.

@arielgabizon
Copy link
Contributor

arielgabizon commented Feb 28, 2017

@nathan-at-least - Not sure why you posted this here. Does that mean we implement payment disclosure only after implementing new multi-joinsplit?
Can someone link here to a description of this new multi join-split algorithm?

@daira
Copy link
Contributor

daira commented Mar 24, 2017

@bitcartel wrote:

Could the following help increase the level of confidence that a presenter of the payment disclosure is indeed the sender (where the sender did not include anything in the memo field) ?

  • Sender retains the ephemeral JoinSplitSig Private Key.
  • Sender uses this private key to sign a payment disclosure / refund address / message.
  • Recipient verifies signed data using the JoinSplitSig Public Key.

Yes, that's what I suggested in #737 (comment) . @nathan-at-least opened this ticket to be for something simpler. However I think we'll end up adding a signature, just not in the initial implementation.

@bitcartel
Copy link
Contributor

bitcartel commented Apr 24, 2017

@daira et al remind me.. why can't we simply retain a record of the symmetric key used for each call to crypto_aead_chacha20poly1305_ietf_encrypt? In JoinSplit.cpp we use the same encryptor object for both note outputs, where for each output, the nonce input to the KDF is incremented in NoteEncryption::encrypt. The resulting symmetric key is different for each note output.

Edit: To (perhaps) answer my own question, with esk if a non-authorized party were to obtain a copy of the payment disclosure, they would still need to know the recipient's payment address in order to get pk_enc needed for decrypting the cipher text. In which case, it would be preferable to what I just wrote above.

@daira
Copy link
Contributor

daira commented Apr 24, 2017

Only recording the secret key would not be sufficient information to prove that the recipient could have decrypted the note ciphertext from the block chain.

I was thinking that the payment disclosure would include pkenc, because it's supposed to be a proof that a given address received a payment, which necessarily reveals the address.

@bitcartel
Copy link
Contributor

Wouldn't an arbitrator need the full payment address, rather than just pkenc ?

@daira
Copy link
Contributor

daira commented Apr 25, 2017

Given esk, pkenc, and the transaction visible on the block chain they can decrypt apk, they don't need to be given it explicitly. (If they were given it then they would still have to check it against the decrypted version.)

Edit: if we have multiple kinds of z-addresses in future, there could in general be information in an address, beside the encryption public key, that isn't in the commitment. Technically this is already the case because the commitment doesn't include whether it is a mainnet or testnet z-address. So the payment disclosure does need to include such information.

@nathan-at-least nathan-at-least removed this from the 1.0.9 milestone May 10, 2017
@nathan-at-least
Copy link
Contributor Author

Bumped out of 1.0.9 which is focused on stabilization rather than big new features.

@bitcartel
Copy link
Contributor

bitcartel commented May 23, 2017

@daira So to clarify, the payment disclosure should include the recipient's shielded payment address.
This would allow the recipient to verify that the payment disclosure belongs to / is relevant to them (since they have the spending key in their wallet for that payment address). It also means that any person looking to validate the payment disclosure would have apk and pkenc, where pkenc is required for decrypting the ciphertext.

@tromer
Copy link
Contributor

tromer commented Sep 15, 2017

Is the payment disclosure supposed to convince a third party that doesn't trust the recipient (as implied in https://github.com/zcash/zips/pull/119/files)?

I think the current protocol doesn't achieve that: the sender and receipient can collude to lie to a third party. For example, suppose they want to hide the fact that they've transferring 100000000 zatoshis. They agree OOB on a note plaintext with v=100000000, but in the broadcast transaction the sender puts a ciphertext which is the encryption of a fake note plaintext with v=3. JoinSplit verification still passes (it never uses the note ciphertexts). And if they produce a payment disclosure using the fake note, the 3rd party verifier will accept it since it matches the ciphertext on the blockchain.

@tromer
Copy link
Contributor

tromer commented Sep 15, 2017

Another attack on the ZIP's protocol, again exploiting inconsistency between ciphertext and JoinSplit:

The sender broadcasts a JoinSplit creating a low-value note, but attaches a ciphertext which is the encryption of a note plaintext claiming high value. He can then claim that he sent a high-value note, and present a payment disclosure that passes verification. But the recipient never received a high-value note, and the sender never nullified one.

@daira
Copy link
Contributor

daira commented Sep 15, 2017

Yes, I believe that payment disclosure proofs that are robust against collusion between the sender and recipient will only be possible with Sapling.

(In the current proposal on #2277, the correctness of epk and the note commitment, which contains esk, are both checked by the circuit, and so even though the correctness of the symmetric encryption isn't directly checked, it must be the case that either the note ciphertext is correct or the payment proof verifier can detect that it is not.)

@tromer
Copy link
Contributor

tromer commented Sep 15, 2017

@daira, the attack in #2036 (comment) doesn't require collusion.

In any case, the ZIP must be clearer about the claimed security properties of the protocol.

@daira
Copy link
Contributor

daira commented Sep 16, 2017

I don't think that attack works: the note commitment revealed by the JoinSplit won't match the one computed from the decrypted note plaintext.

@tromer
Copy link
Contributor

tromer commented Sep 18, 2017

The ZIP is ambiguous on what check is done (see https://github.com/zcash/zips/pull/119/files#r139325414), and the implementation PR does not verify the note commitment (https://github.com/zcash/zcash/pull/2159/files#r139326256).

@tromer
Copy link
Contributor

tromer commented Nov 21, 2017

Can the receiver of a transaction generate a payment disclosure, that will convince a third party?
The ZIP (https://github.com/zcash/zips/pull/119/files) and doc (https://github.com/zcash/zcash/blob/master/doc/payment-disclosure.md) are both silent/ambiguous about this point.

@daira
Copy link
Contributor

daira commented Nov 23, 2017

Not on their own, because they don't have the JoinSplit signature private key. I agree that the ZIP should say this explicitly. Note that anyone can replay a payment disclosure, but only with a message that was signed by a holder of the JoinSplit signature private key. So it is possible to do an interactive proof of payment by requiring a fresh nonce to be included in the message.

@nathan-at-least nathan-at-least added the F-memo-field Feature: Memo field label Feb 6, 2018
@tromer
Copy link
Contributor

tromer commented Nov 25, 2019

This issue is out of date. Sapling changed the underlying protocol, and does not specify any form of payment disclosures yet.

Meanwhile, another feature to consider is: can payment disclosures be used to detect when the note is spent? The spec should say explicitly say either that yes (and specify how, and guarantee completeness and soundness), or no (and guarantee privacy).

@tromer
Copy link
Contributor

tromer commented Nov 25, 2019

Two variants are sketched by @str4d here.

Everything said in zcash/zips#292 applies here too: we need to carefully define, prove and communicate the security properties of the chosen protocol.

@daira daira added this to the Selective disclosure milestone May 4, 2024
@daira
Copy link
Contributor

daira commented May 4, 2024

I'm marking this as blocking zcash/zips#387 because we should go through the discussion and decide whether any of it is relevant to ZIP 311.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
External Encoding F-memo-field Feature: Memo field F-selective-disclosure Feature: Selective disclosure of shielded transaction details. special to Zooko
Projects
None yet
Development

No branches or pull requests

8 participants