world_id_proof/
nullifier.rs1use ark_ff::PrimeField;
4use groth16_material::circom::CircomGroth16Material;
5
6use taceo_oprf::{
7 client::{Connector, VerifiableOprfOutput},
8 core::oprf::BlindingFactor,
9};
10
11use world_id_primitives::{
12 FieldElement, ProofRequest, TREE_DEPTH,
13 circuit_inputs::QueryProofCircuitInput,
14 oprf::{NullifierOprfRequestAuthV1, OprfModule},
15};
16
17use crate::{
18 AuthenticatorProofInput,
19 proof::{OPRF_PROOF_DS, ProofError},
20};
21
22#[derive(Debug, Clone)]
24pub struct OprfNullifier {
25 pub query_proof_input: QueryProofCircuitInput<TREE_DEPTH>,
27 pub verifiable_oprf_output: VerifiableOprfOutput,
29}
30
31impl OprfNullifier {
32 pub async fn generate(
53 services: &[String],
54 threshold: usize,
55 query_material: &CircomGroth16Material,
56 authenticator_input: AuthenticatorProofInput,
57 proof_request: &ProofRequest,
58 connector: Connector,
59 ) -> Result<Self, ProofError> {
60 let mut rng = rand::rngs::OsRng;
61
62 let query_blinding_factor = BlindingFactor::rand(&mut rng);
63
64 let siblings: [ark_babyjubjub::Fq; TREE_DEPTH] =
65 authenticator_input.inclusion_proof.siblings.map(|s| *s);
66
67 let action = *proof_request.computed_action(&mut rng);
68 let query_hash = world_id_primitives::authenticator::oprf_query_digest(
69 authenticator_input.inclusion_proof.leaf_index,
70 action.into(),
71 proof_request.rp_id.into(),
72 );
73 let signature = authenticator_input.private_key.sign(*query_hash);
74
75 let query_proof_input = QueryProofCircuitInput::<TREE_DEPTH> {
76 pk: authenticator_input.key_set.as_affine_array(),
77 pk_index: authenticator_input.key_index.into(),
78 s: signature.s,
79 r: signature.r,
80 merkle_root: *authenticator_input.inclusion_proof.root,
81 depth: ark_babyjubjub::Fq::from(TREE_DEPTH as u64),
82 mt_index: authenticator_input.inclusion_proof.leaf_index.into(),
83 siblings,
84 beta: query_blinding_factor.beta(),
85 rp_id: *FieldElement::from(proof_request.rp_id),
86 action,
87 nonce: *proof_request.nonce,
88 };
89
90 tracing::debug!("generating query proof");
91 let (proof, public_inputs) = query_material.generate_proof(&query_proof_input, &mut rng)?;
92 query_material.verify_proof(&proof, &public_inputs)?;
93 tracing::debug!("generated query proof");
94
95 let auth = NullifierOprfRequestAuthV1 {
96 proof: proof.into(),
97 action,
98 nonce: *proof_request.nonce,
99 merkle_root: *authenticator_input.inclusion_proof.root,
100 current_time_stamp: proof_request.created_at,
101 expiration_timestamp: proof_request.expires_at,
102 signature: proof_request.signature,
103 rp_id: proof_request.rp_id,
104 };
105
106 tracing::debug!("executing distributed OPRF");
107
108 let verifiable_oprf_output = taceo_oprf::client::distributed_oprf(
109 services,
110 OprfModule::Nullifier.to_string().as_str(),
111 threshold,
112 *query_hash,
113 query_blinding_factor,
114 ark_babyjubjub::Fq::from_be_bytes_mod_order(OPRF_PROOF_DS),
115 auth,
116 connector,
117 )
118 .await?;
119
120 Ok(Self {
121 query_proof_input,
122 verifiable_oprf_output,
123 })
124 }
125}