world_id_primitives/
lib.rs1#![cfg_attr(not(test), warn(unused_crate_dependencies))]
7#![deny(clippy::all, clippy::nursery, missing_docs, dead_code)]
8#![allow(clippy::option_if_let_else)]
9
10use alloy_primitives::Keccak256;
11
12pub mod serde_utils;
13use ark_babyjubjub::Fq;
14use ark_ff::{AdditiveGroup, Field, PrimeField, UniformRand};
15use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
16use ruint::aliases::{U160, U256};
17use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as _, ser::Error as _};
18use std::{
19 fmt,
20 io::{Cursor, Read, Write},
21 ops::{Deref, DerefMut},
22 str::FromStr,
23};
24
25pub mod authenticator;
27
28mod config;
30pub use config::Config;
31
32#[cfg(feature = "circuits")]
37pub mod circuit_inputs;
38
39pub mod sponge;
41
42pub mod credential;
44pub use credential::{Credential, CredentialVersion};
45
46pub mod merkle;
48
49pub mod api_types;
51
52#[cfg(feature = "circuits")]
55pub mod oprf;
56
57pub mod nullifier;
59pub use nullifier::SessionNullifier;
60
61pub mod proof;
63pub use proof::ZeroKnowledgeProof;
64
65pub mod rp;
67
68mod signer;
70pub use signer::Signer;
71
72pub mod request;
74pub use request::{
75 ConstraintExpr, ConstraintKind, ConstraintNode, MAX_CONSTRAINT_NODES, ProofRequest,
76 ProofResponse, RequestItem, RequestVersion, ResponseItem, ValidationError,
77};
78
79pub type ScalarField = ark_babyjubjub::Fr;
83
84pub const TREE_DEPTH: usize = 30;
86
87#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
95pub struct FieldElement(Fq);
96
97impl FieldElement {
98 pub const ZERO: Self = Self(Fq::ZERO);
100 pub const ONE: Self = Self(Fq::ONE);
102
103 pub fn serialize_as_bytes<W: Write>(&self, writer: &mut W) -> Result<(), PrimitiveError> {
108 self.0
109 .serialize_compressed(writer)
110 .map_err(|e| PrimitiveError::Serialization(e.to_string()))
111 }
112
113 pub fn deserialize_from_bytes<R: Read>(bytes: &mut R) -> Result<Self, PrimitiveError> {
118 let field_element = Fq::deserialize_compressed(bytes)
119 .map_err(|e| PrimitiveError::Deserialization(e.to_string()))?;
120 Ok(Self(field_element))
121 }
122
123 #[must_use]
125 pub fn from_be_bytes_mod_order(bytes: &[u8]) -> Self {
126 let field_element = Fq::from_be_bytes_mod_order(bytes);
127 Self(field_element)
128 }
129
130 #[must_use]
134 pub fn from_arbitrary_raw_bytes(bytes: &[u8]) -> Self {
135 let mut hasher = Keccak256::new();
136 hasher.update(bytes);
137 let output: [u8; 32] = hasher.finalize().into();
138
139 let n = U256::from_be_bytes(output);
140 let n: U256 = n >> 8;
142
143 let field_element = Fq::from_bigint(n.into());
144
145 match field_element {
146 Some(element) => Self(element),
147 None => unreachable!(
148 "due to the byte reduction, the value is guaranteed to be within the field"
149 ),
150 }
151
152 }
154
155 #[must_use]
157 pub fn random<R: rand::CryptoRng + rand::RngCore>(rng: &mut R) -> Self {
158 let field_element = Fq::rand(rng);
159 Self(field_element)
160 }
161}
162
163impl Deref for FieldElement {
164 type Target = Fq;
165 fn deref(&self) -> &Self::Target {
166 &self.0
167 }
168}
169
170impl DerefMut for FieldElement {
171 fn deref_mut(&mut self) -> &mut Self::Target {
172 &mut self.0
173 }
174}
175
176impl FromStr for FieldElement {
177 type Err = PrimitiveError;
178
179 fn from_str(s: &str) -> Result<Self, Self::Err> {
180 let s = s.trim_start_matches("0x");
181 let u256 = U256::from_str_radix(s, 16).map_err(|_| {
182 PrimitiveError::Deserialization("not a valid hex-encoded number".to_string())
183 })?;
184 u256.try_into()
185 }
186}
187
188impl fmt::Display for FieldElement {
189 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
190 let u256: U256 = (*self).into();
191 write!(f, "{u256:#066x}")
192 }
193}
194
195impl From<Fq> for FieldElement {
196 fn from(value: Fq) -> Self {
197 Self(value)
198 }
199}
200
201impl TryFrom<U256> for FieldElement {
202 type Error = PrimitiveError;
203 fn try_from(value: U256) -> Result<Self, Self::Error> {
204 Ok(Self(
205 value.try_into().map_err(|_| PrimitiveError::NotInField)?,
206 ))
207 }
208}
209
210impl From<U160> for FieldElement {
212 fn from(value: U160) -> Self {
213 let u256 = U256::from(value);
215 let big_int = ark_ff::BigInt(u256.into_limbs());
216 Self(ark_babyjubjub::Fq::new(big_int))
217 }
218}
219
220impl From<FieldElement> for U256 {
221 fn from(value: FieldElement) -> Self {
222 <Self as From<Fq>>::from(value.0)
223 }
224}
225
226impl From<u64> for FieldElement {
227 fn from(value: u64) -> Self {
228 Self(Fq::from(value))
229 }
230}
231
232impl From<u128> for FieldElement {
233 fn from(value: u128) -> Self {
234 Self(Fq::from(value))
235 }
236}
237
238impl Serialize for FieldElement {
239 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
240 where
241 S: Serializer,
242 {
243 if serializer.is_human_readable() {
244 serializer.serialize_str(&self.to_string())
245 } else {
246 let mut writer = Vec::new();
247 self.serialize_compressed(&mut writer)
248 .map_err(S::Error::custom)?;
249 serializer.serialize_bytes(&writer)
250 }
251 }
252}
253
254impl<'de> Deserialize<'de> for FieldElement {
255 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
256 where
257 D: Deserializer<'de>,
258 {
259 if deserializer.is_human_readable() {
260 let s = String::deserialize(deserializer)?;
261 Self::from_str(&s).map_err(D::Error::custom)
262 } else {
263 let bytes = Vec::<u8>::deserialize(deserializer)?;
264 Self::deserialize_from_bytes(&mut Cursor::new(bytes)).map_err(D::Error::custom)
265 }
266 }
267}
268
269#[derive(Debug, thiserror::Error, Clone, PartialEq, Eq)]
271pub enum PrimitiveError {
272 #[error("Serialization error: {0}")]
274 Serialization(String),
275 #[error("Deserialization error: {0}")]
277 Deserialization(String),
278 #[error("Provided value is not in the field")]
280 NotInField,
281 #[error("Provided index is out of bounds")]
283 OutOfBounds,
284 #[error("Invalid input at {attribute}: {reason}")]
286 InvalidInput {
287 attribute: String,
289 reason: String,
291 },
292}
293
294#[cfg(test)]
295mod tests {
296 use super::*;
297 use ruint::uint;
298
299 #[test]
300 fn test_field_element_encoding() {
301 let root = FieldElement::try_from(uint!(
302 0x11d223ce7b91ac212f42cf50f0a3439ae3fcdba4ea32acb7f194d1051ed324c2_U256
303 ))
304 .unwrap();
305
306 assert_eq!(
307 serde_json::to_string(&root).unwrap(),
308 "\"0x11d223ce7b91ac212f42cf50f0a3439ae3fcdba4ea32acb7f194d1051ed324c2\""
309 );
310
311 assert_eq!(
312 root.to_string(),
313 "0x11d223ce7b91ac212f42cf50f0a3439ae3fcdba4ea32acb7f194d1051ed324c2"
314 );
315
316 let fe = FieldElement::ONE;
317 assert_eq!(
318 serde_json::to_string(&fe).unwrap(),
319 "\"0x0000000000000000000000000000000000000000000000000000000000000001\""
320 );
321
322 let md = FieldElement::ZERO;
323 assert_eq!(
324 serde_json::to_string(&md).unwrap(),
325 "\"0x0000000000000000000000000000000000000000000000000000000000000000\""
326 );
327
328 assert_eq!(*FieldElement::ONE, Fq::ONE);
329 }
330
331 #[test]
332 fn test_field_element_decoding() {
333 let root = FieldElement::try_from(uint!(
334 0x11d223ce7b91ac212f42cf50f0a3439ae3fcdba4ea32acb7f194d1051ed324c2_U256
335 ))
336 .unwrap();
337
338 assert_eq!(
339 serde_json::from_str::<FieldElement>(
340 "\"0x11d223ce7b91ac212f42cf50f0a3439ae3fcdba4ea32acb7f194d1051ed324c2\""
341 )
342 .unwrap(),
343 root
344 );
345
346 assert_eq!(
347 FieldElement::from_str(
348 "0x0000000000000000000000000000000000000000000000000000000000000001"
349 )
350 .unwrap(),
351 FieldElement::ONE
352 );
353 }
354
355 #[test]
356 fn test_field_element_binary_encoding_roundtrip() {
357 let root = FieldElement::try_from(uint!(
358 0x11d223ce7b91ac212f42cf50f0a3439ae3fcdba4ea32acb7f194d1051ed324c2_U256
359 ))
360 .unwrap();
361
362 let mut buffer = Vec::new();
363 ciborium::into_writer(&root, &mut buffer).unwrap();
364
365 let decoded: FieldElement = ciborium::from_reader(&buffer[..]).unwrap();
366
367 assert_eq!(root, decoded);
368 }
369
370 #[test]
371 fn test_field_element_binary_encoding_format() {
372 let root = FieldElement::try_from(uint!(
373 0x11d223ce7b91ac212f42cf50f0a3439ae3fcdba4ea32acb7f194d1051ed324c2_U256
374 ))
375 .unwrap();
376
377 let mut buffer = Vec::new();
379 ciborium::into_writer(&root, &mut buffer).unwrap();
380
381 assert_eq!(buffer.len(), 34); assert_eq!(buffer[0], 0x58); assert_eq!(buffer[1], 0x20); let field_bytes = &buffer[2..];
386 assert_eq!(field_bytes.len(), 32);
387
388 let expected_le_bytes =
389 hex::decode("c224d31e05d194f1b7ac32eaa4dbfce39a43a3f050cf422f21ac917bce23d211")
390 .unwrap();
391 assert_eq!(field_bytes, expected_le_bytes.as_slice());
392 }
393}