Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ rust-version = "1.87"
# alloy
alloy = { version = "1.7.3", default-features = false }
alloy-primitives = { version = "1.5.6", default-features = false }
alloy-signer = { version = "1.7.3", default-features = false }
alloy-signer-local = { version = "1.7.3", default-features = false }
alloy-node-bindings = "1.0.42"

anyhow = "1"
Expand Down
3 changes: 2 additions & 1 deletion crates/authenticator/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ alloy = { workspace = true, features = [
"providers",
"contract",
"reqwest",
"signer-local"
] }
anyhow = { workspace = true }
ark-babyjubjub = { workspace = true }
Expand All @@ -39,7 +40,7 @@ reqwest = { workspace = true, features = ["json"] }
poseidon2 = { workspace = true }
eddsa-babyjubjub = { workspace = true }
eyre = { workspace = true }
world-id-primitives = { workspace = true }
world-id-primitives = { workspace = true, features = ["proofs"] }
Comment thread
paolodamico marked this conversation as resolved.
secrecy = { workspace = true }
taceo-oprf = { workspace = true, features = ["client"] }
thiserror = { workspace = true }
Expand Down
5 changes: 1 addition & 4 deletions crates/authenticator/src/authenticator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,6 @@ use world_id_primitives::{
},
};

#[expect(unused_imports, reason = "used for docs")]
use world_id_primitives::{Nullifier, SessionId};

/// Shared helper that polls `GET {gateway_url}/status/{request_id}` and
/// returns the current [`GatewayRequestState`].
pub(crate) async fn fetch_gateway_status(
Expand Down Expand Up @@ -91,7 +88,7 @@ pub struct CredentialInput {
pub struct ProofResult {
/// The session_id_r_seed (`r`), if a session proof was generated.
///
/// The SDK should cache this keyed by [`SessionId::oprf_seed`].
/// The SDK should cache this keyed by [`SessionId::oprf_seed`](world_id_primitives::SessionId::oprf_seed).
pub session_id_r_seed: Option<FieldElement>,

/// The response to deliver to an RP.
Expand Down
18 changes: 13 additions & 5 deletions crates/primitives/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,31 @@ rust-version.workspace = true
repository.workspace = true

[features]
default = []
# Enable OpenAPI schema derives for API types.
openapi = ["dep:utoipa"]
# Enable proof generation types (circuit inputs, Groth16 proof construction).
proofs = ["dep:ark-groth16", "dep:groth16-material", "dep:taceo-groth16-sol"]


[dependencies]
alloy = { workspace = true, features = ["sol-types", "signer-local"] }
alloy-primitives = { workspace = true, default-features = false, features = [
"serde",
"std",
] }
alloy-signer = { workspace = true }
alloy-signer-local = { workspace = true }
ark-babyjubjub = { workspace = true }
ark-bn254 = { workspace = true }
ark-ff = { workspace = true }
ark-groth16 = { workspace = true }
ark-groth16 = { workspace = true, optional = true }
ark-serde-compat = { workspace = true }
arrayvec = { workspace = true, features = ["serde"] }
circom-types = { workspace = true, features = ["groth16"] }
groth16-material = { workspace = true, features = ["circom"] }
groth16-material = { workspace = true, features = ["circom"], optional = true }
eddsa-babyjubjub = { workspace = true }
eyre = { workspace = true }
hex = { workspace = true }
taceo-groth16-sol = { workspace = true }
taceo-groth16-sol = { workspace = true, optional = true }
taceo-oprf = { workspace = true, features = ["types"] }
ruint = { workspace = true, features = ["ark-ff-05"] }
serde_json = { workspace = true }
Expand All @@ -54,3 +59,6 @@ getrandom = { workspace = true, features = ["js"] }
[dev-dependencies]
ark-serialize = { workspace = true }
ciborium = { workspace = true }

[metadata.docs.rs]
features = ["proofs"]
29 changes: 20 additions & 9 deletions crates/primitives/src/credential.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,9 +307,16 @@ impl Credential {
/// # Errors
/// Will error if there are more claims than the maximum allowed.
/// Will error if the claims cannot be lowered into the field. Should not occur in practice.
pub fn claims_hash(&self) -> Result<FieldElement, eyre::Error> {
pub fn claims_hash(&self) -> Result<FieldElement, PrimitiveError> {
if self.claims.len() > Self::MAX_CLAIMS {
eyre::bail!("There can be at most {} claims", Self::MAX_CLAIMS);
return Err(PrimitiveError::InvalidInput {
attribute: "claims".to_string(),
reason: format!(
"there can be at most {} claims, got {}",
Self::MAX_CLAIMS,
self.claims.len()
),
});
}
let mut input = [*FieldElement::ZERO; Self::MAX_CLAIMS];
for (i, claim) in self.claims.iter().enumerate() {
Expand All @@ -326,7 +333,7 @@ impl Credential {
/// # Errors
/// - Will error if there are more claims than the maximum allowed.
/// - Will error if the claims cannot be lowered into the field. Should not occur in practice.
pub fn hash(&self) -> Result<FieldElement, eyre::Error> {
pub fn hash(&self) -> Result<FieldElement, PrimitiveError> {
match self.version {
CredentialVersion::V1 => {
let mut input = [
Expand All @@ -349,7 +356,7 @@ impl Credential {
///
/// # Errors
/// Will error if the credential cannot be hashed.
pub fn sign(self, signer: &EdDSAPrivateKey) -> Result<Self, eyre::Error> {
pub fn sign(self, signer: &EdDSAPrivateKey) -> Result<Self, PrimitiveError> {
let mut credential = self;
credential.signature = Some(signer.sign(*credential.hash()?));
credential.issuer = signer.public();
Expand All @@ -364,16 +371,20 @@ impl Credential {
pub fn verify_signature(
&self,
expected_issuer_pubkey: &EdDSAPublicKey,
) -> Result<bool, eyre::Error> {
) -> Result<bool, PrimitiveError> {
if &self.issuer != expected_issuer_pubkey {
return Err(eyre::eyre!(
"Issuer public key does not match expected public key"
));
return Err(PrimitiveError::InvalidInput {
attribute: "issuer".to_string(),
reason: "issuer public key does not match expected public key".to_string(),
});
}
if let Some(signature) = &self.signature {
return Ok(self.issuer.verify(*self.hash()?, signature));
}
Err(eyre::eyre!("Credential not signed"))
Err(PrimitiveError::InvalidInput {
attribute: "signature".to_string(),
reason: "credential not signed".to_string(),
})
}

/// Compute the `sub` for a credential computed from `leaf_index` and a `blinding_factor`.
Expand Down
1 change: 1 addition & 0 deletions crates/primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ pub use config::Config;
/// Contains the raw circuit input types for the World ID Protocol.
///
/// These types are used to prepare the inputs for the Groth16 circuits.
#[cfg(feature = "proofs")]
pub mod circuit_inputs;

/// SAFE-style sponge utilities and helpers.
Expand Down
11 changes: 8 additions & 3 deletions crates/primitives/src/proof.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use ark_bn254::Bn254;
use ark_groth16::Proof;
use ruint::aliases::U256;
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as _};

#[cfg(feature = "proofs")]
use crate::FieldElement;

/// Encoded World ID Proof.
Expand All @@ -19,10 +18,14 @@ pub struct ZeroKnowledgeProof {
inner: [U256; 5],
}

#[cfg(feature = "proofs")]
impl ZeroKnowledgeProof {
/// Initialize a new proof from a Groth16 proof and Merkle root.
#[must_use]
pub fn from_groth16_proof(groth16_proof: &Proof<Bn254>, merkle_root: FieldElement) -> Self {
pub fn from_groth16_proof(
groth16_proof: &ark_groth16::Proof<ark_bn254::Bn254>,
merkle_root: FieldElement,
) -> Self {
let compressed_proof = taceo_groth16_sol::prepare_compressed_proof(groth16_proof);
Self {
inner: [
Expand All @@ -34,7 +37,9 @@ impl ZeroKnowledgeProof {
],
}
}
}

impl ZeroKnowledgeProof {
/// Outputs the proof as a Solidity-friendly representation.
#[must_use]
pub const fn as_ethereum_representation(&self) -> [U256; 5] {
Expand Down
11 changes: 5 additions & 6 deletions crates/primitives/src/request/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ pub struct ProofRequest {
pub action: Option<FieldElement>,
/// The RP's ECDSA signature over the request.
#[serde(with = "crate::serde_utils::hex_signature")]
pub signature: alloy::signers::Signature,
pub signature: alloy_signer::Signature,
/// Unique nonce for this request provided by the RP.
pub nonce: FieldElement,
/// Specific credential requests. This defines which credentials to ask for.
Expand Down Expand Up @@ -681,14 +681,13 @@ where
mod tests {
use super::*;
use crate::SessionNullifier;
use alloy::{
signers::{SignerSync, local::PrivateKeySigner},
uint,
};
use alloy_signer::SignerSync;
use alloy_signer_local::PrivateKeySigner;
use k256::ecdsa::SigningKey;
use ruint::uint;

// Test helpers
fn test_signature() -> alloy::signers::Signature {
fn test_signature() -> alloy_signer::Signature {
let signer =
PrivateKeySigner::from_signing_key(SigningKey::from_bytes(&[1u8; 32].into()).unwrap());
signer.sign_message_sync(b"test").expect("can sign")
Expand Down
3 changes: 2 additions & 1 deletion crates/primitives/src/signer.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::PrimitiveError;
use alloy::{primitives::Address, signers::local::PrivateKeySigner};
use alloy_primitives::Address;
use alloy_signer_local::PrivateKeySigner;
use eddsa_babyjubjub::{EdDSAPrivateKey, EdDSAPublicKey};
use secrecy::{ExposeSecret, SecretBox};

Expand Down
2 changes: 1 addition & 1 deletion crates/proof/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ eyre = { workspace = true }
zeroize = { workspace = true }

# Internal
world-id-primitives = { workspace = true }
world-id-primitives = { workspace = true, features = ["proofs"] }

[build-dependencies]
eyre = { workspace = true }
Expand Down
2 changes: 1 addition & 1 deletion crates/proof/src/proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ pub fn generate_nullifier_proof<R: Rng + CryptoRng>(
issuer_schema_id: credential.issuer_schema_id.into(),
cred_pk: credential.issuer.pk,
cred_hashes: [
*credential.claims_hash()?,
*credential.claims_hash().map_err(eyre::Report::from)?,
*credential.associated_data_commitment,
],
cred_genesis_issued_at: credential.genesis_issued_at.into(),
Expand Down
2 changes: 1 addition & 1 deletion services/oprf-dev-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,6 @@ tracing = { workspace = true }
uuid = { workspace = true, features = ["serde", "v4"] }
webpki-roots = { workspace = true }
world-id-core = { workspace = true, features = ["authenticator", "embed-zkeys"] }
world-id-primitives = { workspace = true }
world-id-primitives = { workspace = true, features = ["proofs"] }
world-id-proof = { workspace = true }
world-id-test-utils = { workspace = true }
2 changes: 1 addition & 1 deletion services/oprf-node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ tokio-util = { workspace = true }
tracing = { workspace = true }
uuid = { workspace = true, features = ["serde", "v4"] }
world-id-core = { workspace = true, features = ["authenticator", "embed-zkeys"] }
world-id-primitives = { workspace = true }
world-id-primitives = { workspace = true, features = ["proofs"] }

[dev-dependencies]
ark-serialize.workspace = true
Expand Down
Loading