Skip to main content

dpp_crypto/jws/
algorithm.rs

1//! JOSE algorithm constants and allowlist for DPP signatures.
2
3/// JOSE algorithm identifier for Ed25519/EdDSA (RFC 8037 §2).
4pub const EDDSA_ALG: &str = "EdDSA";
5
6/// JWK curve name for Ed25519 (RFC 8037 §2).
7pub const ED25519_CRV: &str = "Ed25519";
8
9/// The single allowed signing algorithm for all DPP credentials and passport proofs.
10///
11/// Pinned at compile time so a future algorithm addition requires a deliberate
12/// change here plus a corresponding bump of the `algorithm` field in `KeyRecord`.
13/// Rejects `alg:none` and all substitution attacks by exhaustive allowlist.
14#[inline]
15pub fn is_allowed_alg(alg: &str) -> bool {
16    alg == EDDSA_ALG
17}
18
19/// The signature algorithm a key pair uses.
20///
21/// There is exactly one variant, and [`is_allowed_alg`] still admits only it.
22/// The type exists so that the algorithm travels *with* the key rather than
23/// being assumed by every reader of it: a verifier can then bind the JWS `alg`
24/// header to what the key record says, instead of letting an attacker-supplied
25/// header select the verification path.
26///
27/// `#[non_exhaustive]` so that adding a second algorithm later is not a
28/// breaking change for downstream matches.
29#[non_exhaustive]
30#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
31pub enum KeyAlgorithm {
32    /// Ed25519 signatures, JOSE `EdDSA` (RFC 8037 §3.1).
33    #[serde(rename = "EdDSA")]
34    Ed25519,
35}
36
37impl KeyAlgorithm {
38    /// The JOSE `alg` header value.
39    #[inline]
40    pub fn jose_alg(self) -> &'static str {
41        match self {
42            Self::Ed25519 => EDDSA_ALG,
43        }
44    }
45
46    /// Parse a JOSE `alg` header value. `None` for anything not allowed here,
47    /// which includes `none`.
48    #[inline]
49    pub fn from_jose_alg(alg: &str) -> Option<Self> {
50        match alg {
51            EDDSA_ALG => Some(Self::Ed25519),
52            _ => None,
53        }
54    }
55
56    /// The JWK members describing `public_key`, for a DID document's
57    /// `publicKeyJwk`.
58    ///
59    /// Lives here rather than in the DID-document builder so the per-algorithm
60    /// match stays exhaustive in the crate that defines the algorithm. A second
61    /// algorithm needs a `kty`/parameter set that only this crate should have
62    /// to know — P-256, for instance, is `kty: "EC"` with both `x` and `y`,
63    /// where Ed25519 is `kty: "OKP"` with `x` alone.
64    pub fn public_key_jwk(self, public_key: &[u8]) -> serde_json::Value {
65        use base64::Engine;
66        let b64 = base64::engine::general_purpose::URL_SAFE_NO_PAD;
67        match self {
68            Self::Ed25519 => serde_json::json!({
69                "kty": "OKP",
70                "crv": ED25519_CRV,
71                "x": b64.encode(public_key),
72            }),
73        }
74    }
75}