use thiserror::Error;
pub const PROOF_VERSION: u32 = 2;
pub const MAX_PROOF_SIZE: usize = 10 * 1024 * 1024;
#[derive(Debug, Error)]
pub enum VerifierError {
#[error("Invalid proof structure: {0}")]
InvalidProofStructure(String),
#[error("Public input mismatch: {0}")]
PublicInputMismatch(String),
#[error("FRI verification failed: {0}")]
FriVerificationFailed(String),
#[error("Constraint check failed: {0}")]
ConstraintCheckFailed(String),
#[error("Deserialization error: {0}")]
DeserializationError(String),
#[error("Invalid policy hash: expected {expected}, got {actual}")]
InvalidPolicyHash { expected: String, actual: String },
#[error("Proof verification failed: {0}")]
VerificationFailed(String),
#[error(
"Policy mismatch: expected policy '{expected}', but proof was generated for '{actual}'"
)]
PolicyMismatch { expected: String, actual: String },
#[error("Limit mismatch: expected {expected}, but proof was generated for {actual}")]
LimitMismatch { expected: u64, actual: u64 },
#[error("Invalid hex format in field '{field}': {reason}")]
InvalidHexFormat { field: String, reason: String },
#[error("Unsupported proof version {version}: only version {supported} is supported")]
UnsupportedProofVersion { version: u32, supported: u32 },
#[error(
"Witness commitment mismatch: the proof's commitment doesn't match the expected commitment"
)]
WitnessCommitmentMismatch,
#[error("Payload amount binding required: {0}")]
PayloadAmountBindingRequired(String),
#[error("Proof too large: {size} bytes exceeds maximum of {max_size} bytes")]
ProofTooLarge { size: usize, max_size: usize },
}
impl VerifierError {
pub fn invalid_structure<S: Into<String>>(msg: S) -> Self {
Self::InvalidProofStructure(msg.into())
}
pub fn verification_failed<S: Into<String>>(msg: S) -> Self {
Self::VerificationFailed(msg.into())
}
pub fn policy_mismatch(expected: &str, actual: &str) -> Self {
Self::PolicyMismatch {
expected: expected.to_string(),
actual: actual.to_string(),
}
}
pub fn limit_mismatch(expected: u64, actual: u64) -> Self {
Self::LimitMismatch { expected, actual }
}
pub fn invalid_hex(field: &str, reason: &str) -> Self {
Self::InvalidHexFormat {
field: field.to_string(),
reason: reason.to_string(),
}
}
pub fn unsupported_version(version: u32) -> Self {
Self::UnsupportedProofVersion {
version,
supported: PROOF_VERSION,
}
}
}
pub fn validate_hex_string(
field: &str,
value: &str,
expected_len: usize,
) -> Result<(), VerifierError> {
if value.len() != expected_len {
return Err(VerifierError::invalid_hex(
field,
&format!("expected {} characters, got {}", expected_len, value.len()),
));
}
for (i, c) in value.chars().enumerate() {
if !c.is_ascii_hexdigit() {
return Err(VerifierError::invalid_hex(
field,
&format!("invalid character '{}' at position {}", c, i),
));
}
if c.is_ascii_uppercase() {
return Err(VerifierError::invalid_hex(
field,
&format!(
"uppercase character '{}' at position {} (must be lowercase)",
c, i
),
));
}
}
Ok(())
}