Skip to main content

world_id_proof/
circuit_inputs.rs

1//! Circuit input types for the World ID Protocol circuits.
2//!
3//! This module requires the `circuits` feature and is not available in WASM builds.
4
5use std::collections::HashMap;
6
7use eddsa_babyjubjub::EdDSASignature;
8use groth16_material::circom::ProofInput;
9use ruint::aliases::U256;
10
11use world_id_primitives::{
12    AuthenticatorPublicKeySet, FieldElement, MAX_AUTHENTICATOR_KEYS, merkle::MerkleInclusionProof,
13};
14
15type BaseField = ark_babyjubjub::Fq;
16type ScalarField = ark_babyjubjub::Fr;
17type Affine = ark_babyjubjub::EdwardsAffine;
18
19#[inline]
20pub(crate) fn fq_to_u256_vec(f: ark_babyjubjub::Fq) -> Vec<U256> {
21    vec![f.into()]
22}
23
24#[inline]
25pub(crate) fn fq_seq_to_u256_vec(fs: &[ark_babyjubjub::Fq]) -> Vec<U256> {
26    fs.iter().copied().map(Into::into).collect()
27}
28
29#[inline]
30pub(crate) fn fr_to_u256_vec(f: ark_babyjubjub::Fr) -> Vec<U256> {
31    vec![f.into()]
32}
33
34#[inline]
35pub(crate) fn affine_to_u256_vec(p: ark_babyjubjub::EdwardsAffine) -> Vec<U256> {
36    vec![p.x.into(), p.y.into()]
37}
38
39#[inline]
40pub(crate) fn affine_seq_to_u256_vec(ps: &[ark_babyjubjub::EdwardsAffine]) -> Vec<U256> {
41    ps.iter()
42        .copied()
43        .flat_map(|p| [p.x.into(), p.y.into()])
44        .collect()
45}
46
47/// The input for the circuit of the OPRF Query Proof `π1`.
48///
49/// TODO: Rename attribute names to match the `Credential` type.
50#[derive(Debug, Clone)]
51pub struct QueryProofCircuitInput<const MAX_DEPTH: usize> {
52    /// The `AuthenticatorPublicKeySet` represented as an array of Affine points.
53    pub pk: [Affine; MAX_AUTHENTICATOR_KEYS],
54    /// The index of the public key which will be used to sign the OPRF query from the `AuthenticatorPublicKeySet`.
55    pub pk_index: BaseField,
56    /// The `s` part of the signature of the query with the public key at the `pk_index`.
57    pub s: ScalarField,
58    /// The `r` part of the signature of the query with the public key at the `pk_index`.
59    pub r: Affine,
60    /// The root of the Merkle tree of the `WorldIDRegistry` contract.
61    pub merkle_root: BaseField,
62    /// The depth of the Merkle tree of the `WorldIDRegistry` contract.
63    pub depth: BaseField,
64    /// The leaf index of the World ID in the Merkle tree of the `WorldIDRegistry` contract.
65    ///
66    /// In the `MerkleInclusionProof` type, this is the `leaf_index` field.
67    pub mt_index: BaseField,
68    /// The siblings of the Merkle proof of the account in the `WorldIDRegistry` contract.
69    pub siblings: [BaseField; MAX_DEPTH],
70    /// The (non-inverted) blinding factor of the OPRF query.
71    pub beta: ScalarField,
72    /// The ID of the RP requesting the proof as registered in the `RpRegistry` contract.
73    ///
74    /// TODO: Will require updates once the new `RpRegistry` is launched.
75    pub rp_id: BaseField,
76    /// The action for the proof request. See `ProofRequest` for more details.
77    pub action: BaseField,
78    /// The nonce of the proof request. See `ProofRequest` for more details.
79    pub nonce: BaseField,
80}
81
82impl<const MAX_DEPTH: usize> ProofInput for QueryProofCircuitInput<MAX_DEPTH> {
83    fn prepare_input(&self) -> HashMap<String, Vec<U256>> {
84        let mut map = HashMap::new();
85        map.insert("pk".to_owned(), affine_seq_to_u256_vec(&self.pk));
86        map.insert("pk_index".to_owned(), fq_to_u256_vec(self.pk_index));
87        map.insert("s".to_owned(), fr_to_u256_vec(self.s));
88        map.insert("r".to_owned(), affine_to_u256_vec(self.r));
89        map.insert("merkle_root".to_owned(), fq_to_u256_vec(self.merkle_root));
90        map.insert("depth".to_owned(), fq_to_u256_vec(self.depth));
91        map.insert("mt_index".to_owned(), fq_to_u256_vec(self.mt_index));
92        map.insert("siblings".to_owned(), fq_seq_to_u256_vec(&self.siblings));
93        map.insert("beta".to_owned(), fr_to_u256_vec(self.beta));
94        map.insert("rp_id".to_owned(), fq_to_u256_vec(self.rp_id));
95        map.insert("action".to_owned(), fq_to_u256_vec(self.action));
96        map.insert("nonce".to_owned(), fq_to_u256_vec(self.nonce));
97        map
98    }
99}
100
101/// The input for the circuit of the Uniqueness Proof `π2` (internally also nullifier proof).
102///
103/// Externally, the Nullifier Proof is exposed to RPs as a Uniqueness Proof or a Session Proof respectively.
104#[derive(Debug, Clone)]
105pub struct NullifierProofCircuitInput<const MAX_DEPTH: usize> {
106    /// The input for the circuit of the OPRF Query Proof from which this nullifier proof is constructed.
107    pub query_input: QueryProofCircuitInput<MAX_DEPTH>,
108
109    // SECTION: Credential Inputs
110    /// The id as registered in the `CredentialSchemaIssuerRegistry` representing the (issuer, schema) pair.
111    ///
112    /// This is the `issuer_schema_id` field of the `Credential` type.
113    pub issuer_schema_id: BaseField,
114    /// The public key of the issuer of the credential. This is stored in the `Credential` type in the `issuer` field.
115    pub cred_pk: Affine,
116    /// A specific commitment to particular claims of the `Credential`. In particular:
117    /// [`claims_hash`, `associated_data_commitment`]
118    pub cred_hashes: [BaseField; 2],
119    /// The `genesis_issued_at` attribute of the `Credential`. See the `Credential` type for more details.
120    pub cred_genesis_issued_at: BaseField,
121    /// The `expires_at` attribute of the `Credential`. See the `Credential` type for more details.
122    pub cred_expires_at: BaseField,
123    /// The `s` part of the signature of the credential (signed by the issuer)
124    pub cred_s: ScalarField,
125    /// The `r` part of the signature of the credential (signed by the issuer)
126    pub cred_r: Affine,
127    /// The timestamp from the request.
128    pub current_timestamp: BaseField,
129    /// The `genesis_issued_at_min` attribute of the `Credential`. See the `Credential` type for more details.
130    pub cred_genesis_issued_at_min: BaseField,
131    /// The `cred_user_id_r` blinding factor used to generate the `sub`.
132    pub cred_sub_blinding_factor: BaseField,
133    /// Packed `Credential` `id` and `issuer_version` that occupies the last
134    /// slot of the credential hash permutation. The value is the field element
135    /// representation of `BigInt([id, issuer_version, 0, 0])`, i.e.
136    /// `id + issuer_version`.
137    pub cred_id: BaseField,
138
139    // SECTION: User Inputs
140    /// The random commitment for future session proofs generated by the Authenticator.
141    ///
142    /// TODO: Rename to match new terms and avoid confusion with World ID <3.0's `identity_commitment`.
143    pub id_commitment_r: BaseField,
144
145    /// The identity commitment for future session proofs.
146    ///
147    /// Is used internally to check for equality against the computed identity commitment.
148    /// If set to 0, all computed identity commitments will be accepted.
149    pub id_commitment: BaseField,
150
151    // SECTION: OPRF Inputs
152    /// The `e` part of the `DLog` equality proof (Fiat-Shamir challenge)
153    pub dlog_e: BaseField,
154    /// The `s` part of the `DLog` equality proof (proof response)
155    pub dlog_s: ScalarField,
156    /// The public key of the OPRF Nodes for the particular RP (this is the `RpNullifierKey`).
157    pub oprf_pk: Affine,
158    /// The combined blinded response after aggregating peer commitments from the OPRF nodes.
159    pub oprf_response_blinded: Affine,
160    /// The unblinded response from from the OPRF nodes.
161    pub oprf_response: Affine,
162
163    // SECTION: RP Inputs
164    /// The hashed signal provided by the RP and committed to by the user. See `ProofRequest` for more details.
165    pub signal_hash: BaseField,
166}
167
168impl<const MAX_DEPTH: usize> ProofInput for NullifierProofCircuitInput<MAX_DEPTH> {
169    fn prepare_input(&self) -> std::collections::HashMap<String, Vec<ruint::aliases::U256>> {
170        let mut map = self.query_input.prepare_input();
171        map.insert(
172            "issuer_schema_id".to_owned(),
173            fq_to_u256_vec(self.issuer_schema_id),
174        );
175        map.insert("cred_pk".to_owned(), affine_to_u256_vec(self.cred_pk));
176        map.insert(
177            "cred_hashes".to_owned(),
178            fq_seq_to_u256_vec(&self.cred_hashes),
179        );
180        map.insert(
181            "cred_genesis_issued_at".to_owned(),
182            fq_to_u256_vec(self.cred_genesis_issued_at),
183        );
184        map.insert(
185            "cred_genesis_issued_at_min".to_owned(),
186            fq_to_u256_vec(self.cred_genesis_issued_at_min),
187        );
188        map.insert(
189            "cred_expires_at".to_owned(),
190            fq_to_u256_vec(self.cred_expires_at),
191        );
192        map.insert("cred_id".to_owned(), fq_to_u256_vec(self.cred_id));
193        map.insert(
194            "cred_user_id_r".to_owned(),
195            fq_to_u256_vec(self.cred_sub_blinding_factor),
196        );
197        map.insert("cred_s".to_owned(), fr_to_u256_vec(self.cred_s));
198        map.insert("cred_r".to_owned(), affine_to_u256_vec(self.cred_r));
199
200        map.insert(
201            "id_commitment_r".to_owned(),
202            fq_to_u256_vec(self.id_commitment_r),
203        );
204        map.insert(
205            "id_commitment".to_owned(),
206            fq_to_u256_vec(self.id_commitment),
207        );
208
209        map.insert("dlog_e".to_owned(), fq_to_u256_vec(self.dlog_e));
210        map.insert("dlog_s".to_owned(), fr_to_u256_vec(self.dlog_s));
211        map.insert("oprf_pk".to_owned(), affine_to_u256_vec(self.oprf_pk));
212        map.insert(
213            "oprf_response_blinded".to_owned(),
214            affine_to_u256_vec(self.oprf_response_blinded),
215        );
216        map.insert(
217            "oprf_response".to_owned(),
218            affine_to_u256_vec(self.oprf_response),
219        );
220        map.insert("signal_hash".to_owned(), fq_to_u256_vec(self.signal_hash));
221        map.insert(
222            "current_timestamp".to_owned(),
223            fq_to_u256_vec(self.current_timestamp),
224        );
225
226        map
227    }
228}
229
230/// Inputs for the "Proof of Ownership" (WIP-103) circuit.
231#[derive(Debug, Clone)]
232pub struct OwnershipProofCircuitInput<const MAX_DEPTH: usize> {
233    /// Private input. The index of the authenticator key used to sign the proof request
234    pub key_index: u64,
235    /// Private input. The full authenticator key set for the user's World ID
236    pub key_set: AuthenticatorPublicKeySet,
237    /// Private input (**except** the `root` and `depth`). The inclusion proof in the `WorldIDRegistry`
238    pub inclusion_proof: MerkleInclusionProof<MAX_DEPTH>,
239    /// **Public input**. The nonce of the proof request as provided by the verifier.
240    pub nonce: FieldElement,
241    /// Private input. Signature from the authenticator on the query.
242    pub signature: EdDSASignature,
243    /// Private input. The commitment's `r` blinder
244    pub commitment_blinder: FieldElement,
245}