// 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.Extensions; using VNLib.Utils.Memory; using static VNLib.Utils.Cryptography.Noscrypt.NoscryptLibrary; namespace VNLib.Utils.Cryptography.Noscrypt { /// /// 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(INostrCrypto noscrypt, 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 NCUtil.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); noscrypt.SignData(in secretkey, entropy, data, signature); } } }