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(
434 &mut self,
435 secret_value: &[u8],
436 public_statement: &[u8],
437 ) -> Result<ZkpProof> {
438 let _ = (secret_value, public_statement);
444 Err(lib_q_core::Error::NotImplemented {
445 feature: "NIST (cSHAKE256) preimage proofs: Keccak-f AIR constraints not implemented"
446 .to_string(),
447 })
448 }
449
450 pub fn prove_computation(
491 &mut self,
492 circuit: &circuit::ArithmeticCircuit<ZkpField>,
493 witness: &[ZkpField],
494 public: &[ZkpField],
495 ) -> Result<ZkpProof> {
496 use crate::circuit::CircuitAir;
497 use crate::stark::{
498 StarkProver,
499 default_config,
500 };
501
502 let air = CircuitAir::new(circuit.clone());
504
505 let trace = air.generate_trace(witness, public)?;
507
508 let config = default_config();
510 let prover = StarkProver::new(config);
511
512 let proof =
514 prover
515 .prove(&air, trace, public)
516 .map_err(|e| lib_q_core::Error::InternalError {
517 operation: "STARK proof generation".to_string(),
518 details: e.to_string(),
519 })?;
520
521 let metadata = ProofMetadata::Circuit {
523 num_witnesses: witness.len().min(u32::MAX as usize) as u32,
524 num_public: public.len().min(u32::MAX as usize) as u32,
525 };
526
527 ZkpProof::from_stark_proof(&proof, metadata)
529 }
530}
531
532#[cfg(not(feature = "zkp"))]
533impl ZkpProver {
534 pub fn new() -> Self {
536 Self {}
537 }
538
539 pub fn prove_secret_value(
541 &mut self,
542 _secret_value: &[u8],
543 _public_statement: &[u8],
544 ) -> Result<ZkpProof> {
545 Err(lib_q_core::Error::NotImplemented {
546 feature: "ZKP feature not enabled".to_string(),
547 })
548 }
549
550 pub fn prove_secret_value_nist(
552 &mut self,
553 _secret_value: &[u8],
554 _public_statement: &[u8],
555 ) -> Result<ZkpProof> {
556 Err(lib_q_core::Error::NotImplemented {
557 feature: "ZKP feature not enabled".to_string(),
558 })
559 }
560}
561
562#[cfg(feature = "zkp")]
565fn verify_secret_value_nist_impl(proof: &ZkpProof, expected_hash: &[u8]) -> Result<bool> {
566 if proof.proof_type != ProofType::Stark {
567 return Ok(false);
568 }
569 if proof.data.is_empty() {
570 return Ok(false);
571 }
572
573 let ProofMetadata::HashPreimageNist { .. } = &proof.metadata else {
574 return Ok(false);
575 };
576
577 let _ = expected_hash;
582 Err(lib_q_core::Error::NotImplemented {
583 feature: "NIST (cSHAKE256) preimage proofs: Keccak-f AIR constraints not implemented"
584 .to_string(),
585 })
586}
587
588#[cfg(feature = "zkp")]
589impl ZkpVerifier {
590 pub fn new() -> Self {
592 Self {}
593 }
594
595 pub fn verify_secret_value(&self, proof: &ZkpProof, preimage: &[u8]) -> Result<bool> {
613 use crate::air::{
614 HashPreimageAir,
615 TraceGenerator,
616 };
617 use crate::stark::{
618 StarkVerifier,
619 default_config,
620 };
621
622 if proof.proof_type != ProofType::Stark {
623 return Ok(false);
624 }
625
626 if proof.data.is_empty() {
627 return Ok(false);
628 }
629
630 let ProofMetadata::HashPreimage { output_size } = &proof.metadata else {
632 return Ok(false);
634 };
635
636 let _ = output_size;
638 let air = HashPreimageAir::new();
639
640 let public_values: Vec<ZkpField> = air.public_values(&preimage.to_vec());
643
644 let stark_proof = proof.to_stark_proof()?;
646
647 let config = default_config();
649 let verifier = StarkVerifier::new(config);
650
651 match verifier.verify(&air, &stark_proof, &public_values) {
653 Ok(()) => Ok(true),
654 Err(_) => Ok(false),
655 }
656 }
657
658 pub fn verify_secret_value_nist(&self, proof: &ZkpProof, expected_hash: &[u8]) -> Result<bool> {
663 verify_secret_value_nist_impl(proof, expected_hash)
664 }
665
666 pub fn verify_computation(
680 &self,
681 proof: &ZkpProof,
682 circuit: &circuit::ArithmeticCircuit<ZkpField>,
683 public: &[ZkpField],
684 ) -> Result<bool> {
685 use crate::circuit::CircuitAir;
686 use crate::stark::{
687 StarkVerifier,
688 default_config,
689 };
690
691 if proof.proof_type != ProofType::Stark {
692 return Ok(false);
693 }
694
695 if proof.data.is_empty() {
696 return Ok(false);
697 }
698
699 let air = CircuitAir::new(circuit.clone());
701
702 let stark_proof = proof.to_stark_proof()?;
704
705 let config = default_config();
707 let verifier = StarkVerifier::new(config);
708
709 match verifier.verify(&air, &stark_proof, public) {
711 Ok(()) => Ok(true),
712 Err(_) => Ok(false),
713 }
714 }
715
716 pub fn verify(&self, proof: ZkpProof, public_statement: &[u8]) -> Result<bool> {
734 if proof.proof_type != ProofType::Stark {
735 return Ok(false);
736 }
737 if proof.data.is_empty() {
738 return Ok(false);
739 }
740 match &proof.metadata {
741 ProofMetadata::HashPreimage { .. } => {
742 self.verify_secret_value(&proof, public_statement)
743 }
744 ProofMetadata::HashPreimageNist { .. } => {
745 verify_secret_value_nist_impl(&proof, public_statement)
746 }
747 ProofMetadata::MerkleInclusion { .. } => verify_membership(&proof, public_statement),
748 _ => Ok(false),
749 }
750 }
751
752 pub fn batch_verify(&self, proofs: &[ZkpProof], publics: &[&[u8]]) -> Result<bool> {
763 if proofs.len() != publics.len() {
764 return Err(lib_q_core::Error::InvalidState {
765 operation: "batch_verify".to_string(),
766 reason: "Number of proofs must match number of public statements".to_string(),
767 });
768 }
769
770 for (proof, public) in proofs.iter().zip(publics.iter()) {
771 match self.verify(proof.clone(), public) {
772 Ok(true) => continue,
773 Ok(false) => return Ok(false),
774 Err(e) => return Err(e),
775 }
776 }
777
778 Ok(true)
779 }
780}
781
782#[cfg(not(feature = "zkp"))]
783impl ZkpVerifier {
784 pub fn new() -> Self {
786 Self {}
787 }
788
789 pub fn verify(&self, _proof: ZkpProof, _public_statement: &[u8]) -> Result<bool> {
791 Err(lib_q_core::Error::NotImplemented {
792 feature: "ZKP feature not enabled".to_string(),
793 })
794 }
795
796 pub fn verify_secret_value_nist(
798 &self,
799 _proof: &ZkpProof,
800 _expected_hash: &[u8],
801 ) -> Result<bool> {
802 Err(lib_q_core::Error::NotImplemented {
803 feature: "ZKP feature not enabled".to_string(),
804 })
805 }
806
807 pub fn batch_verify(&self, _proofs: &[ZkpProof], _publics: &[&[u8]]) -> Result<bool> {
809 Err(lib_q_core::Error::NotImplemented {
810 feature: "ZKP feature not enabled".to_string(),
811 })
812 }
813}
814
815impl Default for ZkpProver {
816 fn default() -> Self {
817 Self::new()
818 }
819}
820
821impl Default for ZkpVerifier {
822 fn default() -> Self {
823 Self::new()
824 }
825}
826
827pub fn available_algorithms() -> Vec<&'static str> {
829 let algorithms = vec![
830 #[cfg(feature = "zkp")]
831 "stark",
832 ];
833
834 algorithms
835}
836
837pub fn create_zkp(algorithm: &str) -> Result<Box<dyn core::any::Any>> {
839 match algorithm {
840 #[cfg(feature = "zkp")]
841 "stark" => Ok(Box::new(ZkpProver::new())),
842
843 _ => Err(lib_q_core::Error::InvalidAlgorithm {
844 algorithm: "Unknown ZKP algorithm",
845 }),
846 }
847}
848
849#[cfg(test)]
850mod tests {
851 use super::*;
852
853 #[test]
854 fn test_zkp_prover_creation() {
855 let _prover = ZkpProver::new();
856 }
858
859 #[test]
860 fn test_zkp_verifier_creation() {
861 let _verifier = ZkpVerifier::new();
862 }
864
865 #[test]
866 fn test_zkp_proof_creation() {
867 let mut prover = ZkpProver::new();
868 let secret_value = b"secret_value";
869 let public_statement = b"public_statement";
870
871 let result = prover.prove_secret_value(secret_value, public_statement);
873 assert!(
875 result.is_ok(),
876 "Proof generation should succeed: {:?}",
877 result.err()
878 );
879 }
880
881 #[cfg(feature = "zkp")]
882 #[test]
883 fn test_nist_secret_value_not_implemented() {
884 let secret = b"nist_secret_value";
887 let mut prover = ZkpProver::new();
888 assert!(
889 matches!(
890 prover.prove_secret_value_nist(secret, b""),
891 Err(lib_q_core::Error::NotImplemented { .. })
892 ),
893 "NIST prove must return NotImplemented"
894 );
895
896 let verifier = ZkpVerifier::new();
897 let mut dummy = ZkpProof {
898 data: alloc::vec![1u8; 8],
899 proof_type: ProofType::Stark,
900 security_level: 1,
901 metadata: ProofMetadata::HashPreimageNist { output_size: 32 },
902 };
903 assert!(
904 matches!(
905 verifier.verify_secret_value_nist(&dummy, &[0u8; 32]),
906 Err(lib_q_core::Error::NotImplemented { .. })
907 ),
908 "NIST verify must return NotImplemented"
909 );
910 dummy.data = alloc::vec![1u8; 8];
912 assert!(
913 matches!(
914 verifier.verify(dummy, &[0u8; 32]),
915 Err(lib_q_core::Error::NotImplemented { .. })
916 ),
917 "verify() must return NotImplemented for NIST proofs"
918 );
919 }
920
921 #[cfg(feature = "zkp")]
922 #[test]
923 fn test_poseidon_proof_rejected_by_nist_verifier() {
924 let secret = b"poseidon_only";
925 let mut prover = ZkpProver::new();
926 let proof = prover
927 .prove_secret_value(secret, b"")
928 .expect("Poseidon prove");
929 let verifier = ZkpVerifier::new();
930 assert!(
931 !verifier
932 .verify_secret_value_nist(&proof, &[0u8; 32])
933 .unwrap(),
934 "Poseidon proof must not be accepted by NIST verifier"
935 );
936 }
937
938 #[cfg(feature = "zkp")]
939 #[test]
940 fn test_verify_rejects_unknown_metadata() {
941 use lib_q_stark_field::PrimeCharacteristicRing;
942 use lib_q_stark_mersenne31::Mersenne31;
943
944 use crate::air::{
945 ArithmeticAir,
946 TraceGenerator,
947 };
948 use crate::stark::{
949 StarkProver,
950 default_config,
951 };
952
953 let air = ArithmeticAir::new(1).expect("ArithmeticAir");
954 let one = <ZkpField as PrimeCharacteristicRing>::ONE;
955 let seven = ZkpField::from(Mersenne31::new(7));
956 let input = alloc::vec![(one, seven)];
957 let trace = air.generate_trace(&input).expect("trace generation");
958 let public_values = air.public_values(&input);
959 let proof_inner = StarkProver::new(default_config())
960 .prove(&air, trace, &public_values)
961 .expect("prove");
962 let proof_bytes = postcard::to_allocvec(&proof_inner).expect("serialize STARK proof");
963
964 let proof = ZkpProof {
965 data: proof_bytes,
966 proof_type: ProofType::Stark,
967 security_level: 1,
968 metadata: ProofMetadata::None,
969 };
970
971 let verifier = ZkpVerifier::new();
972 assert_eq!(
973 verifier.verify(proof, b"public_statement").unwrap(),
974 false,
975 "ProofMetadata::None must return false -- use a type-specific verifier"
976 );
977 }
978
979 #[test]
980 fn test_batch_verify_mismatched_lengths() {
981 let verifier = ZkpVerifier::new();
982 let proofs = vec![ZkpProof {
983 data: vec![0u8; 64],
984 proof_type: ProofType::Stark,
985 security_level: 1,
986 metadata: ProofMetadata::None,
987 }];
988 let publics: &[&[u8]] = &[b"public1" as &[u8], b"public2" as &[u8]];
989
990 let result = verifier.batch_verify(&proofs, publics);
991 assert!(result.is_err());
992 if let Err(lib_q_core::Error::InvalidState { .. }) = result {
993 } else {
995 panic!("Expected InvalidState error");
996 }
997 }
998
999 #[cfg(feature = "zkp")]
1000 #[test]
1001 fn test_proof_metadata_merkle() {
1002 let metadata = ProofMetadata::MerkleInclusion { tree_depth: 8 };
1003 let proof = ZkpProof {
1004 data: vec![0u8; 64],
1005 proof_type: ProofType::Stark,
1006 security_level: 1,
1007 metadata,
1008 };
1009 assert_eq!(proof.merkle_tree_depth(), Some(8));
1010 }
1011
1012 #[cfg(feature = "zkp")]
1013 #[test]
1014 fn test_proof_metadata_none() {
1015 let proof = ZkpProof {
1016 data: vec![0u8; 64],
1017 proof_type: ProofType::Stark,
1018 security_level: 1,
1019 metadata: ProofMetadata::None,
1020 };
1021 assert_eq!(proof.merkle_tree_depth(), None);
1022 }
1023
1024 #[test]
1025 fn test_available_algorithms() {
1026 let algorithms = available_algorithms();
1027 #[cfg(feature = "zkp")]
1028 assert!(!algorithms.is_empty(), "zkp feature enables STARK");
1029 #[cfg(not(feature = "zkp"))]
1030 let _ = algorithms;
1031 }
1032
1033 #[cfg(feature = "zkp")]
1034 #[test]
1035 fn test_create_zkp() {
1036 let algorithms = available_algorithms();
1037 assert!(!algorithms.is_empty());
1038 let algorithm = algorithms[0];
1039 assert!(create_zkp(algorithm).is_ok());
1040 }
1041
1042 #[cfg(feature = "zkp")]
1043 #[test]
1044 fn test_verify_rejects_forged_proof_with_hash_preimage_metadata() {
1045 let proof = ZkpProof {
1046 data: alloc::vec![
1047 0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xAA, 0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xAA, 0xDE, 0xAD,
1048 0xBE, 0xEF, 0xFF, 0xAA, 0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xAA, 0xDE, 0xAD, 0xBE, 0xEF,
1049 0xFF, 0xAA, 0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xAA, 0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xAA,
1050 0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xAA, 0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xAA, 0xDE, 0xAD,
1051 0xBE, 0xEF, 0xFF, 0xAA, 0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xAA, 0xDE, 0xAD, 0xBE, 0xEF,
1052 ],
1053 proof_type: ProofType::Stark,
1054 security_level: 1,
1055 metadata: ProofMetadata::HashPreimage { output_size: 1 },
1056 };
1057 let verifier = ZkpVerifier::new();
1058 let result = verifier.verify(proof, b"expected_hash");
1059 assert!(
1060 matches!(result, Ok(false) | Err(_)),
1061 "forged HashPreimage proof must not return Ok(true)"
1062 );
1063 }
1064
1065 #[cfg(feature = "zkp")]
1066 #[test]
1067 fn test_verify_rejects_forged_proof_with_merkle_metadata() {
1068 let proof = ZkpProof {
1069 data: alloc::vec![
1070 0xCA, 0xFE, 0xBA, 0xBE, 0xCA, 0xFE, 0xBA, 0xBE, 0xCA, 0xFE, 0xBA, 0xBE, 0xCA, 0xFE,
1071 0xBA, 0xBE, 0xCA, 0xFE, 0xBA, 0xBE, 0xCA, 0xFE, 0xBA, 0xBE, 0xCA, 0xFE, 0xBA, 0xBE,
1072 0xCA, 0xFE, 0xBA, 0xBE, 0xCA, 0xFE, 0xBA, 0xBE, 0xCA, 0xFE, 0xBA, 0xBE, 0xCA, 0xFE,
1073 0xBA, 0xBE, 0xCA, 0xFE, 0xBA, 0xBE, 0xCA, 0xFE, 0xBA, 0xBE, 0xCA, 0xFE, 0xBA, 0xBE,
1074 0xCA, 0xFE, 0xBA, 0xBE, 0xCA, 0xFE, 0xBA, 0xBE, 0xCA, 0xFE, 0xBA, 0xBE,
1075 ],
1076 proof_type: ProofType::Stark,
1077 security_level: 1,
1078 metadata: ProofMetadata::MerkleInclusion { tree_depth: 4 },
1079 };
1080 let verifier = ZkpVerifier::new();
1081 let result = verifier.verify(proof, b"wrong_root");
1082 assert!(
1083 matches!(result, Ok(false) | Err(_)),
1084 "forged MerkleInclusion proof must not return Ok(true)"
1085 );
1086 }
1087
1088 #[cfg(feature = "zkp")]
1089 #[test]
1090 fn test_verify_rejects_circuit_metadata_proof() {
1091 let proof = ZkpProof {
1092 data: alloc::vec![0u8; 64],
1093 proof_type: ProofType::Stark,
1094 security_level: 1,
1095 metadata: ProofMetadata::Circuit {
1096 num_witnesses: 2,
1097 num_public: 1,
1098 },
1099 };
1100 let verifier = ZkpVerifier::new();
1101 assert_eq!(
1102 verifier.verify(proof, b"anything").unwrap(),
1103 false,
1104 "Circuit proofs must be rejected by generic verify; use verify_computation"
1105 );
1106 }
1107
1108 #[cfg(feature = "zkp")]
1109 #[test]
1110 fn test_verify_rejects_credential_metadata_proof() {
1111 let proof = ZkpProof {
1112 data: alloc::vec![0u8; 64],
1113 proof_type: ProofType::Stark,
1114 security_level: 1,
1115 metadata: ProofMetadata::Credential {
1116 attribute_sizes: alloc::vec![8, 4],
1117 reveal_mask: alloc::vec![true, false],
1118 },
1119 };
1120 let verifier = ZkpVerifier::new();
1121 assert_eq!(
1122 verifier.verify(proof, b"anything").unwrap(),
1123 false,
1124 "Credential proofs must be rejected by generic verify; use ip::verify_credential_proof"
1125 );
1126 }
1127
1128 #[cfg(feature = "zkp")]
1129 #[test]
1130 fn test_verify_rejects_identity_metadata_proof() {
1131 let proof = ZkpProof {
1132 data: alloc::vec![0u8; 64],
1133 proof_type: ProofType::Stark,
1134 security_level: 1,
1135 metadata: ProofMetadata::Identity { dsa_level: 65 },
1136 };
1137 let verifier = ZkpVerifier::new();
1138 assert_eq!(
1139 verifier.verify(proof, b"anything").unwrap(),
1140 false,
1141 "Identity proofs must be rejected by generic verify; use ip::verify_it_ownership"
1142 );
1143 }
1144
1145 #[cfg(feature = "zkp")]
1146 #[test]
1147 fn test_verify_empty_data_is_rejected() {
1148 let proof = ZkpProof {
1149 data: alloc::vec![],
1150 proof_type: ProofType::Stark,
1151 security_level: 1,
1152 metadata: ProofMetadata::HashPreimage { output_size: 1 },
1153 };
1154 let verifier = ZkpVerifier::new();
1155 assert_eq!(
1156 verifier.verify(proof, b"anything").unwrap(),
1157 false,
1158 "empty proof data must be rejected regardless of metadata"
1159 );
1160 }
1161
1162 #[cfg(feature = "zkp")]
1163 #[test]
1164 fn test_proof_type_only_stark_exists() {
1165 let _stark = ProofType::Stark;
1166 }
1169
1170 #[cfg(feature = "zkp")]
1171 #[test]
1172 fn test_batch_verify_rejects_forged_hash_preimage_proof() {
1173 let forged = ZkpProof {
1174 data: alloc::vec![0xFF; 64],
1175 proof_type: ProofType::Stark,
1176 security_level: 1,
1177 metadata: ProofMetadata::HashPreimage { output_size: 1 },
1178 };
1179 let verifier = ZkpVerifier::new();
1180 let proofs = alloc::vec![forged];
1181 let publics: &[&[u8]] = &[b"anything"];
1182 let result = verifier.batch_verify(&proofs, publics);
1183 assert!(
1184 matches!(result, Ok(false) | Err(_)),
1185 "batch_verify must not accept a forged proof"
1186 );
1187 }
1188
1189 #[cfg(feature = "zkp")]
1190 #[test]
1191 fn test_prove_secret_value_rejects_empty_and_oversized_input() {
1192 let mut prover = ZkpProver::new();
1193 let empty = prover.prove_secret_value(b"", b"");
1194 assert!(empty.is_err());
1195
1196 let oversized = vec![0u8; air::hash_preimage::MAX_PREIMAGE_SIZE + 1];
1197 let too_large = prover.prove_secret_value(&oversized, b"");
1198 assert!(too_large.is_err());
1199 }
1200
1201 #[cfg(feature = "zkp")]
1202 #[test]
1203 fn test_prove_secret_value_nist_rejects_empty_and_oversized_input() {
1204 let mut prover = ZkpProver::new();
1205 let empty = prover.prove_secret_value_nist(b"", b"");
1206 assert!(empty.is_err());
1207
1208 let oversized = vec![0u8; air::hash_preimage_nist::MAX_PREIMAGE_SIZE + 1];
1209 let too_large = prover.prove_secret_value_nist(&oversized, b"");
1210 assert!(too_large.is_err());
1211 }
1212
1213 #[cfg(feature = "zkp")]
1214 #[test]
1215 fn test_verify_secret_value_rejects_invalid_proof_shape_inputs() {
1216 let verifier = ZkpVerifier::new();
1217 let non_stark = ZkpProof {
1218 data: vec![1u8; 16],
1219 proof_type: ProofType::Stark,
1220 security_level: 1,
1221 metadata: ProofMetadata::HashPreimageNist { output_size: 32 },
1222 };
1223 assert!(!verifier.verify_secret_value(&non_stark, b"hash").unwrap());
1224
1225 let empty = ZkpProof {
1226 data: vec![],
1227 proof_type: ProofType::Stark,
1228 security_level: 1,
1229 metadata: ProofMetadata::HashPreimage { output_size: 1 },
1230 };
1231 assert!(!verifier.verify_secret_value(&empty, b"hash").unwrap());
1232 }
1233
1234 #[cfg(feature = "zkp")]
1235 #[test]
1236 fn test_verify_secret_value_nist_rejects_wrong_metadata_and_bad_bytes() {
1237 let verifier = ZkpVerifier::new();
1238 let wrong_meta = ZkpProof {
1239 data: vec![1u8; 16],
1240 proof_type: ProofType::Stark,
1241 security_level: 1,
1242 metadata: ProofMetadata::HashPreimage { output_size: 1 },
1243 };
1244 assert!(
1245 !verifier
1246 .verify_secret_value_nist(&wrong_meta, &[0u8; 32])
1247 .unwrap()
1248 );
1249
1250 let nist_meta = ZkpProof {
1253 data: vec![0xAA; 16],
1254 proof_type: ProofType::Stark,
1255 security_level: 1,
1256 metadata: ProofMetadata::HashPreimageNist { output_size: 32 },
1257 };
1258 assert!(matches!(
1259 verifier.verify_secret_value_nist(&nist_meta, &[0u8; 32]),
1260 Err(lib_q_core::Error::NotImplemented { .. })
1261 ));
1262 }
1263
1264 #[cfg(feature = "zkp")]
1265 #[test]
1266 fn test_verify_computation_rejects_empty_or_non_stark_data() {
1267 use crate::circuit::CircuitBuilder;
1268
1269 let verifier = ZkpVerifier::new();
1270 let circuit = CircuitBuilder::<ZkpField>::new(1, 0).build();
1271
1272 let empty = ZkpProof {
1273 data: vec![],
1274 proof_type: ProofType::Stark,
1275 security_level: 1,
1276 metadata: ProofMetadata::Circuit {
1277 num_witnesses: 1,
1278 num_public: 0,
1279 },
1280 };
1281 assert!(!verifier.verify_computation(&empty, &circuit, &[]).unwrap());
1282 }
1283}