Skip to content

Commit

Permalink
Add a command to download any SRS files of any size (#37)
Browse files Browse the repository at this point in the history
Delegate the downloading of SRS files to the end-user. 

Based on the discussion here
#36 and here
#7
  • Loading branch information
ppoliani committed Feb 23, 2024
1 parent a7f8d90 commit 3155c95
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 85 deletions.
16 changes: 14 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ To install `snarkjs`, just run:
npm install -g snarkjs@latest
```

### Download SRS File

To create a ZKP you would need to download the correct SRS file (based on your circuit size). For example, if your circuit has around 65K constraints then you would need to download the following file https://storage.googleapis.com/zkevm/ptau/powersOfTau28_hez_final_16.ptau.

You can replace the number 16 in the above URL to download the correct SRS file for your circuit.

> You can download the file to any location you wish. You will later provide the location of the file when running the CLI tool.
### Bitcoin wallet

On top that, you'll need your own Bitcoin node/wallet. This application will perform queries to your node/wallet in order to fund your zkapp transactions.
Expand Down Expand Up @@ -63,17 +71,21 @@ The zkapp doesn't have to do anything with the `truncated_txid` field (although
You can deploy a stateless zkapp with the following command:

```shell
$ zkbtc deploy-zkapp --circom-circuit-path examples/circuit/stateless.circom --satoshi-amount 1000
$ zkbtc deploy-zkapp --circom-circuit-path examples/circuit/stateless.circom --srs-path ~/.zkbitcoin/srs_16.ptau --satoshi-amount 1000
```

> Use the `--srs-path` where you downloaded the SRS file. Check "Download SRS File" above.
This will lock 1,000 satoshis in the zkapp and return the transaction ID of the transaction that deployed the zkapp. A stateless zkapp can be referenced by that transaction ID.

Bob can then unlock the funds from the stateless zkapp with the following command:

```shell
$ zkbtc use-zkapp --txid "e793bdd8dfdd9912d971790a5f385ad3f1215dce97e25dbefe5449faba632836" --circom-circuit-path examples/circuit/stateless.circom --proof-inputs '{"preimage":["1"]}' --recipient-address "tb1q6nkpv2j9lxrm6h3w4skrny3thswgdcca8cx9k6"
$ zkbtc use-zkapp --txid "e793bdd8dfdd9912d971790a5f385ad3f1215dce97e25dbefe5449faba632836" --circom-circuit-path examples/circuit/stateless.circom --srs-path ~/.zkbitcoin/srs_16.ptau --proof-inputs '{"preimage":["1"]}' --recipient-address "tb1q6nkpv2j9lxrm6h3w4skrny3thswgdcca8cx9k6"
```

> Use the `--srs-path` where you downloaded the SRS file. Check "Download SRS File" above.
### Stateful zkapps

A stateful zkapp is a zkapp that has a state, and which state can be updated without consuming the zkapp.
Expand Down
24 changes: 22 additions & 2 deletions src/bin/zkbtc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@ use anyhow::{ensure, Context, Result};
use bitcoin::{Address, Txid};
use clap::{Parser, Subcommand};
use log::info;
use std::{collections::HashMap, env, path::PathBuf, str::FromStr};
use std::{
collections::HashMap,
env,
path::{Path, PathBuf},
str::FromStr,
};
use tempdir::TempDir;
use zkbitcoin::{
alice_sign_tx::generate_and_broadcast_transaction,
Expand Down Expand Up @@ -46,6 +51,10 @@ enum Commands {
#[arg(short, long)]
circom_circuit_path: PathBuf,

/// The path to the srs file
#[arg(long)]
srs_path: PathBuf,

/// Optionally, an initial state for stateful zkapps.
#[arg(short, long)]
initial_state: Option<String>,
Expand Down Expand Up @@ -85,6 +94,10 @@ enum Commands {
#[arg(short, long)]
circom_circuit_path: PathBuf,

/// The path to the srs file
#[arg(long)]
srs_path: PathBuf,

/// A JSON string of the proof inputs.
/// For stateful zkapps, we expect at least `amount_in` and `amount_out`.
#[arg(short, long)]
Expand Down Expand Up @@ -155,6 +168,7 @@ async fn main() -> Result<()> {
circom_circuit_path,
initial_state,
satoshi_amount,
srs_path,
} => {
let rpc_ctx = RpcCtx::new(
Some(BITCOIN_JSON_RPC_VERSION),
Expand All @@ -167,6 +181,7 @@ async fn main() -> Result<()> {
deploy_zkapp(
&rpc_ctx,
circom_circuit_path,
srs_path,
initial_state.as_deref(),
*satoshi_amount,
)
Expand All @@ -182,6 +197,7 @@ async fn main() -> Result<()> {
txid,
recipient_address,
circom_circuit_path,
srs_path,
proof_inputs,
} => {
let rpc_ctx = RpcCtx::new(
Expand All @@ -198,6 +214,7 @@ async fn main() -> Result<()> {
txid,
recipient_address,
circom_circuit_path,
srs_path,
proof_inputs.as_deref(),
)
.await?;
Expand Down Expand Up @@ -250,6 +267,7 @@ async fn main() -> Result<()> {
async fn deploy_zkapp(
rpc_ctx: &RpcCtx,
circom_circuit_path: PathBuf,
srs_path: &Path,
initial_state: Option<&str>,
satoshi_amount: u64,
) -> Result<()> {
Expand All @@ -260,7 +278,7 @@ async fn deploy_zkapp(
verifier_key,
circuit_r1cs_path: _,
prover_key_path: _,
} = snarkjs::compile(&tmp_dir, &circom_circuit_path).await?;
} = snarkjs::compile(&tmp_dir, &circom_circuit_path, srs_path).await?;
let vk_hash = verifier_key.hash();
(verifier_key, vk_hash)
};
Expand Down Expand Up @@ -318,6 +336,7 @@ async fn use_zkapp(
txid: &str,
recipient_address: &str,
circom_circuit_path: PathBuf,
srs_path: &Path,
proof_inputs: Option<&str>,
) -> Result<()> {
// parse proof inputs
Expand All @@ -342,6 +361,7 @@ async fn use_zkapp(
bob_address,
txid,
&circom_circuit_path,
srs_path,
proof_inputs,
)
.await?;
Expand Down
6 changes: 4 additions & 2 deletions src/bob_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ impl BobRequest {
bob_address: Address,
txid: bitcoin::Txid, // of zkapp
circom_circuit_path: &Path,
srs_path: &Path,
mut proof_inputs: HashMap<String, Vec<String>>,
) -> Result<Self> {
// fetch transaction + metadata based on txid
Expand Down Expand Up @@ -140,7 +141,7 @@ impl BobRequest {

// prove
let (_proof, public_inputs, _vk) =
snarkjs::prove(circom_circuit_path, &proof_inputs).await?;
snarkjs::prove(circom_circuit_path, srs_path, &proof_inputs).await?;

// extract new_state
let new_state = public_inputs
Expand Down Expand Up @@ -266,7 +267,8 @@ impl BobRequest {
let truncated_txid = truncate_txid(tx.txid());
proof_inputs.insert("truncated_txid".to_string(), vec![truncated_txid]);

let (proof, public_inputs, vk) = snarkjs::prove(circom_circuit_path, &proof_inputs).await?;
let (proof, public_inputs, vk) =
snarkjs::prove(circom_circuit_path, srs_path, &proof_inputs).await?;
debug!(
"- public_inputs used to create the proof: {:?}",
public_inputs.0
Expand Down
1 change: 0 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ pub mod frost;
pub mod json_rpc_stuff;
pub mod plonk;
pub mod snarkjs;
pub mod srs;
pub mod utils;

/// 1. Alice signs a transaction to deploy a smart contract.
Expand Down
28 changes: 17 additions & 11 deletions src/snarkjs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@ use anyhow::{bail, Context, Result};
use log::info;
use tempdir::TempDir;

use crate::{
plonk::{self},
srs,
};
use crate::plonk;

pub struct CompilationResult {
pub verifier_key: plonk::VerifierKey,
Expand All @@ -21,10 +18,11 @@ pub struct CompilationResult {
}

/// Compiles a circom circuit to a wasm and r1cs file.
pub async fn compile(tmp_dir: &TempDir, circom_circuit_path: &Path) -> Result<CompilationResult> {
// SRS
let srs_path = srs::srs_path().await;

pub async fn compile(
tmp_dir: &TempDir,
circom_circuit_path: &Path,
srs_path: &Path,
) -> Result<CompilationResult> {
// set up new paths for files that will be created
let circuit_name = circom_circuit_path
.file_stem()
Expand Down Expand Up @@ -113,6 +111,7 @@ pub async fn compile(tmp_dir: &TempDir, circom_circuit_path: &Path) -> Result<Co
// perhaps I can just use snarkjs as a library directly?
pub async fn prove(
circom_circuit_path: &Path,
srs_path: &Path,
proof_inputs: &HashMap<String, Vec<String>>,
) -> Result<(plonk::Proof, plonk::PublicInputs, plonk::VerifierKey)> {
// create tmp dir
Expand All @@ -123,7 +122,7 @@ pub async fn prove(
verifier_key,
circuit_r1cs_path: _,
prover_key_path,
} = compile(&tmp_dir, circom_circuit_path).await?;
} = compile(&tmp_dir, circom_circuit_path, srs_path).await?;

// write inputs to file
let public_inputs_path = tmp_dir.path().join("proof_inputs.json");
Expand Down Expand Up @@ -246,6 +245,7 @@ pub fn verify_proof(
#[cfg(test)]
mod tests {
use super::*;
use crate::zkbitcoin_folder;

fn full_path_from(path: &Path) -> PathBuf {
PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap()).join(path)
Expand All @@ -255,6 +255,7 @@ mod tests {
#[ignore]
async fn prove_stateless() {
let circom_circuit_path = full_path_from(Path::new("examples/circuit/stateless.circom"));
let srs_path = zkbitcoin_folder().join("srs_16.ptau");
let mut proof_inputs = HashMap::new();
proof_inputs.insert("truncated_txid".to_string(), vec!["0".to_string()]);
proof_inputs.insert(
Expand All @@ -264,7 +265,9 @@ mod tests {
.to_string(),
],
);
let (proof, full_inputs, vk) = prove(&circom_circuit_path, &proof_inputs).await.unwrap();
let (proof, full_inputs, vk) = prove(&circom_circuit_path, &srs_path, &proof_inputs)
.await
.unwrap();

// verify
verify_proof(&vk, &full_inputs.0, &proof).unwrap();
Expand All @@ -278,6 +281,7 @@ mod tests {
.join("examples")
.join("circuit");
let circom_circuit_path = circuit_dir.join("circuit.circom");
let srs_path = zkbitcoin_folder().join("srs_16.ptau");

// // compile to get VK
// let vk = {
Expand All @@ -292,7 +296,9 @@ mod tests {

// prove
let public_inputs = HashMap::new();
let (proof, full_inputs, vk) = prove(&circom_circuit_path, &public_inputs).await.unwrap();
let (proof, full_inputs, vk) = prove(&circom_circuit_path, &srs_path, &public_inputs)
.await
.unwrap();

// verify
verify_proof(&vk, &full_inputs.0, &proof).unwrap();
Expand Down
67 changes: 0 additions & 67 deletions src/srs.rs

This file was deleted.

0 comments on commit 3155c95

Please sign in to comment.