Skip to main content

codec_multikey/
binding.rs

1// SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2//
3// SPDX-License-Identifier: Apache-2.0
4
5use crate::error::{classify_binding_algorithm, classify_binding_type, MultikeyError};
6use crate::parse::ParsedMultikey;
7
8/// Generic binding compatibility rules.
9/// Binding labels are protocol-facing metadata and are validated here
10/// as algorithm constraints over multikey-encoded public keys.
11/// Returns whether a binding-type label is compatible with a codec name.
12///
13/// Generic `Multikey` matches any supported codec; profile-specific labels
14/// match only their one codec. Unknown labels return `false`.
15pub fn binding_type_matches_codec(binding_type: &str, codec_name: &str) -> bool {
16    match binding_type {
17        // Generic Multikey (ALL supported algorithms)
18        "Multikey" => matches!(
19            codec_name,
20            "ed25519-pub"
21                | "ed448-pub"
22                | "x25519-pub"
23                | "p256-pub"
24                | "p384-pub"
25                | "p521-pub"
26                | "rsa-pub"
27                | "secp256k1-pub"
28                | "mldsa-44-pub"
29                | "mldsa-65-pub"
30                | "mldsa-87-pub"
31                | "mlkem-512-pub"
32                | "mlkem-768-pub"
33                | "mlkem-1024-pub"
34        ),
35
36        // Profile-specific / constrained bindings
37        "P256Key2024" => codec_name == "p256-pub",
38        "P384Key2024" => codec_name == "p384-pub",
39        "P521Key2024" => codec_name == "p521-pub",
40        "RsaVerificationKey2024" => codec_name == "rsa-pub",
41        "ML_DSA_44Key2024" => codec_name == "mldsa-44-pub",
42        "ML_DSA_65Key2024" => codec_name == "mldsa-65-pub",
43        "ML_DSA_87Key2024" => codec_name == "mldsa-87-pub",
44        "MLKEM512Key2024" => codec_name == "mlkem-512-pub",
45        "MLKEM768Key2024" => codec_name == "mlkem-768-pub",
46        "MLKEM1024Key2024" => codec_name == "mlkem-1024-pub",
47
48        _ => false,
49    }
50}
51
52/// Binding metadata to validate against a parsed multikey.
53pub struct KeyBindingInput<'a> {
54    /// The binding-type label (e.g. `Multikey`, `P256Key2024`).
55    pub binding_type: &'a str,
56    /// Optional explicit algorithm label; required for non-`Multikey` types.
57    pub algorithm: Option<&'a str>,
58}
59
60/// Validates that a binding's type and algorithm agree with a parsed key.
61///
62/// Fails closed: returns an error on a type/codec mismatch, an algorithm
63/// mismatch, or a missing required algorithm.
64pub fn validate_key_binding(
65    binding: KeyBindingInput<'_>,
66    parsed: &ParsedMultikey,
67) -> Result<(), MultikeyError> {
68    if !binding_type_matches_codec(binding.binding_type, parsed.codec_name) {
69        return Err(MultikeyError::BindingTypeCodecMismatch {
70            binding_type: classify_binding_type(binding.binding_type),
71            codec_name: parsed.codec_name,
72            alg: parsed.alg,
73        });
74    }
75
76    if let Some(binding_alg) = binding.algorithm {
77        if binding_alg != parsed.alg {
78            return Err(MultikeyError::BindingAlgorithmMismatch {
79                binding_alg: classify_binding_algorithm(binding_alg),
80                codec_alg: parsed.alg,
81            });
82        }
83    } else if binding.binding_type != "Multikey" {
84        return Err(MultikeyError::BindingAlgorithmMissing {
85            binding_type: classify_binding_type(binding.binding_type),
86        });
87    }
88
89    Ok(())
90}