#![forbid(unsafe_code)]
use std::collections::HashMap;
use std::sync::Arc;
use async_trait::async_trait;
mod cache;
mod near;
mod transport;
mod types;
pub use cache::AttestationCache;
pub use near::binding::{compose_matches_mr_config, report_data_binds};
pub use near::dcap::{AciDcapVerifierPolicy, ModelIdentity, PolicyError, model_identity};
pub use near::eventlog::{event_log_binds_info, replay_rtmr};
pub use near::nvidia::{
NRAS_GPU_URL, NVIDIA_NRAS_JWKS_URL, NrasVerdict, NvidiaEatKey, check_nras_eat, post_nras,
};
pub use near::report::{
AttestationInfo, AttestationReport, DstackEvent, ModelAttestation, TcbInfo,
};
pub use near::signature::{ChatSignature, chat_signing_text, recover_eip191_address, sha256_hex};
pub use near::tdx::{
DcapQuoteVerifier, PHALA_PCCS_URL, QuoteVerifier, TdxMeasurements, parse_tdx_quote,
verify_tdx_quote,
};
pub use near::{DEFAULT_CACHE_TTL_SECONDS, NearVerifier, TRUST_BOUNDARY};
pub use transport::{MockTransport, ReportTransport, ReqwestTransport, SIGNING_ALGO};
pub use types::{
AttestationChecks, AttestationVerdict, ExchangeInput, IntegrityProof, VerifiedExchange,
VerifyError,
};
#[async_trait]
pub trait ConfidentialVerifier: Send + Sync {
fn provider(&self) -> &str;
async fn verify_attestation(
&self,
model: &str,
nonce: &str,
now_unix: u64,
) -> Result<AttestationVerdict, VerifyError>;
async fn verify_exchange(
&self,
ex: &ExchangeInput<'_>,
) -> Result<VerifiedExchange, VerifyError>;
async fn attestation_cached(
&self,
model: &str,
now_unix: u64,
) -> Result<AttestationVerdict, VerifyError> {
self.verify_attestation(model, &fresh_nonce_hex(), now_unix)
.await
}
}
pub(crate) fn fresh_nonce_hex() -> String {
use rand::RngCore;
let mut nonce = [0u8; 32];
rand::rng().fill_bytes(&mut nonce);
hex::encode(nonce)
}
#[derive(Default, Clone)]
pub struct VerifierRegistry {
map: HashMap<String, Arc<dyn ConfidentialVerifier>>,
}
impl VerifierRegistry {
pub fn new() -> Self {
Self::default()
}
pub fn with(mut self, verifier: Arc<dyn ConfidentialVerifier>) -> Self {
self.map.insert(verifier.provider().to_string(), verifier);
self
}
pub fn get(&self, provider: &str) -> Result<&Arc<dyn ConfidentialVerifier>, VerifyError> {
self.map
.get(provider)
.ok_or_else(|| VerifyError::UnknownProvider(provider.to_string()))
}
pub fn handles(&self, provider: &str) -> bool {
self.map.contains_key(provider)
}
}
#[cfg(test)]
mod tests {
use super::*;
struct StubVerifier;
#[async_trait]
impl ConfidentialVerifier for StubVerifier {
fn provider(&self) -> &str {
"near-ai"
}
async fn verify_attestation(
&self,
model: &str,
nonce: &str,
now_unix: u64,
) -> Result<AttestationVerdict, VerifyError> {
Ok(AttestationVerdict::unverified(model, nonce, now_unix))
}
async fn verify_exchange(
&self,
_ex: &ExchangeInput<'_>,
) -> Result<VerifiedExchange, VerifyError> {
Err(VerifyError::Malformed {
what: "exchange",
detail: "not implemented in P1".to_string(),
})
}
}
#[test]
fn registry_dispatches_by_provider_and_fails_closed_on_unknown() {
let reg = VerifierRegistry::new().with(Arc::new(StubVerifier));
assert!(reg.handles("near-ai"));
assert!(reg.get("near-ai").is_ok());
assert!(!reg.handles("tinfoil"));
match reg.get("tinfoil").err() {
Some(VerifyError::UnknownProvider(p)) => assert_eq!(p, "tinfoil"),
_ => panic!("expected UnknownProvider for an unregistered provider"),
}
}
#[test]
fn unverified_verdict_is_fail_closed() {
let model = "zai-org/GLM-5.1-FP8";
let v = AttestationVerdict::unverified(model, format!("test-nonce-{model}"), 42);
assert!(!v.verified);
assert!(!v.checks.all_pass());
assert!(v.attested_addresses.is_empty());
}
}