baseid_bbs/
predicates.rs

1use baseid_core::claims::PredicateType;
2use serde_json::Value;
3
4/// Evaluate a predicate against a claim value.
5///
6/// Returns true if the predicate is satisfied.
7pub fn evaluate_predicate(value: &Value, predicate: &PredicateType) -> bool {
8    match predicate {
9        PredicateType::GreaterThan(threshold) => {
10            compare_values(value, threshold) == Some(std::cmp::Ordering::Greater)
11        }
12        PredicateType::GreaterThanOrEqual(threshold) => {
13            matches!(
14                compare_values(value, threshold),
15                Some(std::cmp::Ordering::Greater | std::cmp::Ordering::Equal)
16            )
17        }
18        PredicateType::LessThan(threshold) => {
19            compare_values(value, threshold) == Some(std::cmp::Ordering::Less)
20        }
21        PredicateType::LessThanOrEqual(threshold) => {
22            matches!(
23                compare_values(value, threshold),
24                Some(std::cmp::Ordering::Less | std::cmp::Ordering::Equal)
25            )
26        }
27        PredicateType::InSet(set) => set.contains(value),
28        PredicateType::NotInSet(set) => !set.contains(value),
29        PredicateType::NonRevoked => {
30            // Non-revocation requires external accumulator witness -- not checked here
31            true
32        }
33    }
34}
35
36fn compare_values(a: &Value, b: &Value) -> Option<std::cmp::Ordering> {
37    match (a, b) {
38        (Value::Number(a), Value::Number(b)) => {
39            let af = a.as_f64()?;
40            let bf = b.as_f64()?;
41            af.partial_cmp(&bf)
42        }
43        (Value::String(a), Value::String(b)) => Some(a.cmp(b)),
44        _ => None,
45    }
46}