zcash / zcash

Zcash - Internet Money
https://z.cash/
Other
4.93k stars 2.04k forks source link

Payment Offloading protocol for light wallets. #1113

Open nathan-at-least opened 8 years ago

nathan-at-least commented 8 years ago

Suppose a wallet does not have the compute resources or implementation to generate proofs, but wants to delegate those to a third-party service. What are some protocol options to enable this? There are important privacy/security/usability trade-offs.

Rationale: Many existing wallets in Bitcoin land are SPV-ish and rely on a third party to track a blockchain and deliver transactions, while the wallet itself holds private keys. We want to enable the same kind of wallet architecture, although that architecture may have fundamental privacy limitations.

amiller commented 8 years ago

We made some notes about possible approaches in this document: https://docs.google.com/document/d/1gF3_BTP7IwoLOIXoxDxAK1AEdY5QPVL0dXf4EQef3p0

daira commented 8 years ago

An advantage of approach 6 in that document is that it's also applicable to the case where you have a hardware wallet holding spending keys, and your computer may have malware or may be surveiled.

nathan-at-least commented 7 years ago

I believe there's a much easier sweet spot than the google doc brainstorm contains, which I've sketched over in https://github.com/zcash/zips/issues/104 .

str4d commented 7 years ago

In one of our recent topical meetings, we discussed this and decided that @nathan-at-least's DPT case was so close to "DPZ with server controlling keys" that they may as well both be supported by the same wire protocol.

The next step AIUI is to create a PoC:

str4d commented 7 years ago

2120 introduces a JSProofWitness (probably needs a better name), which encapsulates the data sent from the client to the proving service. Currently it just wraps the parameters to joinsplit_gadget<FieldT, NumInputs, NumOutputs>::generate_r1cs_witness.

The next step is to figure out how to reduce the amount of information sent across the wire to exactly what is necessary. @ebfull I expect this will require altering the generate_r1cs_witness API.

str4d commented 7 years ago

Currently serialized in JSProofWitness:

Check boxes mark what is absolutely necessary for the client to send to the proving service.

daira commented 7 years ago

I believe we should only be serializing Merkle authentication paths, not incremental witnesses.

str4d commented 7 years ago

@daira and I discussed this in a pairing.

daira commented 7 years ago

Note that if a proving service enforces that it is paid at the start of a chain, then technically this leaks a small amount of information to payment recipients: if their payment is in the first JoinSplit of a chain, then they know that the sender did not use such a service.

nathan-at-least commented 7 years ago

For 1.0.8, let's move the proof-of-concept server into our release, behind an optional build config, then let's add the proof-of-concept dummy client as a new CI test step.

daira commented 7 years ago

Here's my best proposal for DP-Z in Sapling: https://github.com/zcash/zcash/issues/2171#issuecomment-285963483

str4d commented 7 years ago

I now have a working proof-of-concept for delegated proving with a JavaScript client:

var zcash = require('bitcoinjs-lib')

var tx = new zcash.TransactionBuilder()

tx.addInput('aa94ab02c182214f090e99a0d57021caffd0f195a81c24602b1028b130b63e31', 0)
tx.addShieldedOutput('zcWsmqT4X2V4jgxbgiCzyrAfRT1vi1F4sn7M5Pkh66izzw8Uk7LBGAH3DtcSMJeUb2pi3W4SQF8LMKkU2cUuVP68yAGcomL', 5)
tx.addShieldedOutput('zcWsmqT4X2V4jgxbgiCzyrAfRT1vi1F4sn7M5Pkh66izzw8Uk7LBGAH3DtcSMJeUb2pi3W4SQF8LMKkU2cUuVP68yAGcomL', 10, 'Some memo field')
tx.addShieldedOutput('zcWsmqT4X2V4jgxbgiCzyrAfRT1vi1F4sn7M5Pkh66izzw8Uk7LBGAH3DtcSMJeUb2pi3W4SQF8LMKkU2cUuVP68yAGcomL', 15)
tx.setAnchor('241ed94a72ddb67efb4c9e491090400a29f2d2707ec63d8e2f56a82150349608')

console.log('Getting proofs for transaction…')
try {
  tx.getProofs('tcp://localhost:5555', function () {
    console.log('Done!')
  })
} catch (error) {
  console.log(error)
}

It uses this branch of my bitcoinjs-lib fork (which I have been rebasing often, so don't expect it to remain stable). The branch is NOT production-ready.

nathan-at-least commented 7 years ago

Big new features are postponed out of 1.0.9 which is focusing on safety, stability, and security.

str4d commented 7 years ago

Here is v2 of my proof-of-concept for delegated proving with a JavaScript client:

var zcash = require('bitcoinjs-lib')

var txb = new zcash.TransactionBuilder()

txb.tx.version = 2
txb.addInput(
  'aa94ab02c182214f090e99a0d57021caffd0f195a81c24602b1028b130b63e31', 0, null,
  zcash.script.fromASM('0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 OP_CHECKSIG'))
txb.addShieldedOutput('zcWsmqT4X2V4jgxbgiCzyrAfRT1vi1F4sn7M5Pkh66izzw8Uk7LBGAH3DtcSMJeUb2pi3W4SQF8LMKkU2cUuVP68yAGcomL', 5)
txb.addShieldedOutput('zcWsmqT4X2V4jgxbgiCzyrAfRT1vi1F4sn7M5Pkh66izzw8Uk7LBGAH3DtcSMJeUb2pi3W4SQF8LMKkU2cUuVP68yAGcomL', 10, 'Some memo field')
txb.addShieldedOutput('zcWsmqT4X2V4jgxbgiCzyrAfRT1vi1F4sn7M5Pkh66izzw8Uk7LBGAH3DtcSMJeUb2pi3W4SQF8LMKkU2cUuVP68yAGcomL', 15)
txb.setAnchor('241ed94a72ddb67efb4c9e491090400a29f2d2707ec63d8e2f56a82150349608')

console.log('Getting proofs for transaction…')
try {
  txb.getProofs('tcp://localhost:5555', function () {
    var keyPair = zcash.ECPair.fromWIF('KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn')
    txb.sign(0, keyPair, null, null)
    txb.signShielded()
    var tx = txb.build()
    console.log('Done!')
  })
} catch (error) {
  console.log(error)
}

It uses this new branch of my bitcoinjs-lib fork, which depends on zcash/zcash-primitives-js#1. The branches are NOT production-ready (though closer than before).

prusnak commented 7 years ago

I liked the older example, because it did not need to use the private key (making it really obvious that delegated prover does not need to know the privkey).

Is this really required using the new API?

str4d commented 7 years ago

@prusnak ah, maybe it isn't clear: my PoC is for how the client side works. In particular, the private key visible in v2 is for signing the transparent input; it has nothing to do with the delegated prover, but is necessary to have a more complete PoC that generates valid signed transactions (which the older PoC did not do, simply because I hadn't implemented it yet).

As it happens, the underlying payment offloading protocol does require the proving service to know your private shielded spending keys (they are sent over the wire in the request). For the t -> z case we are primarily working on here, the spending keys are dummy keys (because the inputs are dummy notes), so there is no risk of the server re-directing the funds (because the transparent private key in the v2 POC above never leaves the client). However, for the z -> z case, there is that risk, which is why I am not adding that support to the client library (though it may be useful for e.g. mining pools that want to offload their proof generation to a different server). Removing the need for a delegated prover to posses the spending keys is one of the goals for Sapling.