Skip to content

Commit

Permalink
Merge pull request #10 from cartridge-gg/verifier
Browse files Browse the repository at this point in the history
Feature: Endpoint for Validating Generated Proofs
  • Loading branch information
chudkowsky authored Aug 16, 2024
2 parents a0f7526 + 17f9bdf commit b7ec5cc
Show file tree
Hide file tree
Showing 9 changed files with 143 additions and 44 deletions.
5 changes: 3 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,12 @@ RUN pip install --upgrade pip
COPY --from=builder /app/target/release/prover /usr/local/bin/prover
COPY --from=builder /usr/local/cargo/bin/cairo1-run /usr/local/bin/cairo1-run
COPY --from=prover /usr/bin/cpu_air_prover /usr/local/bin/cpu_air_prover
COPY --from=prover /usr/bin/cpu_air_verifier /usr/local/bin/cpu_air_verifier

COPY --from=builder /app/config/cpu_air_prover_config.json /config/cpu_air_prover_config.json
RUN git clone --depth=1 -b v2.7.0-rc.3 https://github.com/starkware-libs/cairo.git
RUN mv cairo/corelib/ .

RUN git clone --depth=1 -b v2.7.0-rc.3 https://github.com/starkware-libs/cairo.git
RUN mv cairo/corelib/ .
RUN rm -rf cairo

RUN pip install cairo-lang==0.13.1
Expand Down
10 changes: 7 additions & 3 deletions bin/cairo-prove/tests/prove.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,19 @@ use crate::common::read_file;
use cairo_proof_parser::output::{extract_output, ExtractOutputResult};
use cairo_prove::{prove, CliInput};
use serde_json::Value;
use std::path::PathBuf;
use std::{env, path::PathBuf};
use url::Url;
mod common;

#[tokio::test]
async fn test_cairo1_fibonacci() -> Result<(), cairo_prove::ProveError> {
let key = "0x5883b0e30b008e48af3d0bf5cfc138fb6093496da6f87d24b65def88470356d3";
let port = env::var("PORT").unwrap();
let prover_url = Url::parse(&format!("http://localhost:{}", port)).unwrap();
let args = CliInput {
key: key.to_string(),
cairo_version: 1,
url: Url::parse("http://localhost:3040").unwrap(),
url: prover_url,
};

let prover_input =
Expand All @@ -24,10 +26,12 @@ async fn test_cairo1_fibonacci() -> Result<(), cairo_prove::ProveError> {
#[tokio::test]
async fn test_cairo0_fibonacci() -> Result<(), cairo_prove::ProveError> {
let key = "0x5883b0e30b008e48af3d0bf5cfc138fb6093496da6f87d24b65def88470356d3";
let port = env::var("PORT").unwrap();
let prover_url = Url::parse(&format!("http://localhost:{}", port)).unwrap();
let args = CliInput {
key: key.to_string(),
cairo_version: 0,
url: Url::parse("http://localhost:3040").unwrap(),
url: prover_url,
};
let prover_input = read_file(PathBuf::from("examples/CairoZero/prover_input.json")).await?;
let program_input: Value = serde_json::from_str(&prover_input)?;
Expand Down
5 changes: 4 additions & 1 deletion prover-sdk/src/prove_sdk_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,10 @@ impl ProverSDKBuilder {
.base_url
.join("/register")
.map_err(ProverSdkErrors::UrlParseError)?,

verify: self
.base_url
.join("/verify")
.map_err(ProverSdkErrors::UrlParseError)?,
authority: signing_key,
})
}
Expand Down
11 changes: 11 additions & 0 deletions prover-sdk/src/prover_sdk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub struct ProverSDK {
pub prover_cairo1: Url,
pub register: Url,
pub authority: ProverAccessKey,
pub verify: Url,
}

impl ProverSDK {
Expand Down Expand Up @@ -159,4 +160,14 @@ impl ProverSDK {

Ok(response_data)
}
pub async fn verify(self, proof: String) -> Result<String, ProverSdkErrors> {
let response = self
.client
.post(self.verify.clone())
.json(&proof)
.send()
.await?;
let response_data = response.text().await?;
Ok(response_data)
}
}
100 changes: 70 additions & 30 deletions prover-sdk/tests/sdk_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use prover_sdk::{access_key, errors, load};

#[cfg(test)]
mod tests {
use std::env;
use std::path::PathBuf;

use crate::load::{load_cairo0, load_cairo1};
Expand All @@ -17,97 +18,136 @@ mod tests {
fn get_signing_key() -> ProverAccessKey {
ProverAccessKey::from_hex_string(
"0x5883b0e30b008e48af3d0bf5cfc138fb6093496da6f87d24b65def88470356d3",
// Corresponding to 0xd16b71c90dbf897e5964d2f267d04664b3c035036559d712994739ea6cf2fd9f public key.
)
.unwrap()
}
#[tokio::test]
async fn test_prover_cairo0() -> Result<(), ProverSdkErrors> {
let prover_url = Url::parse("http://localhost:3040").unwrap(); // Provide an invalid URL
let port = env::var("PORT").unwrap();
let prover_url = Url::parse(&format!("http://localhost:{}", port)).unwrap();

let sdk = ProverSDK::new(get_signing_key(), prover_url).await?;

let data = load_cairo0(PathBuf::from("../examples/CairoZero/prover_input.json")).await?;
let proof = sdk.prove_cairo0(data).await;
// If authentication fails, print out the error message
assert!(proof.is_ok(), "Failed to prove with invalid url");
// If authentication fails, print out the error message for debugging purposes

assert!(proof.is_ok(), "Failed to generate proof with Cairo 0");

// Verify the generated proof if successful
if let Err(err) = proof {
println!(" error: {}", err);
println!("Error during proof generation: {}", err);
} else {
let result: Result<String, ProverSdkErrors> = sdk.verify(proof.unwrap()).await;
assert!(result.is_ok(), "Failed to verify proof");
assert_eq!(result.unwrap(), "true", "Proof verification failed");
}

Ok(())
}

#[tokio::test]
async fn test_verify_invalid_proof() {
let port = env::var("PORT").unwrap();
let prover_url = Url::parse(&format!("http://localhost:{}", port)).unwrap();

let sdk = ProverSDK::new(get_signing_key(), prover_url).await.unwrap();

// Attempt to verify an invalid proof
let result = sdk.verify("invalid_proof".to_string()).await;

assert!(
result.is_ok(),
"Verification unexpectedly failed for an invalid proof"
);
assert_eq!(
result.unwrap(),
"false",
"Invalid proof was incorrectly verified as valid"
);
}

#[tokio::test]
async fn test_prover_cairo1() -> Result<(), ProverSdkErrors> {
let prover_url = Url::parse("http://localhost:3040").unwrap();
let port = env::var("PORT").unwrap();
let prover_url = Url::parse(&format!("http://localhost:{}", port)).unwrap();

// Act: Attempt to authenticate with the valid private key and invalid URL for authentication
let sdk = ProverSDK::new(get_signing_key(), prover_url).await?;

let data = load_cairo1(PathBuf::from(
"../examples/Cairo/fibonacci_prover_input.json",
))
.await?;
let proof = sdk.prove_cairo1(data).await;
// If authentication fails, print out the error message
assert!(proof.is_ok(), "Failed to prove with invalid url");
// If authentication fails, print out the error message for debugging purposes

assert!(proof.is_ok(), "Failed to generate proof with Cairo 1");

if let Err(err) = proof {
println!(" error: {}", err);
println!("Error during proof generation: {}", err);
} else {
let result: Result<String, ProverSdkErrors> = sdk.verify(proof.unwrap()).await;
assert!(result.is_ok(), "Failed to verify proof");
assert_eq!(result.unwrap(), "true", "Proof verification failed");
}

Ok(())
}

#[tokio::test]
async fn test_invalid_url_auth() -> Result<(), ProverSdkErrors> {
// Arrange: Set up any necessary data or dependencies
let prover_url = Url::parse("http://wrong:1234").unwrap(); // Provide an invalid URL for authentication
// Provide an invalid URL for SDK initialization
let prover_url = Url::parse("http://wrong:1234").unwrap();

// Act: Attempt to authenticate with the valid private key and invalid URL for authentication
let result = ProverSDK::new(get_signing_key(), prover_url).await;
// Assert: Check that authentication fails due to invalid URL

// Assert that SDK initialization fails due to the invalid URL
assert!(
result.is_err(),
"Expected authentication to fail with invalid URL for authentication"
"Expected SDK initialization to fail with an invalid URL"
);
// If authentication fails, print out the error message

if let Err(err) = result {
println!("Error message: {}", err);
println!("Error during SDK initialization: {}", err);
}

Ok(())
}

#[tokio::test]
async fn test_invalid_prover() -> Result<(), ProverSdkErrors> {
// Arrange: Set up any necessary data or dependencies
let prover_url: Url = Url::parse("http://localhost:3040").unwrap();
async fn test_invalid_prover_data() -> Result<(), ProverSdkErrors> {
let port = env::var("PORT").unwrap();
let prover_url = Url::parse(&format!("http://localhost:{}", port)).unwrap();

// Act: Attempt to authenticate with the valid private key and valid URL for authentication
let sdk = ProverSDK::new(get_signing_key(), prover_url).await?;
//Act: Load wrong prover input to test invalid prover version

// Load Cairo 1 prover input data (intentional mismatch)
let data = load_cairo1(PathBuf::from(
"../examples/Cairo/fibonacci_prover_input.json",
))
.await?;

// Attempt to prove using Cairo 0 with incorrect input
let proof = sdk.prove_cairo0(data).await;
// If authentication fails, print out the error message
assert!(proof.is_err(), "Failed to prove with invalid url");

// Assert that proof generation fails due to incorrect input
assert!(
proof.is_err(),
"Expected proof generation to fail with incorrect input"
);

Ok(())
}

#[tokio::test]
async fn test_register() -> Result<(), ProverSdkErrors> {
let prover_url: Url = Url::parse("http://localhost:3040").unwrap();
let port = env::var("PORT").unwrap();
let prover_url = Url::parse(&format!("http://localhost:{}", port)).unwrap();

let new_key = ProverAccessKey::generate();

// Act: Attempt to authenticate with the valid private key
// Initialize the SDK and register the new key
let mut sdk = ProverSDK::new(get_signing_key(), prover_url).await?;
sdk.register(new_key.0.verifying_key()).await?;

// If authentication fails, print out the error message

Ok(())
}
}
1 change: 1 addition & 0 deletions prover/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pub mod auth;
pub mod prove;
pub mod server;
pub mod verifier;
use std::path::PathBuf;

use clap::{arg, Parser, ValueHint};
Expand Down
7 changes: 5 additions & 2 deletions prover/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ use crate::{
self,
authorizer::{Authorizer, FileAuthorizer},
},
prove, Args,
prove,
verifier::verify_proof,
Args,
};
use axum::Router;
use axum::{routing::post, Router};
use prove::errors::ServerError;
use std::{
collections::HashMap,
Expand Down Expand Up @@ -69,6 +71,7 @@ pub async fn start(args: Args) -> Result<(), ServerError> {
.nest("/", ok_router)
.nest("/", auth::auth(&state))
.nest("/prove", prove::router(&state))
.route("/verify", post(verify_proof))
.layer((
RequestBodyLimitLayer::new(100 * 1024 * 1024),
TraceLayer::new_for_http(),
Expand Down
35 changes: 35 additions & 0 deletions prover/src/verifier.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use std::{path::PathBuf, process::Command};

use axum::Json;

pub async fn verify_proof(Json(proof): Json<String>) -> Json<bool> {
// Define the path for the proof file
let file = PathBuf::from("proof");

// Write the proof string to the file
if let Err(e) = std::fs::write(&file, proof) {
eprintln!("Failed to write proof to file: {}", e);
return Json(false);
}

// Create the command to run the verifier
let mut command = Command::new("cpu_air_verifier");
command.arg("--in_file").arg(&file);

// Execute the command and capture the status
let status = command.status();

// Remove the proof file
if let Err(e) = std::fs::remove_file(&file) {
eprintln!("Failed to remove proof file: {}", e);
}

// Check if the command was successful
match status {
Ok(exit_status) => Json(exit_status.success()),
Err(e) => {
eprintln!("Failed to execute verifier: {}", e);
Json(false)
}
}
}
13 changes: 7 additions & 6 deletions scripts/e2e_test.sh
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
#!/usr/bin/env bash

IMAGE_NAME="http_prover_test"

CONTAINER_ENGINE="${CONTAINER_ENGINE:-podman}"
PORT="${PORT:-3040}"
# Check if the image already exists
if podman images | grep -q "$IMAGE_NAME"; then
if $CONTAINER_ENGINE images | grep -q "$IMAGE_NAME"; then
echo "Image $IMAGE_NAME already exists. Skipping build step."
else
echo "Image $IMAGE_NAME does not exist. Building the image..."
podman build -t $IMAGE_NAME .
$CONTAINER_ENGINE build -t $IMAGE_NAME .
if [ $? -ne 0 ]; then
echo "Failed to build the image. Exiting."
exit 1
fi
fi

podman run -d --replace --name http_prover_test \
-p 3040:3000 localhost/http_prover_test \
$CONTAINER_ENGINE run -d --replace --name http_prover_test \
-p $PORT:3000 localhost/http_prover_test \
--jwt-secret-key "jwt" \
--message-expiration-time 3600 \
--session-expiration-time 3600 \
Expand All @@ -27,4 +28,4 @@ fi

cargo test --no-fail-fast --workspace --verbose -- --test-threads=1

podman stop $IMAGE_NAME
$CONTAINER_ENGINE stop $IMAGE_NAME

0 comments on commit b7ec5cc

Please sign in to comment.