1#![cfg_attr(not(feature = "std"), no_std)]
46#![allow(type_alias_bounds)]
49#![deny(unsafe_code)]
50#![deny(unused_qualifications)]
51#![allow(clippy::bool_assert_comparison)]
52#![allow(clippy::clone_on_copy)]
53#![allow(clippy::collapsible_if)]
54#![allow(clippy::get_first)]
55#![allow(clippy::iter_cloned_collect)]
56#![allow(clippy::manual_is_multiple_of)]
57#![allow(clippy::too_many_arguments)]
58#![allow(clippy::unnecessary_lazy_evaluations)]
59
60#[cfg(feature = "alloc")]
61extern crate alloc;
62
63#[cfg(feature = "alloc")]
65use alloc::boxed::Box;
66#[cfg(feature = "alloc")]
67use alloc::string::ToString;
68#[cfg(feature = "alloc")]
69use alloc::vec;
70#[cfg(feature = "alloc")]
71use alloc::vec::Vec;
72
73pub use lib_q_core::Result;
74#[cfg(any(
79 feature = "plonky",
80 feature = "plonky-keccak-air",
81 feature = "plonky-lookup",
82 feature = "plonky-uni-stark",
83 feature = "plonky-batch-stark",
84))]
85pub use lib_q_plonky as plonky;
86
87#[cfg(feature = "zkp")]
89pub mod stark;
90
91#[cfg(feature = "zkp")]
93pub mod circuit;
94
95#[cfg(feature = "zkp")]
97pub mod air;
98
99#[cfg(feature = "zkp")]
101pub mod aggregation;
102
103#[cfg(feature = "zkp")]
105pub mod ip;
106
107#[cfg(feature = "zkp")]
109pub mod merkle;
110
111#[cfg(feature = "zkp")]
113pub mod api;
114
115#[cfg(feature = "zkp")]
116pub mod wire;
117
118#[cfg(feature = "zkp")]
119pub use api::{
120 MerklePath,
121 build_merkle_tree,
122 prove_membership,
123 prove_membership_with_config,
124 prove_preimage,
125 prove_preimage_nist,
126 verify_membership,
127 verify_membership_with_config,
128 verify_membership_with_depth,
129 verify_membership_with_depth_and_config,
130 verify_preimage,
131 verify_preimage_nist,
132};
133
134#[cfg(feature = "wasm")]
135mod wasm;
136
137#[cfg(feature = "zkp")]
138pub use lib_q_stark::{
139 Proof as StarkProof,
140 StarkConfig,
141 StarkGenericConfig,
142 check_constraints,
143 prove,
144 verify,
145};
146#[cfg(feature = "zkp")]
147pub use lib_q_stark_air::Air;
148#[cfg(feature = "zkp")]
149use lib_q_stark_field::extension::Complex;
150#[cfg(feature = "zkp")]
151use lib_q_stark_matrix::dense::RowMajorMatrix;
152#[cfg(feature = "zkp")]
153use lib_q_stark_mersenne31::Mersenne31;
154#[cfg(feature = "zkp")]
155pub use merkle::PoseidonMerkleTree;
156#[cfg(feature = "zkp")]
157use serde::{
158 Deserialize,
159 Serialize,
160};
161
162#[cfg(feature = "zkp")]
163#[allow(unused_imports)]
164use crate::air::TraceGenerator;
165
166#[cfg(feature = "zkp")]
171pub type ZkpField = Complex<Mersenne31>;
172
173#[derive(Debug, Clone, PartialEq, Eq, Default)]
180#[cfg_attr(feature = "zkp", derive(Serialize, Deserialize))]
181pub enum ProofMetadata {
182 #[default]
184 None,
185 MerkleInclusion {
187 tree_depth: u8,
189 },
190 HashPreimage {
192 output_size: u16,
194 },
195 HashPreimageNist {
197 output_size: u16,
199 },
200 Circuit {
202 num_witnesses: u32,
204 num_public: u32,
206 },
207 Credential {
209 attribute_sizes: Vec<u16>,
211 reveal_mask: Vec<bool>,
213 },
214 Identity {
216 dsa_level: u8,
218 },
219 RecoveryPolicy {
221 key_count: u32,
223 air_id: u8,
225 },
226}
227
228#[derive(Debug, Clone)]
230#[cfg_attr(feature = "zkp", derive(serde::Serialize, serde::Deserialize))]
231pub struct ZkpProof {
232 pub data: Vec<u8>,
234 pub proof_type: ProofType,
236 pub security_level: u32,
238 pub metadata: ProofMetadata,
240}
241
242#[cfg(feature = "zkp")]
243impl ZkpProof {
244 pub fn from_stark_proof<C: StarkGenericConfig>(
249 proof: &StarkProof<C>,
250 metadata: ProofMetadata,
251 ) -> Result<Self>
252 where
253 StarkProof<C>: Serialize,
254 {
255 let data = postcard::to_allocvec(proof).map_err(|_| lib_q_core::Error::InternalError {
256 operation: "ZKP proof serialization".to_string(),
257 details: "Failed to serialize STARK proof".to_string(),
258 })?;
259 Ok(Self {
260 data,
261 proof_type: ProofType::Stark,
262 security_level: 1,
263 metadata,
264 })
265 }
266
267 pub fn to_stark_proof<C: StarkGenericConfig>(&self) -> Result<StarkProof<C>>
269 where
270 StarkProof<C>: for<'de> Deserialize<'de>,
271 {
272 postcard::from_bytes(&self.data).map_err(|_| lib_q_core::Error::InternalError {
273 operation: "ZKP proof deserialization".to_string(),
274 details: "Failed to deserialize STARK proof".to_string(),
275 })
276 }
277
278 pub fn merkle_tree_depth(&self) -> Option<u8> {
283 match &self.metadata {
284 ProofMetadata::MerkleInclusion { tree_depth } => Some(*tree_depth),
285 _ => None,
286 }
287 }
288}
289
290#[derive(Debug, Clone, PartialEq, Eq)]
295#[cfg_attr(feature = "zkp", derive(serde::Serialize, serde::Deserialize))]
296pub enum ProofType {
297 Stark,
299}
300
301#[cfg(feature = "zkp")]
303pub struct ZkpProver {
304 }
306
307#[cfg(not(feature = "zkp"))]
308pub struct ZkpProver;
309
310#[cfg(feature = "zkp")]
312pub struct ZkpVerifier {
313 }
315
316#[cfg(not(feature = "zkp"))]
317pub struct ZkpVerifier;
318
319#[cfg(feature = "zkp")]
320impl ZkpProver {
321 pub fn new() -> Self {
323 Self {}
324 }
325
326 pub fn prove_secret_value(
354 &mut self,
355 secret_value: &[u8],
356 _public_statement: &[u8],
357 ) -> Result<ZkpProof> {
358 use crate::air::{
359 HashPreimageAir,
360 TraceGenerator,
361 };
362 use crate::stark::{
363 StarkProver,
364 default_config,
365 };
366
367 if secret_value.is_empty() {
369 return Err(lib_q_core::Error::InvalidState {
370 operation: "prove_secret_value".to_string(),
371 reason: "Secret value cannot be empty".to_string(),
372 });
373 }
374
375 if secret_value.len() > air::hash_preimage::MAX_PREIMAGE_SIZE {
376 return Err(lib_q_core::Error::InvalidState {
377 operation: "prove_secret_value".to_string(),
378 reason: "Secret value exceeds maximum size".to_string(),
379 });
380 }
381
382 let air = HashPreimageAir::new();
384
385 let input = secret_value.to_vec();
387 let trace: RowMajorMatrix<ZkpField> =
388 air.generate_trace(&input)
389 .map_err(|e| lib_q_core::Error::InternalError {
390 operation: "prove_secret_value".to_string(),
391 details: e.to_string(),
392 })?;
393
394 let public_values: Vec<ZkpField> = air.public_values(&input);
396
397 let config = default_config();
399 let prover = StarkProver::new(config);
400
401 let proof = prover.prove(&air, trace, &public_values).map_err(|e| {
403 lib_q_core::Error::InternalError {
404 operation: "STARK proof generation".to_string(),
405 details: e.to_string(),
406 }
407 })?;
408
409 let metadata = ProofMetadata::HashPreimage { output_size: 1u16 };
411
412 ZkpProof::from_stark_proof(&proof, metadata)
414 }
415
416 pub fn prove_secret_value_nist(
427 &mut self,
428 secret_value: &[u8],
429 _public_statement: &[u8],
430 ) -> Result<ZkpProof> {
431 use crate::air::{
432 HASH_OUTPUT_BYTES,
433 HashPreimageNistAir,
434 TraceGenerator,
435 };
436 use crate::stark::{
437 StarkProver,
438 default_config,
439 };
440
441 if secret_value.is_empty() {
442 return Err(lib_q_core::Error::InvalidState {
443 operation: "prove_secret_value_nist".to_string(),
444 reason: "Secret value cannot be empty".to_string(),
445 });
446 }
447 if secret_value.len() > air::hash_preimage_nist::MAX_PREIMAGE_SIZE {
448 return Err(lib_q_core::Error::InvalidState {
449 operation: "prove_secret_value_nist".to_string(),
450 reason: "Secret value exceeds maximum size".to_string(),
451 });
452 }
453
454 let air = HashPreimageNistAir::new();
455 let input = secret_value.to_vec();
456 let trace: RowMajorMatrix<ZkpField> =
457 air.generate_trace(&input)
458 .map_err(|e| lib_q_core::Error::InternalError {
459 operation: "prove_secret_value_nist".to_string(),
460 details: e.to_string(),
461 })?;
462
463 let public_values: Vec<ZkpField> = air.public_values(&input);
464 let config = default_config();
465 let prover = StarkProver::new(config);
466
467 let proof = prover.prove(&air, trace, &public_values).map_err(|e| {
468 lib_q_core::Error::InternalError {
469 operation: "STARK proof generation (NIST)".to_string(),
470 details: e.to_string(),
471 }
472 })?;
473
474 let metadata = ProofMetadata::HashPreimageNist {
475 output_size: HASH_OUTPUT_BYTES as u16,
476 };
477 ZkpProof::from_stark_proof(&proof, metadata)
478 }
479
480 pub fn prove_computation(
521 &mut self,
522 circuit: &circuit::ArithmeticCircuit<ZkpField>,
523 witness: &[ZkpField],
524 public: &[ZkpField],
525 ) -> Result<ZkpProof> {
526 use crate::circuit::CircuitAir;
527 use crate::stark::{
528 StarkProver,
529 default_config,
530 };
531
532 let air = CircuitAir::new(circuit.clone());
534
535 let trace = air.generate_trace(witness, public)?;
537
538 let config = default_config();
540 let prover = StarkProver::new(config);
541
542 let proof =
544 prover
545 .prove(&air, trace, public)
546 .map_err(|e| lib_q_core::Error::InternalError {
547 operation: "STARK proof generation".to_string(),
548 details: e.to_string(),
549 })?;
550
551 let metadata = ProofMetadata::Circuit {
553 num_witnesses: witness.len().min(u32::MAX as usize) as u32,
554 num_public: public.len().min(u32::MAX as usize) as u32,
555 };
556
557 ZkpProof::from_stark_proof(&proof, metadata)
559 }
560}
561
562#[cfg(not(feature = "zkp"))]
563impl ZkpProver {
564 pub fn new() -> Self {
566 Self {}
567 }
568
569 pub fn prove_secret_value(
571 &mut self,
572 _secret_value: &[u8],
573 _public_statement: &[u8],
574 ) -> Result<ZkpProof> {
575 Err(lib_q_core::Error::NotImplemented {
576 feature: "ZKP feature not enabled".to_string(),
577 })
578 }
579
580 pub fn prove_secret_value_nist(
582 &mut self,
583 _secret_value: &[u8],
584 _public_statement: &[u8],
585 ) -> Result<ZkpProof> {
586 Err(lib_q_core::Error::NotImplemented {
587 feature: "ZKP feature not enabled".to_string(),
588 })
589 }
590}
591
592#[cfg(feature = "zkp")]
595fn verify_secret_value_nist_impl(proof: &ZkpProof, expected_hash: &[u8]) -> Result<bool> {
596 use crate::air::{
597 HashPreimageNistAir,
598 expected_hash_to_public_values,
599 };
600 use crate::stark::{
601 StarkVerifier,
602 default_config,
603 };
604
605 if proof.proof_type != ProofType::Stark {
606 return Ok(false);
607 }
608 if proof.data.is_empty() {
609 return Ok(false);
610 }
611
612 let ProofMetadata::HashPreimageNist { .. } = &proof.metadata else {
613 return Ok(false);
614 };
615
616 let air = HashPreimageNistAir::new();
617 let public_values = expected_hash_to_public_values::<ZkpField>(expected_hash);
618
619 let stark_proof = match proof.to_stark_proof() {
620 Ok(p) => p,
621 Err(_) => return Ok(false),
622 };
623
624 let config = default_config();
625 let verifier = StarkVerifier::new(config);
626
627 match verifier.verify(&air, &stark_proof, &public_values) {
628 Ok(()) => Ok(true),
629 Err(_) => Ok(false),
630 }
631}
632
633#[cfg(feature = "zkp")]
634impl ZkpVerifier {
635 pub fn new() -> Self {
637 Self {}
638 }
639
640 pub fn verify_secret_value(&self, proof: &ZkpProof, public_hash: &[u8]) -> Result<bool> {
655 use lib_q_poseidon::{
656 Poseidon,
657 Poseidon128,
658 };
659
660 use crate::air::{
661 HashPreimageAir,
662 bytes_to_poseidon_field,
663 poseidon_slice_to_field,
664 };
665 use crate::stark::{
666 StarkVerifier,
667 default_config,
668 };
669
670 if proof.proof_type != ProofType::Stark {
671 return Ok(false);
672 }
673
674 if proof.data.is_empty() {
675 return Ok(false);
676 }
677
678 let ProofMetadata::HashPreimage { output_size } = &proof.metadata else {
680 return Ok(false);
682 };
683
684 let _ = output_size;
686 let air = HashPreimageAir::new();
687
688 let expected_field_elements = bytes_to_poseidon_field(public_hash);
692 let poseidon_hash = Poseidon128.hash(&expected_field_elements);
693
694 let public_values = poseidon_slice_to_field(&poseidon_hash);
696
697 let stark_proof = proof.to_stark_proof()?;
699
700 let config = default_config();
702 let verifier = StarkVerifier::new(config);
703
704 match verifier.verify(&air, &stark_proof, &public_values) {
706 Ok(()) => Ok(true),
707 Err(_) => Ok(false),
708 }
709 }
710
711 pub fn verify_secret_value_nist(&self, proof: &ZkpProof, expected_hash: &[u8]) -> Result<bool> {
716 verify_secret_value_nist_impl(proof, expected_hash)
717 }
718
719 pub fn verify_computation(
733 &self,
734 proof: &ZkpProof,
735 circuit: &circuit::ArithmeticCircuit<ZkpField>,
736 public: &[ZkpField],
737 ) -> Result<bool> {
738 use crate::circuit::CircuitAir;
739 use crate::stark::{
740 StarkVerifier,
741 default_config,
742 };
743
744 if proof.proof_type != ProofType::Stark {
745 return Ok(false);
746 }
747
748 if proof.data.is_empty() {
749 return Ok(false);
750 }
751
752 let air = CircuitAir::new(circuit.clone());
754
755 let stark_proof = proof.to_stark_proof()?;
757
758 let config = default_config();
760 let verifier = StarkVerifier::new(config);
761
762 match verifier.verify(&air, &stark_proof, public) {
764 Ok(()) => Ok(true),
765 Err(_) => Ok(false),
766 }
767 }
768
769 pub fn verify(&self, proof: ZkpProof, public_statement: &[u8]) -> Result<bool> {
787 if proof.proof_type != ProofType::Stark {
788 return Ok(false);
789 }
790 if proof.data.is_empty() {
791 return Ok(false);
792 }
793 match &proof.metadata {
794 ProofMetadata::HashPreimage { .. } => {
795 self.verify_secret_value(&proof, public_statement)
796 }
797 ProofMetadata::HashPreimageNist { .. } => {
798 verify_secret_value_nist_impl(&proof, public_statement)
799 }
800 ProofMetadata::MerkleInclusion { .. } => verify_membership(&proof, public_statement),
801 _ => Ok(false),
802 }
803 }
804
805 pub fn batch_verify(&self, proofs: &[ZkpProof], publics: &[&[u8]]) -> Result<bool> {
816 if proofs.len() != publics.len() {
817 return Err(lib_q_core::Error::InvalidState {
818 operation: "batch_verify".to_string(),
819 reason: "Number of proofs must match number of public statements".to_string(),
820 });
821 }
822
823 for (proof, public) in proofs.iter().zip(publics.iter()) {
824 match self.verify(proof.clone(), public) {
825 Ok(true) => continue,
826 Ok(false) => return Ok(false),
827 Err(e) => return Err(e),
828 }
829 }
830
831 Ok(true)
832 }
833}
834
835#[cfg(not(feature = "zkp"))]
836impl ZkpVerifier {
837 pub fn new() -> Self {
839 Self {}
840 }
841
842 pub fn verify(&self, _proof: ZkpProof, _public_statement: &[u8]) -> Result<bool> {
844 Err(lib_q_core::Error::NotImplemented {
845 feature: "ZKP feature not enabled".to_string(),
846 })
847 }
848
849 pub fn verify_secret_value_nist(
851 &self,
852 _proof: &ZkpProof,
853 _expected_hash: &[u8],
854 ) -> Result<bool> {
855 Err(lib_q_core::Error::NotImplemented {
856 feature: "ZKP feature not enabled".to_string(),
857 })
858 }
859
860 pub fn batch_verify(&self, _proofs: &[ZkpProof], _publics: &[&[u8]]) -> Result<bool> {
862 Err(lib_q_core::Error::NotImplemented {
863 feature: "ZKP feature not enabled".to_string(),
864 })
865 }
866}
867
868impl Default for ZkpProver {
869 fn default() -> Self {
870 Self::new()
871 }
872}
873
874impl Default for ZkpVerifier {
875 fn default() -> Self {
876 Self::new()
877 }
878}
879
880pub fn available_algorithms() -> Vec<&'static str> {
882 let algorithms = vec![
883 #[cfg(feature = "zkp")]
884 "stark",
885 ];
886
887 algorithms
888}
889
890pub fn create_zkp(algorithm: &str) -> Result<Box<dyn core::any::Any>> {
892 match algorithm {
893 #[cfg(feature = "zkp")]
894 "stark" => Ok(Box::new(ZkpProver::new())),
895
896 _ => Err(lib_q_core::Error::InvalidAlgorithm {
897 algorithm: "Unknown ZKP algorithm",
898 }),
899 }
900}
901
902#[cfg(test)]
903mod tests {
904 use super::*;
905
906 #[test]
907 fn test_zkp_prover_creation() {
908 let _prover = ZkpProver::new();
909 }
911
912 #[test]
913 fn test_zkp_verifier_creation() {
914 let _verifier = ZkpVerifier::new();
915 }
917
918 #[test]
919 fn test_zkp_proof_creation() {
920 let mut prover = ZkpProver::new();
921 let secret_value = b"secret_value";
922 let public_statement = b"public_statement";
923
924 let result = prover.prove_secret_value(secret_value, public_statement);
926 assert!(
928 result.is_ok(),
929 "Proof generation should succeed: {:?}",
930 result.err()
931 );
932 }
933
934 #[cfg(feature = "zkp")]
935 #[test]
936 fn test_nist_secret_value_round_trip() {
937 use digest::{
938 ExtendableOutput,
939 Update,
940 };
941 use lib_q_sha3::CShake256;
942
943 use crate::air::hash_preimage_nist::CSHAKE_DOMAIN;
944
945 let secret = b"nist_secret_value";
946 let mut prover = ZkpProver::new();
947 let proof = prover
948 .prove_secret_value_nist(secret, b"")
949 .expect("prove_secret_value_nist");
950 let mut expected_hash = [0u8; 32];
951 {
952 let mut hasher = CShake256::new_with_function_name(&[], CSHAKE_DOMAIN);
953 hasher.update(secret);
954 hasher.finalize_xof_into(&mut expected_hash);
955 }
956 let verifier = ZkpVerifier::new();
957 assert!(
958 verifier
959 .verify_secret_value_nist(&proof, &expected_hash)
960 .unwrap(),
961 "NIST proof should verify with correct expected hash"
962 );
963 assert!(
965 verifier.verify(proof.clone(), &expected_hash).unwrap(),
966 "verify() must accept NIST proof with correct expected hash"
967 );
968 }
969
970 #[cfg(feature = "zkp")]
971 #[test]
972 fn test_nist_proof_rejected_by_poseidon_verifier() {
973 use digest::{
974 ExtendableOutput,
975 Update,
976 };
977 use lib_q_sha3::CShake256;
978
979 use crate::air::hash_preimage_nist::CSHAKE_DOMAIN;
980
981 let secret = b"nist_only";
982 let mut prover = ZkpProver::new();
983 let proof = prover
984 .prove_secret_value_nist(secret, b"")
985 .expect("NIST prove");
986 let mut expected_hash = [0u8; 32];
987 let mut hasher = CShake256::new_with_function_name(&[], CSHAKE_DOMAIN);
988 hasher.update(secret);
989 hasher.finalize_xof_into(&mut expected_hash);
990 let verifier = ZkpVerifier::new();
991 assert!(
992 !verifier
993 .verify_secret_value(&proof, &expected_hash)
994 .unwrap(),
995 "NIST proof must not be accepted by Poseidon verifier"
996 );
997 }
998
999 #[cfg(feature = "zkp")]
1000 #[test]
1001 fn test_poseidon_proof_rejected_by_nist_verifier() {
1002 let secret = b"poseidon_only";
1003 let mut prover = ZkpProver::new();
1004 let proof = prover
1005 .prove_secret_value(secret, b"")
1006 .expect("Poseidon prove");
1007 let verifier = ZkpVerifier::new();
1008 assert!(
1009 !verifier
1010 .verify_secret_value_nist(&proof, &[0u8; 32])
1011 .unwrap(),
1012 "Poseidon proof must not be accepted by NIST verifier"
1013 );
1014 }
1015
1016 #[cfg(feature = "zkp")]
1017 #[test]
1018 fn test_verify_rejects_unknown_metadata() {
1019 use lib_q_stark_field::PrimeCharacteristicRing;
1020 use lib_q_stark_mersenne31::Mersenne31;
1021
1022 use crate::air::{
1023 ArithmeticAir,
1024 TraceGenerator,
1025 };
1026 use crate::stark::{
1027 StarkProver,
1028 default_config,
1029 };
1030
1031 let air = ArithmeticAir::new(1).expect("ArithmeticAir");
1032 let one = <ZkpField as PrimeCharacteristicRing>::ONE;
1033 let seven = ZkpField::from(Mersenne31::new(7));
1034 let input = alloc::vec![(one, seven)];
1035 let trace = air.generate_trace(&input).expect("trace generation");
1036 let public_values = air.public_values(&input);
1037 let proof_inner = StarkProver::new(default_config())
1038 .prove(&air, trace, &public_values)
1039 .expect("prove");
1040 let proof_bytes = postcard::to_allocvec(&proof_inner).expect("serialize STARK proof");
1041
1042 let proof = ZkpProof {
1043 data: proof_bytes,
1044 proof_type: ProofType::Stark,
1045 security_level: 1,
1046 metadata: ProofMetadata::None,
1047 };
1048
1049 let verifier = ZkpVerifier::new();
1050 assert_eq!(
1051 verifier.verify(proof, b"public_statement").unwrap(),
1052 false,
1053 "ProofMetadata::None must return false -- use a type-specific verifier"
1054 );
1055 }
1056
1057 #[test]
1058 fn test_batch_verify_mismatched_lengths() {
1059 let verifier = ZkpVerifier::new();
1060 let proofs = vec![ZkpProof {
1061 data: vec![0u8; 64],
1062 proof_type: ProofType::Stark,
1063 security_level: 1,
1064 metadata: ProofMetadata::None,
1065 }];
1066 let publics: &[&[u8]] = &[b"public1" as &[u8], b"public2" as &[u8]];
1067
1068 let result = verifier.batch_verify(&proofs, publics);
1069 assert!(result.is_err());
1070 if let Err(lib_q_core::Error::InvalidState { .. }) = result {
1071 } else {
1073 panic!("Expected InvalidState error");
1074 }
1075 }
1076
1077 #[cfg(feature = "zkp")]
1078 #[test]
1079 fn test_proof_metadata_merkle() {
1080 let metadata = ProofMetadata::MerkleInclusion { tree_depth: 8 };
1081 let proof = ZkpProof {
1082 data: vec![0u8; 64],
1083 proof_type: ProofType::Stark,
1084 security_level: 1,
1085 metadata,
1086 };
1087 assert_eq!(proof.merkle_tree_depth(), Some(8));
1088 }
1089
1090 #[cfg(feature = "zkp")]
1091 #[test]
1092 fn test_proof_metadata_none() {
1093 let proof = ZkpProof {
1094 data: vec![0u8; 64],
1095 proof_type: ProofType::Stark,
1096 security_level: 1,
1097 metadata: ProofMetadata::None,
1098 };
1099 assert_eq!(proof.merkle_tree_depth(), None);
1100 }
1101
1102 #[test]
1103 fn test_available_algorithms() {
1104 let algorithms = available_algorithms();
1105 #[cfg(feature = "zkp")]
1106 assert!(!algorithms.is_empty(), "zkp feature enables STARK");
1107 #[cfg(not(feature = "zkp"))]
1108 let _ = algorithms;
1109 }
1110
1111 #[cfg(feature = "zkp")]
1112 #[test]
1113 fn test_create_zkp() {
1114 let algorithms = available_algorithms();
1115 assert!(!algorithms.is_empty());
1116 let algorithm = algorithms[0];
1117 assert!(create_zkp(algorithm).is_ok());
1118 }
1119
1120 #[cfg(feature = "zkp")]
1121 #[test]
1122 fn test_verify_rejects_forged_proof_with_hash_preimage_metadata() {
1123 let proof = ZkpProof {
1124 data: alloc::vec![
1125 0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xAA, 0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xAA, 0xDE, 0xAD,
1126 0xBE, 0xEF, 0xFF, 0xAA, 0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xAA, 0xDE, 0xAD, 0xBE, 0xEF,
1127 0xFF, 0xAA, 0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xAA, 0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xAA,
1128 0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xAA, 0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xAA, 0xDE, 0xAD,
1129 0xBE, 0xEF, 0xFF, 0xAA, 0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xAA, 0xDE, 0xAD, 0xBE, 0xEF,
1130 ],
1131 proof_type: ProofType::Stark,
1132 security_level: 1,
1133 metadata: ProofMetadata::HashPreimage { output_size: 1 },
1134 };
1135 let verifier = ZkpVerifier::new();
1136 let result = verifier.verify(proof, b"expected_hash");
1137 assert!(
1138 matches!(result, Ok(false) | Err(_)),
1139 "forged HashPreimage proof must not return Ok(true)"
1140 );
1141 }
1142
1143 #[cfg(feature = "zkp")]
1144 #[test]
1145 fn test_verify_rejects_forged_proof_with_merkle_metadata() {
1146 let proof = ZkpProof {
1147 data: alloc::vec![
1148 0xCA, 0xFE, 0xBA, 0xBE, 0xCA, 0xFE, 0xBA, 0xBE, 0xCA, 0xFE, 0xBA, 0xBE, 0xCA, 0xFE,
1149 0xBA, 0xBE, 0xCA, 0xFE, 0xBA, 0xBE, 0xCA, 0xFE, 0xBA, 0xBE, 0xCA, 0xFE, 0xBA, 0xBE,
1150 0xCA, 0xFE, 0xBA, 0xBE, 0xCA, 0xFE, 0xBA, 0xBE, 0xCA, 0xFE, 0xBA, 0xBE, 0xCA, 0xFE,
1151 0xBA, 0xBE, 0xCA, 0xFE, 0xBA, 0xBE, 0xCA, 0xFE, 0xBA, 0xBE, 0xCA, 0xFE, 0xBA, 0xBE,
1152 0xCA, 0xFE, 0xBA, 0xBE, 0xCA, 0xFE, 0xBA, 0xBE, 0xCA, 0xFE, 0xBA, 0xBE,
1153 ],
1154 proof_type: ProofType::Stark,
1155 security_level: 1,
1156 metadata: ProofMetadata::MerkleInclusion { tree_depth: 4 },
1157 };
1158 let verifier = ZkpVerifier::new();
1159 let result = verifier.verify(proof, b"wrong_root");
1160 assert!(
1161 matches!(result, Ok(false) | Err(_)),
1162 "forged MerkleInclusion proof must not return Ok(true)"
1163 );
1164 }
1165
1166 #[cfg(feature = "zkp")]
1167 #[test]
1168 fn test_verify_rejects_circuit_metadata_proof() {
1169 let proof = ZkpProof {
1170 data: alloc::vec![0u8; 64],
1171 proof_type: ProofType::Stark,
1172 security_level: 1,
1173 metadata: ProofMetadata::Circuit {
1174 num_witnesses: 2,
1175 num_public: 1,
1176 },
1177 };
1178 let verifier = ZkpVerifier::new();
1179 assert_eq!(
1180 verifier.verify(proof, b"anything").unwrap(),
1181 false,
1182 "Circuit proofs must be rejected by generic verify; use verify_computation"
1183 );
1184 }
1185
1186 #[cfg(feature = "zkp")]
1187 #[test]
1188 fn test_verify_rejects_credential_metadata_proof() {
1189 let proof = ZkpProof {
1190 data: alloc::vec![0u8; 64],
1191 proof_type: ProofType::Stark,
1192 security_level: 1,
1193 metadata: ProofMetadata::Credential {
1194 attribute_sizes: alloc::vec![8, 4],
1195 reveal_mask: alloc::vec![true, false],
1196 },
1197 };
1198 let verifier = ZkpVerifier::new();
1199 assert_eq!(
1200 verifier.verify(proof, b"anything").unwrap(),
1201 false,
1202 "Credential proofs must be rejected by generic verify; use ip::verify_credential_proof"
1203 );
1204 }
1205
1206 #[cfg(feature = "zkp")]
1207 #[test]
1208 fn test_verify_rejects_identity_metadata_proof() {
1209 let proof = ZkpProof {
1210 data: alloc::vec![0u8; 64],
1211 proof_type: ProofType::Stark,
1212 security_level: 1,
1213 metadata: ProofMetadata::Identity { dsa_level: 65 },
1214 };
1215 let verifier = ZkpVerifier::new();
1216 assert_eq!(
1217 verifier.verify(proof, b"anything").unwrap(),
1218 false,
1219 "Identity proofs must be rejected by generic verify; use ip::verify_it_ownership"
1220 );
1221 }
1222
1223 #[cfg(feature = "zkp")]
1224 #[test]
1225 fn test_verify_empty_data_is_rejected() {
1226 let proof = ZkpProof {
1227 data: alloc::vec![],
1228 proof_type: ProofType::Stark,
1229 security_level: 1,
1230 metadata: ProofMetadata::HashPreimage { output_size: 1 },
1231 };
1232 let verifier = ZkpVerifier::new();
1233 assert_eq!(
1234 verifier.verify(proof, b"anything").unwrap(),
1235 false,
1236 "empty proof data must be rejected regardless of metadata"
1237 );
1238 }
1239
1240 #[cfg(feature = "zkp")]
1241 #[test]
1242 fn test_proof_type_only_stark_exists() {
1243 let _stark = ProofType::Stark;
1244 }
1247
1248 #[cfg(feature = "zkp")]
1249 #[test]
1250 fn test_batch_verify_rejects_forged_hash_preimage_proof() {
1251 let forged = ZkpProof {
1252 data: alloc::vec![0xFF; 64],
1253 proof_type: ProofType::Stark,
1254 security_level: 1,
1255 metadata: ProofMetadata::HashPreimage { output_size: 1 },
1256 };
1257 let verifier = ZkpVerifier::new();
1258 let proofs = alloc::vec![forged];
1259 let publics: &[&[u8]] = &[b"anything"];
1260 let result = verifier.batch_verify(&proofs, publics);
1261 assert!(
1262 matches!(result, Ok(false) | Err(_)),
1263 "batch_verify must not accept a forged proof"
1264 );
1265 }
1266
1267 #[cfg(feature = "zkp")]
1268 #[test]
1269 fn test_prove_secret_value_rejects_empty_and_oversized_input() {
1270 let mut prover = ZkpProver::new();
1271 let empty = prover.prove_secret_value(b"", b"");
1272 assert!(empty.is_err());
1273
1274 let oversized = vec![0u8; air::hash_preimage::MAX_PREIMAGE_SIZE + 1];
1275 let too_large = prover.prove_secret_value(&oversized, b"");
1276 assert!(too_large.is_err());
1277 }
1278
1279 #[cfg(feature = "zkp")]
1280 #[test]
1281 fn test_prove_secret_value_nist_rejects_empty_and_oversized_input() {
1282 let mut prover = ZkpProver::new();
1283 let empty = prover.prove_secret_value_nist(b"", b"");
1284 assert!(empty.is_err());
1285
1286 let oversized = vec![0u8; air::hash_preimage_nist::MAX_PREIMAGE_SIZE + 1];
1287 let too_large = prover.prove_secret_value_nist(&oversized, b"");
1288 assert!(too_large.is_err());
1289 }
1290
1291 #[cfg(feature = "zkp")]
1292 #[test]
1293 fn test_verify_secret_value_rejects_invalid_proof_shape_inputs() {
1294 let verifier = ZkpVerifier::new();
1295 let non_stark = ZkpProof {
1296 data: vec![1u8; 16],
1297 proof_type: ProofType::Stark,
1298 security_level: 1,
1299 metadata: ProofMetadata::HashPreimageNist { output_size: 32 },
1300 };
1301 assert!(!verifier.verify_secret_value(&non_stark, b"hash").unwrap());
1302
1303 let empty = ZkpProof {
1304 data: vec![],
1305 proof_type: ProofType::Stark,
1306 security_level: 1,
1307 metadata: ProofMetadata::HashPreimage { output_size: 1 },
1308 };
1309 assert!(!verifier.verify_secret_value(&empty, b"hash").unwrap());
1310 }
1311
1312 #[cfg(feature = "zkp")]
1313 #[test]
1314 fn test_verify_secret_value_nist_rejects_wrong_metadata_and_bad_bytes() {
1315 let verifier = ZkpVerifier::new();
1316 let wrong_meta = ZkpProof {
1317 data: vec![1u8; 16],
1318 proof_type: ProofType::Stark,
1319 security_level: 1,
1320 metadata: ProofMetadata::HashPreimage { output_size: 1 },
1321 };
1322 assert!(
1323 !verifier
1324 .verify_secret_value_nist(&wrong_meta, &[0u8; 32])
1325 .unwrap()
1326 );
1327
1328 let malformed_stark = ZkpProof {
1329 data: vec![0xAA; 16],
1330 proof_type: ProofType::Stark,
1331 security_level: 1,
1332 metadata: ProofMetadata::HashPreimageNist { output_size: 32 },
1333 };
1334 assert!(
1335 !verifier
1336 .verify_secret_value_nist(&malformed_stark, &[0u8; 32])
1337 .unwrap()
1338 );
1339 }
1340
1341 #[cfg(feature = "zkp")]
1342 #[test]
1343 fn test_verify_computation_rejects_empty_or_non_stark_data() {
1344 use crate::circuit::CircuitBuilder;
1345
1346 let verifier = ZkpVerifier::new();
1347 let circuit = CircuitBuilder::<ZkpField>::new(1, 0).build();
1348
1349 let empty = ZkpProof {
1350 data: vec![],
1351 proof_type: ProofType::Stark,
1352 security_level: 1,
1353 metadata: ProofMetadata::Circuit {
1354 num_witnesses: 1,
1355 num_public: 0,
1356 },
1357 };
1358 assert!(!verifier.verify_computation(&empty, &circuit, &[]).unwrap());
1359 }
1360}