diff options
Diffstat (limited to 'back-end/libs/NVault.Crypto.Secp256k1/src/ContextExtensions.cs')
-rw-r--r-- | back-end/libs/NVault.Crypto.Secp256k1/src/ContextExtensions.cs | 274 |
1 files changed, 0 insertions, 274 deletions
diff --git a/back-end/libs/NVault.Crypto.Secp256k1/src/ContextExtensions.cs b/back-end/libs/NVault.Crypto.Secp256k1/src/ContextExtensions.cs deleted file mode 100644 index bb014df..0000000 --- a/back-end/libs/NVault.Crypto.Secp256k1/src/ContextExtensions.cs +++ /dev/null @@ -1,274 +0,0 @@ -// 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 <https://www.gnu.org/licenses/>. - -using System; -using System.Security.Cryptography; -using System.Runtime.InteropServices; - -using VNLib.Hashing; -using VNLib.Utils; -using VNLib.Utils.Memory; -using VNLib.Utils.Extensions; - -using static NVault.Crypto.Secp256k1.LibSecp256k1; - -namespace NVault.Crypto.Secp256k1 -{ - /// <summary> - /// The callback function signature required for ECDH hash functions - /// </summary> - /// <param name="state">The callback state</param> - /// <returns>The return value to be passed as a result of the operation</returns> - public delegate int Secp256k1EcdhHashFunc(in Secp256HashFuncState state); - - public static unsafe class ContextExtensions - { - /// <summary> - /// Signs a 32byte message digest with the specified secret key on the current context and writes the signature to the specified buffer - /// </summary> - /// <param name="context"></param> - /// <param name="secretKey">The 32byte secret key used to sign messages from the user</param> - /// <param name="digest">The 32byte message digest to compute the signature of</param> - /// <param name="signature">The buffer to write the signature output to, must be at-least 64 bytes</param> - /// <returns>The number of bytes written to the signature buffer, or less than 1 if the operation failed</returns> - public static ERRNO SchnorSignDigest(this in Secp256k1Context context, ReadOnlySpan<byte> secretKey, ReadOnlySpan<byte> digest, Span<byte> signature) - { - //Check the signature buffer size - if (signature.Length < SignatureSize) - { - return ERRNO.E_FAIL; - } - - //Message digest must be exactly 32 bytes long - if (digest.Length != (int)HashAlg.SHA256) - { - return ERRNO.E_FAIL; - } - - //Secret key size must be exactly the size of the secret key struct - if(secretKey.Length != sizeof(Secp256k1SecretKey)) - { - return ERRNO.E_FAIL; - } - - //Stack allocated keypair - KeyPair keyPair = new(); - - //Init the secret key struct from key data - Secp256k1SecretKey secKeyStruct = MemoryMarshal.Read<Secp256k1SecretKey>(secretKey); - - //Randomize the context and create the keypair - if (!context.CreateKeyPair(&keyPair, &secKeyStruct)) - { - return ERRNO.E_FAIL; - } - - //Create the random nonce - byte* random = stackalloc byte[RandomBufferSize]; - - //Fill the buffer with random bytes - context.Lib.GetRandomBytes(new Span<byte>(random, RandomBufferSize)); - - try - { - fixed (byte* sigPtr = &MemoryMarshal.GetReference(signature), - digestPtr = &MemoryMarshal.GetReference(digest)) - { - //Sign the message hash and write the output to the signature buffer - if (context.Lib._signHash(context.Context, sigPtr, digestPtr, &keyPair, random) != 1) - { - return ERRNO.E_FAIL; - } - } - } - finally - { - //Erase entropy - MemoryUtil.InitializeBlock(random, RandomBufferSize); - - //Clear the keypair, contains the secret key, even if its stack allocated - MemoryUtil.ZeroStruct(&keyPair); - } - - //Signature size is always 64 bytes - return SignatureSize; - } - - /// <summary> - /// Generates an x-only Schnor encoded public key from the specified secret key on the - /// current context and writes it to the specified buffer. - /// </summary> - /// <param name="context"></param> - /// <param name="secretKey">The 32byte secret key used to derrive the public key from</param> - /// <param name="pubKeyBuffer">The buffer to write the x-only Schnor encoded public key</param> - /// <returns>The number of bytes written to the output buffer, or 0 if the operation failed</returns> - /// <exception cref="CryptographicException"></exception> - public static ERRNO GeneratePubKeyFromSecret(this in Secp256k1Context context, ReadOnlySpan<byte> secretKey, Span<byte> pubKeyBuffer) - { - if (secretKey.Length != sizeof(Secp256k1SecretKey)) - { - throw new CryptographicException($"Your secret key must be exactly {sizeof(Secp256k1SecretKey)} bytes long"); - } - - if (pubKeyBuffer.Length < XOnlyPublicKeySize) - { - throw new CryptographicException($"Your public key buffer must be at least {XOnlyPublicKeySize} bytes long"); - } - - //Protect for released lib - context.Lib.SafeLibHandle.ThrowIfClosed(); - - //Stack allocated keypair and x-only public key - Secp256k1PublicKey xOnlyPubKey = new(); - Secp256k1SecretKey secKeyStruct = MemoryMarshal.Read<Secp256k1SecretKey>(secretKey); - KeyPair keyPair = new(); - - try - { - //Init context and keypair - if (!context.CreateKeyPair(&keyPair, &secKeyStruct)) - { - return ERRNO.E_FAIL; - } - - //X-only public key from the keypair - if (context.Lib._createXonly(context.Context, &xOnlyPubKey, 0, &keyPair) != 1) - { - return ERRNO.E_FAIL; - } - - fixed (byte* pubBuffer = &MemoryMarshal.GetReference(pubKeyBuffer)) - { - //Serialize the public key to the buffer as an X-only public key without leading status byte - if (context.Lib._serializeXonly(context.Context, pubBuffer, &xOnlyPubKey) != 1) - { - return ERRNO.E_FAIL; - } - } - } - finally - { - //Clear the keypair, contains the secret key, even if its stack allocated - MemoryUtil.ZeroStruct(&keyPair); - } - - //PubKey length is constant - return XOnlyPublicKeySize; - } - - /// <summary> - /// Verifies that a given secret key is valid using the current context - /// </summary> - /// <param name="context"></param> - /// <param name="secretKey">The secret key to verify</param> - /// <returns>A boolean value that indicates if the secret key is valid or not</returns> - /// <exception cref="CryptographicException"></exception> - public static bool VerifySecretKey(this in Secp256k1Context context, ReadOnlySpan<byte> secretKey) - { - if (secretKey.Length != sizeof(Secp256k1SecretKey)) - { - throw new CryptographicException($"Your secret key must be exactly {sizeof(Secp256k1SecretKey)} bytes long"); - } - - context.Lib.SafeLibHandle.ThrowIfClosed(); - - //Get sec key ref and verify - fixed(byte* ptr = &MemoryMarshal.GetReference(secretKey)) - { - return context.Lib._secKeyVerify.Invoke(context.Context, ptr) == 1; - } - } - - - [StructLayout(LayoutKind.Sequential)] - private readonly ref struct EcdhHashFuncState - { - public readonly IntPtr HashFunc { get; init; } - public readonly IntPtr Opaque { get; init; } - public readonly int OutLen { get; init; } - } - - /// <summary> - /// Verifies that a given secret key is valid using the current context - /// </summary> - /// <param name="context"></param> - /// <param name="secretKey">The secret key to verify</param> - /// <returns>A boolean value that indicates if the secret key is valid or not</returns> - /// <exception cref="ArgumentException"></exception> - public static bool ComputeSharedKey(this in Secp256k1Context context, Span<byte> data, ReadOnlySpan<byte> xOnlyPubKey, ReadOnlySpan<byte> secretKey, Secp256k1EcdhHashFunc callback, IntPtr opaque) - { - if (secretKey.Length != sizeof(Secp256k1SecretKey)) - { - throw new ArgumentException($"Your secret key buffer must be exactly {sizeof(Secp256k1SecretKey)} bytes long"); - } - - //Init callback state struct - EcdhHashFuncState state = new() - { - HashFunc = Marshal.GetFunctionPointerForDelegate(callback), - Opaque = opaque, - OutLen = data.Length - }; - - context.Lib.SafeLibHandle.ThrowIfClosed(); - - //Stack allocated keypair and x-only public key - Secp256k1PublicKey peerPubKey = new(); - - //Parse the public key from the buffer - fixed (byte* pubkeyPtr = &MemoryMarshal.GetReference(xOnlyPubKey)) - { - context.Lib._xOnlyPubkeyParse(context.Context, &peerPubKey, pubkeyPtr); - } - - fixed (byte* dataPtr = &MemoryMarshal.GetReference(data), - secKeyPtr = &MemoryMarshal.GetReference(secretKey)) - { - return context.Lib._ecdh.Invoke( - context.Context, - dataPtr, - &peerPubKey, - secKeyPtr, - UmanagedEcdhHashFuncCallback, - &state - ) == 1; - } - - /* - * Umanaged wrapper function for invoking the safe user callback - * from the unmanaged lib - */ - static int UmanagedEcdhHashFuncCallback(byte* output, byte* x32, byte* y32, void* opaque) - { - //Recover the callback - if (opaque == null) - { - return 0; - } - - EcdhHashFuncState* state = (EcdhHashFuncState*)opaque; - - //Init user-state structure - Secp256HashFuncState userState = new(output, state->OutLen, x32, 32, new(opaque)); - - //Recover the function pointer - Secp256k1EcdhHashFunc callback = Marshal.GetDelegateForFunctionPointer<Secp256k1EcdhHashFunc>(state->HashFunc); - - //Invoke the callback - return callback(in userState); - } - } - } -}
\ No newline at end of file |