1#![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
12use ark_babyjubjub::Fq;
13use ark_ff::{AdditiveGroup, Field, PrimeField, UniformRand};
14use ruint::aliases::{U160, U256};
15use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as _};
16use std::{
17 fmt,
18 ops::{Deref, DerefMut},
19 str::FromStr,
20};
21
22pub mod authenticator;
24
25mod config;
27pub use config::Config;
28
29pub mod circuit_inputs;
33
34pub mod sponge;
36
37pub mod credential;
39pub use credential::{Credential, CredentialVersion};
40
41pub mod merkle;
43
44pub mod api_types;
46
47pub mod oprf;
49
50mod nullifier;
52pub use nullifier::Nullifier;
53
54mod session;
56pub use session::{SessionFieldElement, SessionId, SessionNullifier};
57
58pub mod proof;
60pub use proof::ZeroKnowledgeProof;
61
62pub mod rp;
64
65pub mod serde_utils;
66
67mod signer;
69pub use signer::Signer;
70
71pub mod request;
73pub use request::{
74 ConstraintExpr, ConstraintKind, ConstraintNode, MAX_CONSTRAINT_NODES, ProofRequest,
75 ProofResponse, RequestItem, RequestVersion, ResponseItem, ValidationError,
76};
77
78pub use eddsa_babyjubjub::{EdDSAPrivateKey, EdDSAPublicKey, EdDSASignature};
79
80pub type ScalarField = ark_babyjubjub::Fr;
84
85pub const TREE_DEPTH: usize = 30;
87
88#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
96pub struct FieldElement(Fq);
97
98impl FieldElement {
99 pub const ZERO: Self = Self(Fq::ZERO);
101 pub const ONE: Self = Self(Fq::ONE);
103
104 #[must_use]
106 pub fn to_be_bytes(&self) -> [u8; 32] {
107 let as_num: U256 = self.to_u256();
108 as_num.to_be_bytes()
109 }
110
111 pub fn from_be_bytes(be_bytes: &[u8; 32]) -> Result<Self, PrimitiveError> {
118 U256::from_be_bytes(*be_bytes).try_into()
119 }
120
121 #[must_use]
127 pub(crate) fn from_be_bytes_mod_order(bytes: &[u8]) -> Self {
128 let field_element = Fq::from_be_bytes_mod_order(bytes);
129 Self(field_element)
130 }
131
132 #[must_use]
135 pub fn from_arbitrary_raw_bytes(bytes: &[u8]) -> Self {
136 let mut hasher = Keccak256::new();
137 hasher.update(bytes);
138 let output: [u8; 32] = hasher.finalize().into();
139
140 let n = U256::from_be_bytes(output);
141 let n: U256 = n >> 8;
143
144 let field_element = Fq::from_bigint(n.into());
145
146 match field_element {
147 Some(element) => Self(element),
148 None => unreachable!(
149 "due to the byte reduction, the value is guaranteed to be within the field"
150 ),
151 }
152
153 }
155
156 #[must_use]
158 pub fn random<R: rand::CryptoRng + rand::RngCore>(rng: &mut R) -> Self {
159 let field_element = Fq::rand(rng);
160 Self(field_element)
161 }
162
163 pub fn to_u256(&self) -> U256 {
165 self.0.into()
166 }
167}
168
169impl Deref for FieldElement {
170 type Target = Fq;
171 fn deref(&self) -> &Self::Target {
172 &self.0
173 }
174}
175
176impl DerefMut for FieldElement {
177 fn deref_mut(&mut self) -> &mut Self::Target {
178 &mut self.0
179 }
180}
181
182impl FromStr for FieldElement {
183 type Err = PrimitiveError;
184
185 fn from_str(s: &str) -> Result<Self, Self::Err> {
191 let s = s.trim_start_matches("0x");
192 let bytes = hex::decode(s)
193 .map_err(|e| PrimitiveError::Deserialization(format!("Invalid hex encoding: {e}")))?;
194 let bytes: [u8; 32] = bytes
195 .try_into()
196 .map_err(|_| PrimitiveError::Deserialization("expected 32 bytes".to_string()))?;
197 Self::from_be_bytes(&bytes)
198 }
199}
200
201impl fmt::Display for FieldElement {
202 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
203 write!(f, "0x{}", hex::encode(self.to_be_bytes()))
204 }
205}
206
207impl From<Fq> for FieldElement {
208 fn from(value: Fq) -> Self {
209 Self(value)
210 }
211}
212
213impl TryFrom<U256> for FieldElement {
214 type Error = PrimitiveError;
215 fn try_from(value: U256) -> Result<Self, Self::Error> {
216 Ok(Self(
217 value.try_into().map_err(|_| PrimitiveError::NotInField)?,
218 ))
219 }
220}
221
222impl From<U160> for FieldElement {
224 fn from(value: U160) -> Self {
225 let u256 = U256::from(value);
227 let big_int = ark_ff::BigInt(u256.into_limbs());
228 Self(ark_babyjubjub::Fq::new(big_int))
229 }
230}
231
232impl From<FieldElement> for U256 {
233 fn from(value: FieldElement) -> Self {
234 <Self as From<Fq>>::from(value.0)
235 }
236}
237
238impl From<u64> for FieldElement {
239 fn from(value: u64) -> Self {
240 Self(Fq::from(value))
241 }
242}
243
244impl From<u128> for FieldElement {
245 fn from(value: u128) -> Self {
246 Self(Fq::from(value))
247 }
248}
249
250impl TryFrom<FieldElement> for u64 {
251 type Error = PrimitiveError;
252 fn try_from(value: FieldElement) -> Result<Self, Self::Error> {
253 let u256 = <U256 as From<Fq>>::from(value.0);
254 u256.try_into().map_err(|_| PrimitiveError::OutOfBounds)
255 }
256}
257
258impl TryFrom<FieldElement> for usize {
259 type Error = PrimitiveError;
260 fn try_from(value: FieldElement) -> Result<Self, Self::Error> {
261 let u256 = <U256 as From<Fq>>::from(value.0);
262 u256.try_into().map_err(|_| PrimitiveError::OutOfBounds)
263 }
264}
265
266impl Serialize for FieldElement {
267 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
268 where
269 S: Serializer,
270 {
271 if serializer.is_human_readable() {
272 serializer.serialize_str(&self.to_string())
273 } else {
274 serializer.serialize_bytes(&self.to_be_bytes())
275 }
276 }
277}
278
279impl<'de> Deserialize<'de> for FieldElement {
280 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
281 where
282 D: Deserializer<'de>,
283 {
284 if deserializer.is_human_readable() {
285 let s = String::deserialize(deserializer)?;
286 Self::from_str(&s).map_err(D::Error::custom)
287 } else {
288 let bytes = Vec::<u8>::deserialize(deserializer)?;
289 let bytes: [u8; 32] = bytes
290 .try_into()
291 .map_err(|_| D::Error::custom("expected 32 bytes"))?;
292 Self::from_be_bytes(&bytes).map_err(D::Error::custom)
293 }
294 }
295}
296
297#[derive(Debug, thiserror::Error, Clone, PartialEq, Eq)]
299pub enum PrimitiveError {
300 #[error("Serialization error: {0}")]
302 Serialization(String),
303 #[error("Deserialization error: {0}")]
305 Deserialization(String),
306 #[error("Provided value is not in the field")]
308 NotInField,
309 #[error("Provided index is out of bounds")]
311 OutOfBounds,
312 #[error("Invalid input at {attribute}: {reason}")]
314 InvalidInput {
315 attribute: String,
317 reason: String,
319 },
320}
321
322#[cfg(test)]
323mod tests {
324 use super::*;
325 use ruint::uint;
326
327 #[test]
328 fn test_field_element_encoding() {
329 let root = FieldElement::try_from(uint!(
330 0x11d223ce7b91ac212f42cf50f0a3439ae3fcdba4ea32acb7f194d1051ed324c2_U256
331 ))
332 .unwrap();
333
334 assert_eq!(
335 serde_json::to_string(&root).unwrap(),
336 "\"0x11d223ce7b91ac212f42cf50f0a3439ae3fcdba4ea32acb7f194d1051ed324c2\""
337 );
338
339 assert_eq!(
340 root.to_string(),
341 "0x11d223ce7b91ac212f42cf50f0a3439ae3fcdba4ea32acb7f194d1051ed324c2"
342 );
343
344 let fe = FieldElement::ONE;
345 assert_eq!(
346 serde_json::to_string(&fe).unwrap(),
347 "\"0x0000000000000000000000000000000000000000000000000000000000000001\""
348 );
349
350 let md = FieldElement::ZERO;
351 assert_eq!(
352 serde_json::to_string(&md).unwrap(),
353 "\"0x0000000000000000000000000000000000000000000000000000000000000000\""
354 );
355
356 assert_eq!(*FieldElement::ONE, Fq::ONE);
357 }
358
359 #[test]
360 fn test_field_element_decoding() {
361 let root = FieldElement::try_from(uint!(
362 0x11d223ce7b91ac212f42cf50f0a3439ae3fcdba4ea32acb7f194d1051ed324c2_U256
363 ))
364 .unwrap();
365
366 assert_eq!(
367 serde_json::from_str::<FieldElement>(
368 "\"0x11d223ce7b91ac212f42cf50f0a3439ae3fcdba4ea32acb7f194d1051ed324c2\""
369 )
370 .unwrap(),
371 root
372 );
373
374 assert_eq!(
375 FieldElement::from_str(
376 "0x0000000000000000000000000000000000000000000000000000000000000001"
377 )
378 .unwrap(),
379 FieldElement::ONE
380 );
381 }
382
383 #[test]
384 fn test_simple_bytes_encoding() {
385 let fe = FieldElement::ONE;
386 let bytes = fe.to_be_bytes();
387 let mut expected = [0u8; 32];
388 expected[31] = 1;
389 assert_eq!(bytes, expected);
390
391 let reversed = FieldElement::from_be_bytes(&bytes).unwrap();
392 assert_eq!(reversed, fe);
393 }
394
395 #[test]
396 fn test_field_element_cbor_encoding_roundtrip() {
397 let root = FieldElement::try_from(uint!(
398 0x11d223ce7b91ac212f42cf50f0a3439ae3fcdba4ea32acb7f194d1051ed324c2_U256
399 ))
400 .unwrap();
401
402 let mut buffer = Vec::new();
403 ciborium::into_writer(&root, &mut buffer).unwrap();
404
405 let decoded: FieldElement = ciborium::from_reader(&buffer[..]).unwrap();
406
407 assert_eq!(root, decoded);
408 }
409
410 #[test]
411 fn test_field_element_binary_encoding_format() {
412 let root = FieldElement::try_from(uint!(
413 0x11d223ce7b91ac212f42cf50f0a3439ae3fcdba4ea32acb7f194d1051ed324c2_U256
414 ))
415 .unwrap();
416
417 let mut buffer = Vec::new();
419 ciborium::into_writer(&root, &mut buffer).unwrap();
420
421 assert_eq!(buffer.len(), 34); assert_eq!(buffer[0], 0x58); assert_eq!(buffer[1], 0x20); let field_bytes = &buffer[2..];
426 assert_eq!(field_bytes.len(), 32);
427
428 let expected_be_bytes =
429 hex::decode("11d223ce7b91ac212f42cf50f0a3439ae3fcdba4ea32acb7f194d1051ed324c2")
430 .unwrap();
431 assert_eq!(field_bytes, expected_be_bytes.as_slice());
432 }
433
434 #[test]
435 fn test_to_be_bytes_from_be_bytes_roundtrip() {
436 let values = [
437 FieldElement::ZERO,
438 FieldElement::ONE,
439 FieldElement::from(255u64),
440 FieldElement::from(u64::MAX),
441 FieldElement::from(u128::MAX),
442 FieldElement::try_from(uint!(
443 0x11d223ce7b91ac212f42cf50f0a3439ae3fcdba4ea32acb7f194d1051ed324c2_U256
444 ))
445 .unwrap(),
446 ];
447 for fe in values {
448 let bytes = fe.to_be_bytes();
449 let recovered = FieldElement::from_be_bytes(&bytes).unwrap();
450 assert_eq!(fe, recovered);
451 }
452 }
453
454 #[test]
458 fn test_from_be_bytes_rejects_value_above_modulus() {
459 let bytes = [0xFF; 32];
461 assert_eq!(
462 FieldElement::from_be_bytes(&bytes),
463 Err(PrimitiveError::NotInField)
464 );
465 }
466
467 #[test]
468 fn test_from_str_rejects_wrong_length() {
469 assert!(FieldElement::from_str("0x01").is_err());
471 assert!(
473 FieldElement::from_str(
474 "0x000000000000000000000000000000000000000000000000000000000000000001"
475 )
476 .is_err()
477 );
478 assert!(
480 FieldElement::from_str(
481 "0xGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG"
482 )
483 .is_err()
484 );
485 }
486
487 #[test]
488 fn test_display_from_str_roundtrip() {
489 let fe = FieldElement::try_from(uint!(
490 0x11d223ce7b91ac212f42cf50f0a3439ae3fcdba4ea32acb7f194d1051ed324c2_U256
491 ))
492 .unwrap();
493 let s = fe.to_string();
494 assert_eq!(FieldElement::from_str(&s).unwrap(), fe);
495 }
496
497 #[test]
498 fn test_json_cbor_consistency() {
499 let fe = FieldElement::try_from(uint!(
502 0x11d223ce7b91ac212f42cf50f0a3439ae3fcdba4ea32acb7f194d1051ed324c2_U256
503 ))
504 .unwrap();
505
506 let json_str = serde_json::to_string(&fe).unwrap();
507 let from_json: FieldElement = serde_json::from_str(&json_str).unwrap();
508
509 let mut cbor_buf = Vec::new();
510 ciborium::into_writer(&fe, &mut cbor_buf).unwrap();
511 let from_cbor: FieldElement = ciborium::from_reader(&cbor_buf[..]).unwrap();
512
513 assert_eq!(from_json, from_cbor);
514 }
515
516 #[test]
517 fn test_to_be_bytes_is_big_endian() {
518 let fe = FieldElement::from(1u64);
519 let bytes = fe.to_be_bytes();
520 assert_eq!(bytes[31], 1); assert_eq!(bytes[..31], [0u8; 31]);
522
523 let fe256 = FieldElement::from(256u64);
524 let bytes = fe256.to_be_bytes();
525 assert_eq!(bytes[30], 1);
526 assert_eq!(bytes[31], 0);
527 }
528
529 #[test]
530 fn test_u256_roundtrip() {
531 let original =
532 uint!(0x11d223ce7b91ac212f42cf50f0a3439ae3fcdba4ea32acb7f194d1051ed324c2_U256);
533 let fe = FieldElement::try_from(original).unwrap();
534 let back: U256 = fe.into();
535 assert_eq!(original, back);
536 }
537}