#![allow(clippy::disallowed_methods)]
#![warn(missing_docs)]
pub mod bundle;
pub mod checkpoint;
pub mod entry;
pub mod error;
pub mod merkle;
pub mod note;
pub mod proof;
pub mod store;
pub mod tile;
pub mod types;
#[cfg(feature = "native")]
pub mod verify;
#[cfg(feature = "native")]
pub mod witness;
pub mod witness_policy;
pub use bundle::{
BundleVerificationReport, CheckpointStatus, DelegationChainLink, DelegationStatus,
InclusionStatus, NamespaceStatus, OfflineBundle, SignatureStatus, WitnessStatus,
};
pub use checkpoint::{Checkpoint, SignedCheckpoint, WitnessCosignature};
pub use entry::{AccessTier, Entry, EntryBody, EntryContent, EntryType};
pub use error::TransparencyError;
pub use merkle::{compute_root, hash_children, hash_leaf, verify_consistency, verify_inclusion};
pub use note::{
C2spSignature, NoteSignature, build_signature_line, compute_ecdsa_key_id, compute_key_id,
parse_signed_note, parse_signed_note_c2sp, serialize_signed_note,
};
pub use proof::{ConsistencyProof, InclusionProof};
pub use tile::{TILE_HEIGHT, TILE_WIDTH, leaf_tile, tile_count, tile_path};
pub use types::{LogOrigin, MerkleHash};
#[cfg(feature = "native")]
mod fs_store;
#[cfg(feature = "native")]
pub use fs_store::FsTileStore;
#[cfg(feature = "s3")]
pub mod s3_store;
#[cfg(feature = "s3")]
pub use s3_store::S3TileStore;
#[cfg(feature = "native")]
pub use store::TileStore;
#[cfg(feature = "native")]
pub use verify::{verify_bundle, verify_checkpoint_signature, verify_witness_cosignatures};
#[cfg(feature = "native")]
pub use witness::{
ALG_COSIGNATURE_V1, CosignRequest, CosignResponse, DEFAULT_WITNESS_TIMEOUT, WitnessClient,
WitnessResult, build_cosignature_line, collect_witness_cosignatures, compute_witness_key_id,
cosignature_signed_message, extract_cosignatures, parse_cosignature, serialize_cosignature,
};
use auths_verifier::CanonicalDid;
pub use auths_keri::witness::independence::{
EquivocationDetection, HonestyCeiling, IndependencePolicy, OperatorAttributes,
WitnessOperatorInfo,
};
pub use witness_policy::{
WitnessPolicy, WitnessPolicyEntry, WitnessPolicyError, ceiling_for_policy_load,
};
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct TrustRoot {
pub log_public_key: auths_verifier::Ed25519PublicKey,
pub log_origin: LogOrigin,
pub witnesses: Vec<TrustRootWitness>,
#[serde(default)]
pub signature_algorithm: auths_verifier::SignatureAlgorithm,
#[serde(default)]
pub ecdsa_log_public_key_der: Option<Vec<u8>>,
#[serde(default = "IndependencePolicy::unconstrained")]
pub independence_policy: IndependencePolicy,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct TrustRootWitness {
pub witness_did: CanonicalDid,
pub name: String,
pub public_key: auths_verifier::Ed25519PublicKey,
#[serde(default)]
pub operator_info: Option<WitnessOperatorInfo>,
}
impl TrustRootWitness {
pub fn operator_attributes(&self) -> Option<OperatorAttributes> {
self.operator_info
.as_ref()
.map(|info| info.to_attributes(hex::encode(self.public_key.as_bytes())))
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct TrustConfig {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub default_log: Option<String>,
pub logs: std::collections::HashMap<String, TrustRoot>,
}
impl TrustConfig {
pub fn get_log(&self, log_id: &str) -> Option<&TrustRoot> {
self.logs.get(log_id)
}
pub fn default_log(&self) -> Option<(&str, &TrustRoot)> {
let id = self.default_log.as_deref()?;
self.logs.get(id).map(|root| (id, root))
}
pub fn validate(&self) -> std::result::Result<(), TransparencyError> {
if let Some(ref id) = self.default_log
&& !self.logs.contains_key(id)
{
return Err(TransparencyError::InvalidNote(format!(
"default_log '{}' not found in logs. Available: {:?}",
id,
self.logs.keys().collect::<Vec<_>>()
)));
}
for (log_id, root) in &self.logs {
if matches!(
root.signature_algorithm,
auths_verifier::SignatureAlgorithm::EcdsaP256
) {
let has_key = root
.ecdsa_log_public_key_der
.as_ref()
.is_some_and(|b| !b.is_empty());
if !has_key {
return Err(TransparencyError::InvalidNote(format!(
"log '{}' declares signature_algorithm=EcdsaP256 but \
ecdsa_log_public_key_der is missing or empty — refuse to \
trust a bundle-carried ECDSA key",
log_id
)));
}
}
}
Ok(())
}
pub fn default_config() -> Self {
use base64::Engine;
use base64::engine::general_purpose::STANDARD;
use std::collections::HashMap;
const REKOR_PROD_PUBKEY_B64: &str = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE2G2Y+2tabdTV5BcGiBIx0a9fAFwrkBbmLSGtks4L3qX6yYY0zufBnhC8Ur/iy55GhWP/9A/bY2LhC30M9+RYtw==";
let rekor_ecdsa_pk_der = STANDARD.decode(REKOR_PROD_PUBKEY_B64).unwrap_or_default();
let rekor_root = TrustRoot {
log_public_key: auths_verifier::Ed25519PublicKey::from_bytes([0u8; 32]),
log_origin: LogOrigin::new_unchecked("rekor.sigstore.dev - 1193050959916656506"),
witnesses: vec![],
signature_algorithm: auths_verifier::SignatureAlgorithm::EcdsaP256,
ecdsa_log_public_key_der: Some(rekor_ecdsa_pk_der),
independence_policy: IndependencePolicy::unconstrained(),
};
let mut logs = HashMap::new();
logs.insert("sigstore-rekor".to_string(), rekor_root);
Self {
default_log: Some("sigstore-rekor".to_string()),
logs,
}
}
}