From 44044eb0fb28b774773e3284fd147c91d59d64e3 Mon Sep 17 00:00:00 2001 From: vnugent Date: Fri, 18 Oct 2024 22:10:17 -0400 Subject: refactor: Wire up unit testing and refactor c# api --- .../src/Singatures/NCSignatureUtil.cs | 175 +++++++++++++++++++++ .../src/Singatures/NoscryptSigner.cs | 167 ++++++++++++++++++++ 2 files changed, 342 insertions(+) create mode 100644 wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Singatures/NCSignatureUtil.cs create mode 100644 wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Singatures/NoscryptSigner.cs (limited to 'wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Singatures') 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 . + +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 +{ + + /// + /// Contains utility methods for signing and verifying data using the noscrypt library + /// + public unsafe static class NCSignatureUtil + { + /// + /// Signs the data using the supplied secret key and + /// entropy pointer + /// + /// The initialized context memory to pass to the library + /// A reference to a structure containing the private key data + /// A pointer to a 32 byte buffer containing high entropy random data + /// A pointer to a buffer containing the data to sign + /// The size of the data buffer in bytes + /// A pointer to a 64 byte buffer to write signature data to + /// + 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(result, raiseOnFailure: true); + } + } + + /// + /// Verifies signed data against the supplied public key + /// + /// The initialized context memory to pass to the library + /// A reference to a structure containing the public key data + /// A pointer to a buffer containing the data to verify + /// The size of the data buffer in bytes + /// A pointer to a 64 byte buffer to read signature data from + /// True if the signature was signed by the supplied public key, false otherwise + 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(result, false); + + return result == NC_SUCCESS; + } + } + + /// + /// Signs the data using the supplied secret key and + /// entropy pointer + /// + /// The initialized context memory to pass to the library + /// A reference to a structure containing the private key data + /// A pointer to a 32 byte buffer containing high entropy random data + /// A pointer to a buffer containing the data to sign + /// A pointer to a 64 byte buffer to write signature data to + /// + public static void SignData( + NCContext context, + ref readonly NCSecretKey secretKey, + ReadOnlySpan random32, + ReadOnlySpan data, + Span 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) + ); + } + + /// + /// Verifies signed data against the supplied public key + /// + /// The initialized context memory to pass to the library + /// A reference to a structure containing the public key data + /// A pointer to a buffer containing the data to verify + /// A pointer to a 64 byte buffer to read signature data from + /// True if the signature was signed by the supplied public key, false otherwise + public static bool VerifyData( + NCContext context, + ref readonly NCPublicKey publicKey, + ReadOnlySpan data, + ReadOnlySpan 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/Singatures/NoscryptSigner.cs b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Singatures/NoscryptSigner.cs new file mode 100644 index 0000000..063d2c0 --- /dev/null +++ b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Singatures/NoscryptSigner.cs @@ -0,0 +1,167 @@ +// 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 . + +using System; + +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.Singatures +{ + + /// + /// A simple wrapper class to sign nostr message data using + /// the noscrypt library + /// + /// The noscrypt library instance + /// A random entropy pool used to source random data for signature entropy + public class NoscryptSigner(NCContext context, IRandomSource random) + { + /// + /// Gets the size of the buffer required to hold the signature + /// + public static int SignatureBufferSize => NC_SIGNATURE_SIZE; + + /// + /// Signs a message using the specified private key and message data + /// + /// The hexadecimal private key used to sign the message + /// The message data to sign + /// A encoder used to convert the signature data to an encoded string + /// The string encoded nostr signature + /// + /// + public string SignData(string hexPrivateKey, ReadOnlySpan message, INostrSignatureEncoder? format = null) + { + ArgumentException.ThrowIfNullOrWhiteSpace(hexPrivateKey); + ArgumentOutOfRangeException.ThrowIfNotEqual(hexPrivateKey.Length / 2, NC_SEC_KEY_SIZE, nameof(hexPrivateKey)); + + //Have to allocate array unfortunately + byte[] privKey = Convert.FromHexString(hexPrivateKey); + try + { + return SignData(privKey.AsSpan(), message, format); + } + finally + { + //Always zero key beofre leaving + MemoryUtil.InitializeBlock(privKey); + } + } + + /// + /// Signs a message using the specified secret key and message data + /// + /// The secret key data buffer + /// The message data to sign + /// A encoder used to convert the signature data to an encoded string + /// The string encoded nostr signature + /// + /// + public string SignData( + ReadOnlySpan secretKey, + ReadOnlySpan message, + INostrSignatureEncoder? format = null + ) + { + return SignData( + in NCKeyUtil.AsSecretKey(secretKey), + message, + format + ); + } + + /// + /// Signs a message using the specified secret key and message data + /// + /// A reference to the secret key structurer + /// The message data to sign + /// A encoder used to convert the signature data to an encoded string + /// The string encoded nostr signature + /// + /// + public string SignData( + ref readonly NCSecretKey secretkey, + ReadOnlySpan message, + INostrSignatureEncoder? format = null + ) + { + //Default to hex encoding because that is the default NIP-01 format + format ??= HexSignatureEncoder.Instance; + + Span sigBuffer = stackalloc byte[SignatureBufferSize]; + + SignData(message, sigBuffer); + + return format.GetString(sigBuffer); + } + + + /// + /// Signs a message using the specified secret key and message data + /// + /// A reference to the secret key structurer + /// The message data to sign + /// A buffer to write signature data to + /// + /// + public void SignData( + ref readonly NCSecretKey secretkey, + ReadOnlySpan data, + Span signature + ) + { + ArgumentOutOfRangeException.ThrowIfLessThan(signature.Length, NC_SIGNATURE_SIZE, nameof(signature)); + + //Signature generation required random entropy to be secure + Span entropy = stackalloc byte[NC_SIG_ENTROPY_SIZE]; + random.GetRandomBytes(entropy); + + NCSignatureUtil.SignData( + context, + in secretkey, + entropy, + data, + signature + ); + } + + public bool VerifyData( + ReadOnlySpan publicKey, + ReadOnlySpan data, + ReadOnlySpan sig + ) + { + return VerifyData( + in NCKeyUtil.AsPublicKey(publicKey), + data, + sig + ); + } + + public bool VerifyData( + ref readonly NCPublicKey pk, + ReadOnlySpan data, + ReadOnlySpan sig + ) + { + return NCSignatureUtil.VerifyData(context, in pk, data, sig); + } + } + +} -- cgit