Skip to content

ChaCha20 / XChaCha20 / Poly1305 AEAD (PR #90 concern B on architecture) - #6

Open
omonien wants to merge 2 commits into
package/aead-architecturefrom
package/chacha-poly1305
Open

ChaCha20 / XChaCha20 / Poly1305 AEAD (PR #90 concern B on architecture)#6
omonien wants to merge 2 commits into
package/aead-architecturefrom
package/chacha-poly1305

Conversation

@omonien

@omonien omonien commented Jul 25, 2026

Copy link
Copy Markdown
Owner

Package B — ChaCha / Poly1305 (on top of architecture package A)

Depends on: package/aead-architecture (PR #5 on this fork).

Donor algorithm work from upstream PR #90algorithms + vectors only, not the PR’s AEAD base/GCM rewrite.

What landed

Component Notes
TCipher_ChaCha20 / TCipher_XChaCha20 Stream ciphers; AEAD is opt-in via Mode := cmPoly1305
TPoly1305 Peer of TGCM under FAuthObj: own Encode/Decode/Done
cmPoly1305 Wired in modes + IV-size exception + authenticated-mode helpers
DECCPUSupport Minimal CPUID flags; defaults stay PAS
Tests Wycheproof JSON + RFC-style AEAD + multi-chunk + empty PT/AAD + wrong tag + post-Done

Explicitly not included

  • AES-NI / UseAESAsm from the donor PR
  • Defaulting ChaCha construction to Poly1305 mode
  • Default-on AVX for Poly
  • Any regression of package A GCM multi-call

Lifecycle

Same as GCM: Init → AAD/tag → Encode*/Decode* → Done → tag.

Tests (Delphi 13 Win32 Console DUnit)

  • TestChaCha20Poly1305: 12/12
  • GCM: 19/19, CCM: 16/16
  • Full suite: 1443 run, 11 failures — pre-existing Keccak only

Design notes: Docs/plans/2026-07-25-chacha-poly1305.md

Upstream strategy

  1. Open/merge architecture PR A against MHumm/development first
  2. Then open package B against development (or stack on A)

Note

High Risk
Large new cryptographic surface (AEAD lifecycle, Poly1305/ChaCha, optional asm) with correctness and interoperability stakes; mistakes affect confidentiality and integrity of encrypted data.

Overview
Adds ChaCha20 and XChaCha20 stream ciphers plus Poly1305 AEAD on top of the existing package A authenticated-cipher model, without adopting PR MHumm#90’s AEAD/GCM redesign.

New surface: cmPoly1305, TPoly1305 (peer of GCM/CCM via FAuthObj), DECCipherModesPoly1305.pas, and DECCPUSupport for optional SIMD. ChaCha/Poly default to pure Pascal (CpuMode); SSE/AVX paths exist but are not auto-selected. AEAD is opt-in with Mode := cmPoly1305; RFC 7539 Poly key derivation uses ChaCha block 0 before payload at counter 1.

Integration: IsAuthenticatedBlockMode and DECCipherFormats now treat GCM/CCM/Poly1305 alike for empty plaintext and AAD-only paths; IV handling allows larger nonces (e.g. XChaCha). AlignPtr32 supports aligned SIMD buffers. DUnit coverage adds TestDECChaChaPoly1305 (Wycheproof-style vectors). Design notes live in Docs/plans/2026-07-25-chacha-poly1305.md.

Reviewed by Cursor Bugbot for commit c6fb30c. Bugbot is set up for automated code reviews on this repo. Configure here.

@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 197cc5f6-52f4-4f86-b921-9b0e1a7c69fb

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch package/chacha-poly1305

Comment @coderabbitai help to get the list of available commands.

Comment thread Source/DECCipherModes.pas Outdated
Comment thread Source/DECCipherModesPoly1305.pas Outdated
@omonien
omonien force-pushed the package/aead-architecture branch from 47c7463 to 58b54d1 Compare July 27, 2026 09:17
@omonien
omonien force-pushed the package/chacha-poly1305 branch from ec6b252 to 156e504 Compare July 27, 2026 09:17
Comment thread Source/DECCiphers.pas
omonien added 2 commits July 27, 2026 13:35
…m donor)

Port ChaCha20, XChaCha20 and Poly1305 onto package A AEAD architecture
(FAuthObj + Encode/Decode/Done lifecycle). Do not re-apply PR MHumm#90 base/GCM rewrite.

- cmPoly1305 mode, IsAuthenticatedBlockMode, IV size exception for Poly1305
- TPoly1305 redesigned for package A API; PAS default; AVX limb bug fixed
- TCipher_ChaCha20 / TCipher_XChaCha20 with opt-in cmPoly1305 AEAD
- DECCPUSupport (CPUID) + AlignPtr32; no AES-NI port
- Formats empty-buffer path generalized via IsAuthenticatedBlockMode
- Unit tests + Wycheproof-style vectors; multi-chunk / lifecycle coverage
…2 AVX XMM.

Restrict cmPoly1305 to stream ciphers (BlockSize < 16) so AES cannot miswire
DoEncode for decrypt; restore ChaCha Context.BufferSize after one-time Poly
key derivation; save/restore XMM6/7 around AVX Poly1305 on Win32 as well as
x64.
@omonien
omonien force-pushed the package/chacha-poly1305 branch from 156e504 to c6fb30c Compare July 27, 2026 11:39
@omonien

omonien commented Jul 27, 2026

Copy link
Copy Markdown
Owner Author

Addressed 2026-07-27 (fork cleanup pass)

Linear stack restored (A → B → C) and Cursor Bugbot / Augment findings handled:

Area Fix
GCM AAD after Encode/Done rejected (sGCMAADLocked)
GCM tag length > 128 EDECAuthLengthException + defensive copy
EncodeCCM / DecodeCCM independent FAuthObj dispatch (no longer forwards through EncodeGCM)
Poly1305 + block ciphers stream-only (BlockSize < 16)
ChaCha Poly init FBufferSize restored to Context.BufferSize
Win32 AVX XMM save/restore on X86ASM
AES-256 AES-NI schedule no +240 encode key; decode at (FRounds+1)*Blocks

Tests (D13 Win32 Console): GCM 21/21, ChaCha20Poly1305 12/12, AESNI 7/7. Pre-existing Keccak reds only.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 3 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit c6fb30c. Configure here.

Comment thread Source/DECCipherModes.pas
else
raise EDECCipherException.CreateResFmt(@sInvalidBlockSize,
[8, GetEnumName(TypeInfo(TCipherMode),
Integer(FMode))]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Poly1305 allows block ciphers

Medium Severity

InitMode treats cmPoly1305 as valid whenever Context.BlockSize is below 16, but several block ciphers (e.g. Blowfish, IDEA with block size 8) satisfy that test. Poly1305 AEAD expects a stream-style DoEncode over arbitrary byte lengths; pairing it with an 8-byte block cipher produces incorrect encryption and authentication without raising an error.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit c6fb30c. Configure here.


// AAD-only messages still need AAD absorption + length block + tag
EnsureAADAbsorbed;
FPadAndFinalizeFunc(Length(FDataToAuthenticate), Int64(FTotalCiphertextBytes));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Poly1305 AAD mutable after absorb

Medium Severity

TPoly1305 does not lock DataToAuthenticate after the first EnsureAADAbsorbed, unlike TGCM. If the property changes after Encode/Decode has started, the MAC keeps the old AAD bytes while Done finalizes using Length(FDataToAuthenticate) for the length block, producing an incorrect tag.

Fix in Cursor Fix in Web

Triggered by learned rule: GCM streaming state machine correctness

Reviewed by Cursor Bugbot for commit c6fb30c. Configure here.

// MAC the ciphertext first, then decrypt
FPolyBlkFunc(PByteArray(Source), Size);
Inc(FTotalCiphertextBytes, UInt64(Size));
FEncryptionMethod(Source, Dest, Size);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Multi-chunk decrypt state rejected

Medium Severity

TPoly1305.Decode invokes FEncryptionMethod, wired to DoEncode for ChaCha20. DoEncode sets cipher state to csEncode, but a second Decode requires csInitialized, csDecode, or csDone. Multi-call streaming decrypt fails after the first chunk even when the MAC path is incremental.

Additional Locations (2)
Fix in Cursor Fix in Web

Triggered by learned rule: GCM streaming state machine correctness

Reviewed by Cursor Bugbot for commit c6fb30c. Configure here.

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.

1 participant