1use 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 ruint::aliases::U256;
11use serde::{Deserialize, Serialize};
12
13use crate::{FieldElement, PrimitiveError};
14
15pub const MAX_AUTHENTICATOR_KEYS: usize = 7;
21
22#[derive(Debug, thiserror::Error, Clone, PartialEq, Eq)]
24pub enum SparseAuthenticatorPubkeysError {
25 #[error(
27 "invalid authenticator pubkey slot {slot_index}; max supported slot is {max_supported_slot}"
28 )]
29 SlotOutOfBounds {
30 slot_index: usize,
32 max_supported_slot: usize,
34 },
35 #[error("invalid authenticator public key at slot {slot_index}: {reason}")]
37 InvalidCompressedPubkey {
38 slot_index: usize,
40 reason: String,
42 },
43}
44
45const OPRF_QUERY_DS: &[u8] = b"World ID Query";
47
48#[must_use]
55pub fn oprf_query_digest(
56 leaf_index: u64,
57 action: FieldElement,
58 query_origin_id: FieldElement,
59) -> FieldElement {
60 let input = [
61 ark_babyjubjub::Fq::from_be_bytes_mod_order(OPRF_QUERY_DS),
62 leaf_index.into(),
63 *query_origin_id,
64 *action,
65 ];
66 poseidon2::bn254::t4::permutation(&input)[1].into()
67}
68
69pub fn decode_sparse_authenticator_pubkeys(
79 pubkeys: Vec<Option<U256>>,
80) -> Result<AuthenticatorPublicKeySet, SparseAuthenticatorPubkeysError> {
81 let last_present_idx = pubkeys.iter().rposition(Option::is_some);
82 if let Some(idx) = last_present_idx
83 && idx >= MAX_AUTHENTICATOR_KEYS
84 {
85 return Err(SparseAuthenticatorPubkeysError::SlotOutOfBounds {
86 slot_index: idx,
87 max_supported_slot: MAX_AUTHENTICATOR_KEYS - 1,
88 });
89 }
90
91 let normalized_len = last_present_idx.map_or(0, |idx| idx + 1);
92 let decoded_pubkeys = pubkeys
93 .into_iter()
94 .take(normalized_len)
95 .enumerate()
96 .map(|(idx, pubkey)| match pubkey {
97 Some(pubkey) => EdDSAPublicKey::from_compressed_bytes(pubkey.to_le_bytes())
98 .map(Some)
99 .map_err(
100 |e| SparseAuthenticatorPubkeysError::InvalidCompressedPubkey {
101 slot_index: idx,
102 reason: e.to_string(),
103 },
104 ),
105 None => Ok(None),
106 })
107 .collect::<Result<Vec<_>, _>>()?;
108
109 Ok(AuthenticatorPublicKeySet(
110 decoded_pubkeys
111 .into_iter()
112 .collect::<ArrayVec<_, MAX_AUTHENTICATOR_KEYS>>(),
113 ))
114}
115
116#[derive(Debug, Clone, Serialize, Deserialize)]
123pub struct AuthenticatorPublicKeySet(ArrayVec<Option<EdDSAPublicKey>, MAX_AUTHENTICATOR_KEYS>);
124
125impl Default for AuthenticatorPublicKeySet {
126 fn default() -> Self {
127 Self(ArrayVec::new())
128 }
129}
130
131impl AuthenticatorPublicKeySet {
132 pub fn new(pubkeys: Vec<EdDSAPublicKey>) -> Result<Self, PrimitiveError> {
140 if pubkeys.len() > MAX_AUTHENTICATOR_KEYS {
141 return Err(PrimitiveError::OutOfBounds);
142 }
143
144 Ok(Self(
145 pubkeys
146 .into_iter()
147 .map(Some)
148 .collect::<ArrayVec<_, MAX_AUTHENTICATOR_KEYS>>(),
149 ))
150 }
151
152 pub fn as_affine_array(&self) -> [EdwardsAffine; MAX_AUTHENTICATOR_KEYS] {
157 let mut array = [EdwardsAffine::default(); MAX_AUTHENTICATOR_KEYS];
158 for (i, pubkey) in self.0.iter().enumerate() {
159 array[i] = pubkey
160 .as_ref()
161 .map_or_else(EdwardsAffine::default, |pubkey| pubkey.pk);
162 }
163 array
164 }
165
166 #[must_use]
168 pub const fn len(&self) -> usize {
169 self.0.len()
170 }
171
172 #[must_use]
174 pub const fn is_empty(&self) -> bool {
175 self.0.is_empty()
176 }
177
178 #[must_use]
183 pub fn get(&self, index: usize) -> Option<&EdDSAPublicKey> {
184 self.0.get(index).and_then(Option::as_ref)
185 }
186
187 pub fn try_set_at_index(
192 &mut self,
193 index: usize,
194 pubkey: EdDSAPublicKey,
195 ) -> Result<(), PrimitiveError> {
196 if index >= self.len() || index >= MAX_AUTHENTICATOR_KEYS {
197 return Err(PrimitiveError::OutOfBounds);
198 }
199 self.0[index] = Some(pubkey);
200 Ok(())
201 }
202
203 pub fn try_clear_at_index(&mut self, index: usize) -> Result<(), PrimitiveError> {
208 if index >= self.len() || index >= MAX_AUTHENTICATOR_KEYS {
209 return Err(PrimitiveError::OutOfBounds);
210 }
211 self.0[index] = None;
212 Ok(())
213 }
214
215 pub fn try_push(&mut self, pubkey: EdDSAPublicKey) -> Result<(), PrimitiveError> {
220 self.0
221 .try_push(Some(pubkey))
222 .map_err(|_| PrimitiveError::OutOfBounds)
223 }
224
225 #[must_use]
230 pub fn leaf_hash(&self) -> Fq {
231 let mut input = [Fq::ZERO; 16];
232
233 input[0] =
234 Fq::from_str("105702839725298824521994315").expect("domain separator fits in field");
235
236 let pk_array = self.as_affine_array();
237 for i in 0..MAX_AUTHENTICATOR_KEYS {
238 input[i * 2 + 1] = pk_array[i].x;
239 input[i * 2 + 2] = pk_array[i].y;
240 }
241
242 poseidon2::bn254::t16::permutation(&input)[1]
243 }
244}
245
246impl Deref for AuthenticatorPublicKeySet {
247 type Target = ArrayVec<Option<EdDSAPublicKey>, MAX_AUTHENTICATOR_KEYS>;
248 fn deref(&self) -> &Self::Target {
249 &self.0
250 }
251}
252
253impl DerefMut for AuthenticatorPublicKeySet {
254 fn deref_mut(&mut self) -> &mut Self::Target {
255 &mut self.0
256 }
257}
258
259pub trait ProtocolSigner {
263 fn sign(&self, message: FieldElement) -> EdDSASignature
266 where
267 Self: Sized + Send + Sync;
268}
269
270#[cfg(test)]
271mod tests {
272 use super::*;
273 use crate::Signer;
274 use ark_serialize::CanonicalSerialize as _;
275
276 fn create_test_pubkey() -> EdDSAPublicKey {
277 EdDSAPublicKey {
278 pk: EdwardsAffine::default(),
279 }
280 }
281
282 fn test_pubkey(seed_byte: u8) -> EdDSAPublicKey {
283 Signer::from_seed_bytes(&[seed_byte; 32])
284 .unwrap()
285 .offchain_signer_pubkey()
286 }
287
288 fn encoded_test_pubkey(seed_byte: u8) -> U256 {
289 let mut compressed = Vec::new();
290 test_pubkey(seed_byte)
291 .pk
292 .serialize_compressed(&mut compressed)
293 .unwrap();
294 U256::from_le_slice(&compressed)
295 }
296
297 #[test]
298 fn test_try_set_at_index_within_bounds() {
299 let mut key_set = AuthenticatorPublicKeySet::default();
300 let pubkey = create_test_pubkey();
301
302 let result = key_set.try_set_at_index(0, pubkey.clone());
304 assert!(result.is_err(), "Should not panic, should return error");
305
306 key_set.try_push(pubkey.clone()).unwrap();
308
309 key_set.try_set_at_index(0, pubkey).unwrap();
311 }
312
313 #[test]
314 fn test_try_set_at_index_at_length() {
315 let mut key_set = AuthenticatorPublicKeySet::default();
316 let pubkey = create_test_pubkey();
317
318 key_set.try_push(pubkey.clone()).unwrap();
320
321 let result = key_set.try_set_at_index(1, pubkey);
323 assert!(result.is_err(), "Should not panic when index equals length");
324 }
325
326 #[test]
327 fn test_try_set_at_index_out_of_bounds() {
328 let mut key_set = AuthenticatorPublicKeySet::default();
329 let pubkey = create_test_pubkey();
330
331 let result = key_set.try_set_at_index(MAX_AUTHENTICATOR_KEYS, pubkey.clone());
333 assert!(
334 result.is_err(),
335 "Should not panic when index >= MAX_AUTHENTICATOR_KEYS"
336 );
337
338 let result = key_set.try_set_at_index(MAX_AUTHENTICATOR_KEYS + 1, pubkey);
339 assert!(
340 result.is_err(),
341 "Should not panic when index > MAX_AUTHENTICATOR_KEYS"
342 );
343 }
344
345 #[test]
346 fn test_try_push_within_capacity() {
347 let mut key_set = AuthenticatorPublicKeySet::default();
348 let pubkey = create_test_pubkey();
349
350 for i in 0..MAX_AUTHENTICATOR_KEYS {
352 let result = key_set.try_push(pubkey.clone());
353 assert!(
354 result.is_ok(),
355 "Should not panic when pushing element {} of {}",
356 i + 1,
357 MAX_AUTHENTICATOR_KEYS
358 );
359 }
360
361 assert_eq!(key_set.len(), MAX_AUTHENTICATOR_KEYS);
362
363 let result = key_set.try_push(pubkey);
364 assert!(result.is_err()); }
366
367 #[test]
368 fn test_as_affine_array_empty_set() {
369 let key_set = AuthenticatorPublicKeySet::default();
370 let array = key_set.as_affine_array();
371
372 assert_eq!(array.len(), MAX_AUTHENTICATOR_KEYS);
374 for affine in &array {
375 assert_eq!(*affine, EdwardsAffine::default());
376 }
377 }
378
379 #[test]
380 fn test_as_affine_array_partial_set() {
381 let mut key_set = AuthenticatorPublicKeySet::default();
382 let pubkey = create_test_pubkey();
383
384 for _ in 0..3 {
386 key_set.try_push(pubkey.clone()).unwrap();
387 }
388
389 let array = key_set.as_affine_array();
390
391 assert_eq!(array.len(), MAX_AUTHENTICATOR_KEYS);
393
394 for item in array.iter().take(3) {
396 assert_eq!(item, &pubkey.pk);
397 }
398
399 for item in array.iter().take(MAX_AUTHENTICATOR_KEYS).skip(3) {
400 assert_eq!(item, &EdwardsAffine::default());
401 }
402 }
403
404 #[test]
405 fn test_decode_sparse_pubkeys_trims_trailing_empty_slots() {
406 let mut encoded_pubkeys = vec![Some(encoded_test_pubkey(1)), Some(encoded_test_pubkey(2))];
407 encoded_pubkeys.extend(vec![None; MAX_AUTHENTICATOR_KEYS + 5]);
408
409 let key_set = decode_sparse_authenticator_pubkeys(encoded_pubkeys).unwrap();
410
411 assert_eq!(key_set.len(), 2);
412 assert_eq!(key_set[0].as_ref().unwrap().pk, test_pubkey(1).pk);
413 assert_eq!(key_set[1].as_ref().unwrap().pk, test_pubkey(2).pk);
414 }
415
416 #[test]
417 fn test_decode_sparse_pubkeys_preserves_interior_holes() {
418 let key_set = decode_sparse_authenticator_pubkeys(vec![
419 Some(encoded_test_pubkey(1)),
420 None,
421 Some(encoded_test_pubkey(2)),
422 ])
423 .unwrap();
424
425 assert_eq!(key_set.len(), 3);
426 assert_eq!(key_set[0].as_ref().unwrap().pk, test_pubkey(1).pk);
427 assert_eq!(key_set[1], None);
428 assert_eq!(key_set[2].as_ref().unwrap().pk, test_pubkey(2).pk);
429 }
430
431 #[test]
432 fn test_decode_sparse_pubkeys_rejects_used_slot_beyond_max() {
433 let mut encoded_pubkeys = vec![None; MAX_AUTHENTICATOR_KEYS + 1];
434 encoded_pubkeys[MAX_AUTHENTICATOR_KEYS] = Some(encoded_test_pubkey(1));
435
436 let error = decode_sparse_authenticator_pubkeys(encoded_pubkeys).unwrap_err();
437 assert!(matches!(
438 error,
439 SparseAuthenticatorPubkeysError::SlotOutOfBounds {
440 slot_index,
441 max_supported_slot
442 } if slot_index == MAX_AUTHENTICATOR_KEYS && max_supported_slot == MAX_AUTHENTICATOR_KEYS - 1
443 ));
444 }
445}