namespace Ckzg;
public static partial class Ckzg
{
public const int BytesPerFieldElement = 32;
public const int FieldElementsPerBlob = 4096;
public const int BytesPerBlob = BytesPerFieldElement * FieldElementsPerBlob;
public const int BytesPerCommitment = 48;
public const int BytesPerProof = 48;
///
/// Loads trusted setup settings from file.
///
/// Settings file path
/// 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.
///
/// Trusted setup settings
/// Thrown when settings are not correct
public static void FreeTrustedSetup(IntPtr ckzgSetup)
{
ThrowOnUninitializedTrustedSetup(ckzgSetup);
InternalFreeTrustedSetup(ckzgSetup);
}
///
/// Calculates commitment for the blob.
///
/// Preallocated buffer of bytes to receive the commitment
/// Flatten array of blob elements
/// 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`.
///
/// 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.
///
/// 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.
///
///
///
///
/// 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 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.
///
/// 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
/// 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
}