Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API: argument order (breaking external Nim/C/Go/Rust EIP-4844 API #394

Merged
merged 1 commit into from
Jun 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Architecture

## APIs

### Argument orders

Function calls have arguments ordered the following way:

1. Context arguments
2. Threadpool context
3. OUT arguments (only written to)
4. INOUT arguments
5. IN arguments

The first context argument should allow method call syntax

In C, length of arrays immediately follow the array, unless there are multiple array arguments with same length.
If an argument is associated with a label, for domain separation for example,
that label precedes the argument.

### Return values

Constantine avoids returning values bigger than the word size
and prefer mutable out parameters.

1. In some cases they introduce extra copies.
2. There is less guarantees over stack space usage.
3. Nim will zero the values without {.noInit.}
and that zeroing might not be optimized away by the compiler
on large inputs like `Fp12[BLS12_381]` 48\*12 bytes = 576 bytes.
4. As we sometimes return SecretBool or status code, this keeps the API consistent.

## Code organization

TBD
12 changes: 6 additions & 6 deletions benchmarks/bench_eth_eip4844_kzg.nim
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ proc benchBlobToKzgCommitment(b: BenchSet, ctx: ptr EthereumKZGContext, iters: i
block:
bench("blob_to_kzg_commitment", $tp.numThreads & " threads", iters):
var commitment {.noInit.}: array[48, byte]
doAssert cttEthKzg_Success == ctx.blob_to_kzg_commitment_parallel(tp, commitment, b.blobs[0].addr)
doAssert cttEthKzg_Success == tp.blob_to_kzg_commitment_parallel(ctx, commitment, b.blobs[0].addr)
let stopParallel = getMonotime()

tp.shutdown()
Expand Down Expand Up @@ -108,7 +108,7 @@ proc benchComputeKzgProof(b: BenchSet, ctx: ptr EthereumKZGContext, iters: int)
bench("compute_kzg_proof", $tp.numThreads & " threads", iters):
var proof {.noInit.}: array[48, byte]
var eval_at_challenge {.noInit.}: array[32, byte]
doAssert cttEthKzg_Success == ctx.compute_kzg_proof_parallel(tp, proof, eval_at_challenge, b.blobs[0].addr, b.challenge)
doAssert cttEthKzg_Success == tp.compute_kzg_proof_parallel(ctx, proof, eval_at_challenge, b.blobs[0].addr, b.challenge)
let stopParallel = getMonotime()

tp.shutdown()
Expand All @@ -135,7 +135,7 @@ proc benchComputeBlobKzgProof(b: BenchSet, ctx: ptr EthereumKZGContext, iters: i
block:
bench("compute_blob_kzg_proof", $tp.numThreads & " threads", iters):
var proof {.noInit.}: array[48, byte]
doAssert cttEthKzg_Success == ctx.compute_blob_kzg_proof_parallel(tp, proof, b.blobs[0].addr, b.commitments[0])
doAssert cttEthKzg_Success == tp.compute_blob_kzg_proof_parallel(ctx, proof, b.blobs[0].addr, b.commitments[0])
let stopParallel = getMonotime()

tp.shutdown()
Expand Down Expand Up @@ -167,7 +167,7 @@ proc benchVerifyBlobKzgProof(b: BenchSet, ctx: ptr EthereumKZGContext, iters: in
let startParallel = getMonotime()
block:
bench("verify_blob_kzg_proof", $tp.numThreads & " threads", iters):
discard ctx.verify_blob_kzg_proof_parallel(tp, b.blobs[0].addr, b.commitments[0], b.proofs[0])
discard tp.verify_blob_kzg_proof_parallel(ctx, b.blobs[0].addr, b.commitments[0], b.proofs[0])
let stopParallel = getMonotime()

tp.shutdown()
Expand Down Expand Up @@ -205,8 +205,8 @@ proc benchVerifyBlobKzgProofBatch(b: BenchSet, ctx: ptr EthereumKZGContext, iter
let startParallel = getMonotime()
block:
bench("verify_blob_kzg_proof (batch " & $i & ')', $tp.numThreads & " threads", iters):
discard ctx.verify_blob_kzg_proof_batch_parallel(
tp,
discard tp.verify_blob_kzg_proof_batch_parallel(
ctx,
b.blobs.asUnchecked(),
b.commitments.asUnchecked(),
b.proofs.asUnchecked(),
Expand Down
43 changes: 31 additions & 12 deletions constantine-go/constantine.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ type (

type EthKzgContext struct {
cCtx *C.ctt_eth_kzg_context
threadpool Threadpool
}

func EthKzgContextNew(trustedSetupFile string) (ctx EthKzgContext, err error) {
Expand All @@ -72,9 +73,14 @@ func EthKzgContextNew(trustedSetupFile string) (ctx EthKzgContext, err error) {
C.GoString(C.ctt_eth_trusted_setup_status_to_string(status)),
)
}
ctx.threadpool.ctx = nil
return ctx, err
}

func (ctx *EthKzgContext) SetThreadpool(tp Threadpool) {
ctx.threadpool = tp
}

func (ctx EthKzgContext) Delete() {
C.ctt_eth_trusted_setup_delete(ctx.cCtx)
}
Expand Down Expand Up @@ -183,9 +189,12 @@ func (ctx EthKzgContext) VerifyBlobKzgProofBatch(blobs []EthBlob, commitments []
// Ethereum EIP-4844 KZG API - Parallel
// -----------------------------------------------------

func (ctx EthKzgContext) BlobToKZGCommitmentParallel(tp Threadpool, blob EthBlob) (commitment EthKzgCommitment, err error) {
func (ctx EthKzgContext) BlobToKZGCommitmentParallel(blob EthBlob) (commitment EthKzgCommitment, err error) {
if ctx.threadpool.ctx == nil {
return commitment, errors.New("BlobToKZGCommitmentParallel: The threadpool is not configured.")
}
status := C.ctt_eth_kzg_blob_to_kzg_commitment_parallel(
ctx.cCtx, tp.ctx,
ctx.threadpool.ctx, ctx.cCtx,
(*C.ctt_eth_kzg_commitment)(unsafe.Pointer(&commitment)),
(*C.ctt_eth_kzg_blob)(unsafe.Pointer(&blob)),
)
Expand All @@ -197,9 +206,12 @@ func (ctx EthKzgContext) BlobToKZGCommitmentParallel(tp Threadpool, blob EthBlob
return commitment, err
}

func (ctx EthKzgContext) ComputeKzgProofParallel(tp Threadpool, blob EthBlob, z EthKzgChallenge) (proof EthKzgProof, y EthKzgEvalAtChallenge, err error) {
func (ctx EthKzgContext) ComputeKzgProofParallel(blob EthBlob, z EthKzgChallenge) (proof EthKzgProof, y EthKzgEvalAtChallenge, err error) {
if ctx.threadpool.ctx == nil {
return proof, y, errors.New("ComputeKzgProofParallel: The Constantine's threadpool is not configured.")
}
status := C.ctt_eth_kzg_compute_kzg_proof_parallel(
ctx.cCtx, tp.ctx,
ctx.threadpool.ctx, ctx.cCtx,
(*C.ctt_eth_kzg_proof)(unsafe.Pointer(&proof)),
(*C.ctt_eth_kzg_eval_at_challenge)(unsafe.Pointer(&y)),
(*C.ctt_eth_kzg_blob)(unsafe.Pointer(&blob)),
Expand All @@ -213,9 +225,12 @@ func (ctx EthKzgContext) ComputeKzgProofParallel(tp Threadpool, blob EthBlob, z
return proof, y, err
}

func (ctx EthKzgContext) ComputeBlobKzgProofParallel(tp Threadpool, blob EthBlob, commitment EthKzgCommitment) (proof EthKzgProof, err error) {
func (ctx EthKzgContext) ComputeBlobKzgProofParallel(blob EthBlob, commitment EthKzgCommitment) (proof EthKzgProof, err error) {
if ctx.threadpool.ctx == nil {
return proof, errors.New("ComputeBlobKzgProofParallel: The threadpool is not configured.")
}
status := C.ctt_eth_kzg_compute_blob_kzg_proof_parallel(
ctx.cCtx, tp.ctx,
ctx.threadpool.ctx, ctx.cCtx,
(*C.ctt_eth_kzg_proof)(unsafe.Pointer(&proof)),
(*C.ctt_eth_kzg_blob)(unsafe.Pointer(&blob)),
(*C.ctt_eth_kzg_commitment)(unsafe.Pointer(&commitment)),
Expand All @@ -228,9 +243,12 @@ func (ctx EthKzgContext) ComputeBlobKzgProofParallel(tp Threadpool, blob EthBlob
return proof, err
}

func (ctx EthKzgContext) VerifyBlobKzgProofParallel(tp Threadpool, blob EthBlob, commitment EthKzgCommitment, proof EthKzgProof) (bool, error) {
func (ctx EthKzgContext) VerifyBlobKzgProofParallel(blob EthBlob, commitment EthKzgCommitment, proof EthKzgProof) (bool, error) {
if ctx.threadpool.ctx == nil {
return false, errors.New("VerifyBlobKzgProofParallel: The threadpool is not configured.")
}
status := C.ctt_eth_kzg_verify_blob_kzg_proof_parallel(
ctx.cCtx, tp.ctx,
ctx.threadpool.ctx, ctx.cCtx,
(*C.ctt_eth_kzg_blob)(unsafe.Pointer(&blob)),
(*C.ctt_eth_kzg_commitment)(unsafe.Pointer(&commitment)),
(*C.ctt_eth_kzg_proof)(unsafe.Pointer(&proof)),
Expand All @@ -244,14 +262,15 @@ func (ctx EthKzgContext) VerifyBlobKzgProofParallel(tp Threadpool, blob EthBlob,
return true, nil
}

func (ctx EthKzgContext) VerifyBlobKzgProofBatchParallel(tp Threadpool, blobs []EthBlob, commitments []EthKzgCommitment, proofs []EthKzgProof, secureRandomBytes [32]byte) (bool, error) {

func (ctx EthKzgContext) VerifyBlobKzgProofBatchParallel(blobs []EthBlob, commitments []EthKzgCommitment, proofs []EthKzgProof, secureRandomBytes [32]byte) (bool, error) {
if len(blobs) != len(commitments) || len(blobs) != len(proofs) {
return false, errors.New("VerifyBlobKzgProofBatch: Lengths of inputs do not match.")
}

if ctx.threadpool.ctx == nil {
return false, errors.New("VerifyBlobKzgProofBatch: The threadpool is not configured.")
}
status := C.ctt_eth_kzg_verify_blob_kzg_proof_batch_parallel(
ctx.cCtx, tp.ctx,
ctx.threadpool.ctx, ctx.cCtx,
*(**C.ctt_eth_kzg_blob)(unsafe.Pointer(&blobs)),
*(**C.ctt_eth_kzg_commitment)(unsafe.Pointer(&commitments)),
*(**C.ctt_eth_kzg_proof)(unsafe.Pointer(&proofs)),
Expand Down
Loading
Loading