c-kzg-4844/bindings/nim/kzg.nim

247 lines
6.4 KiB
Nim

############################################################
# Main API, wrapper on top of C FFI
############################################################
import
std/[streams, strutils],
stew/[results, byteutils],
./kzg_abi
export
results,
kzg_abi
type
KzgCtx* = ref object
val: KzgSettings
KzgProofAndY* = object
proof*: KzgProof
y*: KzgBytes32
G1Data* = array[48, byte]
G2Data* = array[96, byte]
when (NimMajor, NimMinor) < (1, 4):
{.push raises: [Defect].}
else:
{.push raises: [].}
##############################################################
# Private helpers
##############################################################
proc destroy*(x: KzgCtx) =
free_trusted_setup(x.val)
proc newKzgCtx(): KzgCtx =
# Nim finalizer is still broken(v1.6)
# consider to call destroy directly
new(result, destroy)
template getPtr(x: untyped): auto =
when (NimMajor, NimMinor) <= (1,6):
unsafeAddr(x)
else:
addr(x)
template verify(res: KZG_RET, ret: untyped): untyped =
if res != KZG_OK:
return err($res)
ok(ret)
##############################################################
# Public functions
##############################################################
proc loadTrustedSetup*(input: File): Result[KzgCtx, string] =
let
ctx = newKzgCtx()
res = load_trusted_setup_file(ctx.val, input)
verify(res, ctx)
proc loadTrustedSetup*(fileName: string): Result[KzgCtx, string] =
try:
let file = open(fileName)
result = file.loadTrustedSetup()
file.close()
except IOError as ex:
return err(ex.msg)
proc loadTrustedSetup*(g1: openArray[G1Data],
g2: openArray[G2Data]):
Result[KzgCtx, string] =
if g1.len == 0 or g2.len == 0:
return err($KZG_BADARGS)
let
ctx = newKzgCtx()
res = load_trusted_setup(ctx.val,
g1[0][0].getPtr,
g1.len.csize_t,
g2[0][0].getPtr,
g2.len.csize_t)
verify(res, ctx)
proc loadTrustedSetupFromString*(input: string): Result[KzgCtx, string] =
const
NumG2 = 65
G1Len = G1Data.len
G2Len = G2Data.len
var
s = newStringStream(input)
g1: array[FIELD_ELEMENTS_PER_BLOB, G1Data]
g2: array[NumG2, G2Data]
try:
let fieldElems = s.readLine().parseInt()
if fieldElems != FIELD_ELEMENTS_PER_BLOB:
return err("invalid field elemments per blob, expect $1, got $2" % [
$FIELD_ELEMENTS_PER_BLOB, $fieldElems
])
let numG2 = s.readLine().parseInt()
if numG2 != NumG2:
return err("invalid number of G2, expect $1, got $2" % [
$NumG2, $numG2
])
for i in 0 ..< FIELD_ELEMENTS_PER_BLOB:
g1[i] = hexToByteArray[G1Len](s.readLine())
for i in 0 ..< NumG2:
g2[i] = hexToByteArray[G2Len](s.readLine())
except ValueError as ex:
return err(ex.msg)
except OSError as ex:
return err(ex.msg)
except IOError as ex:
return err(ex.msg)
loadTrustedSetup(g1, g2)
proc toCommitment*(ctx: KzgCtx,
blob: KzgBlob):
Result[KzgCommitment, string] {.gcsafe.} =
var ret: KzgCommitment
let res = blob_to_kzg_commitment(ret, blob, ctx.val)
verify(res, ret)
proc computeProof*(ctx: KzgCtx,
blob: KzgBlob,
z: KzgBytes32): Result[KzgProofAndY, string] {.gcsafe.} =
var ret: KzgProofAndY
let res = compute_kzg_proof(
ret.proof,
ret.y,
blob,
z,
ctx.val)
verify(res, ret)
proc computeProof*(ctx: KzgCtx,
blob: KzgBlob,
commitmentBytes: KzgBytes48): Result[KzgProof, string] {.gcsafe.} =
var proof: KzgProof
let res = compute_blob_kzg_proof(
proof,
blob,
commitmentBytes,
ctx.val)
verify(res, proof)
proc verifyProof*(ctx: KzgCtx,
commitment: KzgBytes48,
z: KzgBytes32, # Input Point
y: KzgBytes32, # Claimed Value
proof: KzgBytes48): Result[bool, string] {.gcsafe.} =
var valid: bool
let res = verify_kzg_proof(
valid,
commitment,
z,
y,
proof,
ctx.val)
verify(res, valid)
proc verifyProof*(ctx: KzgCtx,
blob: KzgBlob,
commitment: KzgBytes48,
proof: KzgBytes48): Result[bool, string] {.gcsafe.} =
var valid: bool
let res = verify_blob_kzg_proof(
valid,
blob,
commitment,
proof,
ctx.val)
verify(res, valid)
proc verifyProofs*(ctx: KzgCtx,
blobs: openArray[KzgBlob],
commitments: openArray[KzgBytes48],
proofs: openArray[KzgBytes48]): Result[bool, string] {.gcsafe.} =
if blobs.len != commitments.len:
return err($KZG_BADARGS)
if blobs.len != proofs.len:
return err($KZG_BADARGS)
if blobs.len == 0:
return ok(true)
var valid: bool
let res = verify_blob_kzg_proof_batch(
valid,
blobs[0].getPtr,
commitments[0].getPtr,
proofs[0].getPtr,
blobs.len.csize_t,
ctx.val)
verify(res, valid)
##############################################################
# Zero overhead aliases that match the spec
##############################################################
template loadTrustedSetupFile*(input: File | string): untyped =
loadTrustedSetup(input)
template freeTrustedSetup*(ctx: KzgCtx) =
free_trusted_setup(ctx.val)
template blobToKzgCommitment*(ctx: KzgCtx,
blob: KzgBlob): untyped =
toCommitment(ctx, blob)
template computeKzgProof*(ctx: KzgCtx,
blob: KzgBlob, z: KzgBytes32): untyped =
computeProof(ctx, blob, z)
template computeBlobKzgProof*(ctx: KzgCtx,
blob: KzgBlob,
commitmentBytes: KzgBytes48): untyped =
computeProof(ctx, blob, commitmentBytes)
template verifyKzgProof*(ctx: KzgCtx,
commitment: KzgBytes48,
z: KzgBytes32, # Input Point
y: KzgBytes32, # Claimed Value
proof: KzgBytes48): untyped =
verifyProof(ctx, commitment, z, y, proof)
template verifyBlobKzgProof*(ctx: KzgCtx,
blob: KzgBlob,
commitment: KzgBytes48,
proof: KzgBytes48): untyped =
verifyProof(ctx, blob, commitment, proof)
template verifyBlobKzgProofBatch*(ctx: KzgCtx,
blobs: openArray[KzgBlob],
commitments: openArray[KzgBytes48],
proofs: openArray[KzgBytes48]): untyped =
verifyProofs(ctx, blobs, commitments, proofs)
{. pop .}