// 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 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
{
///
/// Contains utility methods for working with nostr keys
///
public static unsafe class NCKeyUtil
{
///
/// Gets a span of bytes from the current secret key
/// structure
///
///
/// The secret key data span
public unsafe static Span AsSpan(this ref NCSecretKey key)
{
//Safe to cast secret key to bytes, then we can make a span to its memory
ref byte asBytes = ref Unsafe.As(ref key);
return MemoryMarshal.CreateSpan(ref asBytes, sizeof(NCSecretKey));
}
///
/// Gets a span of bytes from the current public key
/// structure
///
///
/// The public key data as a data span
public unsafe static Span AsSpan(this ref NCPublicKey key)
{
//Safe to cast secret key to bytes, then we can make a span to its memory
ref byte asBytes = ref Unsafe.As(ref key);
return MemoryMarshal.CreateSpan(ref asBytes, sizeof(NCPublicKey));
}
///
/// Casts a span of bytes to a secret key reference. Note that
/// the new structure reference will point to the same memory
/// as the span.
///
/// The secret key data
/// A mutable secret key reference
///
public unsafe static ref NCSecretKey AsSecretKey(Span span)
{
ArgumentOutOfRangeException.ThrowIfLessThan(span.Length, sizeof(NCSecretKey), nameof(span));
ref byte asBytes = ref MemoryMarshal.GetReference(span);
return ref Unsafe.As(ref asBytes);
}
///
/// Casts a span of bytes to a public key reference. Note that
/// the new structure reference will point to the same memory
/// as the span.
///
/// The public key data span
/// A mutable reference to the public key structure
///
public unsafe static ref NCPublicKey AsPublicKey(Span span)
{
ArgumentOutOfRangeException.ThrowIfLessThan(span.Length, sizeof(NCPublicKey), nameof(span));
ref byte asBytes = ref MemoryMarshal.GetReference(span);
return ref Unsafe.As(ref asBytes);
}
///
/// Casts a read-only span of bytes to a secret key reference. Note that
/// the new structure reference will point to the same memory as the span.
///
/// The secret key data span
/// A readonly refernce to the secret key structure
///
public unsafe static ref readonly NCSecretKey AsSecretKey(ReadOnlySpan span)
{
ArgumentOutOfRangeException.ThrowIfLessThan(span.Length, sizeof(NCSecretKey), nameof(span));
ref byte asBytes = ref MemoryMarshal.GetReference(span);
return ref Unsafe.As(ref asBytes);
}
///
/// Casts a read-only span of bytes to a public key reference. Note that
/// the new structure reference will point to the same memory as the span.
///
/// The public key data span
/// A readonly reference to the public key structure
///
public unsafe static ref readonly NCPublicKey AsPublicKey(ReadOnlySpan span)
{
ArgumentOutOfRangeException.ThrowIfLessThan(span.Length, sizeof(NCPublicKey), nameof(span));
ref byte asBytes = ref MemoryMarshal.GetReference(span);
return ref Unsafe.As(ref asBytes);
}
///
/// Gets a nostr public key from a secret key.
///
/// A reference to the secret key to get the public key from
/// A reference to the public key structure to write the recovered key to
///
///
public static void GetPublicKey(
NCContext context,
ref readonly NCSecretKey secretKey,
ref NCPublicKey publicKey
)
{
Check(context);
fixed (NCSecretKey* pSecKey = &secretKey)
fixed (NCPublicKey* pPubKey = &publicKey)
{
NCResult result = GetTable(context).NCGetPublicKey(
context.DangerousGetHandle(),
pSecKey,
pPubKey
);
NCUtil.CheckResult(result, raiseOnFailure: true);
}
}
///
/// Validates a secret key is in a valid format.
///
/// A readonly reference to key structure to validate
/// True if the key is consiered valid against the secp256k1 curve
///
///
public static bool ValidateSecretKey(
NCContext context,
ref readonly NCSecretKey secretKey
)
{
Check(context);
fixed (NCSecretKey* pSecKey = &secretKey)
{
NCResult result = GetTable(context).NCValidateSecretKey(
context.DangerousGetHandle(),
pSecKey
);
NCUtil.CheckResult(result, raiseOnFailure: false);
return result == NC_SUCCESS;
}
}
private static void Check(NCContext? context)
{
ArgumentNullException.ThrowIfNull(context);
context.ThrowIfClosed();
}
private static ref readonly FunctionTable GetTable(NCContext ctx)
=> ref ctx.Library.Functions;
}
}