diff --git a/crates/authenticator/Cargo.toml b/crates/authenticator/Cargo.toml index fc0af0bdb..ebb1e5ad7 100644 --- a/crates/authenticator/Cargo.toml +++ b/crates/authenticator/Cargo.toml @@ -19,6 +19,8 @@ include = [ [features] default = ["embed-zkeys"] embed-zkeys = ["world-id-proof/embed-zkeys"] +# Enable ProveKit-backed ownership proof generation. +provekit = ["world-id-proof/zk-ownership-prove", "world-id-primitives/provekit"] # Compress the embedded zkeys to reduce binary size (ARK point compression) compress-zkeys = ["embed-zkeys", "world-id-proof/compress-zkeys"] # Compress the tar archive with zstd @@ -63,7 +65,7 @@ hex = { workspace = true } base64 = { workspace = true } # Internal -world-id-proof = { workspace = true, features = ["zk-ownership-prove"] } +world-id-proof = { workspace = true } world-id-registries = { workspace = true } # Native-only dependencies (not available on wasm32) diff --git a/crates/authenticator/src/prove.rs b/crates/authenticator/src/prove.rs index c12584bda..3b5451ee1 100644 --- a/crates/authenticator/src/prove.rs +++ b/crates/authenticator/src/prove.rs @@ -1,7 +1,9 @@ use secrecy::ExposeSecret; +#[cfg(feature = "provekit")] +use world_id_primitives::OwnershipProof; use world_id_primitives::{ - Credential, FieldElement, OwnershipProof, ProofRequest, ProofResponse, RequestItem, - ResponseItem, SessionId, SessionNullifier, ZeroKnowledgeProof, + Credential, FieldElement, ProofRequest, ProofResponse, RequestItem, ResponseItem, SessionId, + SessionNullifier, ZeroKnowledgeProof, }; use world_id_proof::{ AuthenticatorProofInput, FullOprfOutput, OprfEntrypoint, ProofCompression, @@ -14,6 +16,7 @@ use crate::{ error::AuthenticatorError, }; use world_id_primitives::TREE_DEPTH; +#[cfg(feature = "provekit")] use world_id_proof::{ circuit_inputs::OwnershipProofCircuitInput, ownership_proof::generate_ownership_proof, }; @@ -437,6 +440,7 @@ impl Authenticator { /// /// # Returns /// The [`OwnershipProof`] containing the ZKP and Merkle root. + #[cfg(feature = "provekit")] pub async fn prove_credential_sub( &self, nonce: FieldElement, @@ -473,7 +477,7 @@ impl Authenticator { } } -#[cfg(test)] +#[cfg(all(test, feature = "provekit"))] mod tests { use crate::{ authenticator::Authenticator, diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index b63c4b80d..0657399ff 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -25,6 +25,13 @@ embed-zkeys = ["authenticator", "world-id-proof/embed-zkeys"] compress-zkeys = ["authenticator", "embed-zkeys", "world-id-proof/compress-zkeys"] # Compress the tar archive with zstd zstd-compress-zkeys = ["authenticator", "embed-zkeys", "world-id-proof/zstd-compress-zkeys"] +# Enable ProveKit-backed ownership proofs. +provekit = [ + "authenticator", + "world-id-proof/zk-ownership-prove", + "world-id-authenticator/provekit", + "world-id-primitives/provekit", +] issuer = [ "dep:world-id-issuer", diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index c1efcf31f..f044955f9 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -13,6 +13,8 @@ repository.workspace = true [features] # Enable OpenAPI schema derives for API types. openapi = ["dep:utoipa"] +# Enable ProveKit-backed proof types. +provekit = ["dep:provekit-common"] [dependencies] alloy = { workspace = true, features = ["sol-types", "signer-local"] } @@ -36,7 +38,7 @@ serde = { workspace = true } thiserror = { workspace = true } url = { workspace = true, features = ["serde"] } poseidon2 = { workspace = true } -provekit-common = { workspace = true } +provekit-common = { workspace = true, optional = true } sha3 = { workspace = true, default-features = false } rand = { workspace = true } secrecy = { workspace = true } diff --git a/crates/primitives/src/lib.rs b/crates/primitives/src/lib.rs index c5646d1d7..830e9792f 100644 --- a/crates/primitives/src/lib.rs +++ b/crates/primitives/src/lib.rs @@ -57,7 +57,9 @@ pub use session::{SessionFeType, SessionFieldElement, SessionId, SessionNullifie /// Contains the quintessential zero-knowledge proof type. pub mod proof; -pub use proof::{OwnershipProof, ZeroKnowledgeProof}; +#[cfg(feature = "provekit")] +pub use proof::OwnershipProof; +pub use proof::ZeroKnowledgeProof; /// Contains types specifically related to relying parties. pub mod rp; diff --git a/crates/primitives/src/proof.rs b/crates/primitives/src/proof.rs index 1ab986deb..ecfc9d04f 100644 --- a/crates/primitives/src/proof.rs +++ b/crates/primitives/src/proof.rs @@ -1,6 +1,7 @@ use ruint::aliases::U256; use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as _}; +#[cfg(feature = "provekit")] use crate::FieldElement; /// Encoded World ID Proof. @@ -102,6 +103,7 @@ impl From for [U256; 5] { /// /// Contains the ZKP and the Merkle root public input that the verifier /// doesn't initially provide. +#[cfg(feature = "provekit")] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct OwnershipProof { /// The WHIR R1CS proof from ProveKit. @@ -180,6 +182,7 @@ mod tests { assert!(result.unwrap_err().contains("Invalid length")); } + #[cfg(feature = "provekit")] #[test] fn test_ownership_proof_json_roundtrip() { let whir_proof = provekit_common::WhirR1CSProof { @@ -204,6 +207,7 @@ mod tests { /// This test simulates the data-level check that a verifier would perform: /// if the merkle root stored inside an [`OwnershipProof`] has been tampered /// with, the proof object is distinguishable from the original. + #[cfg(feature = "provekit")] #[test] fn test_ownership_proof_wrong_merkle_root_is_detected() { let whir_proof = provekit_common::WhirR1CSProof { @@ -235,6 +239,7 @@ mod tests { /// This test simulates the data-level check that a verifier would perform: /// if the proof bytes inside an [`OwnershipProof`] have been tampered with, /// the proof object is distinguishable from the original. + #[cfg(feature = "provekit")] #[test] fn test_ownership_proof_tampered_bytes_is_detected() { let original_bytes = vec![0xde, 0xad, 0xbe, 0xef]; diff --git a/crates/proof/Cargo.toml b/crates/proof/Cargo.toml index bacc43a8b..ccc9bc67b 100644 --- a/crates/proof/Cargo.toml +++ b/crates/proof/Cargo.toml @@ -30,8 +30,9 @@ zstd-compress-zkeys = ["embed-zkeys", "dep:zstd"] # Experimental: Feature Flags for Specific Circuits # RATIONALE: We feature flag each circuit and based on the proving/verifying action because each require # a proving and verifying key that generally is above >1Mb. So selecting circuits optimizes bundle size. -zk-ownership-prove = ["dep:provekit-prover"] -zk-ownership-verify = ["dep:provekit-verifier"] +provekit = ["dep:provekit-common", "world-id-primitives/provekit"] +zk-ownership-prove = ["dep:provekit-prover", "provekit"] +zk-ownership-verify = ["dep:provekit-verifier", "provekit"] [dependencies] ark-babyjubjub = { workspace = true } @@ -46,7 +47,7 @@ thiserror = { workspace = true } tracing = { workspace = true } zstd = { workspace = true, optional = true } eddsa-babyjubjub = { workspace = true } -provekit-common = { workspace = true } +provekit-common = { workspace = true, optional = true } provekit-prover = { workspace = true, optional = true } provekit-verifier = { workspace = true, optional = true } rand = { workspace = true } diff --git a/crates/proof/src/lib.rs b/crates/proof/src/lib.rs index bdbf2596c..0ca6ae7e3 100644 --- a/crates/proof/src/lib.rs +++ b/crates/proof/src/lib.rs @@ -20,13 +20,16 @@ pub use oprf_query::{FullOprfOutput, OprfEntrypoint}; pub mod proof; pub use proof::*; +#[cfg(feature = "provekit")] use provekit_common::{InputMap, InputValue, NoirElement}; +#[cfg(feature = "provekit")] use world_id_primitives::FieldElement; -#[cfg(any(feature = "zk-ownership-prove", feature = "zk-ownership-verify"))] +#[cfg(feature = "provekit")] pub mod ownership_proof; +#[cfg(feature = "provekit")] pub use provekit_common::{NoirProof, WhirR1CSProof}; /// Error type for OPRF operations and proof generation. @@ -55,14 +58,17 @@ pub enum ProofError { InternalError(#[from] eyre::Report), } +#[cfg(feature = "provekit")] pub trait NoirCircuitInput { fn into_witness(self) -> Result; } +#[cfg(feature = "provekit")] pub trait NoirRepresentable { fn into_noir_value(self) -> InputValue; } +#[cfg(feature = "provekit")] impl NoirRepresentable for FieldElement { fn into_noir_value(self) -> InputValue { InputValue::Field(NoirElement::from_repr(*self))