world_id_primitives/
authenticator.rs1use std::{
2 ops::{Deref, DerefMut},
3 str::FromStr,
4};
5
6use ark_babyjubjub::{EdwardsAffine, Fq};
7use ark_ff::{AdditiveGroup, PrimeField as _};
8use arrayvec::ArrayVec;
9use eddsa_babyjubjub::{EdDSAPublicKey, EdDSASignature};
10use serde::{Deserialize, Serialize};
11
12use crate::{FieldElement, PrimitiveError};
13
14pub const MAX_AUTHENTICATOR_KEYS: usize = 7;
20
21const OPRF_QUERY_DS: &[u8] = b"World ID Query";
23
24#[must_use]
31pub fn oprf_query_digest(
32 leaf_index: u64,
33 action: FieldElement,
34 query_origin_id: FieldElement,
35) -> FieldElement {
36 let input = [
37 ark_babyjubjub::Fq::from_be_bytes_mod_order(OPRF_QUERY_DS),
38 leaf_index.into(),
39 *query_origin_id,
40 *action,
41 ];
42 poseidon2::bn254::t4::permutation(&input)[1].into()
43}
44
45#[derive(Debug, Clone, Serialize, Deserialize)]
50pub struct AuthenticatorPublicKeySet(ArrayVec<EdDSAPublicKey, MAX_AUTHENTICATOR_KEYS>);
51
52impl AuthenticatorPublicKeySet {
53 pub fn new(pubkeys: Option<Vec<EdDSAPublicKey>>) -> Result<Self, PrimitiveError> {
58 if let Some(pubkeys) = pubkeys {
59 if pubkeys.len() > MAX_AUTHENTICATOR_KEYS {
60 return Err(PrimitiveError::OutOfBounds);
61 }
62
63 Ok(Self(
64 pubkeys
65 .into_iter()
66 .collect::<ArrayVec<_, MAX_AUTHENTICATOR_KEYS>>(),
67 ))
68 } else {
69 Ok(Self(ArrayVec::new()))
70 }
71 }
72
73 pub fn as_affine_array(&self) -> [EdwardsAffine; MAX_AUTHENTICATOR_KEYS] {
77 let mut array = [EdwardsAffine::default(); MAX_AUTHENTICATOR_KEYS];
78 for (i, pubkey) in self.0.iter().enumerate() {
79 array[i] = pubkey.pk;
80 }
81 array
82 }
83
84 #[must_use]
86 pub const fn len(&self) -> usize {
87 self.0.len()
88 }
89
90 #[must_use]
92 pub const fn is_empty(&self) -> bool {
93 self.0.is_empty()
94 }
95
96 #[must_use]
101 pub fn get(&self, index: usize) -> Option<&EdDSAPublicKey> {
102 self.0.get(index)
103 }
104
105 pub fn try_set_at_index(
110 &mut self,
111 index: usize,
112 pubkey: EdDSAPublicKey,
113 ) -> Result<(), PrimitiveError> {
114 if index >= self.len() || index >= MAX_AUTHENTICATOR_KEYS {
115 return Err(PrimitiveError::OutOfBounds);
116 }
117 self.0[index] = pubkey;
118 Ok(())
119 }
120
121 pub fn try_push(&mut self, pubkey: EdDSAPublicKey) -> Result<(), PrimitiveError> {
126 self.0
127 .try_push(pubkey)
128 .map_err(|_| PrimitiveError::OutOfBounds)
129 }
130
131 #[must_use]
136 pub fn leaf_hash(&self) -> Fq {
137 let mut input = [Fq::ZERO; 16];
138
139 input[0] =
140 Fq::from_str("105702839725298824521994315").expect("domain separator fits in field");
141
142 let pk_array = self.as_affine_array();
143 for i in 0..MAX_AUTHENTICATOR_KEYS {
144 input[i * 2 + 1] = pk_array[i].x;
145 input[i * 2 + 2] = pk_array[i].y;
146 }
147
148 poseidon2::bn254::t16::permutation(&input)[1]
149 }
150}
151
152impl Deref for AuthenticatorPublicKeySet {
153 type Target = ArrayVec<EdDSAPublicKey, MAX_AUTHENTICATOR_KEYS>;
154 fn deref(&self) -> &Self::Target {
155 &self.0
156 }
157}
158
159impl DerefMut for AuthenticatorPublicKeySet {
160 fn deref_mut(&mut self) -> &mut Self::Target {
161 &mut self.0
162 }
163}
164
165pub trait ProtocolSigner {
169 fn sign(&self, message: FieldElement) -> EdDSASignature
172 where
173 Self: Sized + Send + Sync;
174}
175
176#[cfg(test)]
177mod tests {
178 use super::*;
179
180 fn create_test_pubkey() -> EdDSAPublicKey {
181 EdDSAPublicKey {
182 pk: EdwardsAffine::default(),
183 }
184 }
185
186 #[test]
187 fn test_try_set_at_index_within_bounds() {
188 let mut key_set = AuthenticatorPublicKeySet::new(None).unwrap();
189 let pubkey = create_test_pubkey();
190
191 let result = key_set.try_set_at_index(0, pubkey.clone());
193 assert!(result.is_err(), "Should not panic, should return error");
194
195 key_set.try_push(pubkey.clone()).unwrap();
197
198 key_set.try_set_at_index(0, pubkey).unwrap();
200 }
201
202 #[test]
203 fn test_try_set_at_index_at_length() {
204 let mut key_set = AuthenticatorPublicKeySet::new(None).unwrap();
205 let pubkey = create_test_pubkey();
206
207 key_set.try_push(pubkey.clone()).unwrap();
209
210 let result = key_set.try_set_at_index(1, pubkey);
212 assert!(result.is_err(), "Should not panic when index equals length");
213 }
214
215 #[test]
216 fn test_try_set_at_index_out_of_bounds() {
217 let mut key_set = AuthenticatorPublicKeySet::new(None).unwrap();
218 let pubkey = create_test_pubkey();
219
220 let result = key_set.try_set_at_index(MAX_AUTHENTICATOR_KEYS, pubkey.clone());
222 assert!(
223 result.is_err(),
224 "Should not panic when index >= MAX_AUTHENTICATOR_KEYS"
225 );
226
227 let result = key_set.try_set_at_index(MAX_AUTHENTICATOR_KEYS + 1, pubkey);
228 assert!(
229 result.is_err(),
230 "Should not panic when index > MAX_AUTHENTICATOR_KEYS"
231 );
232 }
233
234 #[test]
235 fn test_try_push_within_capacity() {
236 let mut key_set = AuthenticatorPublicKeySet::new(None).unwrap();
237 let pubkey = create_test_pubkey();
238
239 for i in 0..MAX_AUTHENTICATOR_KEYS {
241 let result = key_set.try_push(pubkey.clone());
242 assert!(
243 result.is_ok(),
244 "Should not panic when pushing element {} of {}",
245 i + 1,
246 MAX_AUTHENTICATOR_KEYS
247 );
248 }
249
250 assert_eq!(key_set.len(), MAX_AUTHENTICATOR_KEYS);
251
252 let result = key_set.try_push(pubkey);
253 assert!(result.is_err()); }
255
256 #[test]
257 fn test_as_affine_array_empty_set() {
258 let key_set = AuthenticatorPublicKeySet::new(None).unwrap();
259 let array = key_set.as_affine_array();
260
261 assert_eq!(array.len(), MAX_AUTHENTICATOR_KEYS);
263 for affine in &array {
264 assert_eq!(*affine, EdwardsAffine::default());
265 }
266 }
267
268 #[test]
269 fn test_as_affine_array_partial_set() {
270 let mut key_set = AuthenticatorPublicKeySet::new(None).unwrap();
271 let pubkey = create_test_pubkey();
272
273 for _ in 0..3 {
275 key_set.try_push(pubkey.clone()).unwrap();
276 }
277
278 let array = key_set.as_affine_array();
279
280 assert_eq!(array.len(), MAX_AUTHENTICATOR_KEYS);
282
283 for item in array.iter().take(3) {
285 assert_eq!(item, &pubkey.pk);
286 }
287
288 for item in array.iter().take(MAX_AUTHENTICATOR_KEYS).skip(3) {
289 assert_eq!(item, &EdwardsAffine::default());
290 }
291 }
292}