Skip to main content

xml_sec/xmldsig/
pq_algorithm.rs

1//! Explicit experimental XML method identifiers, not W3C-standardized algorithms.
2
3/// FIPS 204/205 parameter sets exposed by libxmlsec1's experimental XML methods.
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
5pub enum PqAlgorithm {
6    /// ML-DSA-44.
7    MlDsa44,
8    /// ML-DSA-65.
9    MlDsa65,
10    /// ML-DSA-87.
11    MlDsa87,
12    /// SLH-DSA-SHA2-128f.
13    SlhDsaSha2_128f,
14    /// SLH-DSA-SHA2-128s.
15    SlhDsaSha2_128s,
16    /// SLH-DSA-SHA2-192f.
17    SlhDsaSha2_192f,
18    /// SLH-DSA-SHA2-192s.
19    SlhDsaSha2_192s,
20    /// SLH-DSA-SHA2-256f.
21    SlhDsaSha2_256f,
22    /// SLH-DSA-SHA2-256s.
23    SlhDsaSha2_256s,
24}
25
26impl PqAlgorithm {
27    /// Recognized experimental parameter sets; permission still requires policy.
28    pub const ALL: [Self; 9] = [
29        Self::MlDsa44,
30        Self::MlDsa65,
31        Self::MlDsa87,
32        Self::SlhDsaSha2_128f,
33        Self::SlhDsaSha2_128s,
34        Self::SlhDsaSha2_192f,
35        Self::SlhDsaSha2_192s,
36        Self::SlhDsaSha2_256f,
37        Self::SlhDsaSha2_256s,
38    ];
39
40    /// Experimental XML URI used by libxmlsec1 1.3.13.
41    pub const fn uri(self) -> &'static str {
42        match self {
43            Self::MlDsa44 => "http://www.aleksey.com/xmlsec/2025/12/xmldsig-more#ml-dsa-44",
44            Self::MlDsa65 => "http://www.aleksey.com/xmlsec/2025/12/xmldsig-more#ml-dsa-65",
45            Self::MlDsa87 => "http://www.aleksey.com/xmlsec/2025/12/xmldsig-more#ml-dsa-87",
46            Self::SlhDsaSha2_128f => {
47                "http://www.aleksey.com/xmlsec/2025/12/xmldsig-more#slh-dsa-sha2-128f"
48            }
49            Self::SlhDsaSha2_128s => {
50                "http://www.aleksey.com/xmlsec/2025/12/xmldsig-more#slh-dsa-sha2-128s"
51            }
52            Self::SlhDsaSha2_192f => {
53                "http://www.aleksey.com/xmlsec/2025/12/xmldsig-more#slh-dsa-sha2-192f"
54            }
55            Self::SlhDsaSha2_192s => {
56                "http://www.aleksey.com/xmlsec/2025/12/xmldsig-more#slh-dsa-sha2-192s"
57            }
58            Self::SlhDsaSha2_256f => {
59                "http://www.aleksey.com/xmlsec/2025/12/xmldsig-more#slh-dsa-sha2-256f"
60            }
61            Self::SlhDsaSha2_256s => {
62                "http://www.aleksey.com/xmlsec/2025/12/xmldsig-more#slh-dsa-sha2-256s"
63            }
64        }
65    }
66
67    /// PKIX OID, with parameters absent (RFC 9881 section 2 / RFC 9909 section 3).
68    /// https://www.rfc-editor.org/rfc/rfc9881.html#section-2
69    /// https://www.rfc-editor.org/rfc/rfc9909.html#section-3
70    pub const fn oid(self) -> &'static str {
71        match self {
72            Self::MlDsa44 => "2.16.840.1.101.3.4.3.17",
73            Self::MlDsa65 => "2.16.840.1.101.3.4.3.18",
74            Self::MlDsa87 => "2.16.840.1.101.3.4.3.19",
75            Self::SlhDsaSha2_128s => "2.16.840.1.101.3.4.3.20",
76            Self::SlhDsaSha2_128f => "2.16.840.1.101.3.4.3.21",
77            Self::SlhDsaSha2_192s => "2.16.840.1.101.3.4.3.22",
78            Self::SlhDsaSha2_192f => "2.16.840.1.101.3.4.3.23",
79            Self::SlhDsaSha2_256s => "2.16.840.1.101.3.4.3.24",
80            Self::SlhDsaSha2_256f => "2.16.840.1.101.3.4.3.25",
81        }
82    }
83
84    pub(crate) const fn object_oid(self) -> pkcs8::der::asn1::ObjectIdentifier {
85        pkcs8::der::asn1::ObjectIdentifier::new_unwrap(self.oid())
86    }
87
88    pub(crate) fn from_oid(oid: pkcs8::der::asn1::ObjectIdentifier) -> Option<Self> {
89        Self::ALL
90            .into_iter()
91            .find(|algorithm| algorithm.object_oid() == oid)
92    }
93
94    /// Exact signature wire width (FIPS 204 table 2 / FIPS 205 table 2).
95    pub const fn signature_len(self) -> usize {
96        match self {
97            Self::MlDsa44 => 2420,
98            Self::MlDsa65 => 3309,
99            Self::MlDsa87 => 4627,
100            Self::SlhDsaSha2_128f => 17088,
101            Self::SlhDsaSha2_128s => 7856,
102            Self::SlhDsaSha2_192f => 35664,
103            Self::SlhDsaSha2_192s => 16224,
104            Self::SlhDsaSha2_256f => 49856,
105            Self::SlhDsaSha2_256s => 29792,
106        }
107    }
108
109    pub(crate) const fn context_element(self) -> &'static str {
110        match self {
111            Self::MlDsa44 | Self::MlDsa65 | Self::MlDsa87 => "MLDSAContextString",
112            _ => "SLHDSAContextString",
113        }
114    }
115}