diff --git a/.github/workflows/csharp-bindings-build.yml b/.github/workflows/csharp-bindings-build.yml
index 50b88ae..002adf3 100644
--- a/.github/workflows/csharp-bindings-build.yml
+++ b/.github/workflows/csharp-bindings-build.yml
@@ -1,11 +1,17 @@
name: C# bindings test and build
on:
+ workflow_dispatch:
+ inputs:
+ version:
+ description: "Binding version override"
push:
branches:
- main
pull_request:
branches:
- main
+env:
+ binding_build_number_based_version: 0.1.1.${{ github.run_number }}
jobs:
build-ckzg:
@@ -13,29 +19,48 @@ jobs:
strategy:
matrix:
target:
- - native: linux-x64
- host: ubuntu-latest
- - native: linux-arm64
- host: ubuntu-latest
- - native: osx-arm64
+ - arch: x86_64-linux-gnu
+ location: linux-x64
+ host: ubuntu-22.04
+ ext: .so
+ reqs:
+ - arch: aarch64-linux-gnu
+ location: linux-arm64
+ host: ubuntu-22.04
+ ext: .so
+ reqs: sudo apt install -y clang binutils-aarch64-linux-gnu libc6-arm64-cross libc6-dev-arm64-cross crossbuild-essential-arm64
+ - arch: arm64-darwin
+ location: osx-arm64
host: macos-latest
- - native: osx-x64
+ ext: .so
+ reqs:
+ - arch: x86_64-darwin
+ location: osx-x64
host: macos-latest
- - native: win-x64
+ ext: .so
+ reqs:
+ #TODO: support arch: x86_64-v2-win
+ - arch:
+ location: win-x64
host: windows-latest
+ ext: .dll
+ reqs:
steps:
- uses: ilammy/msvc-dev-cmd@v1
- uses: actions/checkout@v3
with:
submodules: recursive
- - name: Build native library for ${{ matrix.target.native }}
- run: cd bindings/csharp && make -B ckzg CSHARP_PLATFORM=${{ matrix.target.native }}
+ - name: Install requirements
+ if: ${{ matrix.target.reqs }}
+ run: ${{ matrix.target.reqs }}
+ - name: Build native library for ${{ matrix.target.location }} using native capabilities
+ run: make ckzg -C bindings/csharp CC=clang EXTENSION=${{matrix.target.ext}} LOCATION=${{matrix.target.location}} ARCH=${{matrix.target.arch}}
- name: Upload artifacts
uses: actions/upload-artifact@v3
with:
- name: ckzg-library-${{ matrix.target.native }}
- path: bindings/csharp/Ckzg.Bindings/runtimes/${{ matrix.target.native }}/native
-
+ name: ckzg-library-wrapper-${{ matrix.target.location }}
+ path: bindings/csharp/Ckzg.Bindings/runtimes/${{ matrix.target.location }}/native
+
build-ckzg-dotnet:
runs-on: ubuntu-latest
needs: build-ckzg
@@ -43,37 +68,35 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/download-artifact@v3
with:
- name: ckzg-library-linux-x64
+ name: ckzg-library-wrapper-linux-x64
path: bindings/csharp/Ckzg.Bindings/runtimes/linux-x64/native
- uses: actions/download-artifact@v3
with:
- name: ckzg-library-osx-x64
+ name: ckzg-library-wrapper-osx-x64
path: bindings/csharp/Ckzg.Bindings/runtimes/osx-x64/native
- uses: actions/download-artifact@v3
with:
- name: ckzg-library-win-x64
+ name: ckzg-library-wrapper-win-x64
path: bindings/csharp/Ckzg.Bindings/runtimes/win-x64/native
- uses: actions/download-artifact@v3
with:
- name: ckzg-library-osx-arm64
+ name: ckzg-library-wrapper-osx-arm64
path: bindings/csharp/Ckzg.Bindings/runtimes/osx-arm64/native
- uses: actions/download-artifact@v3
with:
- name: ckzg-library-linux-arm64
+ name: ckzg-library-wrapper-linux-arm64
path: bindings/csharp/Ckzg.Bindings/runtimes/linux-arm64/native
- - name: Setup .NET Core SDK ${{ matrix.dotnet-version }}
+ - name: Setup .NET Core SDK
uses: actions/setup-dotnet@v3
- with:
- dotnet-version: ${{ matrix.dotnet-version }}
- name: Install dependencies
run: cd bindings/csharp && dotnet restore
- name: Test
run: cd bindings/csharp && dotnet test --configuration Release --no-restore
- name: Build
- run: cd bindings/csharp && dotnet build -p:Version=0.1.1.${{github.run_number}} --configuration Release --no-restore
+ run: cd bindings/csharp && dotnet build -p:Version=${{ inputs.version || env.binding_build_number_based_version }} --configuration Release --no-restore
- name: Upload package
uses: actions/upload-artifact@v3
with:
- name: Ckzg.Bindings
+ name: Ckzg.Bindings-${{ inputs.version || env.binding_build_number_based_version }}
path: bindings/csharp/build/Ckzg.Bindings.*.nupkg
diff --git a/bindings/csharp/Ckzg.Bindings/Ckzg.Bindings.cs b/bindings/csharp/Ckzg.Bindings/Ckzg.Bindings.cs
new file mode 100644
index 0000000..d64f58a
--- /dev/null
+++ b/bindings/csharp/Ckzg.Bindings/Ckzg.Bindings.cs
@@ -0,0 +1,62 @@
+using System.Runtime.InteropServices;
+using System.Runtime.Loader;
+
+namespace Ckzg;
+
+public static partial class Ckzg
+{
+ static Ckzg()
+ {
+ AssemblyLoadContext.Default.ResolvingUnmanagedDll += (_, path) =>
+ path.Contains("ckzg", StringComparison.OrdinalIgnoreCase)
+ ? NativeLibrary.Load($"runtimes/{(
+ RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? "linux" :
+ RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? "osx" :
+ RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "win" : "")}-{RuntimeInformation.ProcessArchitecture switch
+ {
+ Architecture.X64 => "x64",
+ Architecture.Arm64 => "arm64",
+ _ => ""
+ }}/native/{path}.{(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "dll" : "so")}")
+ : IntPtr.Zero;
+ }
+
+ [DllImport("ckzg", EntryPoint = "load_trusted_setup_wrap")]
+ private static extern IntPtr InternalLoadTrustedSetup(string filename);
+
+ [DllImport("ckzg", EntryPoint = "free_trusted_setup_wrap", CallingConvention = CallingConvention.Cdecl)]
+ private static extern void InternalFreeTrustedSetup(IntPtr ts);
+
+ [DllImport("ckzg", EntryPoint = "blob_to_kzg_commitment", CallingConvention = CallingConvention.Cdecl)]
+ private static extern unsafe KzgResult BlobToKzgCommitment(byte* commitment, byte* blob, IntPtr ts);
+
+ [DllImport("ckzg", EntryPoint = "compute_kzg_proof", CallingConvention = CallingConvention.Cdecl)]
+ private static extern unsafe KzgResult ComputeKzgProof(byte* proof, byte* blob, byte* z, IntPtr ts);
+
+ [DllImport("ckzg", EntryPoint = "compute_blob_kzg_proof", CallingConvention = CallingConvention.Cdecl)]
+ private static extern unsafe KzgResult ComputeBlobKzgProof(byte* proof, byte* blob, IntPtr ts);
+
+ [DllImport("ckzg", EntryPoint = "verify_kzg_proof", CallingConvention = CallingConvention.Cdecl)]
+ private static extern unsafe KzgResult VerifyKzgProof(out bool result, byte* commitment, byte* z,
+ byte* y, byte* proof, IntPtr ts);
+
+ [DllImport("ckzg", EntryPoint = "verify_blob_kzg_proof", CallingConvention = CallingConvention.Cdecl)]
+ private static extern unsafe KzgResult VerifyBlobKzgProof(out bool result, byte* blob, byte* commitment,
+ byte* proof, IntPtr ts);
+
+ [DllImport("ckzg", EntryPoint = "verify_blob_kzg_proof_batch", CallingConvention = CallingConvention.Cdecl)]
+ private static extern unsafe KzgResult VerifyBlobKzgProofBatch(out bool result, byte* blobs, byte* commitments,
+ byte* proofs, int count, IntPtr ts);
+
+ private enum KzgResult
+ {
+ // Success!
+ Ok,
+ // The supplied data is invalid in some way.
+ BadArgs,
+ // Internal error - this should never occur.
+ Error,
+ // Could not allocate memory.
+ Malloc
+ }
+}
\ No newline at end of file
diff --git a/bindings/csharp/Ckzg.Bindings/Ckzg.Bindings.csproj b/bindings/csharp/Ckzg.Bindings/Ckzg.Bindings.csproj
index 255ae46..1a551e3 100644
--- a/bindings/csharp/Ckzg.Bindings/Ckzg.Bindings.csproj
+++ b/bindings/csharp/Ckzg.Bindings/Ckzg.Bindings.csproj
@@ -1,32 +1,32 @@
-
- Library
- net6.0
- Ckzg
- enable
- enable
- preview
- True
- True
- Ckzg.Bindings
- LICENSE
- 0.1.0.0
-
+
+ Library
+ net6.0
+ Ckzg
+ enable
+ enable
+ preview
+ True
+ True
+ Ckzg.Bindings
+ LICENSE
+ 0.1.0.0
+
-
-
- True
- \
-
-
+
+
+ True
+ \
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
diff --git a/bindings/csharp/Ckzg.Bindings/Ckzg.cs b/bindings/csharp/Ckzg.Bindings/Ckzg.cs
index 9d37ade..179cadd 100644
--- a/bindings/csharp/Ckzg.Bindings/Ckzg.cs
+++ b/bindings/csharp/Ckzg.Bindings/Ckzg.cs
@@ -1,115 +1,222 @@
-using System.Runtime.InteropServices;
-using System.Runtime.Loader;
-
namespace Ckzg;
-public class Ckzg
+public static partial class Ckzg
{
public const int BytesPerFieldElement = 32;
- public const int BytesPerBlob = BytesPerFieldElement * 4096;
+ public const int FieldElementsPerBlob = 4096;
+ public const int BytesPerBlob = BytesPerFieldElement * FieldElementsPerBlob;
public const int BytesPerCommitment = 48;
public const int BytesPerProof = 48;
- public enum Ret
- {
- Ok,
- BadArgs,
- Error,
- Malloc
- }
-
- static Ckzg() => AssemblyLoadContext.Default.ResolvingUnmanagedDll += (assembly, path) => NativeLibrary.Load($"runtimes/{(
- RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? "linux" :
- RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? "osx" :
- RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "win" : "")}-{RuntimeInformation.ProcessArchitecture switch
- {
- Architecture.X64 => "x64",
- Architecture.Arm64 => "arm64",
- _ => ""
- }}/native/{path}.{(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "dll" : "so")}");
-
///
- /// Load trusted setup settings from file
+ /// Loads trusted setup settings from file.
///
/// Settings file path
- /// Trusted setup settings as a pointer or 0 in case of failure
- [DllImport("ckzg", EntryPoint = "load_trusted_setup_wrap")]
- public static extern IntPtr LoadTrustedSetup(string filename);
+ /// Thrown when the file path is not correct
+ /// Thrown when unable to load the setup
+ /// Trusted setup settings as a pointer
+ public static IntPtr LoadTrustedSetup(string filepath)
+ {
+ if (!File.Exists(filepath)) throw new ArgumentException("Trusted setup file does not exist", nameof(filepath));
+
+ IntPtr ckzgSetup = InternalLoadTrustedSetup(filepath);
+
+ if (ckzgSetup == IntPtr.Zero) throw new InvalidOperationException("Unable to load trusted setup");
+ return ckzgSetup;
+ }
///
- /// Frees memory allocated for trusted setup settings
+ /// Frees memory allocated for trusted setup settings.
///
- /// Trusted setup settings
- [DllImport("ckzg", EntryPoint = "free_trusted_setup_wrap", CallingConvention = CallingConvention.Cdecl)]
- public static extern void FreeTrustedSetup(IntPtr ts);
+ /// Trusted setup settings
+ /// Thrown when settings are not correct
+
+ public static void FreeTrustedSetup(IntPtr ckzgSetup)
+ {
+ ThrowOnUninitializedTrustedSetup(ckzgSetup);
+ InternalFreeTrustedSetup(ckzgSetup);
+ }
///
- /// Calculates commitment for the blob
+ /// Calculates commitment for the blob.
///
- /// Preallocated buffer of bytes to receive the commitment
+ /// Preallocated buffer of bytes to receive the commitment
/// Flatten array of blob elements
- /// Trusted setup settings
- /// Returns error code or 0 if successful
- [DllImport("ckzg", EntryPoint = "blob_to_kzg_commitment", CallingConvention = CallingConvention.Cdecl)]
- public unsafe static extern Ret BlobToKzgCommitment(byte* commitment, byte* blob, IntPtr ts);
+ /// Trusted setup settings
+ /// Thrown when length of an argument is not correct or settings are not correct
+ /// Thrown when the library returns unexpected Error code
+ /// Thrown when the library has no enough memory to process
+ public static unsafe void BlobToKzgCommitment(Span commitment, ReadOnlySpan blob, IntPtr ckzgSetup)
+ {
+ ThrowOnUninitializedTrustedSetup(ckzgSetup);
+ ThrowOnInvalidLength(blob, nameof(blob), BytesPerBlob);
+ ThrowOnInvalidLength(commitment, nameof(commitment), BytesPerCommitment);
+
+ fixed (byte* commitmentPtr = commitment, blobPtr = blob)
+ {
+ KzgResult result = BlobToKzgCommitment(commitmentPtr, blobPtr, ckzgSetup);
+ ThrowOnError(result);
+ }
+ }
///
- /// Compute KZG proof at point `z` for the polynomial represented by `blob`.
+ /// Compute KZG proof at point `z` for the polynomial represented by `blob`.
///
- /// Preallocated buffer of bytes to receive the proof
- /// Blob byte array
- ///
- /// Trusted setup settings
- /// Returns error code or 0 if successful
- [DllImport("ckzg", EntryPoint = "compute_kzg_proof", CallingConvention = CallingConvention.Cdecl)]
- public unsafe static extern Ret ComputeKzgProof(byte* proof, byte* blob, byte* z_bytes, IntPtr ts);
+ /// Preallocated buffer of bytes to receive the proof
+ /// Blob bytes
+ /// Z point
+ /// Trusted setup settings
+ /// Thrown when length of an argument is not correct or settings are not correct
+ /// Thrown when the library returns unexpected Error code
+ /// Thrown when the library has no enough memory to process
+ public static unsafe void ComputeKzgProof(Span proof, ReadOnlySpan blob, ReadOnlySpan z,
+ IntPtr ckzgSetup)
+ {
+ ThrowOnUninitializedTrustedSetup(ckzgSetup);
+ ThrowOnInvalidLength(proof, nameof(proof), BytesPerProof);
+ ThrowOnInvalidLength(blob, nameof(blob), BytesPerBlob);
+ ThrowOnInvalidLength(z, nameof(z), BytesPerFieldElement);
+
+ if (z.Length != BytesPerFieldElement) throw new ArgumentException("Invalid z size", nameof(z));
+
+ fixed (byte* proofPtr = proof, blobPtr = blob, zPtr = z)
+ {
+ KzgResult result = ComputeKzgProof(proofPtr, blobPtr, zPtr, ckzgSetup);
+ ThrowOnError(result);
+ }
+ }
///
- /// Given a blob, return the KZG proof that is used to verify it against the commitment.
+ /// Given a blob, return the KZG proof that is used to verify it against the commitment.
///
- /// Preallocated buffer of bytes to receive the proof
- /// Blob byte array
- /// Trusted setup settings
- /// Returns error code or 0 if successful
- [DllImport("ckzg", EntryPoint = "compute_blob_kzg_proof", CallingConvention = CallingConvention.Cdecl)]
- public unsafe static extern Ret ComputeBlobKzgProof(byte* proof, byte* blob, IntPtr ts);
+ /// Preallocated buffer of bytes to receive the proof
+ /// Blob bytes
+ /// Trusted setup settings
+ /// Thrown when length of an argument is not correct or settings are not correct
+ /// Thrown when the library returns unexpected Error code
+ /// Thrown when the library has no enough memory to process
+ public static unsafe void ComputeBlobKzgProof(Span proof, ReadOnlySpan blob, IntPtr ckzgSetup)
+ {
+ ThrowOnUninitializedTrustedSetup(ckzgSetup);
+ ThrowOnInvalidLength(proof, nameof(proof), BytesPerProof);
+ ThrowOnInvalidLength(blob, nameof(blob), BytesPerBlob);
+
+ fixed (byte* proofPtr = proof, blobPtr = blob)
+ {
+ KzgResult result = ComputeBlobKzgProof(proofPtr, blobPtr, ckzgSetup);
+ ThrowOnError(result);
+ }
+ }
///
- ///
+ /// Given a blob and a KZG proof, verify that the blob data corresponds to the provided commitment.
///
- /// True if the proof is valid
- ///
- ///
- ///
- ///
- /// Trusted setup settings
- ///
- [DllImport("ckzg", EntryPoint = "verify_kzg_proof", CallingConvention = CallingConvention.Cdecl)]
- public unsafe static extern Ret VerifyKzgProof(bool* result, byte* commitment_bytes, byte* z_bytes, byte* y_bytes, byte* proof_bytes, IntPtr ts);
-
- ///
- /// Given a blob and a KZG proof, verify that the blob data corresponds to the provided commitment.
- ///
- /// True if the proof is valid
///
///
///
- /// Trusted setup settings
- ///
- [DllImport("ckzg", EntryPoint = "verify_blob_kzg_proof", CallingConvention = CallingConvention.Cdecl)]
- public unsafe static extern Ret VerifyBlobKzgProof(bool* result, byte* blob, byte* commitment_bytes, byte* proof_bytes, IntPtr ts);
+ /// Trusted setup settings
+ /// Thrown when length of an argument is not correct or settings are not correct
+ /// Thrown when the library returns unexpected Error code
+ /// Thrown when the library has no enough memory to process
+ /// Verification result
+ public static unsafe bool VerifyKzgProof(ReadOnlySpan commitment, ReadOnlySpan z, ReadOnlySpan y,
+ ReadOnlySpan proof, IntPtr ckzgSetup)
+ {
+
+ ThrowOnUninitializedTrustedSetup(ckzgSetup);
+ ThrowOnInvalidLength(commitment, nameof(commitment), BytesPerCommitment);
+ ThrowOnInvalidLength(z, nameof(z), BytesPerFieldElement);
+ ThrowOnInvalidLength(y, nameof(y), BytesPerFieldElement);
+ ThrowOnInvalidLength(proof, nameof(proof), BytesPerProof);
+
+ fixed (byte* commitmentPtr = commitment, zPtr = z, yPtr = y, proofPtr = proof)
+ {
+ KzgResult kzgResult = VerifyKzgProof(out var result, commitmentPtr, zPtr, yPtr, proofPtr, ckzgSetup);
+ ThrowOnError(kzgResult);
+ return result;
+ }
+ }
///
- /// Given a list of blobs and blob KZG proofs, verify that they correspond to the provided commitments.
+ /// Given a blob and a KZG proof, verify that the blob data corresponds to the provided commitment.
+ ///
+ /// Blob bytes
+ /// Commitment bytes
+ /// Proof bytes
+ /// Trusted setup settings
+ /// Thrown when length of an argument is not correct or settings are not correct
+ /// Thrown when the library returns unexpected Error code
+ /// Thrown when the library has no enough memory to process
+ /// Verification result
+ public static unsafe bool VerifyBlobKzgProof(ReadOnlySpan blob, ReadOnlySpan commitment,
+ ReadOnlySpan proof, IntPtr ckzgSetup)
+ {
+ ThrowOnUninitializedTrustedSetup(ckzgSetup);
+ ThrowOnInvalidLength(blob, nameof(blob), BytesPerBlob);
+ ThrowOnInvalidLength(commitment, nameof(proof), BytesPerCommitment);
+ ThrowOnInvalidLength(proof, nameof(proof), BytesPerProof);
+
+ fixed (byte* blobPtr = blob, commitmentPtr = commitment, proofPtr = proof)
+ {
+ KzgResult kzgResult = VerifyBlobKzgProof(out var result, blobPtr, commitmentPtr, proofPtr, ckzgSetup);
+ ThrowOnError(kzgResult);
+ return result;
+ }
+ }
+
+ ///
+ /// Given a list of blobs and blob KZG proofs, verify that they correspond to the provided commitments.
///
- /// True if the proofs are valid
/// Blobs as a flattened byte array
/// Commitments as a flattened byte array
/// Proofs as a flattened byte array
/// The number of blobs/commitments/proofs
- /// Trusted setup settings
- ///
- [DllImport("ckzg", EntryPoint = "verify_blob_kzg_proof_batch", CallingConvention = CallingConvention.Cdecl)]
- public unsafe static extern Ret VerifyBlobKzgProofBatch(bool* result, byte* blobs, byte* commitments_bytes, byte* proofs_bytes, int count, IntPtr ts);
-}
+ /// Trusted setup settings
+ /// Thrown when length of an argument is not correct or settings are not correct
+ /// Thrown when the library returns unexpected Error code
+ /// Thrown when the library has no enough memory to process
+ /// Verification result
+ public static unsafe bool VerifyBlobKzgProofBatch(ReadOnlySpan blobs, ReadOnlySpan commitments,
+ ReadOnlySpan proofs, int count, IntPtr ckzgSetup)
+ {
+ ThrowOnUninitializedTrustedSetup(ckzgSetup);
+ ThrowOnInvalidLength(blobs, nameof(blobs), BytesPerBlob * count);
+ ThrowOnInvalidLength(commitments, nameof(proofs), BytesPerCommitment * count);
+ ThrowOnInvalidLength(proofs, nameof(proofs), BytesPerProof * count);
+ fixed (byte* blobsPtr = blobs, commitmentsPtr = commitments, proofsPtr = proofs)
+ {
+ KzgResult kzgResult =
+ VerifyBlobKzgProofBatch(out var result, blobsPtr, commitmentsPtr, proofsPtr, count, ckzgSetup);
+ ThrowOnError(kzgResult);
+ return result;
+ }
+ }
+
+ #region Argument verification helpers
+ private static void ThrowOnError(KzgResult result)
+ {
+ switch (result)
+ {
+ case KzgResult.BadArgs: throw new ArgumentException();
+ case KzgResult.Malloc: throw new InsufficientMemoryException();
+ case KzgResult.Ok:
+ return;
+ default:
+ throw new ApplicationException("KZG returned unexpected result");
+ }
+ }
+
+ private static void ThrowOnUninitializedTrustedSetup(IntPtr ckzgSetup)
+ {
+ if (ckzgSetup == IntPtr.Zero)
+ throw new ArgumentException("Trusted setup is not initialized", nameof(ckzgSetup));
+ }
+
+ private static void ThrowOnInvalidLength(ReadOnlySpan data, string fieldName, int expectedLength)
+ {
+ if (data.Length != expectedLength)
+ throw new ArgumentException("Invalid data size", fieldName);
+ }
+ #endregion
+}
\ No newline at end of file
diff --git a/bindings/csharp/Ckzg.Test/Ckzg.Test.csproj b/bindings/csharp/Ckzg.Test/Ckzg.Test.csproj
index dd34fe9..a0863ed 100644
--- a/bindings/csharp/Ckzg.Test/Ckzg.Test.csproj
+++ b/bindings/csharp/Ckzg.Test/Ckzg.Test.csproj
@@ -1,29 +1,31 @@
-
- net6.0
- enable
- enable
- True
- false
-
+
+ net7.0
+ enable
+ enable
+ True
+ false
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
-
-
- Always
-
-
+
+
+ Always
+
+
diff --git a/bindings/csharp/Ckzg.Test/E2eTests.cs b/bindings/csharp/Ckzg.Test/E2eTests.cs
deleted file mode 100644
index 526e187..0000000
--- a/bindings/csharp/Ckzg.Test/E2eTests.cs
+++ /dev/null
@@ -1,218 +0,0 @@
-using NUnit.Framework;
-using System.IO;
-
-namespace Ckzg.Test;
-
-[TestFixture]
-public class BasicKzgTests
-{
- private IntPtr ts;
-
- const string TestDir = "../../../../../../tests";
- string BlobToKZGCommitmentTests = Path.Join(TestDir, "blob_to_kzg_commitment");
- string ComputeKzgProofTests = Path.Join(TestDir, "compute_kzg_proof");
- string ComputeBlobKzgProofTests = Path.Join(TestDir, "compute_blob_kzg_proof");
- string VerifyKzgProofTests = Path.Join(TestDir, "verify_kzg_proof");
- string VerifyBlobKzgProofTests = Path.Join(TestDir, "verify_blob_kzg_proof");
- string VerifyBlobKzgProofBatchTests = Path.Join(TestDir, "verify_blob_kzg_proof_batch");
-
- public static byte[] StringToByteArray(string hex)
- {
- return Enumerable.Range(0, hex.Length)
- .Where(x => x % 2 == 0)
- .Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
- .ToArray();
- }
-
- public static byte[] GetBytes(String path)
- {
- string hex = System.IO.File.ReadAllText(path);
- return StringToByteArray(hex);
- }
-
- public static byte[] GetFlatBytes(String path)
- {
- List files = Directory.GetFiles(path).ToList();
- files.Sort();
- List filesBytes = new List();
- foreach (String file in files)
- {
- filesBytes.Add(GetBytes(file));
- }
-
- byte[] flatBytes = new byte[filesBytes.Sum(b => b.Length)];
- int offset = 0;
- foreach (byte[] bytes in filesBytes)
- {
- System.Buffer.BlockCopy(bytes, 0, flatBytes, offset, bytes.Length);
- offset += bytes.Length;
- }
-
- return flatBytes;
- }
-
- public static bool GetBoolean(String path)
- {
- return System.IO.File.ReadAllText(path).Contains("true");
- }
-
- [SetUp]
- public void Setup()
- {
- ts = Ckzg.LoadTrustedSetup("trusted_setup.txt");
- Assert.That(ts, Is.Not.EqualTo(IntPtr.Zero));
- }
-
- [TearDown]
- public void Teardown()
- {
- Ckzg.FreeTrustedSetup(ts);
- }
-
- [TestCase]
- public unsafe void TestBlobToKzgCommitment()
- {
- foreach (String test in Directory.GetDirectories(BlobToKZGCommitmentTests))
- {
- byte[] commitment = new byte[48];
- byte[] blob = GetBytes(Path.Join(test, "blob.txt"));
- fixed (byte *pCommitment = commitment, pBlob = blob)
- {
- Ckzg.Ret ret = Ckzg.BlobToKzgCommitment(pCommitment, pBlob, ts);
- if (ret == Ckzg.Ret.Ok)
- {
- byte[] expectedCommitment = GetBytes(Path.Join(test, "commitment.txt"));
- Assert.That(commitment, Is.EqualTo(expectedCommitment));
- }
- else
- {
- Assert.False(System.IO.File.Exists(Path.Join(test, "commitment.txt")));
- }
- }
- }
- }
-
- [TestCase]
- public unsafe void TestComputeKzgProof()
- {
- foreach (String test in Directory.GetDirectories(ComputeKzgProofTests))
- {
- byte[] proof = new byte[48];
- byte[] blob = GetBytes(Path.Join(test, "blob.txt"));
- byte[] inputPoint = GetBytes(Path.Join(test, "input_point.txt"));
- fixed (byte *pProof = proof, pBlob = blob, pInputPoint = inputPoint)
- {
- Ckzg.Ret ret = Ckzg.ComputeKzgProof(pProof, pBlob, pInputPoint, ts);
- if (ret == Ckzg.Ret.Ok)
- {
- byte[] expectedProof = GetBytes(Path.Join(test, "proof.txt"));
- Assert.That(proof, Is.EqualTo(expectedProof));
- }
- else
- {
- Assert.False(System.IO.File.Exists(Path.Join(test, "proof.txt")));
- }
- }
- }
- }
-
- [TestCase]
- public unsafe void TestComputeBlobKzgProof()
- {
- foreach (String test in Directory.GetDirectories(ComputeBlobKzgProofTests))
- {
- byte[] proof = new byte[48];
- byte[] blob = GetBytes(Path.Join(test, "blob.txt"));
- fixed (byte *pProof = proof, pBlob = blob)
- {
- Ckzg.Ret ret = Ckzg.ComputeBlobKzgProof(pProof, pBlob, ts);
- if (ret == Ckzg.Ret.Ok)
- {
- byte[] expectedProof = GetBytes(Path.Join(test, "proof.txt"));
- Assert.That(proof, Is.EqualTo(expectedProof));
- }
- else
- {
- Assert.False(System.IO.File.Exists(Path.Join(test, "proof.txt")));
- }
- }
- }
- }
-
- [TestCase]
- public unsafe void TestVerifyKzgProof()
- {
- foreach (String test in Directory.GetDirectories(VerifyKzgProofTests))
- {
- bool ok = false;
- byte[] commitment = GetBytes(Path.Join(test, "commitment.txt"));
- byte[] inputPoint = GetBytes(Path.Join(test, "input_point.txt"));
- byte[] claimedValue = GetBytes(Path.Join(test, "claimed_value.txt"));
- byte[] proof = GetBytes(Path.Join(test, "proof.txt"));
- fixed (byte *pCommitment = commitment, pInputPoint = inputPoint, pClaimedValue = claimedValue, pProof = proof)
- {
- Ckzg.Ret ret = Ckzg.VerifyKzgProof(&ok, pCommitment, pInputPoint, pClaimedValue, pProof, ts);
- if (ret == Ckzg.Ret.Ok)
- {
- bool expectedOk = GetBoolean(Path.Join(test, "ok.txt"));
- Assert.That(ok, Is.EqualTo(expectedOk));
- }
- else
- {
- Assert.False(System.IO.File.Exists(Path.Join(test, "ok.txt")));
- }
- }
- }
- }
-
- [TestCase]
- public unsafe void TestVerifyBlobKzgProof()
- {
- foreach (String test in Directory.GetDirectories(VerifyBlobKzgProofTests))
- {
- bool ok = false;
- byte[] blob = GetBytes(Path.Join(test, "blob.txt"));
- byte[] commitment = GetBytes(Path.Join(test, "commitment.txt"));
- byte[] proof = GetBytes(Path.Join(test, "proof.txt"));
- fixed (byte *pBlob = blob, pCommitment = commitment, pProof = proof)
- {
- Ckzg.Ret ret = Ckzg.VerifyBlobKzgProof(&ok, pBlob, pCommitment, pProof, ts);
- if (ret == Ckzg.Ret.Ok)
- {
- bool expectedOk = GetBoolean(Path.Join(test, "ok.txt"));
- Assert.That(ok, Is.EqualTo(expectedOk));
- }
- else
- {
- Assert.False(System.IO.File.Exists(Path.Join(test, "ok.txt")));
- }
- }
- }
- }
-
- [TestCase]
- public unsafe void TestVerifyBlobKzgProofBatch()
- {
- foreach (String test in Directory.GetDirectories(VerifyBlobKzgProofBatchTests))
- {
- bool ok = false;
- byte[] blobs = GetFlatBytes(Path.Join(test, "blobs"));
- byte[] commitments = GetFlatBytes(Path.Join(test, "commitments"));
- byte[] proofs = GetFlatBytes(Path.Join(test, "proofs"));
- int count = blobs.Length / Ckzg.BytesPerBlob;
- fixed (byte *pBlobs = blobs, pCommitments = commitments, pProofs = proofs)
- {
- Ckzg.Ret ret = Ckzg.VerifyBlobKzgProofBatch(&ok, pBlobs, pCommitments, pProofs, count, ts);
- if (ret == Ckzg.Ret.Ok)
- {
- bool expectedOk = GetBoolean(Path.Join(test, "ok.txt"));
- Assert.That(ok, Is.EqualTo(expectedOk));
- }
- else
- {
- Assert.False(System.IO.File.Exists(Path.Join(test, "ok.txt")));
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/bindings/csharp/Ckzg.Test/ReferenceTests.cs b/bindings/csharp/Ckzg.Test/ReferenceTests.cs
new file mode 100644
index 0000000..65b31ea
--- /dev/null
+++ b/bindings/csharp/Ckzg.Test/ReferenceTests.cs
@@ -0,0 +1,337 @@
+using Microsoft.Extensions.FileSystemGlobbing;
+using NUnit.Framework;
+using YamlDotNet.Serialization;
+using YamlDotNet.Serialization.NamingConventions;
+
+namespace Ckzg.Test;
+
+[TestFixture]
+public class ReferenceTests
+{
+ [OneTimeSetUp]
+ public void Setup()
+ {
+ _ts = Ckzg.LoadTrustedSetup("trusted_setup.txt");
+ _deserializer = new DeserializerBuilder().WithNamingConvention(CamelCaseNamingConvention.Instance).Build();
+ }
+
+ [OneTimeTearDown]
+ public void Teardown()
+ {
+ Ckzg.FreeTrustedSetup(_ts);
+ }
+
+ [TestCase]
+ public void TestSetupLoaded()
+ {
+ Assert.That(_ts, Is.Not.EqualTo(IntPtr.Zero));
+ }
+
+ private IntPtr _ts;
+ private const string TestDir = "../../../../../../tests";
+ private readonly string _blobToKzgCommitmentTests = Path.Join(TestDir, "blob_to_kzg_commitment");
+ private readonly string _computeKzgProofTests = Path.Join(TestDir, "compute_kzg_proof");
+ private readonly string _computeBlobKzgProofTests = Path.Join(TestDir, "compute_blob_kzg_proof");
+ private readonly string _verifyKzgProofTests = Path.Join(TestDir, "verify_kzg_proof");
+ private readonly string _verifyBlobKzgProofTests = Path.Join(TestDir, "verify_blob_kzg_proof");
+ private readonly string _verifyBlobKzgProofBatchTests = Path.Join(TestDir, "verify_blob_kzg_proof_batch");
+ private IDeserializer _deserializer;
+
+ #region Helper Functions
+
+ private static byte[] GetBytes(string hex)
+ {
+ return Convert.FromHexString(hex[2..]);
+ }
+
+ private static byte[] GetFlatBytes(List strings)
+ {
+ List stringBytes = strings.Select(GetBytes).ToList();
+
+ byte[] flatBytes = new byte[stringBytes.Sum(b => b.Length)];
+ int offset = 0;
+ foreach (byte[] bytes in stringBytes)
+ {
+ Buffer.BlockCopy(bytes, 0, flatBytes, offset, bytes.Length);
+ offset += bytes.Length;
+ }
+
+ return flatBytes;
+ }
+
+ #endregion
+
+ #region BlobToKzgCommitment
+
+ private class BlobToKzgCommitmentInput
+ {
+ public string Blob { get; set; } = null!;
+ }
+
+ private class BlobToKzgCommitmentTest
+ {
+ public BlobToKzgCommitmentInput Input { get; set; } = null!;
+ public string? Output { get; set; } = null!;
+ }
+
+ [TestCase]
+ public void TestBlobToKzgCommitment()
+ {
+ Matcher matcher = new();
+ matcher.AddIncludePatterns(new[] { "*/*/data.yaml" });
+
+ foreach (string testFile in matcher.GetResultsInFullPath(_blobToKzgCommitmentTests))
+ {
+ string yaml = File.ReadAllText(testFile);
+ BlobToKzgCommitmentTest test = _deserializer.Deserialize(yaml);
+ Assert.That(test, Is.Not.EqualTo(null));
+
+ byte[] commitment = new byte[48];
+ byte[] blob = GetBytes(test.Input.Blob);
+
+ try
+ {
+ Ckzg.BlobToKzgCommitment(commitment, blob, _ts);
+ string? commitmentStr = test.Output;
+ Assert.That(commitmentStr, Is.Not.EqualTo(null));
+ byte[] expectedCommitment = GetBytes(commitmentStr);
+ Assert.That(commitment, Is.EqualTo(expectedCommitment));
+ }
+ catch
+ {
+ Assert.That(test.Output, Is.EqualTo(null));
+ }
+ }
+ }
+
+ #endregion
+
+ #region ComputeKzgProof
+
+ private class ComputeKzgProofInput
+ {
+ public string Blob { get; set; } = null!;
+ public string Z { get; set; } = null!;
+ }
+
+ private class ComputeKzgProofTest
+ {
+ public ComputeKzgProofInput Input { get; set; } = null!;
+ public string? Output { get; set; } = null!;
+ }
+
+ [TestCase]
+ public void TestComputeKzgProof()
+ {
+ Matcher matcher = new();
+ matcher.AddIncludePatterns(new[] { "*/*/data.yaml" });
+
+ foreach (string testFile in matcher.GetResultsInFullPath(_computeKzgProofTests))
+ {
+ string yaml = File.ReadAllText(testFile);
+ ComputeKzgProofTest test = _deserializer.Deserialize(yaml);
+ Assert.That(test, Is.Not.EqualTo(null));
+
+ byte[] proof = new byte[48];
+ byte[] blob = GetBytes(test.Input.Blob);
+ byte[] z = GetBytes(test.Input.Z);
+
+ try
+ {
+ Ckzg.ComputeKzgProof(proof, blob, z, _ts);
+ string? proofStr = test.Output;
+ Assert.That(proofStr, Is.Not.EqualTo(null));
+ byte[] expectedProof = GetBytes(proofStr);
+ Assert.That(proof, Is.EqualTo(expectedProof));
+ }
+ catch
+ {
+ Assert.That(test.Output, Is.EqualTo(null));
+ }
+ }
+ }
+
+ #endregion
+
+ #region ComputeBlobKzgProof
+
+ private class ComputeBlobKzgProofInput
+ {
+ public string Blob { get; set; } = null!;
+ }
+
+ private class ComputeBlobKzgProofTest
+ {
+ public ComputeBlobKzgProofInput Input { get; set; } = null!;
+ public string? Output { get; set; } = null!;
+ }
+
+ [TestCase]
+ public void TestComputeBlobKzgProof()
+ {
+ Matcher matcher = new();
+ matcher.AddIncludePatterns(new[] { "*/*/data.yaml" });
+
+ foreach (string testFile in matcher.GetResultsInFullPath(_computeBlobKzgProofTests))
+ {
+ string yaml = File.ReadAllText(testFile);
+ ComputeBlobKzgProofTest test = _deserializer.Deserialize(yaml);
+ Assert.That(test, Is.Not.EqualTo(null));
+
+ byte[] proof = new byte[48];
+ byte[] blob = GetBytes(test.Input.Blob);
+
+ try
+ {
+ Ckzg.ComputeBlobKzgProof(proof, blob, _ts);
+ string? proofStr = test.Output;
+ Assert.That(proofStr, Is.Not.EqualTo(null));
+ byte[] expectedProof = GetBytes(proofStr);
+ Assert.That(proof, Is.EqualTo(expectedProof));
+ }
+ catch
+ {
+ Assert.That(test.Output, Is.EqualTo(null));
+ }
+ }
+ }
+
+ #endregion
+
+ #region VerifyKzgProof
+
+ private class VerifyKzgProofInput
+ {
+ public string Commitment { get; set; } = null!;
+ public string Z { get; set; } = null!;
+ public string Y { get; set; } = null!;
+ public string Proof { get; set; } = null!;
+ }
+
+ private class VerifyKzgProofTest
+ {
+ public VerifyKzgProofInput Input { get; set; } = null!;
+ public bool? Output { get; set; } = null!;
+ }
+
+ [TestCase]
+ public void TestVerifyKzgProof()
+ {
+ Matcher matcher = new();
+ matcher.AddIncludePatterns(new[] { "*/*/data.yaml" });
+
+ foreach (string testFile in matcher.GetResultsInFullPath(_verifyKzgProofTests))
+ {
+ string yaml = File.ReadAllText(testFile);
+ VerifyKzgProofTest test = _deserializer.Deserialize(yaml);
+ Assert.That(test, Is.Not.EqualTo(null));
+
+ byte[] commitment = GetBytes(test.Input.Commitment);
+ byte[] z = GetBytes(test.Input.Z);
+ byte[] y = GetBytes(test.Input.Y);
+ byte[] proof = GetBytes(test.Input.Proof);
+
+ try
+ {
+ bool isCorrect = Ckzg.VerifyKzgProof(commitment, z, y, proof, _ts);
+ Assert.That(isCorrect, Is.EqualTo(test.Output));
+ }
+ catch
+ {
+ Assert.That(test.Output, Is.EqualTo(null));
+ }
+ }
+ }
+
+ #endregion
+
+ #region VerifyBlobKzgProof
+
+ private class VerifyBlobKzgProofInput
+ {
+ public string Blob { get; set; } = null!;
+ public string Commitment { get; set; } = null!;
+ public string Proof { get; set; } = null!;
+ }
+
+ private class VerifyBlobKzgProofTest
+ {
+ public VerifyBlobKzgProofInput Input { get; set; } = null!;
+ public bool? Output { get; set; } = null!;
+ }
+
+ [TestCase]
+ public void TestVerifyBlobKzgProof()
+ {
+ Matcher matcher = new();
+ matcher.AddIncludePatterns(new[] { "*/*/data.yaml" });
+
+ foreach (string testFile in matcher.GetResultsInFullPath(_verifyBlobKzgProofTests))
+ {
+ string yaml = File.ReadAllText(testFile);
+ VerifyBlobKzgProofTest test = _deserializer.Deserialize(yaml);
+ Assert.That(test, Is.Not.EqualTo(null));
+
+ byte[] blob = GetBytes(test.Input.Blob);
+ byte[] commitment = GetBytes(test.Input.Commitment);
+ byte[] proof = GetBytes(test.Input.Proof);
+ try
+ {
+ bool isCorrect = Ckzg.VerifyBlobKzgProof(blob, commitment, proof, _ts);
+ Assert.That(isCorrect, Is.EqualTo(test.Output));
+ }
+ catch
+ {
+ Assert.That(test.Output, Is.EqualTo(null));
+ }
+ }
+ }
+
+ #endregion
+
+ #region VerifyBlobKzgProofBatch
+
+ private class VerifyBlobKzgProofBatchInput
+ {
+ public List Blobs { get; set; } = null!;
+ public List Commitments { get; set; } = null!;
+ public List Proofs { get; set; } = null!;
+ }
+
+ private class VerifyBlobKzgProofBatchTest
+ {
+ public VerifyBlobKzgProofBatchInput Input { get; set; } = null!;
+ public bool? Output { get; set; } = null!;
+ }
+
+ [TestCase]
+ public void TestVerifyBlobKzgProofBatch()
+ {
+ Matcher matcher = new();
+ matcher.AddIncludePatterns(new[] { "*/*/data.yaml" });
+
+ foreach (string testFile in matcher.GetResultsInFullPath(_verifyBlobKzgProofBatchTests))
+ {
+ string yaml = File.ReadAllText(testFile);
+ VerifyBlobKzgProofBatchTest test = _deserializer.Deserialize(yaml);
+ Assert.That(test, Is.Not.EqualTo(null));
+
+ byte[] blobs = GetFlatBytes(test.Input.Blobs);
+ byte[] commitments = GetFlatBytes(test.Input.Commitments);
+ byte[] proofs = GetFlatBytes(test.Input.Proofs);
+ int count = blobs.Length / Ckzg.BytesPerBlob;
+
+ try
+ {
+ bool isCorrect = Ckzg.VerifyBlobKzgProofBatch(blobs, commitments, proofs, count, _ts);
+ Assert.That(isCorrect, Is.EqualTo(test.Output));
+ }
+ catch
+ {
+ Assert.That(test.Output, Is.EqualTo(null));
+ }
+ }
+ }
+
+ #endregion
+}
\ No newline at end of file
diff --git a/bindings/csharp/Makefile b/bindings/csharp/Makefile
index d5fa3dc..af2a782 100644
--- a/bindings/csharp/Makefile
+++ b/bindings/csharp/Makefile
@@ -1,9 +1,9 @@
ifeq ($(OS),Windows_NT)
BLST_BUILDSCRIPT = ./build.bat
BLST_OBJ = blst.lib
- CSHARP_PLATFORM ?= win-x64
+ LOCATION ?= win-x64
CLANG_EXECUTABLE = clang
- CKZG_LIBRARY_PATH = Ckzg.Bindings\runtimes\$(CSHARP_PLATFORM)\native\ckzg.dll
+ CKZG_LIBRARY_PATH = Ckzg.Bindings\runtimes\$(LOCATION)\native\ckzg.dll
else
BLST_BUILDSCRIPT = ./build.sh
BLST_OBJ = libblst.a
@@ -13,20 +13,20 @@ else
UNAME_M := $(shell uname -m)
ifeq ($(UNAME_S),Linux)
ifeq ($(UNAME_M),x86_64)
- CSHARP_PLATFORM ?= linux-x64
+ LOCATION ?= linux-x64
else
- CSHARP_PLATFORM ?= linux-arm64
+ LOCATION ?= linux-arm64
endif
endif
ifeq ($(UNAME_S),Darwin)
ifeq ($(UNAME_M),arm64)
- CSHARP_PLATFORM ?= osx-arm64
+ LOCATION ?= osx-arm64
else
- CSHARP_PLATFORM ?= osx-x64
+ LOCATION ?= osx-x64
endif
endif
- CKZG_LIBRARY_PATH = Ckzg.Bindings/runtimes/$(CSHARP_PLATFORM)/native/ckzg.so
+ CKZG_LIBRARY_PATH = Ckzg.Bindings/runtimes/$(LOCATION)/native/ckzg.so
endif
FIELD_ELEMENTS_PER_BLOB ?= 4096
@@ -36,13 +36,17 @@ TARGETS = ckzg.c ../../src/c_kzg_4844.c ../../blst/$(BLST_OBJ)
CFLAGS += -O2 -Wall -Wextra -shared
CFLAGS += -DFIELD_ELEMENTS_PER_BLOB=$(FIELD_ELEMENTS_PER_BLOB)
CFLAGS += ${addprefix -I,${INCLUDE_DIRS}}
+ifdef ARCH
+ CFLAGS += --target=$(ARCH)
+ BLST_BUILDSCRIPT_FLAGS += --target=$(ARCH)
+endif
.PHONY: all
all: blst ckzg ckzg-dotnet
.PHONY: blst
blst:
- cd ../../blst && $(BLST_BUILDSCRIPT)
+ cd ../../blst && $(BLST_BUILDSCRIPT) $(BLST_BUILDSCRIPT_FLAGS)
.PHONY: ckzg
ckzg: blst
diff --git a/bindings/csharp/kzg_tests.c b/bindings/csharp/kzg_tests.c
deleted file mode 100644
index 9f39542..0000000
--- a/bindings/csharp/kzg_tests.c
+++ /dev/null
@@ -1,45 +0,0 @@
-// RUN: make run-test
-#include "ckzg.h"
-#include
-
-void calculate_proof_and_commitment(char * trusted_setup_path){
- KZGSettings *s = load_trusted_setup_wrap(trusted_setup_path);
- size_t n = 1;
- uint8_t *commitment = (uint8_t *)calloc(48, 1);
- uint8_t *proof = (uint8_t *)calloc(48, 1);
- uint8_t *blob = (uint8_t *)calloc(4096, 32);
- uint8_t *blobHash = (uint8_t *)calloc(32, 1);
- n = 0;
- for(int i = 0; i < 5875; i++){
- if((n + 1) % 32 == 0)n++;
- blob[n] = i % 250;
- n++;
- }
- int res0 = compute_aggregate_kzg_proof(proof, blob, 1, s);
- int res1 = blob_to_kzg_commitment(commitment, blob, s);
-
- FILE *f = fopen("output.txt", "wt");
- // commitment
- for(int i = 0; i < 48; i++){
- fprintf(f, "%02x", commitment[i]);
- }
- fprintf(f, "\n");
-
- // proof
- for(int i = 0; i < 48; i++){
- fprintf(f, "%02x", proof[i]);
- }
- fprintf(f, "\n");
-
- fclose(f);
- free(blob);
- free(commitment);
- free(proof);
- free_trusted_setup_wrap(s);
-}
-
-
-int main() {
- calculate_proof_and_commitment("../../src/trusted_setup.txt");
- return 0;
-}
\ No newline at end of file