Skip to content

Commit

Permalink
Performance improvement to MAC input preparation
Browse files Browse the repository at this point in the history
  • Loading branch information
daviddesmet committed Apr 7, 2022
1 parent 0dce013 commit 03edf80
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 27 deletions.
5 changes: 5 additions & 0 deletions src/NaCl.Core/Base/ChaCha20Base.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
namespace NaCl.Core.Base
{
using System;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;

using Internal;
Expand Down Expand Up @@ -55,6 +56,7 @@ public override void ProcessKeyStreamBlock(ReadOnlySpan<byte> nonce, int counter
/// </summary>
/// <param name="subKey">The subKey.</param>
/// <param name="nonce">The nonce.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void HChaCha20(Span<byte> subKey, ReadOnlySpan<byte> nonce)
{
// See https://tools.ietf.org/html/draft-arciszewski-xchacha-01#section-2.2.
Expand All @@ -80,6 +82,7 @@ public void HChaCha20(Span<byte> subKey, ReadOnlySpan<byte> nonce)
/// </summary>
/// <param name="state">The state.</param>
/// <param name="nonce">The nonce.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void HChaCha20InitialState(Span<uint> state, ReadOnlySpan<byte> nonce)
{
// See https://tools.ietf.org/html/draft-arciszewski-xchacha-01#section-2.2.
Expand Down Expand Up @@ -217,6 +220,7 @@ protected static void ShuffleState(ref Array16<uint> state)
}
*/

[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected static void ShuffleState(Span<uint> state)
{
for (var i = 0; i < 10; i++)
Expand All @@ -232,6 +236,7 @@ protected static void ShuffleState(Span<uint> state)
}
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void QuarterRound(ref uint a, ref uint b, ref uint c, ref uint d)
{
a += b;
Expand Down
24 changes: 11 additions & 13 deletions src/NaCl.Core/Base/Snuffle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@
public abstract class Snuffle
{
public const int BLOCK_SIZE_IN_INTS = 16;
public static int BLOCK_SIZE_IN_BYTES = BLOCK_SIZE_IN_INTS * 4; // 64
public const int BLOCK_SIZE_IN_BYTES = BLOCK_SIZE_IN_INTS * 4; // 64
public const int KEY_SIZE_IN_INTS = 8;
public static int KEY_SIZE_IN_BYTES = KEY_SIZE_IN_INTS * 4; // 32
public const int KEY_SIZE_IN_BYTES = KEY_SIZE_IN_INTS * 4; // 32

public static uint[] SIGMA = new uint[] { 0x61707865, 0x3320646E, 0x79622D32, 0x6B206574 }; //Encoding.ASCII.GetBytes("expand 32-byte k");

Expand Down Expand Up @@ -160,7 +160,7 @@ public virtual byte[] Decrypt(ReadOnlySpan<byte> ciphertext)
throw new ArgumentException($"The {nameof(ciphertext)} is too short.");

var plaintext = new byte[ciphertext.Length - NonceSizeInBytes];
Decrypt(ciphertext.Slice(NonceSizeInBytes), ciphertext.Slice(0, NonceSizeInBytes), plaintext); //Process(ciphertext.Slice(0, NonceSizeInBytes), plaintext, ciphertext.Slice(NonceSizeInBytes));
Decrypt(ciphertext[NonceSizeInBytes..], ciphertext[..NonceSizeInBytes], plaintext); //Process(ciphertext.Slice(0, NonceSizeInBytes), plaintext, ciphertext.Slice(NonceSizeInBytes));
return plaintext;
}

Expand Down Expand Up @@ -222,19 +222,17 @@ private void Process(ReadOnlySpan<byte> nonce, Span<byte> output, ReadOnlySpan<b
}
*/

using (var owner = MemoryPool<byte>.Shared.Rent(BLOCK_SIZE_IN_BYTES))
using var owner = MemoryPool<byte>.Shared.Rent(BLOCK_SIZE_IN_BYTES);
for (var i = 0; i < numBlocks; i++)
{
for (var i = 0; i < numBlocks; i++)
{
ProcessKeyStreamBlock(nonce, i + InitialCounter, owner.Memory.Span);
ProcessKeyStreamBlock(nonce, i + InitialCounter, owner.Memory.Span);

if (i == numBlocks - 1)
Xor(output, input, owner.Memory.Span, length % BLOCK_SIZE_IN_BYTES, offset, i); // last block
else
Xor(output, input, owner.Memory.Span, BLOCK_SIZE_IN_BYTES, offset, i);
if (i == numBlocks - 1)
Xor(output, input, owner.Memory.Span, length % BLOCK_SIZE_IN_BYTES, offset, i); // last block
else
Xor(output, input, owner.Memory.Span, BLOCK_SIZE_IN_BYTES, offset, i);

owner.Memory.Span.Clear();
}
owner.Memory.Span.Clear();
}
}

Expand Down
43 changes: 37 additions & 6 deletions src/NaCl.Core/Base/SnufflePoly1305.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
namespace NaCl.Core.Base
{
using System;
using System.Buffers;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Cryptography;

using Internal;
Expand Down Expand Up @@ -249,7 +251,14 @@ public virtual void Decrypt(ReadOnlySpan<byte> nonce, ReadOnlySpan<byte> ciphert

try
{
Poly1305.VerifyMac(GetMacKey(nonce), GetMacDataRfc8439(associatedData, ciphertext), tag);
var aadPaddedLen = GetPaddedLength(associatedData, Poly1305.MAC_TAG_SIZE_IN_BYTES);
var ciphertextPaddedLen = GetPaddedLength(ciphertext, Poly1305.MAC_TAG_SIZE_IN_BYTES);

var macBuffer = new byte[aadPaddedLen + ciphertextPaddedLen + Poly1305.MAC_TAG_SIZE_IN_BYTES];
var macData = new Span<byte>(macBuffer);

GetMacDataRfc8439(macData, associatedData, aadPaddedLen, ciphertext, ciphertextPaddedLen);
Poly1305.VerifyMac(GetMacKey(nonce), macData, tag);
}
catch (CryptographicException ex) when (ex.Message.Contains("length"))
{
Expand All @@ -273,7 +282,7 @@ private Span<byte> GetMacKey(ReadOnlySpan<byte> nonce)
Span<byte> firstBlock = new byte[Snuffle.BLOCK_SIZE_IN_BYTES];
_macKeySnuffle.ProcessKeyStreamBlock(nonce, 0, firstBlock);

return firstBlock.Slice(0, Poly1305.MAC_KEY_SIZE_IN_BYTES);
return firstBlock[..Poly1305.MAC_KEY_SIZE_IN_BYTES];
}

/// <summary>
Expand All @@ -284,11 +293,11 @@ private Span<byte> GetMacKey(ReadOnlySpan<byte> nonce)
/// <returns>System.Byte[].</returns>
private byte[] GetMacDataRfc8439(ReadOnlySpan<byte> aad, ReadOnlySpan<byte> ciphertext)
{
var aadPaddedLen = (aad.Length % 16 == 0) ? aad.Length : (aad.Length + 16 - aad.Length % 16);
var aadPaddedLen = GetPaddedLength(aad, Poly1305.MAC_TAG_SIZE_IN_BYTES);
var ciphertextLen = ciphertext.Length;
var ciphertextPaddedLen = (ciphertextLen % 16 == 0) ? ciphertextLen : (ciphertextLen + 16 - ciphertextLen % 16);
var ciphertextPaddedLen = GetPaddedLength(ciphertext, Poly1305.MAC_TAG_SIZE_IN_BYTES);

var macData = new byte[aadPaddedLen + ciphertextPaddedLen + 16];
var macData = new byte[aadPaddedLen + ciphertextPaddedLen + Poly1305.MAC_TAG_SIZE_IN_BYTES];

// Mac Text
Array.Copy(aad.ToArray(), macData, aad.Length);
Expand All @@ -301,6 +310,28 @@ private byte[] GetMacDataRfc8439(ReadOnlySpan<byte> aad, ReadOnlySpan<byte> ciph
return macData;
}

private void SetMacLength(Span<byte> macData, int offset, int value) => ArrayUtils.StoreUInt64LittleEndian(macData, offset, (ulong)value);
/// <summary>
/// Prepares the input to MAC, following RFC 8439, section 2.8.
/// </summary>
/// <param name="mac">The resulting mac content.</param>
/// <param name="aad">The associated data.</param>
/// <param name="aadPaddedLen">The associated data padded length.</param>
/// <param name="ciphertext">The ciphertext.</param>
/// <param name="ciphertextPaddedLen">The ciphertext padded length.</param>
/// <returns>System.Byte[].</returns>
private static void GetMacDataRfc8439(Span<byte> mac, ReadOnlySpan<byte> aad, int aadPaddedLen, ReadOnlySpan<byte> ciphertext, int ciphertextPaddedLen)
{
// Mac Text
aad.CopyTo(mac[..aad.Length]);
ciphertext.CopyTo(mac.Slice(aadPaddedLen, ciphertext.Length));

// Mac Length
SetMacLength(mac, aadPaddedLen + ciphertextPaddedLen, aad.Length);
SetMacLength(mac, aadPaddedLen + ciphertextPaddedLen + sizeof(ulong), ciphertext.Length);
}

private static int GetPaddedLength(ReadOnlySpan<byte> input, int size) => (input.Length % size == 0) ? input.Length : (input.Length + size - input.Length % size);

private static void SetMacLength(Span<byte> macData, int offset, int value) => ArrayUtils.StoreUInt64LittleEndian(macData, offset, (ulong)value);
}
}
9 changes: 5 additions & 4 deletions src/NaCl.Core/NaCl.Core.csproj
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup Label="Build">
<TargetFrameworks>netstandard1.6;netstandard2.0;netstandard2.1;netcoreapp3.1;net5.0;net6.0</TargetFrameworks>
<TargetFrameworks Condition="'$(OS)' != 'Unix'">netstandard1.6;netstandard2.0;netstandard2.1;netcoreapp3.1;net45;net48;net5.0;net6.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;netstandard2.1;netcoreapp3.1;net5.0;net6.0</TargetFrameworks>
<TargetFrameworks Condition="'$(OS)' != 'Unix'">netstandard2.0;netstandard2.1;netcoreapp3.1;net45;net48;net5.0;net6.0</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<LangVersion>latest</LangVersion>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
Expand Down Expand Up @@ -46,14 +46,15 @@
</ItemGroup>

<ItemGroup Label="Package References">
<PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All" Version="1.0.0" />
<PackageReference Include="MinVer" Version="2.3.1">
<PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All" Version="1.1.1" />
<PackageReference Include="MinVer" Version="3.1.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

<ItemGroup Label="Package References for Windows" Condition="$(TargetFramework) != 'net6.0' AND $(TargetFramework) != 'net5.0' AND $(TargetFramework) != 'netcoreapp3.1' AND $(TargetFramework) != 'netstandard2.1'">
<PackageReference Include="IndexRange" Version="1.0.1" />
<PackageReference Include="System.Memory" Version="4.5.4" />
</ItemGroup>

Expand Down
2 changes: 1 addition & 1 deletion test/NaCl.Core.Benchmarks/NaCl.Core.Benchmarks.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
</PropertyGroup>

<ItemGroup Label="Package References">
<PackageReference Include="BenchmarkDotNet" Version="0.12.1" />
<PackageReference Include="BenchmarkDotNet" Version="0.13.1" />
</ItemGroup>

<ItemGroup Label="Project References">
Expand Down
5 changes: 2 additions & 3 deletions test/NaCl.Core.Benchmarks/XChaCha20Poly1305Benchmark.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
using System.Collections.Generic;
using System.Security.Cryptography;

using Base;
using Internal;
using NaCl.Core.Base;

using BenchmarkDotNet.Attributes;

Expand Down Expand Up @@ -70,7 +69,7 @@ public void Decrypt(Tests.Vectors.XChaCha20Poly1305TestVector test)
aead.Decrypt(test.Nonce, test.CipherText, test.Tag, plaintext, test.Aad);
}

public IEnumerable<object> TestVectors()
public static IEnumerable<object> TestVectors()
{
//foreach (var test in Tests.Rfc8439TestVector.Rfc7634AeadTestVectors)
// yield return test;
Expand Down

0 comments on commit 03edf80

Please sign in to comment.