diff options
Diffstat (limited to 'back-end/libs')
5 files changed, 146 insertions, 17 deletions
diff --git a/back-end/libs/NVault.Crypto.Secp256k1/src/ContextExtensions.cs b/back-end/libs/NVault.Crypto.Secp256k1/src/ContextExtensions.cs index a89fce8..f5327df 100644 --- a/back-end/libs/NVault.Crypto.Secp256k1/src/ContextExtensions.cs +++ b/back-end/libs/NVault.Crypto.Secp256k1/src/ContextExtensions.cs @@ -24,9 +24,46 @@ using VNLib.Utils.Extensions; using static NVault.Crypto.Secp256k1.LibSecp256k1; - namespace NVault.Crypto.Secp256k1 { + public delegate int Secp256k1EcdhHashFunc(in Secp256HashFuncState state); + + [StructLayout(LayoutKind.Sequential)] + public unsafe readonly ref struct Secp256HashFuncState + { + + /// <summary> + /// The opaque pointer passed to the hash function + /// </summary> + public readonly IntPtr Opaque { get; } + + private readonly byte* _output; + private readonly byte* _xCoord; + private readonly int _outputLength; + private readonly int _xCoordLength; + + internal Secp256HashFuncState(byte* output, int outputLength, byte* xCoord, int xCoordLength, IntPtr opaque) + { + Opaque = opaque; + _output = output; + _outputLength = outputLength; + _xCoord = xCoord; + _xCoordLength = xCoordLength; + } + + /// <summary> + /// Gets the output buffer as a span + /// </summary> + /// <returns>The output buffer span</returns> + public readonly Span<byte> GetOutput() => new(_output, _outputLength); + + /// <summary> + /// Gets the x coordinate argument as a span + /// </summary> + /// <returns>The xcoordinate buffer span</returns> + public readonly ReadOnlySpan<byte> GetXCoordArg() => new(_xCoord, _xCoordLength); + } + public static unsafe class ContextExtensions { /// <summary> @@ -138,7 +175,7 @@ namespace NVault.Crypto.Secp256k1 context.Lib.SafeLibHandle.ThrowIfClosed(); //Stack allocated keypair and x-only public key - XOnlyPubKey xOnlyPubKey = new(); + Secp256k1PublicKey xOnlyPubKey = new(); KeyPair keyPair = new(); try @@ -196,5 +233,74 @@ namespace NVault.Crypto.Secp256k1 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 != SecretKeySize) + { + throw new ArgumentException($"Your public key buffer must be exactly {SecretKeySize} bytes long"); + } + + //Init callback state struct + EcdhHashFuncState state = new() + { + HashFunc = Marshal.GetFunctionPointerForDelegate(callback), + Opaque = opaque, + OutLen = data.Length + }; + + //Stack allocated keypair and x-only public key + Secp256k1PublicKey pubKeyStruct = new(); + //Recover the x-only public key structure + MemoryUtil.CopyStruct(xOnlyPubKey, &pubKeyStruct); + + context.Lib.SafeLibHandle.ThrowIfClosed(); + + fixed (byte* dataPtr = &MemoryMarshal.GetReference(data), + secKeyPtr = &MemoryMarshal.GetReference(secretKey)) + { + return context.Lib._ecdh.Invoke(context.Context, dataPtr, &pubKeyStruct, 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 diff --git a/back-end/libs/NVault.Crypto.Secp256k1/src/LibSecp256k1.cs b/back-end/libs/NVault.Crypto.Secp256k1/src/LibSecp256k1.cs index 80d6eb8..5aeed00 100644 --- a/back-end/libs/NVault.Crypto.Secp256k1/src/LibSecp256k1.cs +++ b/back-end/libs/NVault.Crypto.Secp256k1/src/LibSecp256k1.cs @@ -23,33 +23,37 @@ using VNLib.Utils.Extensions; namespace NVault.Crypto.Secp256k1 { + + internal unsafe delegate int EcdhHasFunc(byte* output, byte* x32, byte* y32, void* data); public unsafe class LibSecp256k1 : VnDisposeable { public const int SecretKeySize = 32; - public const int XOnlyPublicKeySize = 32; public const int SignatureSize = 64; - public const int KeyPairSize = 96; public const int RandomBufferSize = 32; + public const int XOnlyPublicKeySize = 32; /* * Unsafe structures that represent the native keypair and x-only public key * structures. They hold character arrays */ - [StructLayout(LayoutKind.Sequential)] + [StructLayout(LayoutKind.Sequential, Size = 96)] internal struct KeyPair { - public fixed byte data[Length]; - public const int Length = KeyPairSize; + public fixed byte data[96]; } - [StructLayout(LayoutKind.Sequential)] - internal struct XOnlyPubKey + /// <summary> + /// 1:1 with the secp256k1_pubkey structure + /// </summary> + [StructLayout(LayoutKind.Sequential, Size = 64)] + internal struct Secp256k1PublicKey { - public fixed byte data[Length]; - public const int Length = 64; + public fixed byte data[64]; } + + //Native methods [SafeMethodName("secp256k1_context_create")] internal delegate IntPtr CreateContext(int flags); @@ -64,10 +68,10 @@ namespace NVault.Crypto.Secp256k1 internal delegate int KeypairCreate(IntPtr context, KeyPair* keyPair, byte* secretKey); [SafeMethodName("secp256k1_keypair_xonly_pub")] - internal delegate int KeypairXOnlyPub(IntPtr ctx, XOnlyPubKey* pubkey, int pk_parity, KeyPair* keypair); + internal delegate int KeypairXOnlyPub(IntPtr ctx, Secp256k1PublicKey* pubkey, int pk_parity, KeyPair* keypair); [SafeMethodName("secp256k1_xonly_pubkey_serialize")] - internal delegate int XOnlyPubkeySerialize(IntPtr ctx, byte* output32, XOnlyPubKey* pubkey); + internal delegate int XOnlyPubkeySerialize(IntPtr ctx, byte* output32, Secp256k1PublicKey* pubkey); [SafeMethodName("secp256k1_schnorrsig_sign32")] internal delegate int SignHash(IntPtr ctx, byte* sig64, byte* msg32, KeyPair* keypair, byte* aux_rand32); @@ -75,6 +79,21 @@ namespace NVault.Crypto.Secp256k1 [SafeMethodName("secp256k1_ec_seckey_verify")] internal delegate int SecKeyVerify(IntPtr ctx, in byte* seckey); + [SafeMethodName("secp256k1_ec_pubkey_serialize")] + internal delegate int PubKeySerialize(IntPtr ctx, byte* outPubKey, ulong* outLen, Secp256k1PublicKey* pubKey, uint flags); + + [SafeMethodName("secp256k1_ecdh")] + internal delegate int Ecdh( + IntPtr ctx, + byte* output, + Secp256k1PublicKey* pubkey, + byte* scalar, + EcdhHasFunc hashFunc, + void* dataPtr + ); + + + /// <summary> /// Loads the Secp256k1 library from the specified path and creates a wrapper class (loads methods from the library) /// </summary> @@ -122,6 +141,8 @@ namespace NVault.Crypto.Secp256k1 internal readonly XOnlyPubkeySerialize _serializeXonly; internal readonly SignHash _signHash; internal readonly SecKeyVerify _secKeyVerify; + internal readonly PubKeySerialize _pubKeySerialize; + internal readonly Ecdh _ecdh; private readonly IRandomSource _randomSource; /// <summary> @@ -148,6 +169,8 @@ namespace NVault.Crypto.Secp256k1 _serializeXonly = handle.DangerousGetMethod<XOnlyPubkeySerialize>(); _signHash = handle.DangerousGetMethod<SignHash>(); _secKeyVerify = handle.DangerousGetMethod<SecKeyVerify>(); + _pubKeySerialize = handle.DangerousGetMethod<PubKeySerialize>(); + _ecdh = handle.DangerousGetMethod<Ecdh>(); //Store random source _randomSource = randomSource; diff --git a/back-end/libs/NVault.Crypto.Secp256k1/src/NVault.Crypto.Secp256k1.csproj b/back-end/libs/NVault.Crypto.Secp256k1/src/NVault.Crypto.Secp256k1.csproj index 7fa738d..22a7e38 100644 --- a/back-end/libs/NVault.Crypto.Secp256k1/src/NVault.Crypto.Secp256k1.csproj +++ b/back-end/libs/NVault.Crypto.Secp256k1/src/NVault.Crypto.Secp256k1.csproj @@ -20,8 +20,8 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="VNLib.Hashing.Portable" Version="0.1.0-ci0088" /> - <PackageReference Include="VNLib.Utils" Version="0.1.0-ci0088" /> + <PackageReference Include="VNLib.Hashing.Portable" Version="0.1.0-ci0096" /> + <PackageReference Include="VNLib.Utils" Version="0.1.0-ci0096" /> </ItemGroup> </Project> diff --git a/back-end/libs/NVault.VaultExtensions/src/NVault.VaultExtensions.csproj b/back-end/libs/NVault.VaultExtensions/src/NVault.VaultExtensions.csproj index 49d3dc6..d6af22d 100644 --- a/back-end/libs/NVault.VaultExtensions/src/NVault.VaultExtensions.csproj +++ b/back-end/libs/NVault.VaultExtensions/src/NVault.VaultExtensions.csproj @@ -21,7 +21,7 @@ <ItemGroup> <PackageReference Include="VaultSharp" Version="1.13.0.1" /> - <PackageReference Include="VNLib.Plugins.Extensions.Loading" Version="0.1.0-ci0037" /> + <PackageReference Include="VNLib.Plugins.Extensions.Loading" Version="0.1.0-ci0042" /> </ItemGroup> </Project> diff --git a/back-end/libs/NVault.VaultExtensions/src/VaultClientExtensions.cs b/back-end/libs/NVault.VaultExtensions/src/VaultClientExtensions.cs index 5a7c637..9ea9d24 100644 --- a/back-end/libs/NVault.VaultExtensions/src/VaultClientExtensions.cs +++ b/back-end/libs/NVault.VaultExtensions/src/VaultClientExtensions.cs @@ -54,7 +54,7 @@ namespace NVault.VaultExtensions string? value = result.Data.Data.GetValueOrDefault(property)?.ToString(); //Return the secret value as a private string - return value == null ? null : new PrivateString(value); + return value == null ? null : PrivateString.ToPrivateString(value, true); } /// <summary> |