Skip to content

aead: rework traits API#2427

Open
newpavlov wants to merge 7 commits into
masterfrom
aead/minimize
Open

aead: rework traits API#2427
newpavlov wants to merge 7 commits into
masterfrom
aead/minimize

Conversation

@newpavlov
Copy link
Copy Markdown
Member

@newpavlov newpavlov commented May 25, 2026

TODO:

  • Update changelog.
  • Update docs.
  • Test new methods.
  • Migrate implementation crates.

Unresolved questions:

  • Solution for potential incorrect reordering of arguments (nonce, aad, plaintext/ciphertext) with the same type (&[u8]).
  • Should we handle potential fallibility in allocate, extend, and truncate closures?

@newpavlov newpavlov requested a review from tarcieri May 25, 2026 17:09
Comment thread aead/src/lib.rs Outdated
Comment thread aead/src/high_aead.rs Outdated
@newpavlov newpavlov changed the title aead: minimize API surface aead: minimize API surface and add support for variable size nonces May 29, 2026
@newpavlov

This comment was marked as outdated.

@newpavlov newpavlov changed the title aead: minimize API surface and add support for variable size nonces aead: rework traits API May 29, 2026
Comment thread aead/src/tag_pos.rs Outdated
Comment thread aead/src/high_aead.rs Outdated
Comment thread aead/src/lib.rs Outdated
Comment thread aead/src/tag_pos.rs Outdated
@tarcieri
Copy link
Copy Markdown
Member

Overall this doesn't feel like an improvement to me. Several things have changed but I don't think they've changed in ways that make more sense.

@newpavlov
Copy link
Copy Markdown
Member Author

newpavlov commented May 31, 2026

IMO variable nonce support, merging AeadCore and AeadInOut, significantly reducing number of crate features, and making Aead properly dyn-compatible (and potentially implementable by IO-based tokens) make a fair amount of sense.

Comment thread aead/src/utils.rs Outdated
Comment thread aead/src/aead.rs
///
/// # Errors
/// AEAD algorithm implementations may return an error if the plaintext or AAD are too long.
fn encrypt_into_vec(&self, nonce: &[u8], aad: &[u8], plaintext: &[u8]) -> Result<Vec<u8>>;
Copy link
Copy Markdown
Member Author

@newpavlov newpavlov Jun 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed the Payload type for now. I think we either need a more general solution which would help with other methods as well (e.g. Nonce, Aad, Plaintext, etc. wrappers), or we could just tolerate potential incorrect reorderings of the arguments, which are hopefully somewhat unlikely in modern conditions (with IDEs and stuff).

Comment thread aead/src/lib.rs
) -> Result<()>;
aad: &[u8],
plaintext: &[u8],
allocate: impl FnOnce(usize) -> B,
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we handle potential fallibility here and in extend/truncate?

Comment thread aead/src/lib.rs
buffer: &mut dyn Buffer,
aad: &[u8],
buf: &mut B,
extend: impl FnOnce(&mut B, usize),
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about using a pass-through API:

fn encrypt_within<B: AsMut<[u8]>>(
    &self,
    nonce: &Nonce<Self>,
    aad: &[u8],
    buf: B,
    extend: impl FnOnce(&mut B, usize),
) -> Result<B> { ... }

But I decided against it since it may be inefficient for some buffer types (e.g. ArrayVec).

Comment thread aead/src/variable.rs Outdated
Comment on lines +7 to +15
/// Functionality of Authenticated Encryption with Associated Data (AEAD) algorithms
/// with variable nonce and tag size support.
///
/// <div class="warning">
/// Some algorithms support very short nonce and tag sizes. Users should exercise extreme caution
/// while using this trait since incorrect handling of nonces and tags may defeat security
/// provided by the algorithm.
/// </div>
pub trait VariableAead: AeadCore {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a purely additive change which could be added and discussed in its own PR

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also don't understand the supertrait bounds here. It seems like it should be the most flexible, fundamental trait which isn't constrained by knowledge of particular sizes, and support different sizes at runtime.

Copy link
Copy Markdown
Member Author

@newpavlov newpavlov Jun 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I wrote above, I am not sure about what would be the best implementation relationships between the traits, so I am open to alternatives. I got to the current solution from the following factors:

  1. Aead should support variable nonces, so it's blanket implementation should be based on VariableAead.
  2. We want to automatically (or at least easily) implement VariableAead if type implements AeadCore.
  3. We do not have specialization in stable Rust.
  4. We want to guide users towards "default" sizes even if they rely on VariableAead and, as discussed above, we are likely to have separate "variable" types in implementation crates.

We could make VariableAead more "fundamental" than AeadCore, but it would look strange from the naming perspective ("core" becomes a mid-level layer) and it would mean that implementing both VariableAead and AeadCore would be slightly more annoying.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VariableAead is more fundamental in that it can do things an AeadCore cannot, namely implement multiple sizes simultaneously.

An AeadCore bound means a type that impls VariableAead will have an associated set of fixed sizes for things like nonces and tags, which isn't a property a type which supports multiple sizes at runtime can have.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also could view VariableAead as an "extension" of AeadCore for additional support of nonce sizes at runtime, but I understand your position. I will try to play with it later.

Am I correct, that you prefer for AeadCore implementers to not implement VariableAead? And that Aead should be implemented in terms of AeadCore and not VariableAead? Note that we can not have two blanket impls without support of mutually exclusive traits in the language.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think in cases where there is actually a legitimate need to support multiple nonces and tag sizes at runtime, as with AES-GCM, that it can have a VariableAead core which is untyped in regard to nonce and tag sizes, and separately have well-typed wrappers which are newtypes composed in terms of the VariableAead core and delegate to that implementation, rather than using a blanket impl.

The only way such a blanket impl could even work, IMO, is if you kept AeadCore as-is where it only provides the size information, and the blanket impl could use that size information to provide a well-typed API. But I think that makes less sense than just having those types impl the relevant traits directly with a blanket impl that goes the other direction, providing VariableAead for AeadCore implementations.

@tarcieri
Copy link
Copy Markdown
Member

tarcieri commented Jun 5, 2026

I really think, at the very least, this should be broken down into multiple, smaller PRs.

You are trying to rush through a large number of unrelated changes in a single PR shortly before a release.

I would like to see at least two PRs:

  1. A purely additive PR for VariableAead
  2. At least one separate PR for all of the assorted other unrelated changes, which can build on top of the VariableAead PR

Trying to make this many changes so very late in the crate's development lifecycle right before a stable release is highly problematic, IMO, and having them all in a single PR means discussion is unfocused as we're jumping around between all of the different changes rather than focusing on a set of them in isolation.

@newpavlov
Copy link
Copy Markdown
Member Author

Ok, I will remove VariableAead and will add it in a separate PR. But the AeadCore and Aead changes are interconnected and I don't think it makes sense to split them, especially considering that Aead is used by the dev module. The resulting code is pretty small (just 12 methods), so splitting it further would be just a confusing busywork.

@tarcieri
Copy link
Copy Markdown
Member

tarcieri commented Jun 5, 2026

Can we start with VariableAead? It was the whole impetus for making any last minute changes whatsoever.

@newpavlov
Copy link
Copy Markdown
Member Author

I would strongly prefer to start with the AeadCore and Aead changes and to build VaraibleAead on top of it.

I will ignore your "last minute" remarks, otherwise the discussion could get pointlessly heated again and we will get nowhere.

@tarcieri
Copy link
Copy Markdown
Member

tarcieri commented Jun 5, 2026

I would strongly prefer to start with the AeadCore and Aead changes and to build VaraibleAead on top of it.

Where are the actual interdependencies which make that preferable?

@newpavlov
Copy link
Copy Markdown
Member Author

The structure of methods. VariableAead effectively mirrors AeadCore by replacing compile-time sizes with run-time equivalents, so it helps to finalize it first without going through a bunch of annoying iterations.

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.

2 participants