Skip to content

Commit

Permalink
Provide C API to EIP4844
Browse files Browse the repository at this point in the history
  • Loading branch information
mratsim committed Dec 6, 2023
1 parent d2c4edc commit 5110f6a
Show file tree
Hide file tree
Showing 16 changed files with 393 additions and 171 deletions.
6 changes: 3 additions & 3 deletions benchmarks/bench_ethereum_bls_signatures.nim
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ proc benchVerifyMulti*(numSigs, iters: int) =
bench("BLS verif of " & $numSigs & " msgs by "& $numSigs & " pubkeys", "BLS12_381", iters):
for i in 0 ..< triplets.len:
let ok = triplets[i].pubkey.verify(triplets[i].msg, triplets[i].sig)
doAssert ok == cttEthBLS_Success
doAssert ok == cttEthBls_Success

proc benchVerifyBatched*(numSigs, iters: int) =
## Verification of N pubkeys signing for N messages
Expand All @@ -185,7 +185,7 @@ proc benchVerifyBatched*(numSigs, iters: int) =

bench("BLS serial batch verify of " & $numSigs & " msgs by "& $numSigs & " pubkeys (with blinding)", "BLS12_381", iters):
let ok = batch_verify(pubkeys, messages, signatures, secureBlindingBytes)
doAssert ok == cttEthBLS_Success
doAssert ok == cttEthBls_Success

proc benchVerifyBatchedParallel*(numSigs, iters: int) =
## Verification of N pubkeys signing for N messages
Expand Down Expand Up @@ -220,7 +220,7 @@ proc benchVerifyBatchedParallel*(numSigs, iters: int) =

bench("BLS parallel batch verify (" & $tp.numThreads & " threads) of " & $numSigs & " msgs by "& $numSigs & " pubkeys (with blinding)", "BLS12_381", iters):
let ok = tp.batch_verify_parallel(pubkeys, messages, signatures, secureBlindingBytes)
doAssert ok == cttEthBLS_Success, "invalid status: " & $ok
doAssert ok == cttEthBls_Success, "invalid status: " & $ok

tp.shutdown()

Expand Down
12 changes: 6 additions & 6 deletions benchmarks/bench_ethereum_eip4844_kzg.nim
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ proc benchBlobToKzgCommitment(b: BenchSet, ctx: ptr EthereumKZGContext, iters: i
block:
bench("blob_to_kzg_commitment", "serial", iters):
var commitment {.noInit.}: array[48, byte]
doAssert cttEthKZG_Success == ctx.blob_to_kzg_commitment(commitment, b.blobs[0].addr)
doAssert cttEthKzg_Success == ctx.blob_to_kzg_commitment(commitment, b.blobs[0].addr)
let stopSerial = getMonotime()

## We require `tp` to be unintialized as even idle threads somehow reduce perf of serial benches
Expand All @@ -73,7 +73,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 == tp.blob_to_kzg_commitment_parallel(ctx, commitment, b.blobs[0].addr)
doAssert cttEthKzg_Success == tp.blob_to_kzg_commitment_parallel(ctx, commitment, b.blobs[0].addr)
let stopParallel = getMonotime()

let perfSerial = inNanoseconds((stopSerial-startSerial) div iters)
Expand All @@ -89,7 +89,7 @@ proc benchComputeKzgProof(b: BenchSet, ctx: ptr EthereumKZGContext, iters: int)
bench("compute_kzg_proof", "serial", iters):
var proof {.noInit.}: array[48, byte]
var eval_at_challenge {.noInit.}: array[32, byte]
doAssert cttEthKZG_Success == ctx.compute_kzg_proof(proof, eval_at_challenge, b.blobs[0].addr, b.challenge)
doAssert cttEthKzg_Success == ctx.compute_kzg_proof(proof, eval_at_challenge, b.blobs[0].addr, b.challenge)
let stopSerial = getMonotime()

## We require `tp` to be unintialized as even idle threads somehow reduce perf of serial benches
Expand All @@ -100,7 +100,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 == tp.compute_kzg_proof_parallel(ctx, 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()

let perfSerial = inNanoseconds((stopSerial-startSerial) div iters)
Expand All @@ -115,7 +115,7 @@ proc benchComputeBlobKzgProof(b: BenchSet, ctx: ptr EthereumKZGContext, iters: i
block:
bench("compute_blob_kzg_proof", "serial", iters):
var proof {.noInit.}: array[48, byte]
doAssert cttEthKZG_Success == ctx.compute_blob_kzg_proof(proof, b.blobs[0].addr, b.commitments[0])
doAssert cttEthKzg_Success == ctx.compute_blob_kzg_proof(proof, b.blobs[0].addr, b.commitments[0])
let stopSerial = getMonotime()

## We require `tp` to be unintialized as even idle threads somehow reduce perf of serial benches
Expand All @@ -125,7 +125,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 == tp.compute_blob_kzg_proof_parallel(ctx, 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()

let perfSerial = inNanoseconds((stopSerial-startSerial) div iters)
Expand Down
10 changes: 5 additions & 5 deletions constantine-rust/constantine-sys/src/bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3870,11 +3870,11 @@ fn bindgen_test_layout_ctt_eth_bls_signature() {
#[repr(u8)]
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
pub enum ctt_eth_bls_status {
cttEthBLS_Success = 0,
cttEthBLS_VerificationFailure = 1,
cttEthBLS_PointAtInfinity = 2,
cttEthBLS_ZeroLengthAggregation = 3,
cttEthBLS_InconsistentLengthsOfInputs = 4,
cttEthBls_Success = 0,
cttEthBls_VerificationFailure = 1,
cttEthBls_PointAtInfinity = 2,
cttEthBls_ZeroLengthAggregation = 3,
cttEthBls_InconsistentLengthsOfInputs = 4,
}
extern "C" {
#[must_use]
Expand Down
86 changes: 43 additions & 43 deletions constantine/ethereum_bls_signatures.nim
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,12 @@ type
## A BLS12_381 signature for BLS signature schemes with public keys on G1 and signatures on G2
raw: ECP_ShortW_Aff[Fp2[BLS12_381], G2]

CttEthBLSStatus* = enum
cttEthBLS_Success
cttEthBLS_VerificationFailure
cttEthBLS_PointAtInfinity
cttEthBLS_ZeroLengthAggregation
cttEthBLS_InconsistentLengthsOfInputs
cttEthBlsStatus* = enum
cttEthBls_Success
cttEthBls_VerificationFailure
cttEthBls_PointAtInfinity
cttEthBls_ZeroLengthAggregation
cttEthBls_InconsistentLengthsOfInputs

# Comparisons
# ------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -162,7 +162,7 @@ func serialize_pubkey_compressed*(dst: var array[48, byte], public_key: PublicKe
func serialize_signature_compressed*(dst: var array[96, byte], signature: Signature): CttCodecEccStatus {.libPrefix: prefix_ffi.} =
## Serialize a signature in compressed (Zcash) format
##
## Returns cttEthBLS_Success if successful
## Returns cttEthBls_Success if successful
return dst.serialize_g2_compressed(signature.raw)

func deserialize_seckey*(dst: var SecretKey, src: array[32, byte]): CttCodecScalarStatus {.libPrefix: prefix_ffi.} =
Expand Down Expand Up @@ -232,7 +232,7 @@ func sign*(signature: var Signature, secret_key: SecretKey, message: openArray[b
## with the scheme
coreSign(signature.raw, secretKey.raw, message, sha256, 128, augmentation = "", DomainSeparationTag)

func verify*(public_key: PublicKey, message: openArray[byte], signature: Signature): CttEthBLSStatus {.libPrefix: prefix_ffi, genCharAPI.} =
func verify*(public_key: PublicKey, message: openArray[byte], signature: Signature): cttEthBlsStatus {.libPrefix: prefix_ffi, genCharAPI.} =
## Check that a signature is valid for a message
## under the provided public key.
## returns `true` if the signature is valid, `false` otherwise.
Expand All @@ -254,12 +254,12 @@ func verify*(public_key: PublicKey, message: openArray[byte], signature: Signatu

# Deal with cases were pubkey or signature were mistakenly zero-init, due to a generic aggregation tentative for example
if bool(public_key.raw.isInf() or signature.raw.isInf()):
return cttEthBLS_PointAtInfinity
return cttEthBls_PointAtInfinity

let verified = coreVerify(public_key.raw, message, signature.raw, sha256, 128, augmentation = "", DomainSeparationTag)
if verified:
return cttEthBLS_Success
return cttEthBLS_VerificationFailure
return cttEthBls_Success
return cttEthBls_VerificationFailure

template unwrap[T: PublicKey|Signature](elems: openArray[T]): auto =
# Unwrap collection of high-level type into collection of low-level type
Expand Down Expand Up @@ -287,7 +287,7 @@ func aggregate_signatures_unstable_api*(aggregate_sig: var Signature, signatures
return
aggregate_sig.raw.aggregate(signatures.unwrap())

func fast_aggregate_verify*(pubkeys: openArray[PublicKey], message: openArray[byte], aggregate_sig: Signature): CttEthBLSStatus {.libPrefix: prefix_ffi, genCharAPI.} =
func fast_aggregate_verify*(pubkeys: openArray[PublicKey], message: openArray[byte], aggregate_sig: Signature): cttEthBlsStatus {.libPrefix: prefix_ffi, genCharAPI.} =
## Check that a signature is valid for a message
## under the aggregate of provided public keys.
## returns `true` if the signature is valid, `false` otherwise.
Expand All @@ -305,29 +305,29 @@ func fast_aggregate_verify*(pubkeys: openArray[PublicKey], message: openArray[by

if pubkeys.len == 0:
# IETF spec precondition
return cttEthBLS_ZeroLengthAggregation
return cttEthBls_ZeroLengthAggregation

# Deal with cases were pubkey or signature were mistakenly zero-init, due to a generic aggregation tentative for example
if aggregate_sig.raw.isInf().bool:
return cttEthBLS_PointAtInfinity
return cttEthBls_PointAtInfinity

for i in 0 ..< pubkeys.len:
if pubkeys[i].raw.isInf().bool:
return cttEthBLS_PointAtInfinity
return cttEthBls_PointAtInfinity

let verified = fastAggregateVerify(
pubkeys.unwrap(),
message, aggregate_sig.raw,
sha256, 128, DomainSeparationTag)
if verified:
return cttEthBLS_Success
return cttEthBLS_VerificationFailure
return cttEthBls_Success
return cttEthBls_VerificationFailure

# C FFI
func aggregate_verify*(pubkeys: ptr UncheckedArray[PublicKey],
messages: ptr UncheckedArray[View[byte]],
len: int,
aggregate_sig: Signature): CttEthBLSStatus {.libPrefix: prefix_ffi.} =
aggregate_sig: Signature): cttEthBlsStatus {.libPrefix: prefix_ffi.} =
## Verify the aggregated signature of multiple (pubkey, message) pairs
## returns `true` if the signature is valid, `false` otherwise.
##
Expand All @@ -348,27 +348,27 @@ func aggregate_verify*(pubkeys: ptr UncheckedArray[PublicKey],

if len == 0:
# IETF spec precondition
return cttEthBLS_ZeroLengthAggregation
return cttEthBls_ZeroLengthAggregation

# Deal with cases were pubkey or signature were mistakenly zero-init, due to a generic aggregation tentative for example
if aggregate_sig.raw.isInf().bool:
return cttEthBLS_PointAtInfinity
return cttEthBls_PointAtInfinity

for i in 0 ..< len:
if pubkeys[i].raw.isInf().bool:
return cttEthBLS_PointAtInfinity
return cttEthBls_PointAtInfinity

let verified = aggregateVerify(
pubkeys.toOpenArray(len).unwrap(),
messages.toOpenArray(len),
aggregate_sig.raw,
sha256, 128, DomainSeparationTag)
if verified:
return cttEthBLS_Success
return cttEthBLS_VerificationFailure
return cttEthBls_Success
return cttEthBls_VerificationFailure

# Nim
func aggregate_verify*[Msg](pubkeys: openArray[PublicKey], messages: openArray[Msg], aggregate_sig: Signature): CttEthBLSStatus =
func aggregate_verify*[Msg](pubkeys: openArray[PublicKey], messages: openArray[Msg], aggregate_sig: Signature): cttEthBlsStatus =
## Verify the aggregated signature of multiple (pubkey, message) pairs
## returns `true` if the signature is valid, `false` otherwise.
##
Expand All @@ -389,33 +389,33 @@ func aggregate_verify*[Msg](pubkeys: openArray[PublicKey], messages: openArray[M

if pubkeys.len == 0:
# IETF spec precondition
return cttEthBLS_ZeroLengthAggregation
return cttEthBls_ZeroLengthAggregation

if pubkeys.len != messages.len:
return cttEthBLS_InconsistentLengthsOfInputs
return cttEthBls_InconsistentLengthsOfInputs

# Deal with cases were pubkey or signature were mistakenly zero-init, due to a generic aggregation tentative for example
if aggregate_sig.raw.isInf().bool:
return cttEthBLS_PointAtInfinity
return cttEthBls_PointAtInfinity

for i in 0 ..< pubkeys.len:
if pubkeys[i].raw.isInf().bool:
return cttEthBLS_PointAtInfinity
return cttEthBls_PointAtInfinity

let verified = aggregateVerify(
pubkeys.unwrap(),
messages, aggregate_sig.raw,
sha256, 128, DomainSeparationTag)
if verified:
return cttEthBLS_Success
return cttEthBLS_VerificationFailure
return cttEthBls_Success
return cttEthBls_VerificationFailure

# C FFI
func batch_verify*[Msg](pubkeys: ptr UncheckedArray[PublicKey],
messages: ptr UncheckedArray[View[byte]],
signatures: ptr UncheckedArray[Signature],
len: int,
secureRandomBytes: array[32, byte]): CttEthBLSStatus {.libPrefix: prefix_ffi.} =
secureRandomBytes: array[32, byte]): cttEthBlsStatus {.libPrefix: prefix_ffi.} =
## Verify that all (pubkey, message, signature) triplets are valid
## returns `true` if all signatures are valid, `false` if at least one is invalid.
##
Expand All @@ -441,28 +441,28 @@ func batch_verify*[Msg](pubkeys: ptr UncheckedArray[PublicKey],

if len == 0:
# IETF spec precondition
return cttEthBLS_ZeroLengthAggregation
return cttEthBls_ZeroLengthAggregation

# Deal with cases were pubkey or signature were mistakenly zero-init, due to a generic aggregation tentative for example
for i in 0 ..< len:
if pubkeys[i].raw.isInf().bool:
return cttEthBLS_PointAtInfinity
return cttEthBls_PointAtInfinity

for i in 0 ..< len:
if signatures[i].raw.isInf().bool:
return cttEthBLS_PointAtInfinity
return cttEthBls_PointAtInfinity

let verified = batchVerify(
pubkeys.toOpenArray(len).unwrap(),
messages,
signatures.toOpenArray(len).unwrap(),
sha256, 128, DomainSeparationTag, secureRandomBytes)
if verified:
return cttEthBLS_Success
return cttEthBLS_VerificationFailure
return cttEthBls_Success
return cttEthBls_VerificationFailure

# Nim
func batch_verify*[Msg](pubkeys: openArray[PublicKey], messages: openarray[Msg], signatures: openArray[Signature], secureRandomBytes: array[32, byte]): CttEthBLSStatus =
func batch_verify*[Msg](pubkeys: openArray[PublicKey], messages: openarray[Msg], signatures: openArray[Signature], secureRandomBytes: array[32, byte]): cttEthBlsStatus =
## Verify that all (pubkey, message, signature) triplets are valid
## returns `true` if all signatures are valid, `false` if at least one is invalid.
##
Expand All @@ -488,25 +488,25 @@ func batch_verify*[Msg](pubkeys: openArray[PublicKey], messages: openarray[Msg],

if pubkeys.len == 0:
# IETF spec precondition
return cttEthBLS_ZeroLengthAggregation
return cttEthBls_ZeroLengthAggregation

if pubkeys.len != messages.len or pubkeys.len != signatures.len:
return cttEthBLS_InconsistentLengthsOfInputs
return cttEthBls_InconsistentLengthsOfInputs

# Deal with cases were pubkey or signature were mistakenly zero-init, due to a generic aggregation tentative for example
for i in 0 ..< pubkeys.len:
if pubkeys[i].raw.isInf().bool:
return cttEthBLS_PointAtInfinity
return cttEthBls_PointAtInfinity

for i in 0 ..< signatures.len:
if signatures[i].raw.isInf().bool:
return cttEthBLS_PointAtInfinity
return cttEthBls_PointAtInfinity

let verified = batchVerify(
pubkeys.unwrap(),
messages,
signatures.unwrap(),
sha256, 128, DomainSeparationTag, secureRandomBytes)
if verified:
return cttEthBLS_Success
return cttEthBLS_VerificationFailure
return cttEthBls_Success
return cttEthBls_VerificationFailure
Loading

0 comments on commit 5110f6a

Please sign in to comment.