aboutsummaryrefslogtreecommitdiff
path: root/wrappers
diff options
context:
space:
mode:
authorLibravatar vnugent <public@vaughnnugent.com>2024-10-18 22:10:17 -0400
committerLibravatar vnugent <public@vaughnnugent.com>2024-10-18 22:10:17 -0400
commit44044eb0fb28b774773e3284fd147c91d59d64e3 (patch)
tree429860e6ced91b02b7062f86c74120be5d5f0c11 /wrappers
parent6a4a464d9fdc7821cd5c5695656a3fe385497cc5 (diff)
refactor: Wire up unit testing and refactor c# api
Diffstat (limited to 'wrappers')
-rw-r--r--wrappers/dotnet/Taskfile.yaml60
-rw-r--r--wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/.runsettings8
-rw-r--r--wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/README.md4
-rw-r--r--wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/Taskfile.yaml81
-rw-r--r--wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Encryption/NCCipherUtil.cs (renamed from wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Encryption/NCUtilCipher.cs)65
-rw-r--r--wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Encryption/NoscryptMessageCipher.cs (renamed from wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Encryption/NoscryptCipher.cs)63
-rw-r--r--wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/INostrCrypto.cs88
-rw-r--r--wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NCKeyUtil.cs (renamed from wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NCUtil.cs)120
-rw-r--r--wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NoscryptExtensions.cs75
-rw-r--r--wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NoscryptLibrary.cs56
-rw-r--r--wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NostrCrypto.cs167
-rw-r--r--wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Singatures/NCSignatureUtil.cs175
-rw-r--r--wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Singatures/NoscryptSigner.cs (renamed from wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NoscryptSigner.cs)60
-rw-r--r--wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/VNLib.Utils.Cryptography.Noscrypt.csproj24
-rw-r--r--wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/internal/FunctionTable.cs2
-rw-r--r--wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/internal/NCUtil.cs104
-rw-r--r--wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/tests/LibNoscryptTests.cs272
-rw-r--r--wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/tests/NoscryptVectorTests.cs185
-rw-r--r--wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/tests/VNLib.Utils.Cryptography.NoscryptTests.csproj (renamed from wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/tests/NVault.Crypto.NoscryptTests.csproj)20
19 files changed, 897 insertions, 732 deletions
diff --git a/wrappers/dotnet/Taskfile.yaml b/wrappers/dotnet/Taskfile.yaml
deleted file mode 100644
index 9690e07..0000000
--- a/wrappers/dotnet/Taskfile.yaml
+++ /dev/null
@@ -1,60 +0,0 @@
-#Builds c# libraries for produc
-
-version: '3'
-
-vars:
- INT_DIR: '{{.SCRATCH_DIR}}/obj/{{.MODULE_NAME}}/'
- MS_ARGS: '/p:RunAnalyzersDuringBuild=false /p:IntermediateOutputPath="{{.INT_DIR}}" /p:UseCommonOutputDirectory=true /p:BuildInParallel=true /p:MultiProcessorCompilation=true /p:ErrorOnDuplicatePublishOutputFiles=false'
- PACK_OUT: '{{.OUTPUT_DIR}}/{{.HEAD_SHA}}/pkg'
-
-tasks:
-
-#called by build pipeline to build module
- build:
- dir: '{{.USER_WORKING_DIR}}'
- cmds:
- - echo "building module {{.MODULE_NAME}}"
-
- #build debug mode first
- - task: build_debug
- - task: build_release
-
- publish:
- dir: '{{.USER_WORKING_DIR}}'
- cmds:
-
- #push packages to the sleet feed (feed path is vnbuild global)
- - sleet push "{{.PACK_OUT}}/debug/" --source debug --config "{{.SLEET_CONFIG_PATH}}" --force
- - sleet push "{{.PACK_OUT}}/release/" --source release --config "{{.SLEET_CONFIG_PATH}}" --force
-
-#called by build pipeline to clean module
- clean:
- dir: '{{.USER_WORKING_DIR}}'
- cmds:
- #clean solution
- - dotnet clean /p:BuildInParallel=true /p:MultiProcessorCompilation=true
- - for: [ obj/, bin/ ]
- cmd: powershell rm -Recurse -Force "{{.ITEM}}"
-
-#Build tasks that use the solution file to build the module
- build_debug:
- dir: '{{.USER_WORKING_DIR}}'
- internal: true
- cmds:
- - cd {{.MODULE_DIR}} && dotnet publish -c debug {{.MS_ARGS}}
- - cd {{.MODULE_DIR}} && dotnet pack -c debug {{.MS_ARGS}} -o "{{.PACK_OUT}}/debug/"
-
- build_release:
- dir: '{{.USER_WORKING_DIR}}'
- internal: true
- cmds:
- - cd {{.MODULE_DIR}} && dotnet publish -c release {{.MS_ARGS}}
- - cd {{.MODULE_DIR}} && dotnet pack -c release {{.MS_ARGS}} -o "{{.PACK_OUT}}/release/"
-
-
- packsource:
- dir: '{{.USER_WORKING_DIR}}'
- internal: true
- cmds:
- #copy source code to target
- - powershell -Command "Get-ChildItem -Include *.cs,*.csproj -Recurse | Where { \$_.FullName -notlike '*\obj\*' -and \$_.FullName -notlike '*\bin\*' } | Resolve-Path -Relative | tar --files-from - -czf '{{.TARGET}}/src.tgz'" \ No newline at end of file
diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/.runsettings b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/.runsettings
new file mode 100644
index 0000000..bbc95aa
--- /dev/null
+++ b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/.runsettings
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RunSettings>
+ <RunConfiguration>
+ <EnvironmentVariables>
+ <NOSCRYPT_DLL_PATH>../../../../../../../build/windows/debug/noscrypt.dll</NOSCRYPT_DLL_PATH>
+ </EnvironmentVariables>
+ </RunConfiguration>
+</RunSettings> \ No newline at end of file
diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/README.md b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/README.md
new file mode 100644
index 0000000..34f68bf
--- /dev/null
+++ b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/README.md
@@ -0,0 +1,4 @@
+
+# VNLib.Utils.Cryptography.Noscrypt
+
+_A dotnet C# warpper library for noscrypt which is part of the VNLib collection of libraries_ \ No newline at end of file
diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/Taskfile.yaml b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/Taskfile.yaml
new file mode 100644
index 0000000..dfb739f
--- /dev/null
+++ b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/Taskfile.yaml
@@ -0,0 +1,81 @@
+#Builds c# libraries for produc
+
+version: '3'
+
+vars:
+ TARGET_FRAMEWORK: '{{ .TARGET_FRAMEWORK | default "net8.0" }}'
+
+tasks:
+
+#called by build pipeline to build module
+ build:
+ dir: '{{ .USER_WORKING_DIR }}'
+ vars:
+ PACK_OUT: '{{ .OUTPUT_DIR }}/{{ .HEAD_SHA }}/pkg'
+ MS_ARGS:
+ /p:RunAnalyzersDuringBuild=false
+ /p:UseCommonOutputDirectory=true
+ /p:BuildInParallel=true
+ /p:MultiProcessorCompilation=true
+ /p:ErrorOnDuplicatePublishOutputFiles=false
+ cmds:
+ - cmd: echo "building project {{ .PROJECT_NAME }}"
+ silent: true
+
+ #updates the project versions for all inlcuded .NET projects
+ - cmd: dotnet-gitversion.exe /updateprojectfiles
+
+ - cmd: dotnet publish -c debug {{ .MS_ARGS }}
+ - cmd: dotnet publish -c release {{ .MS_ARGS }}
+
+ #create nuget packages and write them directly to the output directory
+ - cmd: dotnet pack {{ .MS_ARGS }} -c debug -o "{{ .PACK_OUT }}/debug/"
+ - cmd: dotnet pack {{ .MS_ARGS }} -c release -o "{{ .PACK_OUT }}/release/"
+
+ postbuild_success:
+ deps:
+ - task: pack_source
+ - task: pack_artifacts
+ vars: { CONFIG: 'debug' }
+ - task: pack_artifacts
+ vars: { CONFIG: 'release' }
+
+ cmds:
+ - cmd: echo 'artifacts packaged'
+ silent: true
+
+ pack_artifacts:
+ dir: '{{ .USER_WORKING_DIR }}'
+ internal: true
+ vars:
+ SOURCE: 'bin/{{ .CONFIG }}/{{ .TARGET_FRAMEWORK }}/publish'
+ TARGET: '{{ .USER_WORKING_DIR }}/bin/{{ .CONFIG }}.tgz'
+ cmds:
+ - cmd: cd {{ .SOURCE }} && tar -czf '{{ lower .TARGET }}' .
+
+ pack_source:
+ dir: '{{ .USER_WORKING_DIR }}'
+ internal: true
+ vars:
+ TARGET: '{{ .USER_WORKING_DIR }}/bin'
+ INCLUDES:
+ src
+ tests
+ README.md
+ Taskfile.yaml
+ EXCLUDES:
+ --exclude='*obj/'
+ --exclude='*bin/'
+ cmds:
+ #copy source code to target
+ - cmd: cd .. && tar {{ .EXCLUDES }} -czf '{{ .TARGET }}/src.tgz' {{ .INCLUDES }}
+
+#called by build pipeline to clean module
+ clean:
+ dir: '{{ .USER_WORKING_DIR }}'
+ cmds:
+ #clean solution
+ - dotnet clean /p:BuildInParallel=true /p:MultiProcessorCompilation=true
+ - for: [ obj/, bin/ ]
+ cmd: '{{ if eq OS "windows" }}powershell rm -Recurse -Force{{ else }}rm -rf{{ end }} "{{ .ITEM }}"'
+
diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Encryption/NCUtilCipher.cs b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Encryption/NCCipherUtil.cs
index 72bb75a..5dc2a94 100644
--- a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Encryption/NCUtilCipher.cs
+++ b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Encryption/NCCipherUtil.cs
@@ -15,20 +15,24 @@
using System;
using System.Diagnostics;
+using System.Runtime.InteropServices;
+
using VNLib.Utils.Cryptography.Noscrypt.@internal;
+using static VNLib.Utils.Cryptography.Noscrypt.NoscryptLibrary;
+
using NCResult = System.Int64;
namespace VNLib.Utils.Cryptography.Noscrypt.Encryption
{
- internal static class NCUtilCipher
+ public unsafe static class NCCipherUtil
{
/*
* This class wraps the low-level cipher functions provided by
* the Noscrypt utility side-car library.
*/
- public static nint Alloc(NCContext ctx, uint version, uint flags)
+ internal static nint Alloc(NCContext ctx, uint version, uint flags)
{
nint cipher = GetTable(ctx).NCUtilCipherAlloc(version, flags);
@@ -43,7 +47,7 @@ namespace VNLib.Utils.Cryptography.Noscrypt.Encryption
return cipher;
}
- public static uint GetFlags(NCContext ctx, nint cipher)
+ internal static uint GetFlags(NCContext ctx, nint cipher)
{
NCResult result = GetTable(ctx).NCUtilCipherGetFlags(cipher);
@@ -52,9 +56,9 @@ namespace VNLib.Utils.Cryptography.Noscrypt.Encryption
return (uint)result;
}
- public static void Free(NCContext ctx, nint cipher) => GetTable(ctx).NCUtilCipherFree(cipher);
+ internal static void Free(NCContext ctx, nint cipher) => GetTable(ctx).NCUtilCipherFree(cipher);
- public static int GetIvSize(NCContext ctx, nint cipher)
+ internal static int GetIvSize(NCContext ctx, nint cipher)
{
NCResult result = GetTable(ctx).NCUtilCipherGetIvSize(cipher);
@@ -63,7 +67,7 @@ namespace VNLib.Utils.Cryptography.Noscrypt.Encryption
return checked((int)result);
}
- public static unsafe void SetProperty(NCContext ctx, nint cipher, uint property, ref readonly byte value, uint valueLen)
+ internal static void SetProperty(NCContext ctx, nint cipher, uint property, ref readonly byte value, uint valueLen)
{
fixed (byte* valPtr = &value)
{
@@ -73,7 +77,7 @@ namespace VNLib.Utils.Cryptography.Noscrypt.Encryption
}
}
- public static uint GetOutputSize(NCContext ctx, nint cipher)
+ internal static uint GetOutputSize(NCContext ctx, nint cipher)
{
NCResult result = GetTable(ctx).NCUtilCipherGetOutputSize(cipher);
@@ -82,7 +86,7 @@ namespace VNLib.Utils.Cryptography.Noscrypt.Encryption
return (uint)result;
}
- public static unsafe uint ReadOutput(NCContext ctx, nint cipher, ref byte outputData, uint outLen)
+ internal static uint ReadOutput(NCContext ctx, nint cipher, ref byte outputData, uint outLen)
{
fixed (byte* outPtr = &outputData)
{
@@ -94,14 +98,14 @@ namespace VNLib.Utils.Cryptography.Noscrypt.Encryption
}
}
- public static unsafe void InitCipher(NCContext ctx, nint cipher, byte* inputPtr, uint inputSize)
+ internal static void InitCipher(NCContext ctx, nint cipher, byte* inputPtr, uint inputSize)
{
NCResult result = GetTable(ctx).NCUtilCipherInit(cipher, inputPtr, inputSize);
NCUtil.CheckResult<FunctionTable.NCUtilCipherInitDelegate>(result, raiseOnFailure: true);
}
- public static unsafe void Update(
+ internal static void Update(
NCContext ctx,
nint cipher,
ref readonly NCSecretKey localKey,
@@ -122,7 +126,46 @@ namespace VNLib.Utils.Cryptography.Noscrypt.Encryption
}
}
- private static ref readonly FunctionTable GetTable(NCContext ctx) => ref ctx.Library.Functions;
+
+#if DEBUG
+ /*
+ * Conversation key is not meant to be a public api. Callers
+ * should use Encrypt/Decrypt methods to handle encryption.
+ *
+ * This method exists for vector testing purposes only.
+ */
+ public static void GetConverstationKey(
+ NCContext ctx,
+ ref readonly NCSecretKey localKey,
+ ref readonly NCPublicKey remoteKey,
+ Span<byte> conversationKeyOut32
+ )
+ {
+ ArgumentNullException.ThrowIfNull(ctx);
+ ArgumentOutOfRangeException.ThrowIfNotEqual(
+ conversationKeyOut32.Length,
+ NC_CONVERSATION_KEY_SIZE,
+ nameof(conversationKeyOut32)
+ );
+
+ fixed (NCSecretKey* sk = &localKey)
+ fixed (NCPublicKey* pk = &remoteKey)
+ fixed(byte* convKey32Ptr = &MemoryMarshal.GetReference(conversationKeyOut32))
+ {
+ NCResult result = GetTable(ctx).NCGetConversationKey(
+ ctx: ctx.DangerousGetHandle(),
+ sk,
+ pk,
+ convKey32Ptr
+ );
+
+ NCUtil.CheckResult<FunctionTable.NCUtilCipherInitDelegate>(result, raiseOnFailure: true);
+ }
+ }
+#endif
+
+ private static ref readonly FunctionTable GetTable(NCContext ctx)
+ => ref ctx.Library.Functions;
}
}
diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Encryption/NoscryptCipher.cs b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Encryption/NoscryptMessageCipher.cs
index b30ea44..e44addf 100644
--- a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Encryption/NoscryptCipher.cs
+++ b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Encryption/NoscryptMessageCipher.cs
@@ -18,6 +18,8 @@ using System.Threading;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
+using Microsoft.Win32.SafeHandles;
+
using VNLib.Utils.Memory;
using VNLib.Utils.Cryptography.Noscrypt.Random;
using static VNLib.Utils.Cryptography.Noscrypt.NoscryptLibrary;
@@ -27,29 +29,54 @@ namespace VNLib.Utils.Cryptography.Noscrypt.Encryption
/// <summary>
/// The noscrypt util cipher wapper
/// </summary>
- /// <param name="ctx"></param>
- /// <param name="flags">Cipher creation flags</param>
+ /// <param name="ctx">A reference to the library context object</param>
+ /// <param name="cipher">A pointer to an existing cipher context that this instance owns</param>
/// <param name="version">The cipher specification version</param>
- public sealed class NoscryptCipher(NCContext ctx, NoscryptCipherVersion version, NoscryptCipherFlags flags) : VnDisposeable
+ public class NoscryptMessageCipher : SafeHandleMinusOneIsInvalid
{
+ private readonly NCContext _context;
+ private readonly NoscryptCipherVersion _version;
private IMemoryHandle<byte>? _ivBuffer;
- private readonly nint _cipher = NCUtilCipher.Alloc(ctx, (uint)version, (uint)flags);
+
+ private NoscryptMessageCipher(NCContext ctx, nint cipher, NoscryptCipherVersion version)
+ : base(ownsHandle: true)
+ {
+ SetHandle(cipher);
+ _context = ctx;
+ _version = version;
+ }
+
+ /// <summary>
+ /// Allocates and initializes a new cipher instance using the specified
+ /// </summary>
+ /// <param name="context">A reference to the noscrypt library context</param>
+ /// <param name="version">The encryption standard to use</param>
+ /// <param name="flags">The raw cipher flags to the pass to the cipher initialization function</param>
+ /// <returns>A new <see cref="NoscryptMessageCipher"/> instance</returns>
+ public static NoscryptMessageCipher Create(NCContext context, NoscryptCipherVersion version, NoscryptCipherFlags flags)
+ {
+ return new(
+ context,
+ NCCipherUtil.Alloc(context, (uint)version, (uint)flags),
+ version
+ );
+ }
/// <summary>
/// The cipher standard version used by this instance
/// </summary>
- public NoscryptCipherVersion Version => version;
+ public NoscryptCipherVersion Version => _version;
/// <summary>
/// Gets the flags set for the cipher instance
/// </summary>
- public uint GetFlags() => NCUtilCipher.GetFlags(ctx, _cipher);
+ public uint GetFlags() => NCCipherUtil.GetFlags(_context, handle);
/// <summary>
/// Gets the cipher's initilaization vector size (or nonce)
/// </summary>
/// <returns>The size of the IV in bytes</returns>
- public int GetIvSize() => NCUtilCipher.GetIvSize(ctx, _cipher);
+ public int GetIvSize() => NCCipherUtil.GetIvSize(_context, handle);
/// <summary>
/// Gets the internal heap buffer that holds the cipher's initalization
@@ -121,9 +148,9 @@ namespace VNLib.Utils.Cryptography.Noscrypt.Encryption
fixed (byte* inputPtr = &inputData)
{
- NCUtilCipher.InitCipher(ctx, _cipher, inputPtr, inputSize);
+ NCCipherUtil.InitCipher(_context, handle, inputPtr, inputSize);
- NCUtilCipher.Update(ctx, _cipher, in localKey, in remoteKey);
+ NCCipherUtil.Update(_context, handle, in localKey, in remoteKey);
}
}
@@ -153,7 +180,7 @@ namespace VNLib.Utils.Cryptography.Noscrypt.Encryption
/// Gets the size of the output buffer required to read the cipher output
/// </summary>
/// <returns>The size of the output in bytes</returns>
- public int GetOutputSize() => checked((int)NCUtilCipher.GetOutputSize(ctx, _cipher));
+ public int GetOutputSize() => checked((int)NCCipherUtil.GetOutputSize(_context, handle));
/// <summary>
/// Reads the output data from the cipher into the specified buffer
@@ -166,7 +193,7 @@ namespace VNLib.Utils.Cryptography.Noscrypt.Encryption
{
ArgumentOutOfRangeException.ThrowIfLessThan(size, GetOutputSize());
- return checked((int)NCUtilCipher.ReadOutput(ctx, _cipher, ref outputData, (uint)size));
+ return checked((int)NCCipherUtil.ReadOutput(_context, handle, ref outputData, (uint)size));
}
/// <summary>
@@ -186,7 +213,7 @@ namespace VNLib.Utils.Cryptography.Noscrypt.Encryption
private IMemoryHandle<byte> AllocIvBuffer()
{
//Use the context heap to allocate the internal iv buffer
- MemoryHandle<byte> buffer = MemoryUtil.SafeAlloc<byte>(ctx.Heap, GetIvSize(), zero: true);
+ MemoryHandle<byte> buffer = MemoryUtil.SafeAlloc<byte>(_context.Heap, GetIvSize(), zero: true);
try
{
@@ -199,9 +226,9 @@ namespace VNLib.Utils.Cryptography.Noscrypt.Encryption
* buffer is required so we don't need to pin managed memory
* nor worry about the GC moving the buffer.
*/
- NCUtilCipher.SetProperty(
- ctx,
- _cipher,
+ NCCipherUtil.SetProperty(
+ _context,
+ DangerousGetHandle(),
NC_ENC_SET_IV,
ref buffer.GetReference(),
(uint)buffer.Length
@@ -217,10 +244,12 @@ namespace VNLib.Utils.Cryptography.Noscrypt.Encryption
}
///<inheritdoc/>
- protected override void Free()
+ protected override bool ReleaseHandle()
{
- NCUtilCipher.Free(ctx, _cipher);
+ NCCipherUtil.Free(_context, handle);
_ivBuffer?.Dispose();
+
+ return true;
}
}
diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/INostrCrypto.cs b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/INostrCrypto.cs
deleted file mode 100644
index 9b4d36c..0000000
--- a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/INostrCrypto.cs
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright (C) 2024 Vaughn Nugent
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as
-// published by the Free Software Foundation, either version 3 of the
-// License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-using System;
-
-using VNLib.Utils.Cryptography.Noscrypt.Encryption;
-
-namespace VNLib.Utils.Cryptography.Noscrypt
-{
- public interface INostrCrypto
- {
-
- /// <summary>
- /// Gets a nostr public key from a secret key.
- /// </summary>
- /// <param name="secretKey">A reference to the secret key to get the public key from</param>
- /// <param name="publicKey">A reference to the public key structure to write the recovered key to</param>
- /// <exception cref="ArgumentException"></exception>
- /// <exception cref="ArgumentNullException"></exception>
- void GetPublicKey(ref readonly NCSecretKey secretKey, ref NCPublicKey publicKey);
-
- /// <summary>
- /// Validates a secret key is in a valid format.
- /// </summary>
- /// <param name="secretKey">A readonly reference to key structure to validate</param>
- /// <returns>True if the key is consiered valid against the secp256k1 curve</returns>
- /// <exception cref="ArgumentException"></exception>
- /// <exception cref="ArgumentNullException"></exception>
- bool ValidateSecretKey(ref readonly NCSecretKey secretKey);
-
- /// <summary>
- /// Allocates a new cipher instance with the supplied options.
- /// </summary>
- /// <param name="version">The cipher specification version</param>
- /// <param name="flags">The cipher initialziation flags</param>
- /// <returns>The cipher instance</returns>
- NoscryptCipher AllocCipher(NoscryptCipherVersion version, NoscryptCipherFlags flags);
-
- /// <summary>
- /// Signs the supplied data with the secret key and random32 nonce, then writes
- /// the message signature to the supplied sig64 buffer.
- /// </summary>
- /// <param name="secretKey">The secret key used to sign the message</param>
- /// <param name="random32">A highly secure random nonce used to seed the signature</param>
- /// <param name="data">A pointer to the first byte in the message to sign</param>
- /// <param name="dataSize">The size of the message in bytes</param>
- /// <param name="sig64">A pointer to the first byte of a 64 byte buffer used to write the message signature to</param>
- /// <exception cref="ArgumentException"></exception>
- /// <exception cref="ArgumentNullException"></exception>
- void SignData(
- ref readonly NCSecretKey secretKey,
- ref readonly byte random32,
- ref readonly byte data,
- uint dataSize,
- ref byte sig64
- );
-
- /// <summary>
- /// Performs cryptographic verification of the supplied data
- /// against the supplied public key.
- /// </summary>
- /// <param name="pubKey">The signer's public key</param>
- /// <param name="data">A pointer to the first byte in the message to sign</param>
- /// <param name="dataSize">The number of bytes in the message</param>
- /// <param name="sig64">A pointer to the signature buffer</param>
- /// <returns>True if the signature could be verified against the public key. False otherwise</returns>
- /// <exception cref="ArgumentException"></exception>
- /// <exception cref="ArgumentNullException"></exception>
- bool VerifyData(
- ref readonly NCPublicKey pubKey,
- ref readonly byte data,
- uint dataSize,
- ref readonly byte sig64
- );
- }
-}
diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NCUtil.cs b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NCKeyUtil.cs
index 307bbc1..50e1c9a 100644
--- a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NCUtil.cs
+++ b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NCKeyUtil.cs
@@ -14,18 +14,21 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
using System;
-using System.Reflection;
-using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+using VNLib.Utils.Extensions;
+using VNLib.Utils.Cryptography.Noscrypt.@internal;
using static VNLib.Utils.Cryptography.Noscrypt.NoscryptLibrary;
using NCResult = System.Int64;
namespace VNLib.Utils.Cryptography.Noscrypt
{
-
- public static class NCUtil
+ /// <summary>
+ /// Contains utility methods for working with nostr keys
+ /// </summary>
+ public static unsafe class NCKeyUtil
{
/// <summary>
/// Gets a span of bytes from the current secret key
@@ -115,79 +118,68 @@ namespace VNLib.Utils.Cryptography.Noscrypt
return ref Unsafe.As<byte, NCPublicKey>(ref asBytes);
}
- internal static void CheckResult<T>(NCResult result, bool raiseOnFailure) where T : Delegate
+ /// <summary>
+ /// Gets a nostr public key from a secret key.
+ /// </summary>
+ /// <param name="secretKey">A reference to the secret key to get the public key from</param>
+ /// <param name="publicKey">A reference to the public key structure to write the recovered key to</param>
+ /// <exception cref="ArgumentException"></exception>
+ /// <exception cref="ArgumentNullException"></exception>
+ public static void GetPublicKey(
+ NCContext context,
+ ref readonly NCSecretKey secretKey,
+ ref NCPublicKey publicKey
+ )
{
- //Only negative values are errors
- if (result >= NC_SUCCESS)
- {
- return;
- }
-
- NCResult asPositive = -result;
+ Check(context);
- // Error code are only 8 bits, if an argument error occured, the
- // argument number will be in the next upper 8 bits
- NCErrorCodes errorCode = (NCErrorCodes)(asPositive & 0xFF);
- byte argNumber = (byte)((asPositive >> 8) & 0xFF);
-
- switch (errorCode)
+ fixed (NCSecretKey* pSecKey = &secretKey)
+ fixed (NCPublicKey* pPubKey = &publicKey)
{
- case NCErrorCodes.E_NULL_PTR:
- RaiseNullArgExceptionForArgumentNumber<T>(argNumber);
- break;
- case NCErrorCodes.E_INVALID_ARG:
- RaiseArgExceptionForArgumentNumber<T>(argNumber);
- break;
- case NCErrorCodes.E_ARGUMENT_OUT_OF_RANGE:
- RaiseOORExceptionForArgumentNumber<T>(argNumber);
- break;
- case NCErrorCodes.E_INVALID_CTX:
- throw new InvalidOperationException("The library context object is null or invalid");
- case NCErrorCodes.E_OPERATION_FAILED:
- RaiseOperationFailedException(raiseOnFailure);
- break;
- case NCErrorCodes.E_VERSION_NOT_SUPPORTED:
- throw new NotSupportedException("The requested version is not supported");
-
- default:
- if(raiseOnFailure)
- {
- throw new InvalidOperationException($"The operation failed with error, code: {errorCode} for arugment {argNumber:x}");
- }
- break;
+ NCResult result = GetTable(context).NCGetPublicKey(
+ context.DangerousGetHandle(),
+ pSecKey,
+ pPubKey
+ );
+
+ NCUtil.CheckResult<FunctionTable.NCGetPublicKeyDelegate>(result, raiseOnFailure: true);
}
}
- private static void RaiseOperationFailedException(bool raise)
+ /// <summary>
+ /// Validates a secret key is in a valid format.
+ /// </summary>
+ /// <param name="secretKey">A readonly reference to key structure to validate</param>
+ /// <returns>True if the key is consiered valid against the secp256k1 curve</returns>
+ /// <exception cref="ArgumentException"></exception>
+ /// <exception cref="ArgumentNullException"></exception>
+ public static bool ValidateSecretKey(
+ NCContext context,
+ ref readonly NCSecretKey secretKey
+ )
{
- if (raise)
+ Check(context);
+
+ fixed (NCSecretKey* pSecKey = &secretKey)
{
- throw new InvalidOperationException("The operation failed for an unknown reason");
- }
- }
+ NCResult result = GetTable(context).NCValidateSecretKey(
+ context.DangerousGetHandle(),
+ pSecKey
+ );
- private static void RaiseNullArgExceptionForArgumentNumber<T>(int argNumber) where T : Delegate
- {
- //Get delegate parameters
- Type type = typeof(T);
- ParameterInfo arg = type.GetMethod("Invoke")!.GetParameters()[argNumber];
- throw new ArgumentNullException(arg.Name, "Argument is null or invalid cannot continue");
- }
+ NCUtil.CheckResult<FunctionTable.NCValidateSecretKeyDelegate>(result, raiseOnFailure: false);
- private static void RaiseArgExceptionForArgumentNumber<T>(int argNumber) where T : Delegate
- {
- //Get delegate parameters
- Type type = typeof(T);
- ParameterInfo arg = type.GetMethod("Invoke")!.GetParameters()[argNumber];
- throw new ArgumentException("Argument is null or invalid cannot continue", arg.Name);
+ return result == NC_SUCCESS;
+ }
}
- private static void RaiseOORExceptionForArgumentNumber<T>(int argNumber) where T : Delegate
+ private static void Check(NCContext? context)
{
- //Get delegate parameters
- Type type = typeof(T);
- ParameterInfo arg = type.GetMethod("Invoke")!.GetParameters()[argNumber];
- throw new ArgumentOutOfRangeException(arg.Name, "Argument is out of range of acceptable values");
+ ArgumentNullException.ThrowIfNull(context);
+ context.ThrowIfClosed();
}
+
+ private static ref readonly FunctionTable GetTable(NCContext ctx)
+ => ref ctx.Library.Functions;
}
}
diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NoscryptExtensions.cs b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NoscryptExtensions.cs
deleted file mode 100644
index e96ff96..0000000
--- a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NoscryptExtensions.cs
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright (C) 2024 Vaughn Nugent
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as
-// published by the Free Software Foundation, either version 3 of the
-// License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-using System;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-using static VNLib.Utils.Cryptography.Noscrypt.NoscryptLibrary;
-
-namespace VNLib.Utils.Cryptography.Noscrypt
-{
-
- public static class NoscryptExtensions
- {
- public static void SignData(
- this INostrCrypto lib,
- ref readonly NCSecretKey secKey,
- ReadOnlySpan<byte> random32,
- ReadOnlySpan<byte> data,
- Span<byte> signatureBuffer
- )
- {
- ArgumentOutOfRangeException.ThrowIfLessThan(signatureBuffer.Length, NC_SIGNATURE_SIZE, nameof(signatureBuffer));
- ArgumentOutOfRangeException.ThrowIfLessThan(random32.Length, 32, nameof(random32));
- ArgumentOutOfRangeException.ThrowIfZero(data.Length, nameof(data));
-
- lib.SignData(
- secretKey: in secKey,
- random32: in MemoryMarshal.GetReference(random32),
- data: in MemoryMarshal.GetReference(data),
- dataSize: (uint)data.Length,
- sig64: ref MemoryMarshal.GetReference(signatureBuffer)
- );
- }
-
-#if DEBUG
- /*
- * Conversation key is not meant to be a public api. Callers
- * should use Encrypt/Decrypt methods to handle encryption.
- *
- * This method exists for vector testing purposes only.
- */
- public static void GetConverstationKey(
- this NostrCrypto lib,
- ref readonly NCSecretKey secretKey,
- ref readonly NCPublicKey publicKey,
- Span<byte> conversationKeyOut32
- )
- {
- ArgumentNullException.ThrowIfNull(lib);
- ArgumentOutOfRangeException.ThrowIfNotEqual(conversationKeyOut32.Length, NC_CONVERSATION_KEY_SIZE, nameof(conversationKeyOut32));
-
- //Get the conversation key
- lib.GetConverstationKey(
- secretKey: in secretKey,
- publicKey: in publicKey,
- key32: ref MemoryMarshal.GetReference(conversationKeyOut32)
- );
-
- }
-#endif
- }
-}
diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NoscryptLibrary.cs b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NoscryptLibrary.cs
index 35c6a49..2df63eb 100644
--- a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NoscryptLibrary.cs
+++ b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NoscryptLibrary.cs
@@ -37,6 +37,7 @@ namespace VNLib.Utils.Cryptography.Noscrypt
public unsafe sealed class NoscryptLibrary(SafeLibraryHandle Library, bool OwnsHandle) : VnDisposeable
{
public const string NoscryptDefaultLibraryName = "noscrypt";
+ public const string NoscryptDllPathEnvName = "NOSCRYPT_DLL_PATH";
//Constant values match the noscrypt.h header
public const int NC_SEC_KEY_SIZE = 0x20;
@@ -172,33 +173,16 @@ namespace VNLib.Utils.Cryptography.Noscrypt
}
/// <summary>
- /// Initializes a new NostrCrypto context wraper directly that owns the internal context.
- /// This may be done once at app startup and is thread-safe for the rest of the
- /// application lifetime.
- /// </summary>
- /// <param name="heap">The heap to allocate the context from</param>
- /// <param name="entropy32">The random entropy data to initialize the context with</param>
- /// <returns>The library wrapper handle</returns>
- public NostrCrypto InitializeCrypto(IUnmangedHeap heap, ReadOnlySpan<byte> entropy32)
- {
- ArgumentNullException.ThrowIfNull(heap);
-
- //Create the crypto interface from the new context object
- return new NostrCrypto(
- context: Initialize(heap, entropy32),
- ownsContext: true
- );
- }
-
- /// <summary>
- /// Initializes a new NostrCrypto context wraper directly that owns the internal context.
- /// This may be done once at app startup and is thread-safe for the rest of the
- /// application lifetime.
+ /// Initialize a new NCContext for use. This may be done once at app startup
+ /// and is thread-safe for the rest of the application lifetime.
/// </summary>
- /// <param name="heap">The heap to allocate the context from</param>
- /// <param name="random">Random source used to generate context entropy</param>
- /// <returns>The library wrapper handle</returns>
- public NostrCrypto InitializeCrypto(IUnmangedHeap heap, IRandomSource random)
+ /// <param name="heap"></param>
+ /// <param name="enropy32">The 32byte random seed/nonce for the noscrypt context</param>
+ /// <returns>The inialized context</returns>
+ /// <exception cref="OutOfMemoryException"></exception>
+ /// <exception cref="ArgumentNullException"></exception>
+ /// <exception cref="ArgumentOutOfRangeException"></exception>
+ public NCContext Initialize(IUnmangedHeap heap, IRandomSource random)
{
ArgumentNullException.ThrowIfNull(random);
@@ -206,13 +190,9 @@ namespace VNLib.Utils.Cryptography.Noscrypt
Span<byte> entropy = stackalloc byte[NC_CTX_ENTROPY_SIZE];
random.GetRandomBytes(entropy);
- NostrCrypto nc = InitializeCrypto(heap, entropy);
-
- MemoryUtil.InitializeBlock(entropy);
-
- return nc;
+ return Initialize(heap, entropy);
}
-
+
///<inheritdoc/>
protected override void Free()
{
@@ -256,6 +236,16 @@ namespace VNLib.Utils.Cryptography.Noscrypt
/// </summary>
/// <returns>The loaded library instance</returns>
/// <exception cref="DllNotFoundException"></exception>
- public static NoscryptLibrary LoadDefault() => Load(NoscryptDefaultLibraryName, DllImportSearchPath.SafeDirectories);
+ public static NoscryptLibrary LoadDefault()
+ {
+ string? libPath = Environment.GetEnvironmentVariable(NoscryptDllPathEnvName);
+ libPath ??= NoscryptDefaultLibraryName;
+
+ Console.WriteLine("Loading library {0}", libPath);
+
+ libPath = libPath.Replace("\"", "");
+
+ return Load(libPath);
+ }
}
}
diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NostrCrypto.cs b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NostrCrypto.cs
deleted file mode 100644
index 1e833d2..0000000
--- a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NostrCrypto.cs
+++ /dev/null
@@ -1,167 +0,0 @@
-// Copyright (C) 2024 Vaughn Nugent
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as
-// published by the Free Software Foundation, either version 3 of the
-// License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-using System;
-using System.Runtime.CompilerServices;
-using System.Diagnostics.CodeAnalysis;
-
-using VNLib.Utils.Cryptography.Noscrypt.@internal;
-using VNLib.Utils.Cryptography.Noscrypt.Encryption;
-using static VNLib.Utils.Cryptography.Noscrypt.NoscryptLibrary;
-
-using NCResult = System.Int64;
-
-namespace VNLib.Utils.Cryptography.Noscrypt
-{
- /// <summary>
- /// A default implementation of the <see cref="INostrCrypto"/> interface
- /// </summary>
- /// <param name="context">The initialized library context</param>
- public unsafe class NostrCrypto(NCContext context, bool ownsContext) : VnDisposeable, INostrCrypto
- {
- /// <summary>
- /// Gets the underlying library context.
- /// </summary>
- public NCContext Context => context;
-
- private ref readonly FunctionTable Functions => ref context.Library.Functions;
-
- ///<inheritdoc/>
- public NoscryptCipher AllocCipher(NoscryptCipherVersion version, NoscryptCipherFlags flags) => new (context, version, flags);
-
- ///<inheritdoc/>
- public void GetPublicKey(ref readonly NCSecretKey secretKey, ref NCPublicKey publicKey)
- {
- Check();
-
- fixed (NCSecretKey* pSecKey = &secretKey)
- fixed (NCPublicKey* pPubKey = &publicKey)
- {
- NCResult result = Functions.NCGetPublicKey.Invoke(context.DangerousGetHandle(), pSecKey, pPubKey);
- NCUtil.CheckResult<FunctionTable.NCGetPublicKeyDelegate>(result, true);
- }
- }
-
- ///<inheritdoc/>
- public void SignData(
- ref readonly NCSecretKey secretKey,
- ref readonly byte random32,
- ref readonly byte data,
- uint dataSize,
- ref byte sig64
- )
- {
- Check();
-
- fixed (NCSecretKey* pSecKey = &secretKey)
- fixed (byte* pData = &data, pSig = &sig64, pRandom = &random32)
- {
- NCResult result = Functions.NCSignData.Invoke(
- ctx: context.DangerousGetHandle(),
- sk: pSecKey,
- random32: pRandom,
- data: pData,
- dataSize,
- sig64: pSig
- );
-
- NCUtil.CheckResult<FunctionTable.NCSignDataDelegate>(result, true);
- }
- }
-
- ///<inheritdoc/>
- public bool ValidateSecretKey(ref readonly NCSecretKey secretKey)
- {
- Check();
-
- IntPtr libCtx = context.DangerousGetHandle();
-
- fixed (NCSecretKey* pSecKey = &secretKey)
- {
- /*
- * Validate should return a result of 1 if the secret key is valid
- * or a 0 if it is not.
- */
- NCResult result = Functions.NCValidateSecretKey.Invoke(libCtx, pSecKey);
- NCUtil.CheckResult<FunctionTable.NCValidateSecretKeyDelegate>(result, false);
-
- return result == NC_SUCCESS;
- }
- }
-
- ///<inheritdoc/>
- public bool VerifyData(
- ref readonly NCPublicKey pubKey,
- ref readonly byte data,
- uint dataSize,
- ref readonly byte sig64
- )
- {
- Check();
-
- fixed(NCPublicKey* pPubKey = &pubKey)
- fixed (byte* pData = &data, pSig = &sig64)
- {
- NCResult result = Functions.NCVerifyData.Invoke(context.DangerousGetHandle(), pPubKey, pData, dataSize, pSig);
- NCUtil.CheckResult<FunctionTable.NCVerifyDataDelegate>(result, false);
-
- return result == NC_SUCCESS;
- }
- }
-
-#if DEBUG
-
- /// <summary>
- /// DEBUG ONLY: Gets the conversation key for the supplied secret key and public key
- /// </summary>
- /// <param name="secretKey">The sender's private key</param>
- /// <param name="publicKey">The receiver's public key</param>
- /// <param name="key32">A pointer to the 32byte buffer to write the conversation key to</param>
- public void GetConverstationKey(
- ref readonly NCSecretKey secretKey,
- ref readonly NCPublicKey publicKey,
- ref byte key32
- )
- {
- Check();
-
- fixed (NCSecretKey* pSecKey = &secretKey)
- fixed (NCPublicKey* pPubKey = &publicKey)
- fixed (byte* pKey = &key32)
- {
- NCResult result = Functions.NCGetConversationKey.Invoke(context.DangerousGetHandle(), pSecKey, pPubKey, pKey);
- NCUtil.CheckResult<FunctionTable.NCGetConversationKeyDelegate>(result, true);
- }
- }
-
-#endif
- ///<inheritdoc/>
- protected override void Free()
- {
- if(ownsContext)
- {
- context.Dispose();
- }
- }
-
- private static void ThrowIfNullRef([DoesNotReturnIf(false)] ref readonly byte value, string name)
- {
- if(Unsafe.IsNullRef(in value))
- {
- throw new ArgumentNullException(name);
- }
- }
- }
-}
diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Singatures/NCSignatureUtil.cs b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Singatures/NCSignatureUtil.cs
new file mode 100644
index 0000000..2755ceb
--- /dev/null
+++ b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Singatures/NCSignatureUtil.cs
@@ -0,0 +1,175 @@
+// Copyright (C) 2024 Vaughn Nugent
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+using System;
+using System.Runtime.InteropServices;
+
+using VNLib.Utils.Extensions;
+using VNLib.Utils.Cryptography.Noscrypt.@internal;
+using static VNLib.Utils.Cryptography.Noscrypt.NoscryptLibrary;
+
+using NCResult = System.Int64;
+
+namespace VNLib.Utils.Cryptography.Noscrypt.Singatures
+{
+
+ /// <summary>
+ /// Contains utility methods for signing and verifying data using the noscrypt library
+ /// </summary>
+ public unsafe static class NCSignatureUtil
+ {
+ /// <summary>
+ /// Signs the data using the supplied secret key and
+ /// entropy pointer
+ /// </summary>
+ /// <param name="context">The initialized context memory to pass to the library</param>
+ /// <param name="secretKey">A reference to a structure containing the private key data</param>
+ /// <param name="random32">A pointer to a 32 byte buffer containing high entropy random data</param>
+ /// <param name="data">A pointer to a buffer containing the data to sign</param>
+ /// <param name="dataSize">The size of the data buffer in bytes</param>
+ /// <param name="sig64">A pointer to a 64 byte buffer to write signature data to</param>
+ /// <exception cref="InvalidOperationException"></exception>
+ public static void SignData(
+ NCContext context,
+ ref readonly NCSecretKey secretKey,
+ ref readonly byte random32,
+ ref readonly byte data,
+ uint dataSize,
+ ref byte sig64
+ )
+ {
+ Check(context);
+
+ fixed (NCSecretKey* pSecKey = &secretKey)
+ fixed (byte* pData = &data, pSig = &sig64, pRandom = &random32)
+ {
+ NCResult result = GetTable(context).NCSignData(
+ ctx: context.DangerousGetHandle(),
+ sk: pSecKey,
+ random32: pRandom,
+ data: pData,
+ dataSize,
+ sig64: pSig
+ );
+
+ NCUtil.CheckResult<FunctionTable.NCSignDataDelegate>(result, raiseOnFailure: true);
+ }
+ }
+
+ /// <summary>
+ /// Verifies signed data against the supplied public key
+ /// </summary>
+ /// <param name="context">The initialized context memory to pass to the library</param>
+ /// <param name="publicKey">A reference to a structure containing the public key data</param>
+ /// <param name="data">A pointer to a buffer containing the data to verify</param>
+ /// <param name="dataSize">The size of the data buffer in bytes</param>
+ /// <param name="sig64">A pointer to a 64 byte buffer to read signature data from</param>
+ /// <returns>True if the signature was signed by the supplied public key, false otherwise</returns>
+ public static bool VerifyData(
+ NCContext context,
+ ref readonly NCPublicKey publicKey,
+ ref readonly byte data,
+ uint dataSize,
+ ref readonly byte sig64
+ )
+ {
+ Check(context);
+
+ fixed (NCPublicKey* pPubKey = &publicKey)
+ fixed (byte* pData = &data, pSig = &sig64)
+ {
+ NCResult result = GetTable(context).NCVerifyData(
+ context.DangerousGetHandle(),
+ pk: pPubKey,
+ data: pData,
+ dataSize,
+ sig64: pSig
+ );
+
+ NCUtil.CheckResult<FunctionTable.NCVerifyDataDelegate>(result, false);
+
+ return result == NC_SUCCESS;
+ }
+ }
+
+ /// <summary>
+ /// Signs the data using the supplied secret key and
+ /// entropy pointer
+ /// </summary>
+ /// <param name="context">The initialized context memory to pass to the library</param>
+ /// <param name="secretKey">A reference to a structure containing the private key data</param>
+ /// <param name="random32">A pointer to a 32 byte buffer containing high entropy random data</param>
+ /// <param name="data">A pointer to a buffer containing the data to sign</param>
+ /// <param name="signatureBuffer">A pointer to a 64 byte buffer to write signature data to</param>
+ /// <exception cref="InvalidOperationException"></exception>
+ public static void SignData(
+ NCContext context,
+ ref readonly NCSecretKey secretKey,
+ ReadOnlySpan<byte> random32,
+ ReadOnlySpan<byte> data,
+ Span<byte> signatureBuffer
+ )
+ {
+ ArgumentOutOfRangeException.ThrowIfLessThan(signatureBuffer.Length, NC_SIGNATURE_SIZE, nameof(signatureBuffer));
+ ArgumentOutOfRangeException.ThrowIfLessThan(random32.Length, 32, nameof(random32));
+ ArgumentOutOfRangeException.ThrowIfZero(data.Length, nameof(data));
+
+ SignData(
+ context,
+ secretKey: in secretKey,
+ random32: in MemoryMarshal.GetReference(random32),
+ data: in MemoryMarshal.GetReference(data),
+ dataSize: (uint)data.Length,
+ sig64: ref MemoryMarshal.GetReference(signatureBuffer)
+ );
+ }
+
+ /// <summary>
+ /// Verifies signed data against the supplied public key
+ /// </summary>
+ /// <param name="context">The initialized context memory to pass to the library</param>
+ /// <param name="publicKey">A reference to a structure containing the public key data</param>
+ /// <param name="data">A pointer to a buffer containing the data to verify</param>
+ /// <param name="signatureBuffer">A pointer to a 64 byte buffer to read signature data from</param>
+ /// <returns>True if the signature was signed by the supplied public key, false otherwise</returns>
+ public static bool VerifyData(
+ NCContext context,
+ ref readonly NCPublicKey publicKey,
+ ReadOnlySpan<byte> data,
+ ReadOnlySpan<byte> signatureBuffer
+ )
+ {
+ ArgumentOutOfRangeException.ThrowIfLessThan(signatureBuffer.Length, NC_SIGNATURE_SIZE, nameof(signatureBuffer));
+ ArgumentOutOfRangeException.ThrowIfZero(data.Length, nameof(data));
+
+ return VerifyData(
+ context,
+ publicKey: in publicKey,
+ data: in MemoryMarshal.GetReference(data),
+ dataSize: (uint)data.Length,
+ sig64: ref MemoryMarshal.GetReference(signatureBuffer)
+ );
+ }
+
+ private static void Check(NCContext? context)
+ {
+ ArgumentNullException.ThrowIfNull(context);
+ context.ThrowIfClosed();
+ }
+
+ private static ref readonly FunctionTable GetTable(NCContext ctx)
+ => ref ctx.Library.Functions;
+ }
+}
diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NoscryptSigner.cs b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Singatures/NoscryptSigner.cs
index c81790b..063d2c0 100644
--- a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NoscryptSigner.cs
+++ b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Singatures/NoscryptSigner.cs
@@ -14,21 +14,23 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
using System;
-using VNLib.Utils.Cryptography.Noscrypt.Random;
-using VNLib.Utils.Extensions;
-using VNLib.Utils.Memory;
+using VNLib.Utils.Memory;
+using VNLib.Utils.Extensions;
+using VNLib.Utils.Cryptography.Noscrypt;
+using VNLib.Utils.Cryptography.Noscrypt.Random;
using static VNLib.Utils.Cryptography.Noscrypt.NoscryptLibrary;
-namespace VNLib.Utils.Cryptography.Noscrypt
+namespace VNLib.Utils.Cryptography.Noscrypt.Singatures
{
+
/// <summary>
/// A simple wrapper class to sign nostr message data using
/// the noscrypt library
/// </summary>
/// <param name="noscrypt">The noscrypt library instance</param>
/// <param name="random">A random entropy pool used to source random data for signature entropy</param>
- public class NoscryptSigner(INostrCrypto noscrypt, IRandomSource random)
+ public class NoscryptSigner(NCContext context, IRandomSource random)
{
/// <summary>
/// Gets the size of the buffer required to hold the signature
@@ -72,12 +74,16 @@ namespace VNLib.Utils.Cryptography.Noscrypt
/// <exception cref="ArgumentException"></exception>
/// <exception cref="ArgumentOutOfRangeException"></exception>
public string SignData(
- ReadOnlySpan<byte> secretKey,
- ReadOnlySpan<byte> message,
+ ReadOnlySpan<byte> secretKey,
+ ReadOnlySpan<byte> message,
INostrSignatureEncoder? format = null
)
{
- return SignData(in NCUtil.AsSecretKey(secretKey), message, format);
+ return SignData(
+ in NCKeyUtil.AsSecretKey(secretKey),
+ message,
+ format
+ );
}
/// <summary>
@@ -90,8 +96,8 @@ namespace VNLib.Utils.Cryptography.Noscrypt
/// <exception cref="ArgumentException"></exception>
/// <exception cref="ArgumentOutOfRangeException"></exception>
public string SignData(
- ref readonly NCSecretKey secretkey,
- ReadOnlySpan<byte> message,
+ ref readonly NCSecretKey secretkey,
+ ReadOnlySpan<byte> message,
INostrSignatureEncoder? format = null
)
{
@@ -115,8 +121,8 @@ namespace VNLib.Utils.Cryptography.Noscrypt
/// <exception cref="ArgumentException"></exception>
/// <exception cref="ArgumentOutOfRangeException"></exception>
public void SignData(
- ref readonly NCSecretKey secretkey,
- ReadOnlySpan<byte> data,
+ ref readonly NCSecretKey secretkey,
+ ReadOnlySpan<byte> data,
Span<byte> signature
)
{
@@ -126,7 +132,35 @@ namespace VNLib.Utils.Cryptography.Noscrypt
Span<byte> entropy = stackalloc byte[NC_SIG_ENTROPY_SIZE];
random.GetRandomBytes(entropy);
- noscrypt.SignData(in secretkey, entropy, data, signature);
+ NCSignatureUtil.SignData(
+ context,
+ in secretkey,
+ entropy,
+ data,
+ signature
+ );
+ }
+
+ public bool VerifyData(
+ ReadOnlySpan<byte> publicKey,
+ ReadOnlySpan<byte> data,
+ ReadOnlySpan<byte> sig
+ )
+ {
+ return VerifyData(
+ in NCKeyUtil.AsPublicKey(publicKey),
+ data,
+ sig
+ );
+ }
+
+ public bool VerifyData(
+ ref readonly NCPublicKey pk,
+ ReadOnlySpan<byte> data,
+ ReadOnlySpan<byte> sig
+ )
+ {
+ return NCSignatureUtil.VerifyData(context, in pk, data, sig);
}
}
diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/VNLib.Utils.Cryptography.Noscrypt.csproj b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/VNLib.Utils.Cryptography.Noscrypt.csproj
index 4d1868c..29a4b8f 100644
--- a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/VNLib.Utils.Cryptography.Noscrypt.csproj
+++ b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/VNLib.Utils.Cryptography.Noscrypt.csproj
@@ -1,5 +1,5 @@
<Project Sdk="Microsoft.NET.Sdk">
-
+
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
@@ -9,7 +9,7 @@
<RootNamespace>VNLib.Utils.Cryptography.Noscrypt</RootNamespace>
<AssemblyName>VNLib.Utils.Cryptography.Noscrypt</AssemblyName>
</PropertyGroup>
-
+
<PropertyGroup>
<Authors>Vaughn Nugent</Authors>
<Company>Vaughn Nugent</Company>
@@ -19,10 +19,22 @@
<PackageProjectUrl>https://www.vaughnnugent.com/resources/software/modules/Noscrypt</PackageProjectUrl>
<RepositoryUrl>https://github.com/VnUgE/noscryot/tree/master/dotnet/VNLib.Utils.Cryptography.Noscrypt</RepositoryUrl>
</PropertyGroup>
-
+
<ItemGroup>
- <PackageReference Include="VNLib.Hashing.Portable" Version="0.1.0-ci0124" />
- <PackageReference Include="VNLib.Utils" Version="0.1.0-ci0124" />
+ <None Include="..\README.md">
+ <Pack>True</Pack>
+ <PackagePath>\</PackagePath>
+ </None>
+ <None Include="..\..\..\..\LICENSE">
+ <Pack>True</Pack>
+ <PackagePath>\</PackagePath>
+ <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+ </None>
</ItemGroup>
-
+
+ <ItemGroup>
+ <PackageReference Include="VNLib.Hashing.Portable" Version="0.1.0-ci0202" />
+ <PackageReference Include="VNLib.Utils" Version="0.1.0-ci0202" />
+ </ItemGroup>
+
</Project>
diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/internal/FunctionTable.cs b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/internal/FunctionTable.cs
index 0cda5e2..269ae4d 100644
--- a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/internal/FunctionTable.cs
+++ b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/internal/FunctionTable.cs
@@ -119,7 +119,7 @@ namespace VNLib.Utils.Cryptography.Noscrypt.@internal
internal delegate NCResult NCSignDataDelegate(IntPtr ctx, NCSecretKey* sk, byte* random32, byte* data, uint dataSize, byte* sig64);
[SafeMethodName("NCVerifyData")]
- internal delegate NCResult NCVerifyDataDelegate(IntPtr ctx, NCPublicKey* sk, byte* data, uint dataSize, byte* sig64);
+ internal delegate NCResult NCVerifyDataDelegate(IntPtr ctx, NCPublicKey* pk, byte* data, uint dataSize, byte* sig64);
[SafeMethodName("NCGetConversationKey")]
internal delegate NCResult NCGetConversationKeyDelegate(IntPtr ctx, NCSecretKey* sk, NCPublicKey* pk, byte* keyOut32);
diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/internal/NCUtil.cs b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/internal/NCUtil.cs
new file mode 100644
index 0000000..16f46c6
--- /dev/null
+++ b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/internal/NCUtil.cs
@@ -0,0 +1,104 @@
+// Copyright (C) 2024 Vaughn Nugent
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+using System;
+using System.Reflection;
+using static VNLib.Utils.Cryptography.Noscrypt.NoscryptLibrary;
+
+using NCResult = System.Int64;
+
+namespace VNLib.Utils.Cryptography.Noscrypt.@internal
+{
+
+ public static class NCUtil
+ {
+
+
+ internal static void CheckResult<T>(NCResult result, bool raiseOnFailure) where T : Delegate
+ {
+ //Only negative values are errors
+ if (result >= NC_SUCCESS)
+ {
+ return;
+ }
+
+ NCResult asPositive = -result;
+
+ // Error code are only 8 bits, if an argument error occured, the
+ // argument number will be in the next upper 8 bits
+ NCErrorCodes errorCode = (NCErrorCodes)(asPositive & 0xFF);
+ byte argNumber = (byte)(asPositive >> 8 & 0xFF);
+
+ switch (errorCode)
+ {
+ case NCErrorCodes.E_NULL_PTR:
+ RaiseNullArgExceptionForArgumentNumber<T>(argNumber);
+ break;
+ case NCErrorCodes.E_INVALID_ARG:
+ RaiseArgExceptionForArgumentNumber<T>(argNumber);
+ break;
+ case NCErrorCodes.E_ARGUMENT_OUT_OF_RANGE:
+ RaiseOORExceptionForArgumentNumber<T>(argNumber);
+ break;
+ case NCErrorCodes.E_INVALID_CTX:
+ throw new InvalidOperationException("The library context object is null or invalid");
+ case NCErrorCodes.E_OPERATION_FAILED:
+ RaiseOperationFailedException(raiseOnFailure);
+ break;
+ case NCErrorCodes.E_VERSION_NOT_SUPPORTED:
+ throw new NotSupportedException("The requested version is not supported");
+
+ default:
+ if (raiseOnFailure)
+ {
+ throw new InvalidOperationException($"The operation failed with error, code: {errorCode} for arugment {argNumber:x}");
+ }
+ break;
+ }
+ }
+
+ private static void RaiseOperationFailedException(bool raise)
+ {
+ if (raise)
+ {
+ throw new InvalidOperationException("The operation failed for an unknown reason");
+ }
+ }
+
+ private static void RaiseNullArgExceptionForArgumentNumber<T>(int argNumber) where T : Delegate
+ {
+ //Get delegate parameters
+ Type type = typeof(T);
+ ParameterInfo arg = type.GetMethod("Invoke")!.GetParameters()[argNumber];
+ throw new ArgumentNullException(arg.Name, "Argument is null or invalid cannot continue");
+ }
+
+ private static void RaiseArgExceptionForArgumentNumber<T>(int argNumber) where T : Delegate
+ {
+ //Get delegate parameters
+ Type type = typeof(T);
+ ParameterInfo arg = type.GetMethod("Invoke")!.GetParameters()[argNumber];
+ throw new ArgumentException("Argument is null or invalid cannot continue", arg.Name);
+ }
+
+ private static void RaiseOORExceptionForArgumentNumber<T>(int argNumber) where T : Delegate
+ {
+ //Get delegate parameters
+ Type type = typeof(T);
+ ParameterInfo arg = type.GetMethod("Invoke")!.GetParameters()[argNumber];
+ throw new ArgumentOutOfRangeException(arg.Name, "Argument is out of range of acceptable values");
+ }
+ }
+}
diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/tests/LibNoscryptTests.cs b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/tests/LibNoscryptTests.cs
index ffa9cb6..b8d9623 100644
--- a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/tests/LibNoscryptTests.cs
+++ b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/tests/LibNoscryptTests.cs
@@ -1,25 +1,15 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
-using System;
-using System.Text;
-using System.Text.Json;
-
using VNLib.Hashing;
using VNLib.Utils.Memory;
-using VNLib.Utils.Extensions;
-using VNLib.Utils.Cryptography.Noscrypt.Encryption;
using VNLib.Utils.Cryptography.Noscrypt.Random;
+using VNLib.Utils.Cryptography.Noscrypt.Singatures;
namespace VNLib.Utils.Cryptography.Noscrypt.Tests
{
[TestClass()]
public class LibNoscryptTests : IDisposable
{
-
- const string NoscryptLibWinDebug = @"../../../../../../../build/windows/Debug/noscrypt.dll";
- const string NoscryptLinuxDebug = @"../../../../../../../build/linux/libnoscrypt.so";
-
-
//Keys generated using npx noskey package
const string TestPrivateKeyHex = "98c642360e7163a66cee5d9a842b252345b6f3f3e21bd3b7635d5e6c20c7ea36";
const string TestPublicKeyHex = "0db15182c4ad3418b4fbab75304be7ade9cfa430a21c1c5320c9298f54ea5406";
@@ -27,56 +17,40 @@ namespace VNLib.Utils.Cryptography.Noscrypt.Tests
const string TestPrivateKeyHex2 = "3032cb8da355f9e72c9a94bbabae80ca99d3a38de1aed094b432a9fe3432e1f2";
const string TestPublicKeyHex2 = "421181660af5d39eb95e48a0a66c41ae393ba94ffeca94703ef81afbed724e5a";
- const string Nip44VectorTestFile = "nip44.vectors.json";
-
#nullable disable
private NoscryptLibrary _testLib;
- private JsonDocument _testVectors;
#nullable enable
[TestInitialize]
public void Initialize()
{
- _testLib = Environment.OSVersion.Platform switch
- {
- PlatformID.Win32NT => NoscryptLibrary.Load(NoscryptLibWinDebug),
- PlatformID.Unix => NoscryptLibrary.Load(NoscryptLinuxDebug),
- _ => throw new PlatformNotSupportedException()
- };
-
- _testVectors = JsonDocument.Parse(File.ReadAllText(Nip44VectorTestFile));
+ _testLib = NoscryptLibrary.LoadDefault();
}
-
[TestMethod()]
public void InitializeTest()
{
- //Random context seed
- ReadOnlySpan<byte> seed = RandomHash.GetRandomBytes(32);
-
//Init new context and interface
- NCContext context = _testLib.Initialize(MemoryUtil.Shared, seed);
-
- using NostrCrypto crypto = new(context, true);
+ using NCContext context = _testLib.Initialize(MemoryUtil.Shared, NCFallbackRandom.Shared);
}
[TestMethod()]
public void ValidateSecretKeyTest()
{
//Random context seed
- ReadOnlySpan<byte> seed = RandomHash.GetRandomBytes(32);
ReadOnlySpan<byte> secretKey = RandomHash.GetRandomBytes(32);
Span<byte> publicKey = stackalloc byte[32];
- using NostrCrypto crypto = _testLib.InitializeCrypto(MemoryUtil.Shared, seed);
+ using NCContext context = _testLib.Initialize(MemoryUtil.Shared, NCFallbackRandom.Shared);
//validate the secret key
- Assert.IsTrue(crypto.ValidateSecretKey(in NCUtil.AsSecretKey(secretKey)));
+ Assert.IsTrue(NCKeyUtil.ValidateSecretKey(context, in NCKeyUtil.AsSecretKey(secretKey)));
//Generate the public key
- crypto.GetPublicKey(
- in NCUtil.AsSecretKey(secretKey),
- ref NCUtil.AsPublicKey(publicKey)
+ NCKeyUtil.GetPublicKey(
+ context,
+ in NCKeyUtil.AsSecretKey(secretKey),
+ ref NCKeyUtil.AsPublicKey(publicKey)
);
//Make sure the does not contain all zeros
@@ -86,33 +60,31 @@ namespace VNLib.Utils.Cryptography.Noscrypt.Tests
[TestMethod()]
public void TestGetPublicKey()
{
- //Random context seed
- ReadOnlySpan<byte> seed = RandomHash.GetRandomBytes(32);
-
- using NostrCrypto crypto = _testLib.InitializeCrypto(MemoryUtil.Shared, seed);
+ using NCContext context = _testLib.Initialize(MemoryUtil.Shared, NCFallbackRandom.Shared);
//Test known key 1
TestKnownKeys(
- crypto,
+ context,
Convert.FromHexString(TestPrivateKeyHex),
Convert.FromHexString(TestPublicKeyHex)
);
//Test known key 2
TestKnownKeys(
- crypto,
+ context,
Convert.FromHexString(TestPrivateKeyHex2),
Convert.FromHexString(TestPublicKeyHex2)
);
- static void TestKnownKeys(NostrCrypto lib, ReadOnlySpan<byte> knownSec, ReadOnlySpan<byte> kownPub)
+ static void TestKnownKeys(NCContext context, ReadOnlySpan<byte> knownSec, ReadOnlySpan<byte> kownPub)
{
NCPublicKey pubKey;
//Invoke test function
- lib.GetPublicKey(
- in NCUtil.AsSecretKey(knownSec),
+ NCKeyUtil.GetPublicKey(
+ context,
+ in NCKeyUtil.AsSecretKey(knownSec),
ref pubKey
);
@@ -125,176 +97,104 @@ namespace VNLib.Utils.Cryptography.Noscrypt.Tests
[TestMethod()]
public void TestPublicApiArgValidations()
{
- //Random context seed
- ReadOnlySpan<byte> seed = RandomHash.GetRandomBytes(32);
-
- using NostrCrypto crypto = _testLib.InitializeCrypto(MemoryUtil.Shared, seed);
+ using NCContext context = _testLib.Initialize(MemoryUtil.Shared, NCFallbackRandom.Shared);
+ byte[] bin16 = new byte[16];
+ byte[] bin32 = new byte[32];
+ byte[] bin64 = new byte[64];
NCSecretKey secKey = default;
NCPublicKey pubKey = default;
//noThrow (its a bad sec key but it should not throw)
- crypto.ValidateSecretKey(ref secKey);
- Assert.ThrowsException<ArgumentNullException>(() => crypto.ValidateSecretKey(ref NCSecretKey.NullRef));
+ NCKeyUtil.ValidateSecretKey(context, in secKey);
+ Assert.ThrowsException<ArgumentNullException>(() => NCKeyUtil.ValidateSecretKey(null!, ref NCSecretKey.NullRef));
+ Assert.ThrowsException<ArgumentNullException>(() => NCKeyUtil.ValidateSecretKey(context, ref NCSecretKey.NullRef));
//public key
- Assert.ThrowsException<ArgumentNullException>(() => crypto.GetPublicKey(ref NCSecretKey.NullRef, ref pubKey));
- Assert.ThrowsException<ArgumentNullException>(() => crypto.GetPublicKey(in secKey, ref NCPublicKey.NullRef));
- }
-
- [TestMethod()]
- public void CorrectEncryptionTest()
- {
- using NostrCrypto nc = _testLib.InitializeCrypto(MemoryUtil.Shared, RandomHash.GetRandomBytes(32));
-
- using NoscryptCipher cipher = nc.AllocCipher(NoscryptCipherVersion.Nip44, NoscryptCipherFlags.EncryptDefault);
-
- using IMemoryHandle<byte> ctBuffer = MemoryUtil.SafeAllocNearestPage(1200, false);
-
- foreach (EncryptionVector v in GetEncryptionVectors())
- {
-
- ReadOnlySpan<byte> secKey1 = Convert.FromHexString(v.sec1);
- ReadOnlySpan<byte> secKey2 = Convert.FromHexString(v.sec2);
- ReadOnlySpan<byte> plainText = Encoding.UTF8.GetBytes(v.plaintext);
- ReadOnlySpan<byte> nonce = Convert.FromHexString(v.nonce);
- ReadOnlySpan<byte> message = Convert.FromBase64String(v.payload);
-
- NCPublicKey pub2;
-
- //Recover public keys
- nc.GetPublicKey(in NCUtil.AsSecretKey(secKey2), ref pub2);
-
- //Assign existing nonce
- nonce.CopyTo(cipher.IvBuffer);
-
- cipher.Update(
- in NCUtil.AsSecretKey(secKey1),
- in pub2,
- plainText
- );
-
- Span<byte> outputBuffer = ctBuffer.AsSpan(0, cipher.GetOutputSize());
-
- Assert.AreEqual<int>(cipher.ReadOutput(outputBuffer), message.Length);
-
- //Make sure the cipher text matches the expected payload
- if (!outputBuffer.SequenceEqual(message))
- {
- Console.WriteLine($"Input data: {v.plaintext}");
- Console.WriteLine($" \n{Convert.ToHexString(outputBuffer)}\n{Convert.ToHexString(message)}");
- Assert.Fail($"Cipher text does not match expected message");
- }
- }
- }
-
- [TestMethod()]
- public void CorrectDecryptionTest()
- {
- using NostrCrypto nc = _testLib.InitializeCrypto(MemoryUtil.Shared, NCFallbackRandom.Shared);
-
- using NoscryptCipher msgCipher = nc.AllocCipher(NoscryptCipherVersion.Nip44, NoscryptCipherFlags.DecryptDefault);
-
- using IMemoryHandle<byte> ptBuffer = MemoryUtil.SafeAllocNearestPage(1200, false);
-
- foreach (EncryptionVector vector in GetEncryptionVectors())
- {
- ReadOnlySpan<byte> secKey1 = Convert.FromHexString(vector.sec1);
- ReadOnlySpan<byte> secKey2 = Convert.FromHexString(vector.sec2);
- ReadOnlySpan<byte> expectedPt = Encoding.UTF8.GetBytes(vector.plaintext);
- ReadOnlySpan<byte> message = Convert.FromBase64String(vector.payload);
-
- NCPublicKey pub2 = default;
+ Assert.ThrowsException<ArgumentNullException>(() => NCKeyUtil.GetPublicKey(null!, in secKey, ref pubKey));
+ Assert.ThrowsException<ArgumentNullException>(() => NCKeyUtil.GetPublicKey(context, ref NCSecretKey.NullRef, ref pubKey));
+ Assert.ThrowsException<ArgumentNullException>(() => NCKeyUtil.GetPublicKey(context, in secKey, ref NCPublicKey.NullRef));
+
+ /*
+ * VERIFY DATA
+ */
+ //Null context
+ Assert.ThrowsException<ArgumentNullException>(() =>
+ NCSignatureUtil.VerifyData(null!, ref pubKey, bin32, bin64)
+ );
- //Recover public keys
- nc.GetPublicKey(in NCUtil.AsSecretKey(secKey2), ref pub2);
+ //Null pubkey
+ Assert.ThrowsException<ArgumentNullException>(() =>
+ NCSignatureUtil.VerifyData(context, ref NCPublicKey.NullRef, bin32, bin64)
+ );
- //update performs the decryption operation (mac is also verified by default)
- msgCipher.Update(
- in NCUtil.AsSecretKey(secKey1),
- in pub2,
- message
- );
+ //No data buffer
+ Assert.ThrowsException<ArgumentOutOfRangeException>(() =>
+ NCSignatureUtil.VerifyData(context, ref pubKey, [], bin64)
+ );
- int outLen = msgCipher.GetOutputSize();
- Assert.IsTrue(outLen == expectedPt.Length);
+ //No signature
+ Assert.ThrowsException<ArgumentOutOfRangeException>(() =>
+ NCSignatureUtil.VerifyData(context, ref pubKey, bin32, [])
+ );
- Span<byte> plaintext = ptBuffer.AsSpan(0, outLen);
+ //Signature too small
+ Assert.ThrowsException<ArgumentOutOfRangeException>(() =>
+ NCSignatureUtil.VerifyData(context, ref pubKey, bin32, bin32)
+ );
- msgCipher.ReadOutput(plaintext);
+ /*
+ * SIGN DATA
+ */
- if (!plaintext.SequenceEqual(expectedPt))
- {
- Console.WriteLine($"Input data: {vector.plaintext}");
- Console.WriteLine($" \n{Convert.ToHexString(plaintext)}\n{Convert.ToHexString(expectedPt)}");
- Assert.Fail("Decrypted data does not match expected plaintext");
- }
- }
- }
+ //Null context
+ Assert.ThrowsException<ArgumentNullException>(() =>
+ NCSignatureUtil.SignData(null!, ref secKey, bin32, bin32, bin64)
+ );
+ //Null secret key
+ Assert.ThrowsException<ArgumentNullException>(() =>
+ NCSignatureUtil.SignData(context, ref NCSecretKey.NullRef, bin32, bin32, bin64)
+ );
- //Converstation key is only available in debug builds
-#if DEBUG
+ //No entropy
+ Assert.ThrowsException<ArgumentOutOfRangeException>(() =>
+ NCSignatureUtil.SignData(context, ref secKey, [], bin32, bin64)
+ );
- [TestMethod()]
- public void ConverstationKeyTest()
- {
- using NostrCrypto nc = _testLib.InitializeCrypto(MemoryUtil.Shared, RandomHash.GetRandomBytes(32));
-
- Span<byte> convKeyOut = stackalloc byte[32];
+ //No data
+ Assert.ThrowsException<ArgumentOutOfRangeException>(() =>
+ NCSignatureUtil.SignData(context, ref secKey, bin32, [], bin64)
+ );
- foreach (EncryptionVector v in GetEncryptionVectors())
- {
- ReadOnlySpan<byte> secKey1 = Convert.FromHexString(v.sec1);
- ReadOnlySpan<byte> secKey2 = Convert.FromHexString(v.sec2);
- ReadOnlySpan<byte> conversationKey = Convert.FromHexString(v.conversation_key);
+ //No signature
+ Assert.ThrowsException<ArgumentOutOfRangeException>(() =>
+ NCSignatureUtil.SignData(context, ref secKey, bin32, bin32, [])
+ );
- NCPublicKey pubkey2 = default;
- nc.GetPublicKey(in NCUtil.AsSecretKey(secKey2), ref pubkey2);
+ //Signature too small
+ Assert.ThrowsException<ArgumentOutOfRangeException>(() =>
+ NCSignatureUtil.SignData(context, ref secKey, bin32, bin32, bin32)
+ );
- nc.GetConverstationKey(
- in NCUtil.AsSecretKey(secKey1),
- in pubkey2,
- convKeyOut
- );
+ //Entropy too small
+ Assert.ThrowsException<ArgumentOutOfRangeException>(() =>
+ NCSignatureUtil.SignData(context, ref secKey, bin16, bin32, bin32)
+ );
- Assert.IsTrue(conversationKey.SequenceEqual(convKeyOut));
+ /*
+ * Cipher api
+ */
- MemoryUtil.InitializeBlock(convKeyOut);
- }
- }
-#endif
+ NoscryptSigner signer = new(context, NCFallbackRandom.Shared);
- private EncryptionVector[] GetEncryptionVectors()
- {
- return _testVectors.RootElement.GetProperty("v2")
- .GetProperty("valid")
- .GetProperty("encrypt_decrypt")
- .EnumerateArray()
- .Select(v => v.Deserialize<EncryptionVector>()!)
- .ToArray();
+
}
void IDisposable.Dispose()
{
_testLib.Dispose();
- _testVectors.Dispose();
GC.SuppressFinalize(this);
}
-
- private sealed class EncryptionVector
- {
- public string sec1 { get; set; } = string.Empty;
-
- public string sec2 { get; set; } = string.Empty;
-
- public string nonce { get; set; } = string.Empty;
-
- public string plaintext { get; set; } = string.Empty;
-
- public string payload { get; set; } = string.Empty;
-
- public string conversation_key { get; set; } = string.Empty;
- }
}
}
diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/tests/NoscryptVectorTests.cs b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/tests/NoscryptVectorTests.cs
new file mode 100644
index 0000000..1a2f5d2
--- /dev/null
+++ b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/tests/NoscryptVectorTests.cs
@@ -0,0 +1,185 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+using System;
+using System.Text;
+using System.Text.Json;
+using VNLib.Utils.Memory;
+using VNLib.Utils.Extensions;
+using VNLib.Utils.Cryptography.Noscrypt.Encryption;
+using VNLib.Utils.Cryptography.Noscrypt.Random;
+
+namespace VNLib.Utils.Cryptography.Noscrypt.Tests
+{
+
+ [TestClass()]
+ public class NoscryptVectorTests : IDisposable
+ {
+ const string Nip44VectorTestFile = "nip44.vectors.json";
+
+#nullable disable
+ private NoscryptLibrary _testLib;
+ private JsonDocument _testVectors;
+#nullable enable
+
+ [TestInitialize]
+ public void Initialize()
+ {
+ _testLib = NoscryptLibrary.LoadDefault();
+ _testVectors = JsonDocument.Parse(File.ReadAllText(Nip44VectorTestFile));
+ }
+
+ [TestMethod()]
+ public void CorrectEncryptionTest()
+ {
+ using NCContext context = _testLib.Initialize(MemoryUtil.Shared, NCFallbackRandom.Shared);
+ using NoscryptMessageCipher cipher = NoscryptMessageCipher.Create(context, NoscryptCipherVersion.Nip44, NoscryptCipherFlags.EncryptDefault);
+
+ using IMemoryHandle<byte> ctBuffer = MemoryUtil.SafeAllocNearestPage(1200, false);
+
+ foreach (EncryptionVector v in GetEncryptionVectors())
+ {
+
+ ReadOnlySpan<byte> secKey1 = Convert.FromHexString(v.sec1);
+ ReadOnlySpan<byte> secKey2 = Convert.FromHexString(v.sec2);
+ ReadOnlySpan<byte> plainText = Encoding.UTF8.GetBytes(v.plaintext);
+ ReadOnlySpan<byte> nonce = Convert.FromHexString(v.nonce);
+ ReadOnlySpan<byte> message = Convert.FromBase64String(v.payload);
+
+ NCPublicKey pub2;
+
+ //Recover public keys
+ NCKeyUtil.GetPublicKey(context, in NCKeyUtil.AsSecretKey(secKey2), ref pub2);
+
+ //Assign existing nonce
+ nonce.CopyTo(cipher.IvBuffer);
+
+ cipher.Update(
+ in NCKeyUtil.AsSecretKey(secKey1),
+ in pub2,
+ plainText
+ );
+
+ Span<byte> outputBuffer = ctBuffer.AsSpan(0, cipher.GetOutputSize());
+
+ Assert.AreEqual<int>(cipher.ReadOutput(outputBuffer), message.Length);
+
+ //Make sure the cipher text matches the expected payload
+ if (!outputBuffer.SequenceEqual(message))
+ {
+ Console.WriteLine($"Input data: {v.plaintext}");
+ Console.WriteLine($" \n{Convert.ToHexString(outputBuffer)}\n{Convert.ToHexString(message)}");
+ Assert.Fail($"Cipher text does not match expected message");
+ }
+ }
+ }
+
+ [TestMethod()]
+ public void CorrectDecryptionTest()
+ {
+ using NCContext context = _testLib.Initialize(MemoryUtil.Shared, NCFallbackRandom.Shared);
+ using NoscryptMessageCipher msgCipher = NoscryptMessageCipher.Create(context, NoscryptCipherVersion.Nip44, NoscryptCipherFlags.DecryptDefault);
+
+ using IMemoryHandle<byte> ptBuffer = MemoryUtil.SafeAllocNearestPage(1200, false);
+
+ foreach (EncryptionVector vector in GetEncryptionVectors())
+ {
+ ReadOnlySpan<byte> secKey1 = Convert.FromHexString(vector.sec1);
+ ReadOnlySpan<byte> secKey2 = Convert.FromHexString(vector.sec2);
+ ReadOnlySpan<byte> expectedPt = Encoding.UTF8.GetBytes(vector.plaintext);
+ ReadOnlySpan<byte> message = Convert.FromBase64String(vector.payload);
+
+ NCPublicKey pub2 = default;
+
+ //Recover public keys
+ NCKeyUtil.GetPublicKey(context, in NCKeyUtil.AsSecretKey(secKey2), ref pub2);
+
+ //update performs the decryption operation (mac is also verified by default)
+ msgCipher.Update(
+ in NCKeyUtil.AsSecretKey(secKey1),
+ in pub2,
+ message
+ );
+
+ int outLen = msgCipher.GetOutputSize();
+ Assert.IsTrue(outLen == expectedPt.Length);
+
+ Span<byte> plaintext = ptBuffer.AsSpan(0, outLen);
+
+ msgCipher.ReadOutput(plaintext);
+
+ if (!plaintext.SequenceEqual(expectedPt))
+ {
+ Console.WriteLine($"Input data: {vector.plaintext}");
+ Console.WriteLine($" \n{Convert.ToHexString(plaintext)}\n{Convert.ToHexString(expectedPt)}");
+ Assert.Fail("Decrypted data does not match expected plaintext");
+ }
+ }
+ }
+
+
+ //Converstation key is only available in debug builds
+#if DEBUG
+
+ [TestMethod()]
+ public void ConverstationKeyTest()
+ {
+ using NCContext context = _testLib.Initialize(MemoryUtil.Shared, NCFallbackRandom.Shared);
+
+ Span<byte> convKeyOut = stackalloc byte[32];
+
+ foreach (EncryptionVector v in GetEncryptionVectors())
+ {
+ ReadOnlySpan<byte> secKey1 = Convert.FromHexString(v.sec1);
+ ReadOnlySpan<byte> secKey2 = Convert.FromHexString(v.sec2);
+ ReadOnlySpan<byte> conversationKey = Convert.FromHexString(v.conversation_key);
+
+ NCPublicKey pubkey2 = default;
+ NCKeyUtil.GetPublicKey(context, in NCKeyUtil.AsSecretKey(secKey2), ref pubkey2);
+
+ NCCipherUtil.GetConverstationKey(
+ context,
+ in NCKeyUtil.AsSecretKey(secKey1),
+ in pubkey2,
+ convKeyOut
+ );
+
+ Assert.IsTrue(conversationKey.SequenceEqual(convKeyOut));
+
+ MemoryUtil.InitializeBlock(convKeyOut);
+ }
+ }
+#endif
+
+ private EncryptionVector[] GetEncryptionVectors()
+ {
+ return _testVectors.RootElement.GetProperty("v2")
+ .GetProperty("valid")
+ .GetProperty("encrypt_decrypt")
+ .EnumerateArray()
+ .Select(v => v.Deserialize<EncryptionVector>()!)
+ .ToArray();
+ }
+
+ void IDisposable.Dispose()
+ {
+ _testLib.Dispose();
+ _testVectors.Dispose();
+ GC.SuppressFinalize(this);
+ }
+
+ private sealed class EncryptionVector
+ {
+ public string sec1 { get; set; } = string.Empty;
+
+ public string sec2 { get; set; } = string.Empty;
+
+ public string nonce { get; set; } = string.Empty;
+
+ public string plaintext { get; set; } = string.Empty;
+
+ public string payload { get; set; } = string.Empty;
+
+ public string conversation_key { get; set; } = string.Empty;
+ }
+ }
+}
diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/tests/NVault.Crypto.NoscryptTests.csproj b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/tests/VNLib.Utils.Cryptography.NoscryptTests.csproj
index 5917b15..a4542a6 100644
--- a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/tests/NVault.Crypto.NoscryptTests.csproj
+++ b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/tests/VNLib.Utils.Cryptography.NoscryptTests.csproj
@@ -1,32 +1,30 @@
-<Project Sdk="Microsoft.NET.Sdk">
-
+<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
-
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
+ <AssemblyVersion>0.2.0.0</AssemblyVersion>
+ <FileVersion>0.2.0.0</FileVersion>
+ <InformationalVersion>0.2.0-c-sharp.95+Branch.c-sharp.Sha.6a4a464d9fdc7821cd5c5695656a3fe385497cc5</InformationalVersion>
+ <Version>0.2.0-c-sharp0095</Version>
</PropertyGroup>
-
<ItemGroup>
- <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
- <PackageReference Include="MSTest.TestAdapter" Version="3.4.1" />
- <PackageReference Include="MSTest.TestFramework" Version="3.4.1" />
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
+ <PackageReference Include="MSTest.TestAdapter" Version="3.6.1" />
+ <PackageReference Include="MSTest.TestFramework" Version="3.6.1" />
<PackageReference Include="coverlet.collector" Version="6.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
-
<ItemGroup>
<ProjectReference Include="..\src\VNLib.Utils.Cryptography.Noscrypt.csproj" />
</ItemGroup>
-
<ItemGroup>
<None Update="nip44.vectors.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
-
-</Project>
+</Project> \ No newline at end of file