identity-kit 0.3.0

DID, key management and verifiable credential primitives
Documentation
[package]
name = "identity-kit"
version = "0.3.0"
edition = "2024"
rust-version = "1.95"
description = "DID, key management and verifiable credential primitives"
license = "Apache-2.0"
repository = "https://github.com/impierce/identity-kit"
keywords = ["did", "ssi", "digital-credentials", "vc"]
categories = ["cryptography", "authentication"]
include = ["/src", "/tests/vectors", "/CHANGELOG.md", "/README.md", "/LICENSE"]

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]

[features]
default = ["secp256k1", "software", "did-key", "did-jwk", "did-web", "reqwest", "vc", "status-list", "sd-jwt", "domain-linkage", "linked-vp"]
# ES256K signatures and `secp256k1` keys, via `k256`.
secp256k1 = ["dep:k256"]
# RS256 and PS256 signatures, via `rsa`; keys of at least 2048 bits (RFC 7518 §3.3, §3.5).
rsa = ["dep:rsa"]
# `InMemoryKeyStore`: a key store for tests and development, with an optional deterministic seed.
in-memory = ["dep:getrandom"]
# `SoftwareKeyStore`: a key store over a private JWK set file.
software = ["dep:getrandom"]
# `Pkcs11KeyStore`: a key store over a PKCS#11 module (an HSM, SoftHSM2), via `cryptoki`; the
# blocking module calls run on `tokio`'s blocking pool.
pkcs11 = ["dep:cryptoki", "dep:tokio", "tokio/rt"]
# `keys::testsuite`, the behavioural suite every key store must pass, and `vectors`, the
# specification vectors the tests run against.
test-vectors = []
# The `did:key` method (`methods::key`).
did-key = []
# The `did:jwk` method (`methods::jwk`).
did-jwk = []
# The `did:web` method (`methods::web`) over an injected `HttpClient`.
did-web = []
# `resolver::JwksResolver`: the keys of an HTTPS issuer from its JWT VC issuer metadata, over
# `did:web`'s `HttpClient`.
jwks = ["did-web"]
# The hardened default `HttpClient` for `did:web`, via `reqwest` with `rustls` and `ring`.
reqwest = ["did-web", "dep:reqwest", "dep:rustls", "dep:tokio"]
# Development and tests only: `ReqwestClient::builder` with opt-ins that let the client reach
# loopback and private addresses over plain `http`. Never in `default`; enable it under
# `[dev-dependencies]` so a release build does not contain it.
local-network = ["reqwest"]
# Verifiable credentials and presentations as JWTs (`vc`), via `chrono` for timestamps.
vc = ["dep:chrono"]
# The IETF Token Status List (`status_list`) for JWT and SD-JWT credentials alike: `miniz_oxide`
# for the compressed list.
status-list = ["vc", "dep:miniz_oxide"]
# SD-JWT (RFC 9901) and SD-JWT VC (`sd_jwt_vc`), with the Token Status List: `getrandom` for salts.
sd-jwt = ["vc", "status-list", "dep:getrandom"]
# DIF Well Known DID Configuration (`domain_linkage`), over the `vc` module and `did:web`'s `HttpClient`.
domain-linkage = ["vc", "did-web"]
# DIF Linked Verifiable Presentation (`linked_vp`), over the `vc` module and `did:web`'s `HttpClient`.
linked-vp = ["vc", "did-web"]
# OpenAPI schemas (`utoipa::ToSchema`) for the public JSON types.
utoipa = ["dep:utoipa"]

[dependencies]
async-trait = "0.1"
base64 = { version = "0.23", default-features = false, features = ["std"] }
bs58 = "0.5"
chrono = { version = "0.4", default-features = false, features = ["now", "serde", "std"], optional = true }
cryptoki = { version = "0.12", optional = true }
ed25519-dalek = { version = "3.0", features = ["pkcs8"] }
getrandom = { version = "0.4", features = ["std"], optional = true }
indexmap = { version = "2.0", features = ["serde"] }
jsonwebtoken = { version = "11.1", default-features = false }
k256 = { version = "0.14", default-features = false, features = ["ecdsa", "pkcs8", "std"], optional = true }
miniz_oxide = { version = "0.9", optional = true }
p256 = { version = "0.14", default-features = false, features = ["ecdsa", "pkcs8", "std"] }
reqwest = { version = "0.13", default-features = false, features = ["rustls-no-provider", "http2", "gzip"], optional = true }
rsa = { version = "0.10.0-rc.19", default-features = false, features = ["encoding", "sha2", "std"], optional = true }
rustls = { version = "0.23", default-features = false, features = ["ring", "std", "tls12"], optional = true }
serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0", features = ["float_roundtrip", "preserve_order"] }
sha2 = "0.11"
thiserror = "2.0"
tokio = { version = "1.0", features = ["net"], optional = true }
url = "2.5"
utoipa = { version = "6.0", optional = true }
zeroize = { version = "1.8", features = ["derive"] }

[dev-dependencies]
boon = "0.6"
flate2 = "1.0"
jsonwebtoken = { version = "11.1", default-features = false, features = ["rust_crypto"] }
proptest = "1.0"
tempfile = "3.0"
tokio = { version = "1.0", features = ["io-util", "macros", "net", "rt", "rt-multi-thread", "sync"] }
wiremock = "0.6"

[workspace]
members = ["xtask"]
exclude = ["fuzz"]

[lints.rust]
unsafe_code = "forbid"
missing_docs = "warn"
missing_debug_implementations = "warn"
unreachable_pub = "warn"

[lints.clippy]
pedantic = { level = "warn", priority = -1 }
# A style choice: `#[must_use]` on every pure function would be noise.
must_use_candidate = "allow"
# A style choice: `assert!(v.is_empty())` reads better than `assert_eq!(v, [] as [T; 0])`.
assert_is_empty = "allow"
dbg_macro = "warn"
todo = "warn"
print_stdout = "warn"
print_stderr = "warn"

# For cargo-mutants (`.cargo/mutants.toml`): test builds without debug info, which keeps the
# rebuild per mutant short.
[profile.mutants]
inherits = "test"
debug = "none"