// 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);
}
}
}