csv_adapter_core/
proof_verify.rs1use crate::error::{AdapterError, Result};
6use crate::proof::ProofBundle;
7use crate::signature::{verify_signatures, Signature, SignatureScheme};
8
9pub fn verify_proof(
23 bundle: &ProofBundle,
24 seal_registry: impl Fn(&[u8]) -> bool,
25 signature_scheme: SignatureScheme,
26) -> Result<()> {
27 bundle
29 .transition_dag
30 .validate_structure()
31 .map_err(|e| AdapterError::Generic(format!("Invalid DAG structure: {}", e)))?;
32
33 verify_bundle_signatures(bundle, signature_scheme)?;
35
36 if seal_registry(bundle.seal_ref.seal_id.as_ref()) {
38 return Err(AdapterError::SealReplay(format!(
39 "Seal {:?} has already been used",
40 bundle.seal_ref
41 )));
42 }
43
44 if bundle.inclusion_proof.proof_bytes.is_empty() {
46 return Err(AdapterError::InclusionProofFailed(
47 "Empty inclusion proof".to_string(),
48 ));
49 }
50
51 if bundle.finality_proof.confirmations == 0 {
53 return Err(AdapterError::FinalityNotReached(
54 "No confirmations yet".to_string(),
55 ));
56 }
57
58 Ok(())
59}
60
61fn verify_bundle_signatures(bundle: &ProofBundle, scheme: SignatureScheme) -> Result<()> {
68 if bundle.signatures.is_empty() {
70 return Err(AdapterError::SignatureVerificationFailed(
71 "No signatures in proof bundle".to_string(),
72 ));
73 }
74
75 let mut signatures = Vec::with_capacity(bundle.signatures.len());
84
85 for (i, sig_bytes) in bundle.signatures.iter().enumerate() {
86 if sig_bytes.len() < 4 {
88 return Err(AdapterError::SignatureVerificationFailed(format!(
89 "Signature {} too short for header",
90 i
91 )));
92 }
93
94 let pk_len =
96 u32::from_le_bytes([sig_bytes[0], sig_bytes[1], sig_bytes[2], sig_bytes[3]]) as usize;
97
98 if sig_bytes.len() < 4 + pk_len {
99 return Err(AdapterError::SignatureVerificationFailed(format!(
100 "Signature {} too short for public key",
101 i
102 )));
103 }
104
105 let public_key = sig_bytes[4..4 + pk_len].to_vec();
106 let signature = sig_bytes[4 + pk_len..].to_vec();
107
108 let message = bundle.transition_dag.root_commitment.as_bytes().to_vec();
110
111 signatures.push(Signature::new(signature, public_key, message));
112 }
113
114 verify_signatures(&signatures, scheme)
116}
117
118#[cfg(test)]
119mod tests {
120 use super::*;
121 use crate::dag::{DAGNode, DAGSegment};
122 use crate::hash::Hash;
123 use crate::proof::{FinalityProof, InclusionProof};
124 use crate::seal::{AnchorRef, SealRef};
125 use crate::signature::SignatureScheme;
126
127 fn make_secp256k1_signature_bytes(message: &[u8; 32]) -> Vec<u8> {
128 use secp256k1::{Message, Secp256k1, SecretKey};
129 let secp = Secp256k1::new();
130 let secret_key = SecretKey::new(&mut secp256k1::rand::thread_rng());
131 let public_key = secp256k1::PublicKey::from_secret_key(&secp, &secret_key);
132 let msg = Message::from_digest_slice(message).unwrap();
133 let signature = secp.sign_ecdsa(&msg, &secret_key);
134 let sig_bytes = signature.serialize_compact();
135 let pubkey_bytes = public_key.serialize();
136 let mut encoded = Vec::with_capacity(4 + pubkey_bytes.len() + sig_bytes.len());
138 encoded.extend_from_slice(&(pubkey_bytes.len() as u32).to_le_bytes());
139 encoded.extend_from_slice(&pubkey_bytes);
140 encoded.extend_from_slice(&sig_bytes);
141 encoded
142 }
143
144 fn make_ed25519_signature_bytes(message: &[u8]) -> Vec<u8> {
145 use ed25519_dalek::{Signer, SigningKey};
146 let signing_key = SigningKey::generate(&mut rand::rngs::OsRng);
147 let verifying_key = signing_key.verifying_key();
148 let signature = signing_key.sign(message);
149 let mut encoded = Vec::with_capacity(4 + 32 + 64);
151 encoded.extend_from_slice(&32u32.to_le_bytes());
152 encoded.extend_from_slice(&verifying_key.to_bytes());
153 encoded.extend_from_slice(&signature.to_bytes());
154 encoded
155 }
156
157 fn test_bundle_with_signatures() -> Result<ProofBundle> {
158 let message = [0u8; 32];
160 let signature = make_secp256k1_signature_bytes(&message);
161
162 let bundle = ProofBundle::new(
163 DAGSegment::new(
164 vec![DAGNode::new(
165 Hash::new([1u8; 32]),
166 vec![0x01, 0x02],
167 vec![signature.clone()],
168 vec![],
169 vec![],
170 )],
171 Hash::zero(),
172 ),
173 vec![signature],
174 SealRef::new(vec![1, 2, 3], Some(42))
175 .map_err(|e| AdapterError::Generic(e.to_string()))?,
176 AnchorRef::new(vec![4, 5, 6], 100, vec![])
177 .map_err(|e| AdapterError::Generic(e.to_string()))?,
178 InclusionProof::new(vec![0xCD; 32], Hash::new([2u8; 32]), 0)
179 .map_err(|e| AdapterError::Generic(e.to_string()))?,
180 FinalityProof::new(vec![], 6, false)
181 .map_err(|e| AdapterError::Generic(e.to_string()))?,
182 )
183 .map_err(|e| AdapterError::Generic(e.to_string()))?;
184 Ok(bundle)
185 }
186
187 #[test]
188 fn test_verify_proof_valid() {
189 let bundle = test_bundle_with_signatures().unwrap();
190 let seal_registry = |_seal_id: &[u8]| false;
191 assert!(verify_proof(&bundle, seal_registry, SignatureScheme::Secp256k1).is_ok());
192 }
193
194 #[test]
195 fn test_verify_proof_seal_replay() {
196 let bundle = test_bundle_with_signatures().unwrap();
197 let seal_registry = |seal_id: &[u8]| seal_id == [1, 2, 3];
198 assert!(verify_proof(&bundle, seal_registry, SignatureScheme::Secp256k1).is_err());
199 }
200
201 #[test]
202 fn test_verify_proof_no_signatures() {
203 let mut bundle = test_bundle_with_signatures().unwrap();
204 bundle.signatures.clear();
205 let seal_registry = |_seal_id: &[u8]| false;
206 assert!(verify_proof(&bundle, seal_registry, SignatureScheme::Secp256k1).is_err());
207 }
208
209 #[test]
210 fn test_verify_proof_no_confirmations() {
211 let mut bundle = test_bundle_with_signatures().unwrap();
212 bundle.finality_proof.confirmations = 0;
213 let seal_registry = |_seal_id: &[u8]| false;
214 assert!(verify_proof(&bundle, seal_registry, SignatureScheme::Secp256k1).is_err());
215 }
216
217 #[test]
218 fn test_verify_proof_invalid_signature_format() {
219 let mut bundle = test_bundle_with_signatures().unwrap();
220 bundle.signatures[0] = vec![0x00, 0x00]; let seal_registry = |_seal_id: &[u8]| false;
223 assert!(verify_proof(&bundle, seal_registry, SignatureScheme::Secp256k1).is_err());
224 }
225
226 #[test]
227 fn test_verify_proof_ed25519_valid_format() {
228 let message = [0u8; 32];
230 let signature = make_ed25519_signature_bytes(&message);
231
232 let mut bundle = test_bundle_with_signatures().unwrap();
233 bundle.signatures = vec![signature];
234
235 let seal_registry = |_seal_id: &[u8]| false;
236 assert!(verify_proof(&bundle, seal_registry, SignatureScheme::Ed25519).is_ok());
237 }
238}