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 Offloading protocol for light wallets. #1113

Open
nathan-at-least opened this issue Jul 19, 2016 · 16 comments

Comments

@nathan-at-least
Copy link
Contributor

commented Jul 19, 2016

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

This comment has been minimized.

Copy link

commented Jul 19, 2016

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

@daira

This comment has been minimized.

Copy link
Contributor

commented Jul 19, 2016

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

This comment has been minimized.

Copy link
Contributor Author

commented Feb 6, 2017

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

@str4d

This comment has been minimized.

Copy link
Contributor

commented Feb 20, 2017

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:

  • Split the current asyncrpcoperation_sendmany.cpp code up into "transaction preparation / sending" and "proving".
  • Create a standalone binary containing the "proving" part + an RPC server.
  • Extend zcashd to optionally leverage this for proving instead of doing so internally (via a config flag).
@str4d

This comment has been minimized.

Copy link
Contributor

commented Feb 22, 2017

#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

This comment has been minimized.

Copy link
Contributor

commented Feb 22, 2017

Currently serialized in JSProofWitness:

  • uint252 phi
  • uint256 rt
  • uint256 h_sig
  • boost::array<JSInput, NumInputs> inputs
    • ZCIncrementalWitness witness
      • ZCIncrementalMerkleTree tree
        • boost::optional<uint256> left
        • boost::optional<uint256> right
        • std::vector<boost::optional<uint256>> parents
      • std::vector<uint256> filled
      • boost::optional<ZCIncrementalMerkleTree> cursor
        • boost::optional<uint256> left
        • boost::optional<uint256> right
        • std::vector<boost::optional<uint256>> parents
    • Note note
      • uint256 a_pk
      • uint64_t value
      • uint256 rho
      • uint256 r
    • SpendingKey key == uint252 - secret data for z -> *
  • boost::array<Note, NumOutputs> outputs
    • uint256 a_pk
    • uint64_t value
    • uint256 rho
    • uint256 r
  • uint64_t vpub_old
  • uint64_t vpub_new - zero for t -> z and z -> z

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

@daira

This comment has been minimized.

Copy link
Contributor

commented Feb 23, 2017

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

@str4d

This comment has been minimized.

Copy link
Contributor

commented Feb 24, 2017

@daira and I discussed this in a pairing.

  • Only API part that needs changing from above is IncrementalWitness -> MerklePath
    • Use a more efficient serialization for MerklePath than the Bitcoin system - @ebfull are they serialized anywhere yet?
  • There is no point in not supporting z->* trusting proving service with a_sks, because the savings in on-the-wire data (if client specifies all randomness) are insignificant (values for input notes, plus vpub_new).
  • Because the client provides h_sig instead of randomSeed and joinSplitPubKey, a malicious client could provide an h_sig not derived from the nullifiers and the proving service could not detect this, causing it to generate an invalid proof.
    • This is not a concern, because the client will most likely be paying per proof.
  • If the proving service has a relationship with the client (aside: has privacy implications), it can detect that the client has not paid it and refuse to provide any more service.
  • Proving service can get paid in two ways that don't compromise privacy:
    • Out-of-band (e.g. monthly payment)
    • As one of the JoinSplits
      • Therefore client needs to be able to send a list of JoinSplits to the proving service, so the service can detect it is being paid in an output Note (by inspecting a_pk and value).
        • This doesn't prevent the client from incorrectly encrypting the Note on the blockchain, but the proving service could just save that particular Note to ensure they can spend it in the face of invalid on-chain encryption.
      • Client could get proofs and then just not publish the one that pays the prover
      • But the proving service can always figure out which JoinSplits are chained
        • If has blockchain, can look up valid roots and then test chained ones
        • If no blockchain, can brute-force from MerklePath
      • So it can enforce via the API that it gets paid at the start of the chain.
@daira

This comment has been minimized.

Copy link
Contributor

commented Feb 24, 2017

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

This comment has been minimized.

Copy link
Contributor Author

commented Mar 6, 2017

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.

@nathan-at-least nathan-at-least added this to the 1.0.8 milestone Mar 6, 2017

@daira

This comment has been minimized.

Copy link
Contributor

commented Mar 12, 2017

Here's my best proposal for DP-Z in Sapling: #2171 (comment)

@daira daira modified the milestones: 1.0.9, 1.0.8 Mar 20, 2017

@str4d

This comment has been minimized.

Copy link
Contributor

commented Apr 12, 2017

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.

@daira daira moved this from Work Queue to Awaiting Review in Payment Offloading (Delegated Proving T) Apr 20, 2017

@nathan-at-least nathan-at-least removed this from the 1.0.9 milestone May 10, 2017

@nathan-at-least

This comment has been minimized.

Copy link
Contributor Author

commented May 10, 2017

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

@str4d

This comment has been minimized.

Copy link
Contributor

commented Jun 9, 2017

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-hackworks/zcash-primitives-js#1. The branches are NOT production-ready (though closer than before).

@prusnak

This comment has been minimized.

Copy link
Contributor

commented Jun 9, 2017

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

This comment has been minimized.

Copy link
Contributor

commented Jun 9, 2017

@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.

@daira daira added this to Discussion in Sapling Protocol Upgrade Jul 14, 2017

@nathan-at-least nathan-at-least changed the title Delegated Proving protocol for light wallets. Payment Offloading protocol for light wallets. Aug 11, 2017

zkbot added a commit that referenced this issue Sep 25, 2017

Auto merge of #2120 - str4d:1113-dpt, r=<try>
Experimental feature: remote proving service

This implements proving service support in `z_sendmany` and adds two new binaries:

- `zcash-proving-service`: runs a single ZMQ thread to listen on a port for witness data, and returns the corresponding proof.
- `ExampleProvingServiceClient` (in `src/zcash`): creates five new `JSDescription`s using the proving service to calculate the proofs, and validates each proof.

To build: `CONFIGURE_FLAGS="--with-proving-service" ./zcutil/build.sh`

This is an experimental feature, and the network protocol is likely to change. Until the protocol has been specified in a ZIP, do not rely on it for interoperation.

Part of #1113. Closes #2066.

zkbot added a commit that referenced this issue Dec 19, 2017

Auto merge of #2120 - str4d:1113-dpt, r=<try>
Experimental feature: remote proving service

This implements proving service support in `z_sendmany` and adds two new binaries:

- `zcash-proving-service`: listens on (one or both of) ZMQ and WebSocket ports for witness data, and returns the corresponding proof.
- `ExampleProvingServiceClient` (in `src/zcash`): creates five new `JSDescription`s using the proving service to calculate the proofs, and validates each proof.

To build: `CONFIGURE_FLAGS="--with-proving-service-daemon" ./zcutil/build.sh`

This is an experimental feature, and the network protocol is likely to change. Until the protocol has been specified in a ZIP, do not rely on it for interoperation.

Part of #1113. Closes #2066.

zkbot added a commit that referenced this issue Dec 21, 2017

Auto merge of #2120 - str4d:1113-dpt, r=<try>
Experimental feature: remote proving service

This implements proving service support in `z_sendmany` and adds two new binaries:

- `zcash-proving-service`: listens on (one or both of) ZMQ and WebSocket ports for witness data, and returns the corresponding proof.
- `ExampleProvingServiceClient` (in `src/zcash`): creates five new `JSDescription`s using the proving service to calculate the proofs, and validates each proof.

To build: `CONFIGURE_FLAGS="--with-proving-service-daemon" ./zcutil/build.sh`

This is an experimental feature, and the network protocol is likely to change. Until the protocol has been specified in a ZIP, do not rely on it for interoperation.

Part of #1113. Closes #2066.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.