2023-03-08 13:04:30 +00:00
|
|
|
############################################################
|
|
|
|
# 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)
|
|
|
|
|
2023-03-09 04:05:25 +00:00
|
|
|
template verify(res: KZG_RET, ret: untyped): untyped =
|
2023-03-08 13:04:30 +00:00
|
|
|
if res != KZG_OK:
|
|
|
|
return err($res)
|
2023-03-09 04:05:25 +00:00
|
|
|
ok(ret)
|
2023-03-08 13:04:30 +00:00
|
|
|
|
|
|
|
##############################################################
|
|
|
|
# Public functions
|
|
|
|
##############################################################
|
|
|
|
|
|
|
|
proc loadTrustedSetup*(input: File): Result[KzgCtx, string] =
|
|
|
|
let
|
|
|
|
ctx = newKzgCtx()
|
|
|
|
res = load_trusted_setup_file(ctx.val, input)
|
2023-03-09 04:05:25 +00:00
|
|
|
verify(res, ctx)
|
2023-03-08 13:04:30 +00:00
|
|
|
|
|
|
|
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)
|
2023-03-09 04:05:25 +00:00
|
|
|
verify(res, ctx)
|
2023-03-08 13:04:30 +00:00
|
|
|
|
|
|
|
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.} =
|
2023-03-09 04:05:25 +00:00
|
|
|
var ret: KzgCommitment
|
|
|
|
let res = blob_to_kzg_commitment(ret, blob, ctx.val)
|
|
|
|
verify(res, ret)
|
2023-03-08 13:04:30 +00:00
|
|
|
|
|
|
|
proc computeProof*(ctx: KzgCtx,
|
|
|
|
blob: KzgBlob,
|
|
|
|
z: KzgBytes32): Result[KzgProofAndY, string] {.gcsafe.} =
|
2023-03-09 04:05:25 +00:00
|
|
|
var ret: KzgProofAndY
|
2023-03-08 13:04:30 +00:00
|
|
|
let res = compute_kzg_proof(
|
2023-03-09 04:05:25 +00:00
|
|
|
ret.proof,
|
|
|
|
ret.y,
|
2023-03-08 13:04:30 +00:00
|
|
|
blob,
|
|
|
|
z,
|
|
|
|
ctx.val)
|
2023-03-09 04:05:25 +00:00
|
|
|
verify(res, ret)
|
2023-03-08 13:04:30 +00:00
|
|
|
|
|
|
|
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)
|
2023-03-09 04:05:25 +00:00
|
|
|
verify(res, proof)
|
2023-03-08 13:04:30 +00:00
|
|
|
|
|
|
|
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)
|
2023-03-09 04:05:25 +00:00
|
|
|
verify(res, valid)
|
2023-03-08 13:04:30 +00:00
|
|
|
|
|
|
|
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)
|
2023-03-09 04:05:25 +00:00
|
|
|
verify(res, valid)
|
2023-03-08 13:04:30 +00:00
|
|
|
|
|
|
|
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)
|
2023-03-09 04:05:25 +00:00
|
|
|
verify(res, valid)
|
2023-03-08 13:04:30 +00:00
|
|
|
|
|
|
|
##############################################################
|
|
|
|
# Zero overhead aliases that match the spec
|
|
|
|
##############################################################
|
|
|
|
|
|
|
|
template loadTrustedSetupFile*(input: File | string): untyped =
|
|
|
|
loadTrustedSetup(input)
|
|
|
|
|
2023-03-21 02:30:50 +00:00
|
|
|
template freeTrustedSetup*(ctx: KzgCtx) =
|
|
|
|
free_trusted_setup(ctx.val)
|
|
|
|
|
2023-03-08 13:04:30 +00:00
|
|
|
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 .}
|