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