Skip to content

Conversation

@tl-Roberto-Mancinelli
Copy link
Contributor

@tl-Roberto-Mancinelli tl-Roberto-Mancinelli commented Nov 23, 2025

Summary

This PR adds Native AOT (Ahead-of-Time) compilation support to the TrueLayer.Signing library, enabling better performance and reduced startup times for .NET applications.

Key Changes

  • Removed Jose.JWT dependency: Replaced with custom implementation to eliminate reflection-based code
  • Added JSON Source Generation: Implemented SigningJsonContext for AOT-compatible JSON serialization
  • Custom Base64Url encoding: Implemented custom Base64Url encoder/decoder without reflection
  • Custom JWS verification: Replaced Jose.JWT's verification logic with direct cryptographic operations
  • Target framework dependencies: Split dependencies by target framework (net10.0, net9.0, net8.0, netstandard2.0, netstandard2.1)
  • AOT annotations: Added IsAotCompatible, IsTrimmable, EnableTrimAnalyzer, and EnableSingleFileAnalyzer properties
  • Fixed XML documentation warnings: Added missing XML comments for public API members

Benchmark (net10/small payment)

current:

Method Mean Error StdDev Rank Gen0 Allocated
'Verify Request' 667.5 us 12.92 us 13.82 us 1 0.9766 9.13 KB
'Sign Request' 677.5 us 12.80 us 14.22 us 1 7.12 KB

v0.2.5 - jose-jwt:

Method Mean Error StdDev Rank Gen0 Allocated
'Verify Request' 665.5 us 4.21 us 3.52 us 1 0.9766 14.73 KB
'Sign Request' 677.6 us 10.55 us 11.29 us 1 0.9766 13.47 KB

v0.1.16

Method Mean Error StdDev Rank Gen0 Allocated
'Verify Request' 679.9 us 13.26 us 16.28 us 1 1.9531 21.56 KB
'Sign Request' 682.2 us 13.60 us 13.36 us 1 0.9766 13.67 KB

@tl-Roberto-Mancinelli
Copy link
Contributor Author

/pretag

@tl-gitops-watcher
Copy link

Created pre-tag v0.3.2-pre0 (View in CircleCi)

@tl-Roberto-Mancinelli tl-Roberto-Mancinelli changed the title perf(PAYINS-1388): Enable AOT perf(PAYINS-1388): Add AOT support Nov 24, 2025
@tl-Roberto-Mancinelli tl-Roberto-Mancinelli changed the title perf(PAYINS-1388): Add AOT support perf(PAYINS-1388): Add native AOT support Nov 28, 2025
@tl-Roberto-Mancinelli
Copy link
Contributor Author

/pretag

@tl-gitops-watcher
Copy link

Created pre-tag v0.3.2-pre1 (View in CircleCi)

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds Native AOT (Ahead-of-Time) compilation support to the TrueLayer.Signing library by removing reflection-based dependencies and implementing custom AOT-compatible alternatives for JWT operations.

Key Changes

  • Removed Jose.JWT dependency and replaced with custom Base64Url encoding and JWS signature verification
  • Added JSON Source Generation context (SigningJsonContext) for AOT-compatible serialization on .NET 5.0+
  • Configured AOT and trimming settings in the project file with framework-specific dependency versions

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
csharp/test/UsageTest.cs Removed unused Jose.JWT import
csharp/test/SigningFunction.cs Removed unused Jose.JWT import
csharp/test/ErrorTest.cs Removed unused Jose.JWT import
csharp/src/truelayer-signing.csproj Added AOT compatibility flags and reorganized dependencies by target framework with version updates
csharp/src/Verifier.cs Replaced Jose.JWT with custom JWS header parsing and signature verification using direct cryptographic operations
csharp/src/Util.cs Added SigningJsonContext for source generation, enhanced GetString() to handle JsonElement deserialization
csharp/src/Signer.cs Replaced Jose.JWT signing with custom JWS creation using manual Base64Url encoding and hash signing, added XML documentation
csharp/src/Base64Url.cs New custom Base64Url encoder/decoder implementation for AOT compatibility

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 348 to 372
// Build the signing input: base64url(header).base64url(payload)
// For detached signatures, we reconstruct using the provided payload
var payloadB64 = Base64Url.Encode(payload);
var signingInput = new byte[headerB64.Length + 1 + payloadB64.Length];
#if NET5_0_OR_GREATER
// Use Span-based API for better performance on modern .NET
Encoding.ASCII.GetBytes(headerB64, signingInput.AsSpan(0, headerB64.Length));
signingInput[headerB64.Length] = (byte)'.';
Encoding.ASCII.GetBytes(payloadB64, signingInput.AsSpan(headerB64.Length + 1));
#else
Encoding.UTF8.GetBytes(headerB64, 0, headerB64.Length, signingInput, 0);
signingInput[headerB64.Length] = (byte)'.';
Encoding.UTF8.GetBytes(payloadB64, 0, payloadB64.Length, signingInput, headerB64.Length + 1);
#endif

// Compute SHA-512 hash of the signing input (ES512 uses SHA-512)
#if NET5_0_OR_GREATER
var hash = SHA512.HashData(signingInput);
#else
byte[] hash;
using (var sha512 = SHA512.Create())
{
hash = sha512.ComputeHash(signingInput);
}
#endif
Copy link
Contributor

Choose a reason for hiding this comment

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

This code seems shared between the Signer and Verifier, could we extract to a Util?

Copy link
Contributor

Choose a reason for hiding this comment

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

Also we differ between ASCII and UTF8 encoding in the if block, why is that?

Copy link
Contributor Author

@tl-Roberto-Mancinelli tl-Roberto-Mancinelli Nov 28, 2025

Choose a reason for hiding this comment

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

the output in this case is the same as base64url is producing ASCII only but better to align both paths

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

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants