1#![cfg_attr(not(feature = "std"), no_std)]
48#![allow(type_alias_bounds)]
51#![deny(unsafe_code)]
52#![deny(unused_qualifications)]
53#![allow(clippy::bool_assert_comparison)]
54#![allow(clippy::clone_on_copy)]
55#![allow(clippy::collapsible_if)]
56#![allow(clippy::get_first)]
57#![allow(clippy::iter_cloned_collect)]
58#![allow(clippy::manual_is_multiple_of)]
59#![allow(clippy::too_many_arguments)]
60#![allow(clippy::unnecessary_lazy_evaluations)]
61#![allow(clippy::assign_op_pattern)]
64#![allow(clippy::needless_range_loop)]
65#![allow(clippy::manual_memcpy)]
66#![allow(clippy::double_must_use)]
67
68#[cfg(feature = "alloc")]
69extern crate alloc;
70
71#[cfg(feature = "alloc")]
73use alloc::boxed::Box;
74#[cfg(feature = "alloc")]
75use alloc::string::ToString;
76#[cfg(feature = "alloc")]
77use alloc::vec;
78#[cfg(feature = "alloc")]
79use alloc::vec::Vec;
80
81pub use lib_q_core::Result;
82#[cfg(any(
87 feature = "plonky",
88 feature = "plonky-keccak-air",
89 feature = "plonky-lookup",
90 feature = "plonky-uni-stark",
91 feature = "plonky-batch-stark",
92))]
93pub use lib_q_plonky as plonky;
94
95#[cfg(feature = "zkp")]
97pub mod stark;
98
99#[cfg(feature = "zkp")]
101pub mod stark_baby_bear;
102
103#[cfg(feature = "zkp")]
105pub mod circuit;
106
107#[cfg(feature = "zkp")]
109pub mod air;
110
111#[cfg(feature = "zkp")]
113pub mod aggregation;
114
115#[cfg(feature = "zkp")]
117pub mod ip;
118
119#[cfg(feature = "zkp")]
121pub mod merkle;
122
123#[cfg(feature = "zkp")]
125pub mod merkle_baby_bear;
126
127#[cfg(feature = "zkp")]
129pub mod api;
130
131#[cfg(feature = "zkp")]
132pub mod wire;
133
134#[cfg(feature = "zkp")]
137pub mod membership;
138
139#[cfg(feature = "zkp")]
140pub use api::{
141 MerklePath,
142 build_merkle_tree,
143 prove_membership,
144 prove_membership_with_config,
145 prove_preimage,
146 prove_preimage_nist,
147 verify_membership,
148 verify_membership_with_config,
149 verify_membership_with_depth,
150 verify_membership_with_depth_and_config,
151 verify_preimage,
152 verify_preimage_nist,
153};
154
155#[cfg(feature = "wasm")]
156mod wasm;
157
158#[cfg(feature = "zkp")]
159pub use lib_q_stark::{
160 Proof as StarkProof,
161 StarkConfig,
162 StarkGenericConfig,
163 check_constraints,
164 prove,
165 verify,
166};
167#[cfg(feature = "zkp")]
168pub use lib_q_stark_air::Air;
169#[cfg(feature = "zkp")]
170use lib_q_stark_field::extension::Complex;
171#[cfg(feature = "zkp")]
172use lib_q_stark_matrix::dense::RowMajorMatrix;
173#[cfg(feature = "zkp")]
174use lib_q_stark_mersenne31::Mersenne31;
175#[cfg(feature = "zkp")]
176pub use merkle::PoseidonMerkleTree;
177#[cfg(feature = "zkp")]
178use serde::{
179 Deserialize,
180 Serialize,
181};
182
183#[cfg(feature = "zkp")]
184#[allow(unused_imports)]
185use crate::air::TraceGenerator;
186
187#[cfg(feature = "zkp")]
192pub type ZkpField = Complex<Mersenne31>;
193
194#[derive(Debug, Clone, PartialEq, Eq, Default)]
201#[cfg_attr(feature = "zkp", derive(Serialize, Deserialize))]
202pub enum ProofMetadata {
203 #[default]
205 None,
206 MerkleInclusion {
208 tree_depth: u8,
210 },
211 HashPreimage {
213 output_size: u16,
215 },
216 HashPreimageNist {
218 output_size: u16,
220 },
221 Circuit {
223 num_witnesses: u32,
225 num_public: u32,
227 },
228 Credential {
230 attribute_sizes: Vec<u16>,
232 reveal_mask: Vec<bool>,
234 },
235 Identity {
237 dsa_level: u8,
239 },
240 RecoveryPolicy {
242 key_count: u32,
244 air_id: u8,
246 },
247 UnlinkableMembership {
249 tree_depth: u8,
253 digest_width: u8,
255 zk: bool,
259 },
260}
261
262#[derive(Debug, Clone)]
264#[cfg_attr(feature = "zkp", derive(serde::Serialize, serde::Deserialize))]
265pub struct ZkpProof {
266 pub data: Vec<u8>,
268 pub proof_type: ProofType,
270 pub security_level: u32,
272 pub metadata: ProofMetadata,
274}
275
276#[cfg(feature = "zkp")]
277impl ZkpProof {
278 pub fn from_stark_proof<C: StarkGenericConfig>(
283 proof: &StarkProof<C>,
284 metadata: ProofMetadata,
285 ) -> Result<Self>
286 where
287 StarkProof<C>: Serialize,
288 {
289 let data = postcard::to_allocvec(proof).map_err(|_| lib_q_core::Error::InternalError {
290 operation: "ZKP proof serialization".to_string(),
291 details: "Failed to serialize STARK proof".to_string(),
292 })?;
293 Ok(Self {
294 data,
295 proof_type: ProofType::Stark,
296 security_level: 1,
297 metadata,
298 })
299 }
300
301 pub fn to_stark_proof<C: StarkGenericConfig>(&self) -> Result<StarkProof<C>>
303 where
304 StarkProof<C>: for<'de> Deserialize<'de>,
305 {
306 postcard::from_bytes(&self.data).map_err(|_| lib_q_core::Error::InternalError {
307 operation: "ZKP proof deserialization".to_string(),
308 details: "Failed to deserialize STARK proof".to_string(),
309 })
310 }
311
312 pub fn merkle_tree_depth(&self) -> Option<u8> {
317 match &self.metadata {
318 ProofMetadata::MerkleInclusion { tree_depth } => Some(*tree_depth),
319 ProofMetadata::UnlinkableMembership { tree_depth, .. } => Some(*tree_depth),
320 _ => None,
321 }
322 }
323}
324
325#[derive(Debug, Clone, PartialEq, Eq)]
334#[cfg_attr(feature = "zkp", derive(serde::Serialize, serde::Deserialize))]
335pub enum ProofType {
336 Stark,
338}
339
340#[cfg(feature = "zkp")]
342pub struct ZkpProver {
343 }
345
346#[cfg(not(feature = "zkp"))]
347pub struct ZkpProver;
348
349#[cfg(feature = "zkp")]
351pub struct ZkpVerifier {
352 }
354
355#[cfg(not(feature = "zkp"))]
356pub struct ZkpVerifier;
357
358#[cfg(feature = "zkp")]
359impl ZkpProver {
360 pub fn new() -> Self {
362 Self {}
363 }
364
365 pub fn prove_secret_value(
393 &mut self,
394 secret_value: &[u8],
395 _public_statement: &[u8],
396 ) -> Result<ZkpProof> {
397 use crate::air::{
398 HashPreimageAir,
399 TraceGenerator,
400 };
401 use crate::stark::{
402 StarkProver,
403 default_config,
404 };
405
406 if secret_value.is_empty() {
408 return Err(lib_q_core::Error::InvalidState {
409 operation: "prove_secret_value".to_string(),
410 reason: "Secret value cannot be empty".to_string(),
411 });
412 }
413
414 if secret_value.len() > air::hash_preimage::MAX_PREIMAGE_SIZE {
415 return Err(lib_q_core::Error::InvalidState {
416 operation: "prove_secret_value".to_string(),
417 reason: "Secret value exceeds maximum size".to_string(),
418 });
419 }
420
421 let air = HashPreimageAir::new();
423
424 let input = secret_value.to_vec();
426 let trace: RowMajorMatrix<ZkpField> =
427 air.generate_trace(&input)
428 .map_err(|e| lib_q_core::Error::InternalError {
429 operation: "prove_secret_value".to_string(),
430 details: e.to_string(),
431 })?;
432
433 let public_values: Vec<ZkpField> = air.public_values(&input);
435
436 let config = default_config();
438 let prover = StarkProver::new(config);
439
440 let proof = prover.prove(&air, trace, &public_values).map_err(|e| {
442 lib_q_core::Error::InternalError {
443 operation: "STARK proof generation".to_string(),
444 details: e.to_string(),
445 }
446 })?;
447
448 let metadata = ProofMetadata::HashPreimage { output_size: 1u16 };
450
451 ZkpProof::from_stark_proof(&proof, metadata)
453 }
454
455 pub fn prove_secret_value_nist(
473 &mut self,
474 secret_value: &[u8],
475 public_statement: &[u8],
476 ) -> Result<ZkpProof> {
477 let _ = (secret_value, public_statement);
483 Err(lib_q_core::Error::NotImplemented {
484 feature: "NIST (cSHAKE256) preimage proofs: Keccak-f AIR constraints not implemented"
485 .to_string(),
486 })
487 }
488
489 pub fn prove_computation(
530 &mut self,
531 circuit: &circuit::ArithmeticCircuit<ZkpField>,
532 witness: &[ZkpField],
533 public: &[ZkpField],
534 ) -> Result<ZkpProof> {
535 use crate::circuit::CircuitAir;
536 use crate::stark::{
537 StarkProver,
538 default_config,
539 };
540
541 let air = CircuitAir::new(circuit.clone());
543
544 let trace = air.generate_trace(witness, public)?;
546
547 let config = default_config();
549 let prover = StarkProver::new(config);
550
551 let proof =
553 prover
554 .prove(&air, trace, public)
555 .map_err(|e| lib_q_core::Error::InternalError {
556 operation: "STARK proof generation".to_string(),
557 details: e.to_string(),
558 })?;
559
560 let metadata = ProofMetadata::Circuit {
562 num_witnesses: witness.len().min(u32::MAX as usize) as u32,
563 num_public: public.len().min(u32::MAX as usize) as u32,
564 };
565
566 ZkpProof::from_stark_proof(&proof, metadata)
568 }
569}
570
571#[cfg(not(feature = "zkp"))]
572impl ZkpProver {
573 pub fn new() -> Self {
575 Self {}
576 }
577
578 pub fn prove_secret_value(
580 &mut self,
581 _secret_value: &[u8],
582 _public_statement: &[u8],
583 ) -> Result<ZkpProof> {
584 Err(lib_q_core::Error::NotImplemented {
585 feature: "ZKP feature not enabled".to_string(),
586 })
587 }
588
589 pub fn prove_secret_value_nist(
591 &mut self,
592 _secret_value: &[u8],
593 _public_statement: &[u8],
594 ) -> Result<ZkpProof> {
595 Err(lib_q_core::Error::NotImplemented {
596 feature: "ZKP feature not enabled".to_string(),
597 })
598 }
599}
600
601#[cfg(feature = "zkp")]
604fn verify_secret_value_nist_impl(proof: &ZkpProof, expected_hash: &[u8]) -> Result<bool> {
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 _ = expected_hash;
621 Err(lib_q_core::Error::NotImplemented {
622 feature: "NIST (cSHAKE256) preimage proofs: Keccak-f AIR constraints not implemented"
623 .to_string(),
624 })
625}
626
627#[cfg(feature = "zkp")]
628impl ZkpVerifier {
629 pub fn new() -> Self {
631 Self {}
632 }
633
634 pub fn verify_secret_value(&self, proof: &ZkpProof, preimage: &[u8]) -> Result<bool> {
652 use crate::air::{
653 HashPreimageAir,
654 TraceGenerator,
655 };
656 use crate::stark::{
657 StarkVerifier,
658 default_config,
659 };
660
661 if proof.proof_type != ProofType::Stark {
662 return Ok(false);
663 }
664
665 if proof.data.is_empty() {
666 return Ok(false);
667 }
668
669 let ProofMetadata::HashPreimage { output_size } = &proof.metadata else {
671 return Ok(false);
673 };
674
675 let _ = output_size;
677 let air = HashPreimageAir::new();
678
679 let public_values: Vec<ZkpField> = air.public_values(&preimage.to_vec());
682
683 let stark_proof = proof.to_stark_proof()?;
685
686 let config = default_config();
688 let verifier = StarkVerifier::new(config);
689
690 match verifier.verify(&air, &stark_proof, &public_values) {
692 Ok(()) => Ok(true),
693 Err(_) => Ok(false),
694 }
695 }
696
697 pub fn verify_secret_value_nist(&self, proof: &ZkpProof, expected_hash: &[u8]) -> Result<bool> {
702 verify_secret_value_nist_impl(proof, expected_hash)
703 }
704
705 pub fn verify_computation(
719 &self,
720 proof: &ZkpProof,
721 circuit: &circuit::ArithmeticCircuit<ZkpField>,
722 public: &[ZkpField],
723 ) -> Result<bool> {
724 use crate::circuit::CircuitAir;
725 use crate::stark::{
726 StarkVerifier,
727 default_config,
728 };
729
730 if proof.proof_type != ProofType::Stark {
731 return Ok(false);
732 }
733
734 if proof.data.is_empty() {
735 return Ok(false);
736 }
737
738 let air = CircuitAir::new(circuit.clone());
740
741 let stark_proof = proof.to_stark_proof()?;
743
744 let config = default_config();
746 let verifier = StarkVerifier::new(config);
747
748 match verifier.verify(&air, &stark_proof, public) {
750 Ok(()) => Ok(true),
751 Err(_) => Ok(false),
752 }
753 }
754
755 pub fn verify(&self, proof: ZkpProof, public_statement: &[u8]) -> Result<bool> {
773 if proof.proof_type != ProofType::Stark {
774 return Ok(false);
775 }
776 if proof.data.is_empty() {
777 return Ok(false);
778 }
779 match &proof.metadata {
780 ProofMetadata::HashPreimage { .. } => {
781 self.verify_secret_value(&proof, public_statement)
782 }
783 ProofMetadata::HashPreimageNist { .. } => {
784 verify_secret_value_nist_impl(&proof, public_statement)
785 }
786 ProofMetadata::MerkleInclusion { .. } => verify_membership(&proof, public_statement),
787 ProofMetadata::UnlinkableMembership { .. } => {
788 membership::verify_unlinkable_membership_bytes(&proof, public_statement)
789 }
790 _ => Ok(false),
791 }
792 }
793
794 pub fn batch_verify(&self, proofs: &[ZkpProof], publics: &[&[u8]]) -> Result<bool> {
805 if proofs.len() != publics.len() {
806 return Err(lib_q_core::Error::InvalidState {
807 operation: "batch_verify".to_string(),
808 reason: "Number of proofs must match number of public statements".to_string(),
809 });
810 }
811
812 for (proof, public) in proofs.iter().zip(publics.iter()) {
813 match self.verify(proof.clone(), public) {
814 Ok(true) => continue,
815 Ok(false) => return Ok(false),
816 Err(e) => return Err(e),
817 }
818 }
819
820 Ok(true)
821 }
822}
823
824#[cfg(not(feature = "zkp"))]
825impl ZkpVerifier {
826 pub fn new() -> Self {
828 Self {}
829 }
830
831 pub fn verify(&self, _proof: ZkpProof, _public_statement: &[u8]) -> Result<bool> {
833 Err(lib_q_core::Error::NotImplemented {
834 feature: "ZKP feature not enabled".to_string(),
835 })
836 }
837
838 pub fn verify_secret_value_nist(
840 &self,
841 _proof: &ZkpProof,
842 _expected_hash: &[u8],
843 ) -> Result<bool> {
844 Err(lib_q_core::Error::NotImplemented {
845 feature: "ZKP feature not enabled".to_string(),
846 })
847 }
848
849 pub fn batch_verify(&self, _proofs: &[ZkpProof], _publics: &[&[u8]]) -> Result<bool> {
851 Err(lib_q_core::Error::NotImplemented {
852 feature: "ZKP feature not enabled".to_string(),
853 })
854 }
855}
856
857impl Default for ZkpProver {
858 fn default() -> Self {
859 Self::new()
860 }
861}
862
863impl Default for ZkpVerifier {
864 fn default() -> Self {
865 Self::new()
866 }
867}
868
869pub fn available_algorithms() -> Vec<&'static str> {
871 let algorithms = vec![
872 #[cfg(feature = "zkp")]
873 "stark",
874 ];
875
876 algorithms
877}
878
879pub fn create_zkp(algorithm: &str) -> Result<Box<dyn core::any::Any>> {
881 match algorithm {
882 #[cfg(feature = "zkp")]
883 "stark" => Ok(Box::new(ZkpProver::new())),
884
885 _ => Err(lib_q_core::Error::InvalidAlgorithm {
886 algorithm: "Unknown ZKP algorithm",
887 }),
888 }
889}
890
891#[cfg(test)]
892mod tests {
893 use super::*;
894
895 #[test]
896 fn test_zkp_prover_creation() {
897 let _prover = ZkpProver::new();
898 }
900
901 #[test]
902 fn test_zkp_verifier_creation() {
903 let _verifier = ZkpVerifier::new();
904 }
906
907 #[test]
908 fn test_zkp_proof_creation() {
909 let mut prover = ZkpProver::new();
910 let secret_value = b"secret_value";
911 let public_statement = b"public_statement";
912
913 let result = prover.prove_secret_value(secret_value, public_statement);
915 assert!(
917 result.is_ok(),
918 "Proof generation should succeed: {:?}",
919 result.err()
920 );
921 }
922
923 #[cfg(feature = "zkp")]
924 #[test]
925 fn test_nist_secret_value_not_implemented() {
926 let secret = b"nist_secret_value";
929 let mut prover = ZkpProver::new();
930 assert!(
931 matches!(
932 prover.prove_secret_value_nist(secret, b""),
933 Err(lib_q_core::Error::NotImplemented { .. })
934 ),
935 "NIST prove must return NotImplemented"
936 );
937
938 let verifier = ZkpVerifier::new();
939 let mut dummy = ZkpProof {
940 data: alloc::vec![1u8; 8],
941 proof_type: ProofType::Stark,
942 security_level: 1,
943 metadata: ProofMetadata::HashPreimageNist { output_size: 32 },
944 };
945 assert!(
946 matches!(
947 verifier.verify_secret_value_nist(&dummy, &[0u8; 32]),
948 Err(lib_q_core::Error::NotImplemented { .. })
949 ),
950 "NIST verify must return NotImplemented"
951 );
952 dummy.data = alloc::vec![1u8; 8];
954 assert!(
955 matches!(
956 verifier.verify(dummy, &[0u8; 32]),
957 Err(lib_q_core::Error::NotImplemented { .. })
958 ),
959 "verify() must return NotImplemented for NIST proofs"
960 );
961 }
962
963 #[cfg(feature = "zkp")]
964 #[test]
965 fn test_poseidon_proof_rejected_by_nist_verifier() {
966 let secret = b"poseidon_only";
967 let mut prover = ZkpProver::new();
968 let proof = prover
969 .prove_secret_value(secret, b"")
970 .expect("Poseidon prove");
971 let verifier = ZkpVerifier::new();
972 assert!(
973 !verifier
974 .verify_secret_value_nist(&proof, &[0u8; 32])
975 .unwrap(),
976 "Poseidon proof must not be accepted by NIST verifier"
977 );
978 }
979
980 #[cfg(feature = "zkp")]
981 #[test]
982 fn test_verify_rejects_unknown_metadata() {
983 use lib_q_stark_field::PrimeCharacteristicRing;
984 use lib_q_stark_mersenne31::Mersenne31;
985
986 use crate::air::{
987 ArithmeticAir,
988 TraceGenerator,
989 };
990 use crate::stark::{
991 StarkProver,
992 default_config,
993 };
994
995 let air = ArithmeticAir::new(1).expect("ArithmeticAir");
996 let one = <ZkpField as PrimeCharacteristicRing>::ONE;
997 let seven = ZkpField::from(Mersenne31::new(7));
998 let input = alloc::vec![(one, seven)];
999 let trace = air.generate_trace(&input).expect("trace generation");
1000 let public_values = air.public_values(&input);
1001 let proof_inner = StarkProver::new(default_config())
1002 .prove(&air, trace, &public_values)
1003 .expect("prove");
1004 let proof_bytes = postcard::to_allocvec(&proof_inner).expect("serialize STARK proof");
1005
1006 let proof = ZkpProof {
1007 data: proof_bytes,
1008 proof_type: ProofType::Stark,
1009 security_level: 1,
1010 metadata: ProofMetadata::None,
1011 };
1012
1013 let verifier = ZkpVerifier::new();
1014 assert_eq!(
1015 verifier.verify(proof, b"public_statement").unwrap(),
1016 false,
1017 "ProofMetadata::None must return false -- use a type-specific verifier"
1018 );
1019 }
1020
1021 #[test]
1022 fn test_batch_verify_mismatched_lengths() {
1023 let verifier = ZkpVerifier::new();
1024 let proofs = vec![ZkpProof {
1025 data: vec![0u8; 64],
1026 proof_type: ProofType::Stark,
1027 security_level: 1,
1028 metadata: ProofMetadata::None,
1029 }];
1030 let publics: &[&[u8]] = &[b"public1" as &[u8], b"public2" as &[u8]];
1031
1032 let result = verifier.batch_verify(&proofs, publics);
1033 assert!(result.is_err());
1034 if let Err(lib_q_core::Error::InvalidState { .. }) = result {
1035 } else {
1037 panic!("Expected InvalidState error");
1038 }
1039 }
1040
1041 #[cfg(feature = "zkp")]
1042 #[test]
1043 fn test_proof_metadata_merkle() {
1044 let metadata = ProofMetadata::MerkleInclusion { tree_depth: 8 };
1045 let proof = ZkpProof {
1046 data: vec![0u8; 64],
1047 proof_type: ProofType::Stark,
1048 security_level: 1,
1049 metadata,
1050 };
1051 assert_eq!(proof.merkle_tree_depth(), Some(8));
1052 }
1053
1054 #[cfg(feature = "zkp")]
1055 #[test]
1056 fn test_proof_metadata_none() {
1057 let proof = ZkpProof {
1058 data: vec![0u8; 64],
1059 proof_type: ProofType::Stark,
1060 security_level: 1,
1061 metadata: ProofMetadata::None,
1062 };
1063 assert_eq!(proof.merkle_tree_depth(), None);
1064 }
1065
1066 #[test]
1067 fn test_available_algorithms() {
1068 let algorithms = available_algorithms();
1069 #[cfg(feature = "zkp")]
1070 assert!(!algorithms.is_empty(), "zkp feature enables STARK");
1071 #[cfg(not(feature = "zkp"))]
1072 let _ = algorithms;
1073 }
1074
1075 #[cfg(feature = "zkp")]
1076 #[test]
1077 fn test_create_zkp() {
1078 let algorithms = available_algorithms();
1079 assert!(!algorithms.is_empty());
1080 let algorithm = algorithms[0];
1081 assert!(create_zkp(algorithm).is_ok());
1082 }
1083
1084 #[cfg(feature = "zkp")]
1085 #[test]
1086 fn test_verify_rejects_forged_proof_with_hash_preimage_metadata() {
1087 let proof = ZkpProof {
1088 data: alloc::vec![
1089 0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xAA, 0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xAA, 0xDE, 0xAD,
1090 0xBE, 0xEF, 0xFF, 0xAA, 0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xAA, 0xDE, 0xAD, 0xBE, 0xEF,
1091 0xFF, 0xAA, 0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xAA, 0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xAA,
1092 0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xAA, 0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xAA, 0xDE, 0xAD,
1093 0xBE, 0xEF, 0xFF, 0xAA, 0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xAA, 0xDE, 0xAD, 0xBE, 0xEF,
1094 ],
1095 proof_type: ProofType::Stark,
1096 security_level: 1,
1097 metadata: ProofMetadata::HashPreimage { output_size: 1 },
1098 };
1099 let verifier = ZkpVerifier::new();
1100 let result = verifier.verify(proof, b"expected_hash");
1101 assert!(
1102 matches!(result, Ok(false) | Err(_)),
1103 "forged HashPreimage proof must not return Ok(true)"
1104 );
1105 }
1106
1107 #[cfg(feature = "zkp")]
1108 #[test]
1109 fn test_verify_rejects_forged_proof_with_merkle_metadata() {
1110 let proof = ZkpProof {
1111 data: alloc::vec![
1112 0xCA, 0xFE, 0xBA, 0xBE, 0xCA, 0xFE, 0xBA, 0xBE, 0xCA, 0xFE, 0xBA, 0xBE, 0xCA, 0xFE,
1113 0xBA, 0xBE, 0xCA, 0xFE, 0xBA, 0xBE, 0xCA, 0xFE, 0xBA, 0xBE, 0xCA, 0xFE, 0xBA, 0xBE,
1114 0xCA, 0xFE, 0xBA, 0xBE, 0xCA, 0xFE, 0xBA, 0xBE, 0xCA, 0xFE, 0xBA, 0xBE, 0xCA, 0xFE,
1115 0xBA, 0xBE, 0xCA, 0xFE, 0xBA, 0xBE, 0xCA, 0xFE, 0xBA, 0xBE, 0xCA, 0xFE, 0xBA, 0xBE,
1116 0xCA, 0xFE, 0xBA, 0xBE, 0xCA, 0xFE, 0xBA, 0xBE, 0xCA, 0xFE, 0xBA, 0xBE,
1117 ],
1118 proof_type: ProofType::Stark,
1119 security_level: 1,
1120 metadata: ProofMetadata::MerkleInclusion { tree_depth: 4 },
1121 };
1122 let verifier = ZkpVerifier::new();
1123 let result = verifier.verify(proof, b"wrong_root");
1124 assert!(
1125 matches!(result, Ok(false) | Err(_)),
1126 "forged MerkleInclusion proof must not return Ok(true)"
1127 );
1128 }
1129
1130 #[cfg(feature = "zkp")]
1131 #[test]
1132 fn test_verify_rejects_circuit_metadata_proof() {
1133 let proof = ZkpProof {
1134 data: alloc::vec![0u8; 64],
1135 proof_type: ProofType::Stark,
1136 security_level: 1,
1137 metadata: ProofMetadata::Circuit {
1138 num_witnesses: 2,
1139 num_public: 1,
1140 },
1141 };
1142 let verifier = ZkpVerifier::new();
1143 assert_eq!(
1144 verifier.verify(proof, b"anything").unwrap(),
1145 false,
1146 "Circuit proofs must be rejected by generic verify; use verify_computation"
1147 );
1148 }
1149
1150 #[cfg(feature = "zkp")]
1151 #[test]
1152 fn test_verify_rejects_credential_metadata_proof() {
1153 let proof = ZkpProof {
1154 data: alloc::vec![0u8; 64],
1155 proof_type: ProofType::Stark,
1156 security_level: 1,
1157 metadata: ProofMetadata::Credential {
1158 attribute_sizes: alloc::vec![8, 4],
1159 reveal_mask: alloc::vec![true, false],
1160 },
1161 };
1162 let verifier = ZkpVerifier::new();
1163 assert_eq!(
1164 verifier.verify(proof, b"anything").unwrap(),
1165 false,
1166 "Credential proofs must be rejected by generic verify; use ip::verify_credential_proof"
1167 );
1168 }
1169
1170 #[cfg(feature = "zkp")]
1171 #[test]
1172 fn test_verify_rejects_identity_metadata_proof() {
1173 let proof = ZkpProof {
1174 data: alloc::vec![0u8; 64],
1175 proof_type: ProofType::Stark,
1176 security_level: 1,
1177 metadata: ProofMetadata::Identity { dsa_level: 65 },
1178 };
1179 let verifier = ZkpVerifier::new();
1180 assert_eq!(
1181 verifier.verify(proof, b"anything").unwrap(),
1182 false,
1183 "Identity proofs must be rejected by generic verify; use ip::verify_it_ownership"
1184 );
1185 }
1186
1187 #[cfg(feature = "zkp")]
1188 #[test]
1189 fn test_verify_empty_data_is_rejected() {
1190 let proof = ZkpProof {
1191 data: alloc::vec![],
1192 proof_type: ProofType::Stark,
1193 security_level: 1,
1194 metadata: ProofMetadata::HashPreimage { output_size: 1 },
1195 };
1196 let verifier = ZkpVerifier::new();
1197 assert_eq!(
1198 verifier.verify(proof, b"anything").unwrap(),
1199 false,
1200 "empty proof data must be rejected regardless of metadata"
1201 );
1202 }
1203
1204 #[cfg(feature = "zkp")]
1205 #[test]
1206 fn test_proof_type_only_stark_exists() {
1207 let _stark = ProofType::Stark;
1208 }
1212
1213 #[cfg(feature = "zkp")]
1214 #[test]
1215 fn test_batch_verify_rejects_forged_hash_preimage_proof() {
1216 let forged = ZkpProof {
1217 data: alloc::vec![0xFF; 64],
1218 proof_type: ProofType::Stark,
1219 security_level: 1,
1220 metadata: ProofMetadata::HashPreimage { output_size: 1 },
1221 };
1222 let verifier = ZkpVerifier::new();
1223 let proofs = alloc::vec![forged];
1224 let publics: &[&[u8]] = &[b"anything"];
1225 let result = verifier.batch_verify(&proofs, publics);
1226 assert!(
1227 matches!(result, Ok(false) | Err(_)),
1228 "batch_verify must not accept a forged proof"
1229 );
1230 }
1231
1232 #[cfg(feature = "zkp")]
1233 #[test]
1234 fn test_prove_secret_value_rejects_empty_and_oversized_input() {
1235 let mut prover = ZkpProver::new();
1236 let empty = prover.prove_secret_value(b"", b"");
1237 assert!(empty.is_err());
1238
1239 let oversized = vec![0u8; air::hash_preimage::MAX_PREIMAGE_SIZE + 1];
1240 let too_large = prover.prove_secret_value(&oversized, b"");
1241 assert!(too_large.is_err());
1242 }
1243
1244 #[cfg(feature = "zkp")]
1245 #[test]
1246 fn test_prove_secret_value_nist_rejects_empty_and_oversized_input() {
1247 let mut prover = ZkpProver::new();
1248 let empty = prover.prove_secret_value_nist(b"", b"");
1249 assert!(empty.is_err());
1250
1251 let oversized = vec![0u8; air::hash_preimage_nist::MAX_PREIMAGE_SIZE + 1];
1252 let too_large = prover.prove_secret_value_nist(&oversized, b"");
1253 assert!(too_large.is_err());
1254 }
1255
1256 #[cfg(feature = "zkp")]
1257 #[test]
1258 fn test_verify_secret_value_rejects_invalid_proof_shape_inputs() {
1259 let verifier = ZkpVerifier::new();
1260 let non_stark = ZkpProof {
1261 data: vec![1u8; 16],
1262 proof_type: ProofType::Stark,
1263 security_level: 1,
1264 metadata: ProofMetadata::HashPreimageNist { output_size: 32 },
1265 };
1266 assert!(!verifier.verify_secret_value(&non_stark, b"hash").unwrap());
1267
1268 let empty = ZkpProof {
1269 data: vec![],
1270 proof_type: ProofType::Stark,
1271 security_level: 1,
1272 metadata: ProofMetadata::HashPreimage { output_size: 1 },
1273 };
1274 assert!(!verifier.verify_secret_value(&empty, b"hash").unwrap());
1275 }
1276
1277 #[cfg(feature = "zkp")]
1278 #[test]
1279 fn test_verify_secret_value_nist_rejects_wrong_metadata_and_bad_bytes() {
1280 let verifier = ZkpVerifier::new();
1281 let wrong_meta = ZkpProof {
1282 data: vec![1u8; 16],
1283 proof_type: ProofType::Stark,
1284 security_level: 1,
1285 metadata: ProofMetadata::HashPreimage { output_size: 1 },
1286 };
1287 assert!(
1288 !verifier
1289 .verify_secret_value_nist(&wrong_meta, &[0u8; 32])
1290 .unwrap()
1291 );
1292
1293 let nist_meta = ZkpProof {
1296 data: vec![0xAA; 16],
1297 proof_type: ProofType::Stark,
1298 security_level: 1,
1299 metadata: ProofMetadata::HashPreimageNist { output_size: 32 },
1300 };
1301 assert!(matches!(
1302 verifier.verify_secret_value_nist(&nist_meta, &[0u8; 32]),
1303 Err(lib_q_core::Error::NotImplemented { .. })
1304 ));
1305 }
1306
1307 #[cfg(feature = "zkp")]
1308 #[test]
1309 fn test_verify_computation_rejects_empty_or_non_stark_data() {
1310 use crate::circuit::CircuitBuilder;
1311
1312 let verifier = ZkpVerifier::new();
1313 let circuit = CircuitBuilder::<ZkpField>::new(1, 0).build();
1314
1315 let empty = ZkpProof {
1316 data: vec![],
1317 proof_type: ProofType::Stark,
1318 security_level: 1,
1319 metadata: ProofMetadata::Circuit {
1320 num_witnesses: 1,
1321 num_public: 0,
1322 },
1323 };
1324 assert!(!verifier.verify_computation(&empty, &circuit, &[]).unwrap());
1325 }
1326}