mirror of
https://github.com/luxfi/c-kzg-4844.git
synced 2026-11-03 06:54:56 +00:00
328 lines
9.4 KiB
Nim
328 lines
9.4 KiB
Nim
############################################################
|
|
# Main API, wrapper on top of C FFI
|
|
############################################################
|
|
|
|
import
|
|
std/[streams, strutils],
|
|
stew/[assign2, byteutils],
|
|
results,
|
|
./kzg_abi
|
|
|
|
export
|
|
results,
|
|
kzg_abi.KzgBlob,
|
|
kzg_abi.KzgBytes32,
|
|
kzg_abi.KzgBytes48,
|
|
kzg_abi.KzgCell,
|
|
kzg_abi.KzgCommitment,
|
|
kzg_abi.KzgProof
|
|
|
|
const
|
|
TrustedSetupNotLoadedErr* = "Trusted setup is not loaded."
|
|
TrustedSetupAlreadyLoadedErr* = "Trusted setup is already loaded."
|
|
|
|
type
|
|
KzgCtx = object
|
|
initialized: bool
|
|
settings: ptr KzgSettings
|
|
|
|
KzgProofAndY* = object
|
|
proof*: KzgProof
|
|
y*: KzgBytes32
|
|
|
|
KzgCells* = array[CELLS_PER_EXT_BLOB, KzgCell]
|
|
KzgCellsAndKzgProofs* = object
|
|
cells*: array[CELLS_PER_EXT_BLOB, KzgCell]
|
|
proofs*: array[CELLS_PER_EXT_BLOB, KzgProof]
|
|
|
|
when (NimMajor, NimMinor) < (1, 4):
|
|
{.push raises: [Defect].}
|
|
else:
|
|
{.push raises: [].}
|
|
|
|
##############################################################
|
|
# Global variables
|
|
##############################################################
|
|
|
|
var gCtx: KzgCtx
|
|
gCtx.initialized = false
|
|
gCtx.settings = nil
|
|
|
|
##############################################################
|
|
# Private helpers
|
|
##############################################################
|
|
|
|
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, precompute: Natural): Result[void, string] {.gcsafe.} =
|
|
if gCtx.initialized:
|
|
return err(TrustedSetupAlreadyLoadedErr)
|
|
gCtx.settings = cast[ptr KzgSettings](alloc0(sizeof(KzgSettings)))
|
|
let res = load_trusted_setup_file(gCtx.settings, input, precompute.uint64)
|
|
if res != KZG_OK:
|
|
dealloc(gCtx.settings)
|
|
gCtx.settings = nil
|
|
return err($res)
|
|
gCtx.initialized = true
|
|
return ok()
|
|
|
|
proc loadTrustedSetup*(fileName: string, precompute: Natural): Result[void, string] {.gcsafe.} =
|
|
try:
|
|
let file = open(fileName)
|
|
result = file.loadTrustedSetup(precompute)
|
|
file.close()
|
|
except IOError as ex:
|
|
return err(ex.msg)
|
|
|
|
proc loadTrustedSetup*(g1MonomialBytes: openArray[byte],
|
|
g1LagrangeBytes: openArray[byte],
|
|
g2MonomialBytes: openArray[byte],
|
|
precompute: Natural):
|
|
Result[void, string] {.gcsafe.} =
|
|
if gCtx.initialized:
|
|
return err(TrustedSetupAlreadyLoadedErr)
|
|
if g1MonomialBytes.len == 0 or g1LagrangeBytes.len == 0 or g2MonomialBytes.len == 0:
|
|
return err($KZG_BADARGS)
|
|
|
|
gCtx.settings = cast[ptr KzgSettings](alloc0(sizeof(KzgSettings)))
|
|
let res = load_trusted_setup(gCtx.settings,
|
|
g1MonomialBytes[0].getPtr,
|
|
g1MonomialBytes.len.uint64,
|
|
g1LagrangeBytes[0].getPtr,
|
|
g1LagrangeBytes.len.uint64,
|
|
g2MonomialBytes[0].getPtr,
|
|
g2MonomialBytes.len.uint64,
|
|
precompute.uint64)
|
|
if res != KZG_OK:
|
|
dealloc(gCtx.settings)
|
|
gCtx.settings = nil
|
|
return err($res)
|
|
gCtx.initialized = true
|
|
return ok()
|
|
|
|
proc loadTrustedSetupFromString*(input: string, precompute: Natural): Result[void, string] {.gcsafe.} =
|
|
const
|
|
NumG1 = FIELD_ELEMENTS_PER_BLOB
|
|
NumG2 = 65
|
|
G1Len = 48
|
|
G2Len = 96
|
|
|
|
var
|
|
s = newStringStream(input)
|
|
g1MonomialBytes: array[NumG1 * G1Len, byte]
|
|
g1LagrangeBytes: array[NumG1 * G1Len, byte]
|
|
g2MonomialBytes: array[NumG2 * G2Len, byte]
|
|
|
|
try:
|
|
let numG1 = s.readLine().parseInt()
|
|
if numG1 != NumG1:
|
|
return err("invalid number of G1 points, expect $1, got $2" % [
|
|
$NumG1, $numG1
|
|
])
|
|
let numG2 = s.readLine().parseInt()
|
|
if numG2 != NumG2:
|
|
return err("invalid number of G2 points, expect $1, got $2" % [
|
|
$NumG2, $numG2
|
|
])
|
|
|
|
for i in 0 ..< NumG1:
|
|
let p = hexToByteArray[G1Len](s.readLine())
|
|
assign(g1LagrangeBytes.toOpenArray(i * G1Len, ((i + 1) * G1Len) - 1), p)
|
|
|
|
for i in 0 ..< NumG2:
|
|
let p = hexToByteArray[G2Len](s.readLine())
|
|
assign(g2MonomialBytes.toOpenArray(i * G2Len, ((i + 1) * G2Len) - 1), p)
|
|
|
|
for i in 0 ..< NumG1:
|
|
let p = hexToByteArray[G1Len](s.readLine())
|
|
assign(g1MonomialBytes.toOpenArray(i * G1Len, ((i + 1) * G1Len) - 1), p)
|
|
|
|
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(g1MonomialBytes, g1LagrangeBytes, g2MonomialBytes, precompute)
|
|
|
|
proc freeTrustedSetup*(): Result[void, string] {.gcsafe.} =
|
|
if not gCtx.initialized:
|
|
return err(TrustedSetupNotLoadedErr)
|
|
free_trusted_setup(gCtx.settings)
|
|
gCtx.initialized = false
|
|
dealloc(gCtx.settings)
|
|
gCtx.settings = nil
|
|
return ok()
|
|
|
|
proc blobToKzgCommitment*(blob: KzgBlob): Result[KzgCommitment, string] {.gcsafe.} =
|
|
if not gCtx.initialized:
|
|
return err(TrustedSetupNotLoadedErr)
|
|
var ret: KzgCommitment
|
|
let res = blob_to_kzg_commitment(ret, blob.getPtr, gCtx.settings)
|
|
verify(res, ret)
|
|
|
|
proc computeKzgProof*(blob: KzgBlob,
|
|
z: KzgBytes32): Result[KzgProofAndY, string] {.gcsafe.} =
|
|
if not gCtx.initialized:
|
|
return err(TrustedSetupNotLoadedErr)
|
|
var ret: KzgProofAndY
|
|
let res = compute_kzg_proof(
|
|
ret.proof,
|
|
ret.y,
|
|
blob.getPtr,
|
|
z.getPtr,
|
|
gCtx.settings)
|
|
verify(res, ret)
|
|
|
|
proc computeBlobKzgProof*(blob: KzgBlob,
|
|
commitmentBytes: KzgBytes48): Result[KzgProof, string] {.gcsafe.} =
|
|
if not gCtx.initialized:
|
|
return err(TrustedSetupNotLoadedErr)
|
|
var proof: KzgProof
|
|
let res = compute_blob_kzg_proof(
|
|
proof,
|
|
blob.getPtr,
|
|
commitmentBytes.getPtr,
|
|
gCtx.settings)
|
|
verify(res, proof)
|
|
|
|
proc verifyKzgProof*(commitment: KzgBytes48,
|
|
z: KzgBytes32, # Input Point
|
|
y: KzgBytes32, # Claimed Value
|
|
proof: KzgBytes48): Result[bool, string] {.gcsafe.} =
|
|
if not gCtx.initialized:
|
|
return err(TrustedSetupNotLoadedErr)
|
|
var valid: bool
|
|
let res = verify_kzg_proof(
|
|
valid,
|
|
commitment.getPtr,
|
|
z.getPtr,
|
|
y.getPtr,
|
|
proof.getPtr,
|
|
gCtx.settings)
|
|
verify(res, valid)
|
|
|
|
proc verifyBlobKzgProof*(blob: KzgBlob,
|
|
commitment: KzgBytes48,
|
|
proof: KzgBytes48): Result[bool, string] {.gcsafe.} =
|
|
if not gCtx.initialized:
|
|
return err(TrustedSetupNotLoadedErr)
|
|
var valid: bool
|
|
let res = verify_blob_kzg_proof(
|
|
valid,
|
|
blob.getPtr,
|
|
commitment.getPtr,
|
|
proof.getPtr,
|
|
gCtx.settings)
|
|
verify(res, valid)
|
|
|
|
proc verifyBlobKzgProofBatch*(blobs: openArray[KzgBlob],
|
|
commitments: openArray[KzgBytes48],
|
|
proofs: openArray[KzgBytes48]): Result[bool, string] {.gcsafe.} =
|
|
if not gCtx.initialized:
|
|
return err(TrustedSetupNotLoadedErr)
|
|
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.uint64,
|
|
gCtx.settings)
|
|
verify(res, valid)
|
|
|
|
proc computeCells*(blob: KzgBlob): Result[KzgCells, string] {.gcsafe.} =
|
|
if not gCtx.initialized:
|
|
return err(TrustedSetupNotLoadedErr)
|
|
var ret: KzgCells
|
|
var cellsPtr: ptr KzgCell = ret[0].getPtr
|
|
let res = compute_cells_and_kzg_proofs(
|
|
cellsPtr,
|
|
nil,
|
|
blob.getPtr,
|
|
gCtx.settings)
|
|
verify(res, ret)
|
|
|
|
proc computeCellsAndKzgProofs*(blob: KzgBlob): Result[KzgCellsAndKzgProofs, string] {.gcsafe.} =
|
|
if not gCtx.initialized:
|
|
return err(TrustedSetupNotLoadedErr)
|
|
var ret: KzgCellsAndKzgProofs
|
|
var cellsPtr: ptr KzgCell = ret.cells[0].getPtr
|
|
var proofsPtr: ptr KzgProof = ret.proofs[0].getPtr
|
|
let res = compute_cells_and_kzg_proofs(
|
|
cellsPtr,
|
|
proofsPtr,
|
|
blob.getPtr,
|
|
gCtx.settings)
|
|
verify(res, ret)
|
|
|
|
proc recoverCellsAndKzgProofs*(cellIndices: openArray[uint64],
|
|
cells: openArray[KzgCell]): Result[KzgCellsAndKzgProofs, string] {.gcsafe.} =
|
|
if not gCtx.initialized:
|
|
return err(TrustedSetupNotLoadedErr)
|
|
if cells.len != cellIndices.len:
|
|
return err($KZG_BADARGS)
|
|
if cells.len == 0:
|
|
return err($KZG_BADARGS)
|
|
|
|
var ret: KzgCellsAndKzgProofs
|
|
var recoveredCellsPtr: ptr KzgCell = ret.cells[0].getPtr
|
|
var recoveredProofsPtr: ptr KzgProof = ret.proofs[0].getPtr
|
|
let res = recover_cells_and_kzg_proofs(
|
|
recoveredCellsPtr,
|
|
recoveredProofsPtr,
|
|
cellIndices[0].getPtr,
|
|
cells[0].getPtr,
|
|
cells.len.uint64,
|
|
gCtx.settings)
|
|
verify(res, ret)
|
|
|
|
proc verifyCellKzgProofBatch*(commitments: openArray[KzgBytes48],
|
|
cellIndices: openArray[uint64],
|
|
cells: openArray[KzgCell],
|
|
proofs: openArray[KzgBytes48]): Result[bool, string] {.gcsafe.} =
|
|
if not gCtx.initialized:
|
|
return err(TrustedSetupNotLoadedErr)
|
|
if commitments.len != cells.len:
|
|
return err($KZG_BADARGS)
|
|
if cellIndices.len != cells.len:
|
|
return err($KZG_BADARGS)
|
|
if proofs.len != cells.len:
|
|
return err($KZG_BADARGS)
|
|
if cells.len == 0:
|
|
return ok(true)
|
|
|
|
var valid: bool
|
|
let res = verify_cell_kzg_proof_batch(
|
|
valid,
|
|
commitments[0].getPtr,
|
|
cellIndices[0].getPtr,
|
|
cells[0].getPtr,
|
|
proofs[0].getPtr,
|
|
cells.len.uint64,
|
|
gCtx.settings)
|
|
verify(res, valid)
|
|
|
|
{. pop .}
|