From b10639a7c3ece5c577ce8e1c3fe5eca55edd1f4b Mon Sep 17 00:00:00 2001 From: user <303926+HarryR@users.noreply.github.com> Date: Sun, 8 Feb 2026 16:59:21 +0530 Subject: [PATCH] Removed risc-zero experiment (migrated to vaportpm-zk) --- .gitmodules | 4 - experiments/risc-zero/.gitignore | 1 - experiments/risc-zero/Cargo.toml | 30 --- experiments/risc-zero/Makefile | 28 --- experiments/risc-zero/README.md | 154 -------------- experiments/risc-zero/methods/Cargo.toml | 10 - experiments/risc-zero/methods/build.rs | 3 - .../risc-zero/methods/ec-bench/Cargo.toml | 24 --- .../risc-zero/methods/ec-bench/src/main.rs | 56 ------ .../risc-zero/methods/guest/Cargo.toml | 28 --- .../risc-zero/methods/guest/src/main.rs | 81 -------- experiments/risc-zero/methods/src/lib.rs | 1 - .../risc-zero/rustcrypto-elliptic-curves | 1 - experiments/risc-zero/src/host.rs | 8 - experiments/risc-zero/src/inputs.rs | 32 --- experiments/risc-zero/src/lib.rs | 25 --- experiments/risc-zero/tests/cycle_count.rs | 126 ------------ experiments/risc-zero/tests/ec_benchmarks.rs | 188 ------------------ 18 files changed, 800 deletions(-) delete mode 100644 experiments/risc-zero/.gitignore delete mode 100644 experiments/risc-zero/Cargo.toml delete mode 100644 experiments/risc-zero/Makefile delete mode 100644 experiments/risc-zero/README.md delete mode 100644 experiments/risc-zero/methods/Cargo.toml delete mode 100644 experiments/risc-zero/methods/build.rs delete mode 100644 experiments/risc-zero/methods/ec-bench/Cargo.toml delete mode 100644 experiments/risc-zero/methods/ec-bench/src/main.rs delete mode 100644 experiments/risc-zero/methods/guest/Cargo.toml delete mode 100644 experiments/risc-zero/methods/guest/src/main.rs delete mode 100644 experiments/risc-zero/methods/src/lib.rs delete mode 160000 experiments/risc-zero/rustcrypto-elliptic-curves delete mode 100644 experiments/risc-zero/src/host.rs delete mode 100644 experiments/risc-zero/src/inputs.rs delete mode 100644 experiments/risc-zero/src/lib.rs delete mode 100644 experiments/risc-zero/tests/cycle_count.rs delete mode 100644 experiments/risc-zero/tests/ec_benchmarks.rs diff --git a/.gitmodules b/.gitmodules index 4d7c990..e69de29 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +0,0 @@ -[submodule "experiments/risc-zero/rustcrypto-elliptic-curves"] - path = experiments/risc-zero/rustcrypto-elliptic-curves - url = https://github.com/HarryR/RustCrypto-elliptic-curves.git - branch = risc0-p256-p384-unified diff --git a/experiments/risc-zero/.gitignore b/experiments/risc-zero/.gitignore deleted file mode 100644 index 9bf95ea..0000000 --- a/experiments/risc-zero/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.pb \ No newline at end of file diff --git a/experiments/risc-zero/Cargo.toml b/experiments/risc-zero/Cargo.toml deleted file mode 100644 index 8fdab5d..0000000 --- a/experiments/risc-zero/Cargo.toml +++ /dev/null @@ -1,30 +0,0 @@ -[package] -name = "vaportpm-zk-experiment" -version = "0.1.0" -edition = "2021" - -# Standalone workspace - isolated from main project -[workspace] - -[dependencies] -# Reference existing crates -vaportpm-verify = { path = "../../crates/vaportpm-verify" } -vaportpm-attest = { path = "../../crates/vaportpm-attest" } - -# RISC Zero -risc0-zkvm = "3.0" -vaportpm-zk-methods = { path = "methods" } - -# Serialization -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -hex = "0.4" -serde-big-array = "0.5" - -# Time -pki-types = { package = "rustls-pki-types", version = "1.13" } - -[dev-dependencies] -# For integration tests -hex-literal = "0.4" -bincode = "1.3" diff --git a/experiments/risc-zero/Makefile b/experiments/risc-zero/Makefile deleted file mode 100644 index 5afa3e5..0000000 --- a/experiments/risc-zero/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -.PHONY: build test clean cycles setup - -# Dev mode - fast execution, no real proofs -export RISC0_DEV_MODE=1 - -build: - cargo build - -test: - cargo test -- --nocapture - -# Cycle count specifically -cycles: - rm -f profile.pb && RISC0_PPROF_OUT=./profile.pb cargo test --release test_p256_ecdsa_cycles -- --nocapture && ~/go/bin/go tool pprof -text profile.pb - #rm -f profile.pb && RISC0_PPROF_OUT=./profile.pb cargo test --release test_p384_ecdsa_cycles -- --nocapture && ~/go/bin/go tool pprof -text profile.pb - #rm -f profile.pb && RISC0_PPROF_OUT=./profile.pb cargo test --release test_gcp_attestation_cycle_count -- --nocapture && ~/go/bin/go tool pprof -text profile.pb - #rm -f profile.pb && RISC0_PPROF_OUT=./profile.pb cargo test --release test_nitro_attestation_cycle_count -- --nocapture && ~/go/bin/go tool pprof -text profile.pb - -pprof-ui: - ~/go/bin/go tool pprof -http 0.0.0.0:8090 profile.pb - -clean: - cargo clean - -# Install prerequisites -setup: - curl -L https://risczero.com/install | bash - rzup install diff --git a/experiments/risc-zero/README.md b/experiments/risc-zero/README.md deleted file mode 100644 index ddf10d3..0000000 --- a/experiments/risc-zero/README.md +++ /dev/null @@ -1,154 +0,0 @@ -# RISC Zero ZK Verification Experiment - -This experiment runs `verify_decoded_attestation_output` inside RISC Zero zkVM to measure cycle counts and understand complexity. - -## Prerequisites - -1. Install the RISC Zero toolchain: - ```bash - # Install rzup (RISC Zero's toolchain manager) - curl -L https://risczero.com/install | bash - - # Restart shell or source profile, then install toolchain - rzup install - ``` - -## Usage - -### Run Cycle Count Tests - -```bash -cd experiments/risc-zero - -# Enable dev mode (fast execution, no real proofs) -export RISC0_DEV_MODE=1 - -# Run all cycle count tests -make cycles -``` - -Or run tests directly: -```bash -RISC0_DEV_MODE=1 cargo test -- --nocapture -``` - -### Expected Output - -``` -=== GCP Attestation Verification (Optimized + zerocopy) === -Flat input size: 5792 bytes -Total cycles: 882866 -Segments: 2 - -=== Nitro Attestation Verification (Optimized + zerocopy) === -Flat input size: 6446 bytes -Total cycles: 4177180 -Segments: 5 -``` - -## Host-to-Guest Communication - -Attestation data is passed from host to guest using an internal flat binary format (`vaportpm_verify::flat`). This avoids JSON parsing and hex decoding inside the zkVM, which would waste cycles on string manipulation rather than cryptographic verification. - -The host performs all text parsing (JSON, hex, PEM) upfront, converts to `DecodedAttestationOutput`, then serializes via `flat::to_bytes()`. The guest deserializes with `flat::from_bytes()` and calls `verify_decoded_attestation_output()` — the same verification function used by the native path. The flat format uses a zerocopy header for zero-allocation parsing of fixed fields. - -## Public Inputs - -The ZK circuit commits the following public inputs to the journal: - -| Field | Type | Description | -|-------|------|-------------| -| `pcr_hash` | `[u8; 32]` | SHA-256 of canonically-serialized PCR bank | -| `ak_pubkey` | `P256PublicKey` | AK public key (P-256 x/y coordinates) | -| `nonce` | `[u8; 32]` | Freshness nonce from TPM Quote | -| `provider` | `u8` | 0 = AWS, 1 = GCP | -| `verified_at` | `u64` | Verification timestamp (Unix seconds) | - -The `pcr_hash` is computed inside the guest as `SHA256(alg_u16_le || count || idx0 || value0 || idx1 || value1 || ...)` over the validated PCR bank, providing a compact commitment to all 24 PCR values. - -## Structure - -``` -experiments/risc-zero/ -├── Cargo.toml # Host crate (standalone workspace) -├── Makefile # Build/test commands -├── rustcrypto-elliptic-curves/ # Git submodule (P-384 fork) -├── src/ -│ ├── lib.rs # Library root -│ ├── host.rs # Host utilities -│ └── inputs.rs # ZkPublicInputs type -├── tests/ -│ ├── cycle_count.rs # Integration tests (cycle measurement) -│ └── ec_benchmarks.rs # EC operation benchmarks -└── methods/ - ├── Cargo.toml # Methods crate - ├── build.rs # Embeds guest ELF - ├── src/lib.rs # Re-exports generated constants - └── guest/ - ├── Cargo.toml # Guest deps + crypto patches - └── src/main.rs # Guest circuit -``` - -## How It Works - -1. The **host** (`tests/cycle_count.rs`) prepares inputs and measures cycles: - - Loads test fixtures (GCP AMD and Nitro attestations) - - Parses JSON and decodes hex/PEM on the host side - - Serializes to flat binary format via `flat::to_bytes()` with appended timestamp - - Runs the guest in dev mode (no real proofs) and reports cycle counts - -2. The **guest program** (`methods/guest/src/main.rs`) runs inside the zkVM: - - Reads flat binary input via `env::stdin()` - - Parses with `flat::from_bytes()` (zerocopy header, no allocations for fixed fields) - - Calls `verify_decoded_attestation_output()` (identical verification to native) - - Computes canonical PCR hash over the validated bank - - Commits public inputs to the journal - -## Accelerated Cryptography - -The guest uses RISC Zero's patched crypto crates for hardware-accelerated precompiles: - -| Crate | Precompile | Notes | -|-------|------------|-------| -| `sha2` | SHA-256/SHA-384 | Used extensively in cert validation | -| `p256` | P-256 ECDSA | GCP uses P-256 for AK signatures | -| `p384` | P-384 ECDSA | Nitro uses P-384 for all signatures (via fork) | -| `rsa` | RSA | GCP uses RSA-4096 certificates | -| `crypto-bigint` | Modular arithmetic | Accelerates bigint operations | - -These patches are applied via `[patch.crates-io]` in the guest Cargo.toml. The P-384 acceleration requires the `elliptic-curves` submodule. - -### P-384 Support (Nitro) - -AWS Nitro uses **P-384 ECDSA** exclusively for its certificate chain. This experiment uses a patched version of `elliptic-curves` with P-384 acceleration via `risc0-bigint2`. - -**Upstream PR:** https://github.com/risc0/RustCrypto-elliptic-curves/pull/15 - -The P-384 patch is included as a git submodule at `rustcrypto-elliptic-curves/`, tracking the `risc0-p256-p384-unified` branch from the fork. - -### Why Nitro is ~4.7x slower than GCP - -Both P-256 and P-384 have precompile acceleration, but the cost difference comes from volume. Nitro requires **5 P-384 ECDSA verifications**: -- 1 COSE signature verification (~1M cycles: ~400k P-384 verify + ~570k SHA-512 over COSE document) -- 4 certificate chain verifications (~400k cycles each) - -GCP uses RSA-4096 (cheap with dedicated precompile) and a single P-256 ECDSA verification (~250k cycles), keeping the total well under 1M cycles. - -Batch multi-scalar multiplication could theoretically help, but ECDSA verify requires independent scalar muls per signature (different messages and keys), and the RISC Zero precompile interface doesn't expose batching. This is effectively the floor for Nitro's chain structure. - -## Notes - -- This is a **research experiment** to evaluate ZK attestation verification feasibility -- Uses dev mode for fast iteration (no real proofs generated) -- The main project is completely unchanged -- Cycle counts give rough indication of proving cost -- GCP verification is production-viable at ~883K cycles (2 segments) -- Nitro verification is viable at ~4.2M cycles with P-384 acceleration (pending upstream merge) - -## Dependencies - -This experiment requires the P-384 accelerated elliptic-curves fork which hasn't yet been upstreamed to RISC-Zero. After cloning, initialize the submodule: - -```bash -git submodule update --init --recursive -``` diff --git a/experiments/risc-zero/methods/Cargo.toml b/experiments/risc-zero/methods/Cargo.toml deleted file mode 100644 index 4564bb4..0000000 --- a/experiments/risc-zero/methods/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "vaportpm-zk-methods" -version = "0.1.0" -edition = "2021" - -[build-dependencies] -risc0-build = "3.0" - -[package.metadata.risc0] -methods = ["guest", "ec-bench"] diff --git a/experiments/risc-zero/methods/build.rs b/experiments/risc-zero/methods/build.rs deleted file mode 100644 index 08a8a4e..0000000 --- a/experiments/risc-zero/methods/build.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - risc0_build::embed_methods(); -} diff --git a/experiments/risc-zero/methods/ec-bench/Cargo.toml b/experiments/risc-zero/methods/ec-bench/Cargo.toml deleted file mode 100644 index 7bfcee6..0000000 --- a/experiments/risc-zero/methods/ec-bench/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "ec-bench-guest" -version = "0.1.0" -edition = "2021" - -[workspace] - -[dependencies] -risc0-zkvm = { version = "3.0", default-features = false, features = ["std"] } -p256 = { version = "0.13", default-features = false, features = ["ecdsa"] } -p384 = { version = "=0.13.0", default-features = false, features = ["ecdsa"] } -ecdsa = { version = "0.16", default-features = false } -sha2 = "0.10" -hex-literal = "0.4" - -[patch.crates-io] -# RISC Zero accelerated crypto -sha2 = { git = "https://github.com/risc0/RustCrypto-hashes", tag = "sha2-v0.10.8-risczero.0" } -crypto-bigint = { git = "https://github.com/risc0/RustCrypto-crypto-bigint", tag = "v0.5.5-risczero.0" } - -# Unified P-256/P-384 RISC Zero acceleration (local fork) -p256 = { path = "../../rustcrypto-elliptic-curves/p256" } -p384 = { path = "../../rustcrypto-elliptic-curves/p384" } -primeorder = { path = "../../rustcrypto-elliptic-curves/primeorder" } diff --git a/experiments/risc-zero/methods/ec-bench/src/main.rs b/experiments/risc-zero/methods/ec-bench/src/main.rs deleted file mode 100644 index 1674c68..0000000 --- a/experiments/risc-zero/methods/ec-bench/src/main.rs +++ /dev/null @@ -1,56 +0,0 @@ -#![no_main] - -use risc0_zkvm::guest::env; - -risc0_zkvm::guest::entry!(main); - -/// Benchmark type to run -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[repr(u8)] -pub enum BenchType { - P256 = 0, - P384 = 1, -} - -fn main() { - // Read which benchmark to run - let bench_type: u8 = env::read(); - - // Read the test data - let pubkey_bytes: Vec = env::read(); - let message_hash: [u8; 32] = env::read(); - let signature_bytes: Vec = env::read(); - - let result = match bench_type { - 0 => verify_p256(&pubkey_bytes, &message_hash, &signature_bytes), - 1 => verify_p384(&pubkey_bytes, &message_hash, &signature_bytes), - _ => panic!("Unknown benchmark type"), - }; - - // Commit the result - env::commit(&result); -} - -fn verify_p256(pubkey_bytes: &[u8], message_hash: &[u8; 32], signature_bytes: &[u8]) -> bool { - use p256::ecdsa::{signature::hazmat::PrehashVerifier, Signature, VerifyingKey}; - - let verifying_key = VerifyingKey::from_sec1_bytes(pubkey_bytes) - .expect("Invalid P-256 public key"); - - let signature = Signature::from_slice(signature_bytes) - .expect("Invalid P-256 signature"); - - verifying_key.verify_prehash(message_hash, &signature).is_ok() -} - -fn verify_p384(pubkey_bytes: &[u8], message_hash: &[u8; 32], signature_bytes: &[u8]) -> bool { - use p384::ecdsa::{signature::hazmat::PrehashVerifier, Signature, VerifyingKey}; - - let verifying_key = VerifyingKey::from_sec1_bytes(pubkey_bytes) - .expect("Invalid P-384 public key"); - - let signature = Signature::from_slice(signature_bytes) - .expect("Invalid P-384 signature"); - - verifying_key.verify_prehash(message_hash, &signature).is_ok() -} diff --git a/experiments/risc-zero/methods/guest/Cargo.toml b/experiments/risc-zero/methods/guest/Cargo.toml deleted file mode 100644 index 14ebd8e..0000000 --- a/experiments/risc-zero/methods/guest/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "vaportpm-zk-guest" -version = "0.1.0" -edition = "2021" - -[workspace] - -[dependencies] -risc0-zkvm = { version = "3.0", default-features = false, features = ["std"] } -vaportpm-verify = { path = "../../../../crates/vaportpm-verify" } -vaportpm-attest = { path = "../../../../crates/vaportpm-attest" } -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -hex = "0.4" -sha2 = "0.10" -rsa = "=0.9.9" # Force version for risczero patch -pki-types = { package = "rustls-pki-types", version = "1.13" } - -[patch.crates-io] -# RISC Zero accelerated crypto -sha2 = { git = "https://github.com/risc0/RustCrypto-hashes", tag = "sha2-v0.10.8-risczero.0" } -rsa = { git = "https://github.com/risc0/RustCrypto-RSA", tag = "v0.9.9-risczero.0" } -crypto-bigint = { git = "https://github.com/risc0/RustCrypto-crypto-bigint", tag = "v0.5.5-risczero.0" } - -# Unified P-256/P-384 RISC Zero acceleration (local fork) -p256 = { path = "../../rustcrypto-elliptic-curves/p256" } -p384 = { path = "../../rustcrypto-elliptic-curves/p384" } -primeorder = { path = "../../rustcrypto-elliptic-curves/primeorder" } diff --git a/experiments/risc-zero/methods/guest/src/main.rs b/experiments/risc-zero/methods/guest/src/main.rs deleted file mode 100644 index d1567dc..0000000 --- a/experiments/risc-zero/methods/guest/src/main.rs +++ /dev/null @@ -1,81 +0,0 @@ -#![no_main] - -use pki_types::UnixTime; -use risc0_zkvm::guest::env; -use serde::{Deserialize, Serialize}; -use sha2::{Digest, Sha256}; -use std::io::Read; -use std::time::Duration; -use vaportpm_verify::{flat, verify_decoded_attestation_output, CloudProvider, P256PublicKey, PcrBank}; - -risc0_zkvm::guest::entry!(main); - -/// Public inputs committed by the ZK circuit -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct ZkPublicInputs { - pub pcr_hash: [u8; 32], - pub ak_pubkey: P256PublicKey, - pub nonce: [u8; 32], - pub provider: u8, - pub verified_at: u64, -} - -fn main() { - // Read raw bytes - no serde deserialization! - let mut input_bytes = Vec::::new(); - env::stdin().read_to_end(&mut input_bytes).unwrap(); - - // Last 8 bytes are the verification timestamp - if input_bytes.len() < 8 { - panic!("Input too short - missing timestamp"); - } - let time_bytes: [u8; 8] = input_bytes[input_bytes.len() - 8..].try_into().unwrap(); - let time_secs = u64::from_le_bytes(time_bytes); - let time = UnixTime::since_unix_epoch(Duration::from_secs(time_secs)); - - // Parse flat binary format (everything except the trailing timestamp) - let flat_data = &input_bytes[..input_bytes.len() - 8]; - let decoded = flat::from_bytes(flat_data).expect("Failed to parse flat input"); - - // Verify using decoded path (no hex::decode, no PEM parsing) - let result = - verify_decoded_attestation_output(&decoded, time).expect("Attestation verification failed"); - - // Compute canonical PCR hash from pre-decoded binary data - let pcr_hash = compute_pcr_hash(&decoded.pcrs); - - // Map provider to u8 (root hash already verified against known roots) - let provider = match result.provider { - CloudProvider::Aws => 0u8, - CloudProvider::Gcp => 1u8, - }; - - // Build and commit public inputs - let public_inputs = ZkPublicInputs { - pcr_hash, - ak_pubkey: decoded.ak_pubkey, - nonce: decoded.nonce, - provider, - verified_at: result.verified_at, - }; - - env::commit(&public_inputs); -} - -/// Compute canonical PCR hash from a validated PcrBank -/// -/// Canonicalization: [alg_u16 LE, count] then each [idx, value...] in index order -fn compute_pcr_hash(pcrs: &PcrBank) -> [u8; 32] { - let mut hasher = Sha256::new(); - - let alg_u16 = pcrs.algorithm() as u16; - hasher.update(alg_u16.to_le_bytes()); - hasher.update([24u8]); - - for (idx, value) in pcrs.values().enumerate() { - hasher.update([idx as u8]); - hasher.update(value); - } - - hasher.finalize().into() -} diff --git a/experiments/risc-zero/methods/src/lib.rs b/experiments/risc-zero/methods/src/lib.rs deleted file mode 100644 index 1bdb308..0000000 --- a/experiments/risc-zero/methods/src/lib.rs +++ /dev/null @@ -1 +0,0 @@ -include!(concat!(env!("OUT_DIR"), "/methods.rs")); diff --git a/experiments/risc-zero/rustcrypto-elliptic-curves b/experiments/risc-zero/rustcrypto-elliptic-curves deleted file mode 160000 index b29e27f..0000000 --- a/experiments/risc-zero/rustcrypto-elliptic-curves +++ /dev/null @@ -1 +0,0 @@ -Subproject commit b29e27fe3a23c9aec0b6afe06011474d54411070 diff --git a/experiments/risc-zero/src/host.rs b/experiments/risc-zero/src/host.rs deleted file mode 100644 index bcac9bf..0000000 --- a/experiments/risc-zero/src/host.rs +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 - -//! Host-side utilities for the ZK experiment -//! -//! This module provides helpers for running attestation verification -//! inside the RISC Zero zkVM from the host side. - -pub use crate::inputs::ZkPublicInputs; diff --git a/experiments/risc-zero/src/inputs.rs b/experiments/risc-zero/src/inputs.rs deleted file mode 100644 index 90d20e9..0000000 --- a/experiments/risc-zero/src/inputs.rs +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 - -//! ZK public inputs for attestation verification - -use serde::{Deserialize, Serialize}; -use serde_big_array::BigArray; - -/// Public inputs committed by the ZK circuit -/// -/// These values are revealed to the verifier and represent the -/// verified attestation claims. -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -pub struct ZkPublicInputs { - /// SHA256 of canonically-serialized PCRs - pub pcr_hash: [u8; 32], - /// P-256 uncompressed public key: 0x04 || x || y - #[serde(with = "BigArray")] - pub ak_pubkey: [u8; 65], - /// Freshness nonce - pub nonce: [u8; 32], - /// Cloud provider: 0 = AWS, 1 = GCP - pub provider: u8, - /// Timestamp used for verification (seconds since Unix epoch) - pub verified_at: u64, -} - -impl ZkPublicInputs { - /// Provider constant for AWS - pub const PROVIDER_AWS: u8 = 0; - /// Provider constant for GCP - pub const PROVIDER_GCP: u8 = 1; -} diff --git a/experiments/risc-zero/src/lib.rs b/experiments/risc-zero/src/lib.rs deleted file mode 100644 index aec0644..0000000 --- a/experiments/risc-zero/src/lib.rs +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 - -//! RISC Zero ZK experiment for vaportpm attestation verification -//! -//! This crate provides an experimental integration of vaportpm attestation -//! verification with RISC Zero's zkVM. The goal is to measure cycle counts -//! and understand the complexity of running attestation verification in ZK. -//! -//! # Structure -//! -//! - `inputs`: Public input types committed by the ZK circuit -//! - `host`: Host-side utilities for running the zkVM -//! -//! # Usage -//! -//! Run the cycle count tests: -//! ```bash -//! cd experiments/risc-zero -//! make cycles -//! ``` - -pub mod host; -pub mod inputs; - -pub use inputs::ZkPublicInputs; diff --git a/experiments/risc-zero/tests/cycle_count.rs b/experiments/risc-zero/tests/cycle_count.rs deleted file mode 100644 index 4a39bb5..0000000 --- a/experiments/risc-zero/tests/cycle_count.rs +++ /dev/null @@ -1,126 +0,0 @@ -use risc0_zkvm::{default_executor, ExecutorEnv}; -use std::fs; -use vaportpm_attest::a9n::AttestationOutput; -use vaportpm_verify::{flat, DecodedAttestationOutput}; -use vaportpm_zk_methods::VAPORTPM_ZK_GUEST_ELF; - -/// Timestamp for GCP test fixture (Feb 2, 2026 when certificates are valid) -const GCP_FIXTURE_TIMESTAMP_SECS: u64 = 1770019200; - -/// Timestamp for Nitro test fixture (Feb 3, 2026 within cert validity window) -const NITRO_FIXTURE_TIMESTAMP_SECS: u64 = 1770116400; - -#[test] -fn test_gcp_attestation_cycle_count() { - // Load test fixture - let attestation_json = - fs::read_to_string("../../crates/vaportpm-verify/test-gcp-amd-fixture.json") - .expect("Failed to load GCP fixture"); - - // Parse JSON on host - let output: AttestationOutput = - serde_json::from_str(&attestation_json).expect("Failed to parse attestation JSON"); - - // Decode to binary format on host - let decoded = - DecodedAttestationOutput::decode(&output).expect("Failed to decode attestation"); - - // Convert to flat binary format with timestamp appended - let mut flat_bytes = flat::to_bytes(&decoded); - flat_bytes.extend_from_slice(&GCP_FIXTURE_TIMESTAMP_SECS.to_le_bytes()); - - let env = ExecutorEnv::builder() - .write_slice(&flat_bytes) // write_slice instead of write! - .build() - .unwrap(); - - let executor = default_executor(); - let session = executor.execute(env, VAPORTPM_ZK_GUEST_ELF).unwrap(); - - println!(); - println!("=== GCP Attestation Verification (Optimized + zerocopy) ==="); - println!("Flat input size: {} bytes", flat_bytes.len()); - println!("Total cycles: {}", session.cycles()); - println!("Segments: {}", session.segments.len()); - println!(); -} - -#[test] -fn test_nitro_attestation_cycle_count() { - // Load test fixture - let attestation_json = - fs::read_to_string("../../crates/vaportpm-verify/test-nitro-fixture.json") - .expect("Failed to load Nitro fixture"); - - // Parse JSON on host - let output: AttestationOutput = - serde_json::from_str(&attestation_json).expect("Failed to parse attestation JSON"); - - // Decode to binary format on host - let decoded = - DecodedAttestationOutput::decode(&output).expect("Failed to decode attestation"); - - // Convert to flat binary format with timestamp appended - let mut flat_bytes = flat::to_bytes(&decoded); - flat_bytes.extend_from_slice(&NITRO_FIXTURE_TIMESTAMP_SECS.to_le_bytes()); - - let env = ExecutorEnv::builder() - .write_slice(&flat_bytes) - .build() - .unwrap(); - - let executor = default_executor(); - let session = executor.execute(env, VAPORTPM_ZK_GUEST_ELF).unwrap(); - - println!(); - println!("=== Nitro Attestation Verification (Optimized + zerocopy) ==="); - println!("Flat input size: {} bytes", flat_bytes.len()); - println!("Total cycles: {}", session.cycles()); - println!("Segments: {}", session.segments.len()); - println!(); -} - -#[test] -fn test_data_size_comparison() { - // Load test fixture - let attestation_json = - fs::read_to_string("../../crates/vaportpm-verify/test-gcp-amd-fixture.json") - .expect("Failed to load GCP fixture"); - - println!("\n=== Original JSON approach ==="); - println!("JSON string length: {} bytes", attestation_json.len()); - - // Parse JSON on host - let output: AttestationOutput = - serde_json::from_str(&attestation_json).expect("Failed to parse attestation JSON"); - - // Decode to binary format - let decoded = - DecodedAttestationOutput::decode(&output).expect("Failed to decode attestation"); - - // Flat binary format (what we now use) + timestamp - let flat_bytes = flat::to_bytes(&decoded); - println!("\n=== Flat binary approach (zerocopy) ==="); - println!("Flat binary size: {} bytes (+ 8 bytes timestamp)", flat_bytes.len()); - - println!("\nComponent sizes:"); - println!(" header: {} bytes (zerocopy, zero-copy parse)", flat::HEADER_SIZE); - println!(" quote_attest: {} bytes", decoded.quote_attest.len()); - println!(" quote_signature: {} bytes", decoded.quote_signature.len()); - - match &decoded.platform { - vaportpm_verify::DecodedPlatformAttestation::Gcp { cert_chain_der } => { - let total_cert_bytes: usize = cert_chain_der.iter().map(|c| c.len()).sum(); - println!( - " cert_chain_der: {} certs, {} total bytes", - cert_chain_der.len(), - total_cert_bytes - ); - } - _ => {} - } - - let pcr_bytes: usize = decoded.pcrs.values().map(|v| v.len()).sum(); - println!(" pcrs: {} entries, {} total bytes", vaportpm_verify::PCR_COUNT, pcr_bytes); - println!(); -} diff --git a/experiments/risc-zero/tests/ec_benchmarks.rs b/experiments/risc-zero/tests/ec_benchmarks.rs deleted file mode 100644 index a12378b..0000000 --- a/experiments/risc-zero/tests/ec_benchmarks.rs +++ /dev/null @@ -1,188 +0,0 @@ -//! Isolated EC benchmarks for comparing P-256 and P-384 performance -//! -//! These tests measure cycle counts for single ECDSA signature verifications -//! to isolate EC performance from other factors (JSON parsing, X.509, etc.) - -use risc0_zkvm::{default_executor, ExecutorEnv}; -use vaportpm_zk_methods::EC_BENCH_GUEST_ELF; - -/// P-256 test vector - valid ECDSA P-256 signature -mod p256_test_vector { - use hex_literal::hex; - - // Public key in uncompressed SEC1 format (0x04 || x || y) - pub const PUBLIC_KEY: [u8; 65] = hex!( - "0460fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6" - "7903fe1008b8bc99a41ae9e95628bc64f2f1b20c2d7e9f5177a3c294d4462299" - ); - - // SHA-256 hash of the message "sample" - pub const MESSAGE_HASH: [u8; 32] = hex!( - "af2bdbe1aa9b6ec1e2ade1d694f41fc71a831d0268e9891562113d8a62add1bf" - ); - - // ECDSA signature (r || s) in fixed-size format - pub const SIGNATURE: [u8; 64] = hex!( - "efd48b2aacb6a8fd1140dd9cd45e81d69d2c877b56aaf991c34d0ea84eaf3716" - "f7cb1c942d657c41d436c7a1b6e29f65f3e900dbb9aff4064dc4ab2f843acda8" - ); -} - -/// P-384 test vector - valid ECDSA P-384 signature -mod p384_test_vector { - use hex_literal::hex; - - // Public key in uncompressed SEC1 format (0x04 || x || y) - pub const PUBLIC_KEY: [u8; 97] = hex!( - "043e80bb19d6500788aaadfab3970aa5c39e75d79bf8dc81e823d4908301a6ffb0" - "ee8fc6e4c76cf03d46a7a379769815c90d23c1bcdbcf4dd37f434f05ae9c524c" - "7f7219c3deaa778eefe3e8e620da823c2670cb023321ce851322bbd1c44932aa" - ); - - // SHA-256 hash of the message "sample" (same as P-256 for fair comparison) - pub const MESSAGE_HASH: [u8; 32] = hex!( - "af2bdbe1aa9b6ec1e2ade1d694f41fc71a831d0268e9891562113d8a62add1bf" - ); - - // ECDSA signature (r || s) in fixed-size format - pub const SIGNATURE: [u8; 96] = hex!( - "d4bc0c427c75dcbfa66c3a7f09a54465d43f69d7978ee454d8abf022621f585a" - "70535448bb1e50647009b6ef6f818400efaa015e183dc460bc456057c555ac95" - "27f34cbbbf325986e463531910176a988c4b3468727172d614ccdcade0ae89df" - ); -} - -#[test] -fn test_p256_ecdsa_cycles() { - let bench_type: u8 = 0; // P-256 - let pubkey = p256_test_vector::PUBLIC_KEY.to_vec(); - let message_hash = p256_test_vector::MESSAGE_HASH; - let signature = p256_test_vector::SIGNATURE.to_vec(); - - let env = ExecutorEnv::builder() - .write(&bench_type) - .unwrap() - .write(&pubkey) - .unwrap() - .write(&message_hash) - .unwrap() - .write(&signature) - .unwrap() - .build() - .unwrap(); - - let executor = default_executor(); - let session = executor.execute(env, EC_BENCH_GUEST_ELF).unwrap(); - - // Verify the signature was valid - let result: bool = session.journal.decode().unwrap(); - assert!(result, "P-256 signature verification should succeed"); - - println!(); - println!("=== P-256 ECDSA Verification ==="); - println!("Total cycles: {}", session.cycles()); - println!("Segments: {}", session.segments.len()); - println!(); -} - -#[test] -fn test_p384_ecdsa_cycles() { - let bench_type: u8 = 1; // P-384 - let pubkey = p384_test_vector::PUBLIC_KEY.to_vec(); - let message_hash = p384_test_vector::MESSAGE_HASH; - let signature = p384_test_vector::SIGNATURE.to_vec(); - - let env = ExecutorEnv::builder() - .write(&bench_type) - .unwrap() - .write(&pubkey) - .unwrap() - .write(&message_hash) - .unwrap() - .write(&signature) - .unwrap() - .build() - .unwrap(); - - let executor = default_executor(); - let session = executor.execute(env, EC_BENCH_GUEST_ELF).unwrap(); - - // Verify the signature was valid - let result: bool = session.journal.decode().unwrap(); - assert!(result, "P-384 signature verification should succeed"); - - println!(); - println!("=== P-384 ECDSA Verification ==="); - println!("Total cycles: {}", session.cycles()); - println!("Segments: {}", session.segments.len()); - println!(); -} - -/// Run both benchmarks and print comparison -#[test] -fn test_ec_comparison() { - // P-256 - let p256_cycles = { - let bench_type: u8 = 0; - let pubkey = p256_test_vector::PUBLIC_KEY.to_vec(); - let message_hash = p256_test_vector::MESSAGE_HASH; - let signature = p256_test_vector::SIGNATURE.to_vec(); - - let env = ExecutorEnv::builder() - .write(&bench_type) - .unwrap() - .write(&pubkey) - .unwrap() - .write(&message_hash) - .unwrap() - .write(&signature) - .unwrap() - .build() - .unwrap(); - - let executor = default_executor(); - let session = executor.execute(env, EC_BENCH_GUEST_ELF).unwrap(); - - let result: bool = session.journal.decode().unwrap(); - assert!(result, "P-256 signature verification should succeed"); - - session.cycles() - }; - - // P-384 - let p384_cycles = { - let bench_type: u8 = 1; - let pubkey = p384_test_vector::PUBLIC_KEY.to_vec(); - let message_hash = p384_test_vector::MESSAGE_HASH; - let signature = p384_test_vector::SIGNATURE.to_vec(); - - let env = ExecutorEnv::builder() - .write(&bench_type) - .unwrap() - .write(&pubkey) - .unwrap() - .write(&message_hash) - .unwrap() - .write(&signature) - .unwrap() - .build() - .unwrap(); - - let executor = default_executor(); - let session = executor.execute(env, EC_BENCH_GUEST_ELF).unwrap(); - - let result: bool = session.journal.decode().unwrap(); - assert!(result, "P-384 signature verification should succeed"); - - session.cycles() - }; - - println!(); - println!("=== EC Performance Comparison ==="); - println!("P-256 ECDSA verify: {} cycles", p256_cycles); - println!("P-384 ECDSA verify: {} cycles", p384_cycles); - println!("Ratio (P-384/P-256): {:.2}x", p384_cycles as f64 / p256_cycles as f64); - println!(); - println!("Expected ratio: 1.5-2.0x (due to larger field size)"); - println!(); -}