Skip to content

feat: add Signature and KEM factory enums - #85

Open
VedantMadane wants to merge 1 commit into
bcgit:mainfrom
VedantMadane:fix/issue-68
Open

feat: add Signature and KEM factory enums#85
VedantMadane wants to merge 1 commit into
bcgit:mainfrom
VedantMadane:fix/issue-68

Conversation

@VedantMadane

Copy link
Copy Markdown

Summary

Implements Signature and KEM factories in bouncycastle-factory, addressing maintainer feedback on closed PR #84 / issue #68.

The previous PR only added empty stub structs at the workspace root. This replaces that with full enum factories that follow the existing HashFactory / MACFactory / RNGFactory pattern.

Design

Core Signer / SignatureVerifier / KEMEncapsulator / KEMDecapsulator traits are parameterized by const-generic key and ciphertext/signature sizes. A single enum wrapping ML-DSA-44/65/87 (or ML-KEM-512/768/1024) cannot implement those traits with one fixed size set.

So this PR:

  1. SignatureFactory / KEMFactory enums — algorithm selectors implementing AlgorithmFactory (Default / Default128Bit / Default256Bit / new(name)).
  2. Key enums (SignaturePublicKey, SignaturePrivateKey, KEMPublicKey, KEMPrivateKey) that encapsulate all supported key objects with encode / from_bytes pass-through.
  3. Streaming engine enums (SignatureSigner, SignatureVerifierEngine) that encapsulate the underlying ML-DSA state machines after sign_init / verify_init.
  4. Inherent methods with the same shape as the core traits that match and pass through to the underlying types.

Defaults

Helper Signature KEM
default() ML-DSA-65 ML-KEM-768
default_128_bit() ML-DSA-44 ML-KEM-512
default_256_bit() ML-DSA-87 ML-KEM-1024

Tests

crypto/factory/tests/signature_kem_factory_tests.rs covers defaults, name lookup, full sign/verify and encaps/decaps round-trips for every parameter set, streaming sign/verify, and algorithm/key mismatch errors.

Fixes #68

Supersedes #84

Implement SignatureFactory and KEMFactory in bouncycastle-factory as
enums that encapsulate all supported ML-DSA / ML-KEM parameter sets,
following the existing Hash/MAC/RNG factory pattern.

- SignatureFactory / KEMFactory implement AlgorithmFactory (defaults,
  128/256-bit defaults, construction by algorithm name)
- Key enums wrap public/private keys with encode/from_bytes pass-through
- SignatureSigner / SignatureVerifierEngine wrap streaming engines
- Inherent methods mirror Signer/SignatureVerifier/KEMEncapsulator/
  KEMDecapsulator and dispatch to the underlying types

Const-generic sizes on the core traits prevent a single enum from
implementing those traits directly; the factory APIs pass through with
type-erased keys and Vec encodings instead.

Fixes bcgit#68

Signed-off-by: Vedant Madane <6527493+VedantMadane@users.noreply.github.com>
@VedantMadane

Copy link
Copy Markdown
Author

Follow-up: reopen was blocked after the force-push (GitHub 422), so the complete implementation is in #85 on the same branch fix/issue-68. Thanks again for the guidance.

@ounsworth

ounsworth commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Thank you for the contribution.
This is closer than your previous PR (in that it actually contains code now 😆 ), but there are still some gaps to close before merging, including potentially a research task.

The core idea of the factories is that they are an enum that impl's the same traits as the types that it's encapsulating so that you can pass the factory enum itself as a dyn TRAIT for whatever trait it's implementing.

As an example:

/// Wrapper object for all algorithms that impl [`KDF`].
pub enum KDFFactory {
    ///
    #[allow(non_camel_case_types)]
    HKDF_SHA256(hkdf::HKDF_SHA256),
    ...


impl KDF for KDFFactory {
    fn derive_key(
        self,
        key: &impl KeyMaterialTrait,
       ...
}

You have, as an example:

/// Wrapper for all supported KEM public (encapsulation) keys.
pub enum KEMPublicKey {
    /// ML-KEM-512 public key.
    MLKEM512(mlkem::MLKEM512PublicKey),
    ...
}


impl KEMPublicKey {
    /// Encode the public key to its standard byte encoding.
    pub fn encode(&self) -> Vec<u8> {
          ....
        }
    }

That should instead be:

use bouncycastle-core::traits::KEMPublicKey;

/// Wrapper for all supported KEM public (encapsulation) keys that impl [`KEMPublicKey`]
pub enum KEMPublicKeyFactory {
    /// ML-KEM-512 public key.
    MLKEM512(mlkem::MLKEM512PublicKey),
    ...
}

impl KEMPublicKey for KEMPublicKeyFactory {
    ....
}

Now that I'm taking a closer look at this, there are generic params on the KEMPublicKey trait which might make this approach more complicated, and this may end up being a bit of a research task that requires a bit of a redesign of how we're doing factories. If you want to do some playing around with how to get the various Signature and KEM traits in core::traits to work on factory objects, and either get it working and submit a PR, or say that it doesn't work and instead suggest an alternate pattern for the factory objects, that would be a great help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fill in missing Factory objects

2 participants