Dependency Policy
This file defines how dependencies are introduced into Yggdrasil.
Approved Now
blake2: pure Rust hashing for Blake2b-based primitives.clap: pure Rust CLI argument parser with derive macros; needed for the node binary’s command-line interface. Rejected alternative was manualstd::env::argsparsing which provides no help text, completion, or structured subcommands. No native build requirements.curve25519-dalek: curve operations used in the crypto foundation.curve25519-elligator2: pure Rust legacy elligator2 mapping support needed to mirrorcardano-crypto-praosbatch-compatible VRF hash-to-curve behavior; rejected alternatives were FFI bindings to libsodium/cardano C code and ad-hoc local finite-field reimplementations, and this crate introduces no hidden native build requirements.ed25519-dalek: pure Rust Ed25519 signing and verification built on RustCrypto and dalek primitives.k256: pure Rust secp256k1 elliptic curve implementation from RustCrypto; provides ECDSA (PrehashVerifier) and Schnorr (BIP-340) signature verification required by PlutusV2 builtins (VerifyEcdsaSecp256k1Signature,VerifySchnorrSecp256k1Signature). Rejected alternatives weresecp256k1crate (wraps C libsecp256k1 — forbidden FFI) andp256/local reimplementation. Features enabled:ecdsa,schnorr,std. No native build requirements.num-bigint,num-integer,num-traits: pure Rust arbitrary-precision integer arithmetic from thenumcrate family; required by the consensus crate for deterministic Praos leader-value check (check_leader_value) and by the ledger/Plutus crates for upstream-compatibleIntegerhandling in Plutus constants,PlutusData, CBOR bignums, and integer builtins. The upstream Haskell node usesNaturalandRationalfor the VRF output comparison and unboundedIntegerfor Plutus arithmetic; these crates provide the equivalent Rust primitives. Rejected alternatives were ad-hoc inline 512-bit integer implementations (error-prone and difficult to audit), fixed-widthi128/u256limits (valid on-chain Plutus scripts can exceed them), and f64 floating-point arithmetic (non-deterministic across platforms). No native build requirements.bls12_381: pure Rust BLS12-381 pairing-friendly elliptic curve implementation from zkcrypto; required by CIP-0381 PlutusV3 BLS builtins (17 primitives: G1/G2 arithmetic, compress/uncompress, hash-to-curve, Miller loop, and final verify). Rejected alternatives wereblstcrate (wraps C code — forbidden FFI) andark-bls12-381(large dependency tree with optional assembly backends). Features enabled:experimental(required forHashToCurvetrait). Depends ondigest 0.9which requires a companionsha2 0.9for hash-to-curve operations (seesha2_09below). No native build requirements.sha2_09(renamedsha2 = "0.9"): providesdigest 0.9-compatible SHA-256 required bybls12_381 0.8’sExpandMsgXmdhash-to-curve expander. The workspace’s primarysha2 0.10usesdigest 0.10, which is a different major version with incompatible trait signatures. This renamed dependency is scoped to the crypto crate’s BLS12-381 module only. No native build requirements.ripemd: pure Rust RIPEMD-160 hash from RustCrypto; required by PlutusV3 builtinRipemd_160. No alternative exists in the pure Rust ecosystem. No native build requirements.sha2: pure Rust SHA-512 required for Praos-compatible VRF proof-to-output hashing; rejected alternatives were hidden FFI wrappers and reimplementing SHA-512 locally, and it introduces no native build requirements.sha3: pure Rust SHA3-256 and Keccak-256 hashes from RustCrypto; required by PlutusV2 builtinSha3_256and PlutusV3 builtinKeccak_256. No alternative exists in the pure Rust ecosystem. No native build requirements.serde: structured data interchange where handwritten or generated types require it.serde_json: JSON serialization/deserialization for node configuration files; natural companion toserdewith no additional native requirements. Matches the Cardano node’s JSON-based configuration format.serde_yaml: pure Rust YAML serialization/deserialization used by the node CLI config loader as a fallback alongside JSON (load_effective_config), matching operator workflows that use YAML-formatted config files. Rejected alternatives were (1) hard-failing on non-JSON config files despite upstream ecosystem YAML usage and (2) introducing a custom ad-hoc YAML parser. No native build requirements.serde_cbor: pure Rust CBOR serialization/deserialization for file-backed storage block payloads (FileImmutable/FileVolatile) to move persisted block blobs from JSON to deterministic binary encoding while retaining legacy JSON read compatibility during migration. Rejected alternatives were (1) adding ad-hoc block CBOR codec duplication inside storage before ledger-levelBlockCBOR traits exist, and (2) keeping JSON block persistence, which is larger/slower and less parity-aligned with upstream binary storage expectations. No native build requirements.thiserror: library error types.eyre: binary error reporting.subtle: constant-time comparisons for secret material.tokio: async runtime for networking and orchestration work.zeroize: deterministic zeroing of secret material on drop; already a transitive dependency viacurve25519-dalekanded25519-dalek, so adding it directly introduces no new supply chain surface.bech32(R330, added for the R326-R459 sister-tools port arc): pure Rust BIP-0173 / Bech32m encoding fromrust-bitcoin/rust-bech32v0.11.0. MIT-licensed (allowed bydeny.toml), zero transitive dependencies (onlystdfeature on its own implementation). Foundation forcrates/tools/bech32/(R447 relocated) which replicates the upstreamIntersectMBO/bech32binary’s CLI surface byte-for-byte; consumed across R331-R334 (Phase A.1 of the sister-tools port arc). Rejected alternatives were (1) reimplementing Bech32m locally — error-prone for a checksum format with subtle BIP-0173/Bech32m polynomial differences, and (2) FFI to the Haskellbech32package (forbidden per the no-FFI policy). No native build requirements.
Sister-tools port arc — deferred candidates (R340+, R367+)
The R326-R459 sister-tools port arc will eventually need an HTTP server crate for cardano-submit-api (the /api/submit/tx endpoint) and a log-rotation crate for cardano-tracer. Per the R330 dependency-audit policy, those are NOT pre-added to [workspace.dependencies] — they’ll land at the round that actually consumes them, with the transitive-dep audit done in context.
- HTTP server for cardano-submit-api (R338-R345 land): chose raw
tokio::net::TcpListenermatchingnode/src/metrics_server.rs— single endpoint, no TLS, no content negotiation. Zero new deps. Closed at R345. - HTTP server for cardano-tracer (R406 audit; R408+ land): chose
axum0.7 (different decision from cardano-submit-api). Driven by the 4-server complexity + per-server TLS termination + content negotiation. Seedocs/operational-runs/2026-05-10-round-398-dep-audit-tracerenv-decision.mdD2 audit for the side-by-side justification. - Log rotation for cardano-tracer (deferred — R394 shipped pure-Rust rotation policy helpers without any external rotation crate):
tracing-appendernot needed; rotation policy is a thintokio::time::intervalover the existingcrates/tools/cardano-tracer/src/handlers/logs/rotator.rspure helpers (R447 relocated) when the IO orchestration round lands. - Optional fuzz-distribution (deferred to R434 —
tx-generatorTx fuzz): candidate isrand(already a transitive dep viaed25519-dalek/curve25519-dalek, so promoting to a direct workspace dep would not add transitive surface).
Each deferred candidate will be added to [workspace.dependencies] only when its consumer round lands, with the cargo deny check + cargo audit checks run against the actual transitive tree rather than against speculative additions.
Sister-tools port arc — R398 audit (cardano-tracer R398-R410 sub-arc)
Three new dependencies approved at R398 for landing during the
R398-R410 cardano-tracer subsystem build-out. Each has a full
audit-evidence + rejected-alternatives section in
docs/operational-runs/2026-05-10-round-398-dep-audit-tracerenv-decision.md;
the summary entries below cite the canonical recommended feature
sets.
lettre0.11 (LANDED at R403): pure-Rust SMTP client forcardano-tracer/src/handlers/notifications/email::create_and_send_email(closed the R388SmtpSendStatuscarve-out). Final pin:default-features = false, features = ["smtp-transport", "tokio1-rustls", "ring", "webpki-roots", "builder"]. The recommended R398 audit-document feature list was extended at R403 land time withring(rustls crypto provider) +webpki-roots(Mozilla CA bundle) — both required by lettre’stokio1-rustlsdependency at compile time. License: MIT/Apache-2.0 dual. Verified at R403 viacargo tree -p yggdrasil-cardano-tracer | grep -iE "openssl|native-tls"— zero hits, transitive tree clean of all three banned crates perdeny.toml:88-91. Rejected alternatives: hand-rolled SMTP client (massive RFC 5321 + STARTTLS + SASL scope, security risk); skip SMTP entirely (cardano-tracer never matches upstream’s email-notification surface).axum0.8 +tower0.5 +rustls-pemfile2 (LANDED at R408): HTTP server stack forcardano-tracer/src/handlers/metrics/{prometheus, monitoring, timeseries_server, servers}— 4 separate HTTP servers per upstream’s design + per-server TLS termination viatlsSettingsChain+Accept-header content negotiation. Final pin:axum = { version = "0.8", default-features = false, features = ["http1", "tokio", "json"] };tower = { version = "0.5", default-features = false, features = ["util"] };rustls-pemfile = "2". License: all MIT. The R398 audit document recommended axum 0.7; at R408 land time the workspace landed axum 0.8 (the latest stable release; same default-features-off- http1+tokio+json feature pin).
hyperis a transitive dependency of axum 0.8 (no direct workspace entry needed). Verified at R408 viacargo tree -p yggdrasil-cardano-tracer | grep -iE "openssl|native-tls"— zero hits, transitive tree clean of all three banned crates perdeny.toml:88-91. Rejected alternatives: raw-tokio matchingcardano-submit-api/src/rest/web.rs(rejected because cardano-tracer’s per-server TLS + 4-route dispatch + content negotiation makes hand-rolling rustls integration four times structurally wrong; the cardano-submit-api precedent does not carry over).
- http1+tokio+json feature pin).
- (R398 audit version, kept as historical record):
axum0.7 land)**: HTTP server stack forcardano-tracer/src/handlers/metrics/{prometheus, monitoring, timeseries_server, servers}— 4 separate HTTP servers per upstream’s design + per-server TLS termination viatlsSettingsChain+Accept-header content negotiation. Pinaxum = { version = "0.7", default-features = false, features = ["http1", "tokio", "json"] };hyper = { version = "1", features = ["http1", "server"] };tower = { version = "0.5", features = ["util"] };rustls-pemfile = "2". License: all MIT. Combined transitive surface ~10 unique TLS-stack crates after rustls deduplication with lettre’stokio1-rustls. Rejected alternatives: raw-tokio matchingcardano-submit-api/src/rest/web.rs(rejected because cardano-tracer’s per-server TLS + 4-route dispatch + content negotiation makes hand-rolling rustls integration four times structurally wrong; the cardano-submit-api precedent does not carry over). maud0.27 (R406 land alongside axum): compile-time HTML templating forRouteDictionary::render_html(closes the R391RenderHtmlStatuscarve-out — replaces upstream’sText.Blaze.HtmlrenderListOfConnectedNodes). License: MIT. Zero transitive deps (proc-macro only). Rejected alternative: hand-rolled inline renderer (viable since the HTML page is small, ≤ 100 LOC, but maud’s compile-time template syntax catches typos- auto-escapes user content + zero runtime cost). Fallback if maud audit fails at R406: hand-rolled inline renderer kept as a documented carve-out option.
Sister-tools port arc — R468 audit (cardano-tracer TLS)
Two new dependencies approved at R468 to close the long-deferred
tls_bind_plan_status + tls_termination_status descriptors in
crates/tools/cardano-tracer/src/handlers/.
-
axum-server0.7 (LANDED at R468): TLS-terminated HTTP server for cardano-tracer Prometheus + Monitoring endpoints when the operator config hasforce_ssl: true. Final pin:default-features = false, features = ["tls-rustls"]. Pulls rustls + tokio-rustls + rustls-pki-types + rustls-webpki. Audited againstdeny.toml:90no-openssl ban viacargo tree -p yggdrasil-cardano-tracer: noopenssl,openssl-sys,native-tls. License: MIT/Apache-2.0 (dual-licensed). Pure Rust transitive tree. -
rustls0.23 (LANDED at R468): required directly socardano-tracer’sserve_router_with_tlscan callrustls::crypto::ring::default_provider().install_default()(rustls 0.23 requires the application to explicitly choose a crypto provider beforeServerConfig::builderruns). Final pin:default-features = false, features = ["ring", "std", "tls12"]. Pickedringoveraws-lc-rsbecause the latter pullsaws-lc-sysC bindings (against Yggdrasil’s no-FFI policy spirit).ringis license-clarified indeny.toml(MIT AND ISC AND OpenSSL). Pure Rust transitive tree (uses assembly internally for crypto primitives, no external C libraries linked).
Review Required
- Any new cryptography crate.
- Any dependency that enables native code, assembly, or bundled C libraries.
- Any storage dependency that constrains on-disk format or migration strategy.
- Any new CBOR encoding/decoding library or framework used by
crates/ledger.
Forbidden
- Haskell runtime bindings.
- C-backed cryptography wrappers.
- Dependencies that hide FFI behind default features.
Process
When adding a new dependency, record why it is needed, what alternatives were rejected, and whether the crate brings in any native toolchain requirements.