From 3d0b9ab2f3b6acb91a8441792fc708c563d85fc9 Mon Sep 17 00:00:00 2001 From: Mamy Ratsimbazafy Date: Thu, 14 Sep 2023 22:04:02 +0200 Subject: [PATCH] pass all verify_blob_kzg_proof tests --- .../kzg_polynomial_commitments.nim | 12 ++--- ...eum_eip4844_kzg_polynomial_commitments.nim | 54 +++++++++++++++++++ constantine/math/polynomials/polynomials.nim | 29 ++++++---- tests/t_ethereum_eip4844_deneb_kzg.nim | 18 +++++++ 4 files changed, 97 insertions(+), 16 deletions(-) diff --git a/constantine/commitments/kzg_polynomial_commitments.nim b/constantine/commitments/kzg_polynomial_commitments.nim index 16d09da1..eb2e469b 100644 --- a/constantine/commitments/kzg_polynomial_commitments.nim +++ b/constantine/commitments/kzg_polynomial_commitments.nim @@ -205,11 +205,9 @@ func kzg_prove*[N: static int, C: static Curve]( # Compute 1/(ωⁱ - z) with ω a root of unity, i in [0, N). # zIndex = i if ωⁱ - z == 0 (it is the i-th root of unity) and -1 otherwise. - var zIndex = invRootsMinusZ[].inverseRootsMinusZ_vartime(domain, challenge) - - # debugEcho "\n\n roots[1]: ", domain.rootsOfUnity[1].toHex() - # debugEcho "\n\n roots[2]: ", domain.rootsOfUnity[2].toHex() - + let zIndex = invRootsMinusZ[].inverseRootsMinusZ_vartime( + domain, challenge, + earlyReturnOnZero = false) if zIndex == -1: # p(z) @@ -293,10 +291,10 @@ func kzg_verify*[F2; C: static Curve]( tauG2Jac.fromAffine(tauG2) commitmentJac.fromAffine(commitment) - tau_minus_challenge_G2.scalarMul(challenge) + tau_minus_challenge_G2.scalarMul_vartime(challenge) tau_minus_challenge_G2.diff(tauG2Jac, tau_minus_challenge_G2) - commitment_minus_eval_at_challenge_G1.scalarMul(eval_at_challenge) + commitment_minus_eval_at_challenge_G1.scalarMul_vartime(eval_at_challenge) commitment_minus_eval_at_challenge_G1.diff(commitmentJac, commitment_minus_eval_at_challenge_G1) var tmzG2 {.noInit.}: ECP_ShortW_Aff[F2, G2] diff --git a/constantine/ethereum_eip4844_kzg_polynomial_commitments.nim b/constantine/ethereum_eip4844_kzg_polynomial_commitments.nim index 1bd8ab65..ad9695af 100644 --- a/constantine/ethereum_eip4844_kzg_polynomial_commitments.nim +++ b/constantine/ethereum_eip4844_kzg_polynomial_commitments.nim @@ -388,6 +388,60 @@ func compute_blob_kzg_proof*( freeHeap(poly) return cttEthKZG_Success +func verify_blob_kzg_proof*( + ctx: ptr EthereumKZGContext, + blob: ptr Blob, + commitment_bytes: array[48, byte], + proof_bytes: array[48, byte]): CttEthKzgStatus = + ## Given a blob and a KZG proof, verify that the blob data corresponds to the provided commitment. + + var commitment {.noInit.}: KZGCommitment + check commitment.bytes_to_kzg_commitment(commitment_bytes) + + # Blob -> Polynomial + let poly = allocHeapAligned(PolynomialEval[FIELD_ELEMENTS_PER_BLOB, Fr[BLS12_381]], 64) + var status = poly.blob_to_field_polynomial(blob) + if status == cttCodecScalar_ScalarLargerThanCurveOrder: + freeHeap(poly) + return cttEthKZG_ScalarLargerThanCurveOrder + elif status != cttCodecScalar_Success: + debugEcho "Unreachable status in compute_kzg_proof: ", status + debugEcho "Panicking ..." + quit 1 + + var proof {.noInit.}: KZGProof + check proof.bytes_to_kzg_proof(proof_bytes) + + var challengeFr {.noInit.}: Fr[BLS12_381] + challengeFr.fiatShamirChallenge(blob[], commitment_bytes) + + var challenge, eval_at_challenge {.noInit.}: matchingOrderBigInt(BLS12_381) + challenge.fromField(challengeFr) + + let invRootsMinusZ = allocHeapAligned(array[FIELD_ELEMENTS_PER_BLOB, Fr[BLS12_381]], alignment = 64) + + # Compute 1/(ωⁱ - z) with ω a root of unity, i in [0, N). + # zIndex = i if ωⁱ - z == 0 (it is the i-th root of unity) and -1 otherwise. + let zIndex = invRootsMinusZ[].inverseRootsMinusZ_vartime( + ctx.domain, challengeFr, + earlyReturnOnZero = true) + + if zIndex == -1: + var eval_at_challenge_fr{.noInit.}: Fr[BLS12_381] + eval_at_challenge_fr.evalPolyAt_vartime( + poly[], challengeFr, + invRootsMinusZ[], + ctx.domain) + eval_at_challenge.fromField(eval_at_challenge_fr) + else: + eval_at_challenge.fromField(poly.evals[zIndex]) + + let verif = kzg_verify(commitment.raw, challenge, eval_at_challenge, proof.raw, ctx.srs_monomial_g2.coefs[1]) + if verif: + return cttEthKZG_Success + else: + return cttEthKZG_VerificationFailure + # Ethereum Trusted Setup # ------------------------------------------------------------ diff --git a/constantine/math/polynomials/polynomials.nim b/constantine/math/polynomials/polynomials.nim index 6e97881a..b595d20d 100644 --- a/constantine/math/polynomials/polynomials.nim +++ b/constantine/math/polynomials/polynomials.nim @@ -51,14 +51,19 @@ type func inverseRootsMinusZ_vartime*[N: static int, Field]( invRootsMinusZ: var array[N, Field], domain: PolyDomainEval[N, Field], - z: Field): int = + z: Field, + earlyReturnOnZero: static bool): int = ## Compute 1/(ωⁱ-z) for i in [0, N) ## ## Returns -1 if z ∉ {1, ω, ω², ... , ωⁿ⁻¹} ## Returns the index of ωⁱ==z otherwise ## - ## If ωⁱ-z == 0, the other inverses are still computed - ## and 0 is returned at that index. + ## If ωⁱ-z == 0 AND earlyReturnOnZero is false + ## the other inverses are still computed + ## and 0 is returned at that index + ## If ωⁱ-z == 0 AND earlyReturnOnZero is true + ## the index of ωⁱ==z is returned + ## the content of invRootsMinusZ is undefined # Mongomery's batch inversion # ω is a root of unity of order N, @@ -69,13 +74,19 @@ func inverseRootsMinusZ_vartime*[N: static int, Field]( accInv.setOne() var index0 = -1 - for i in 0 ..< N: - rootsMinusZ[i].diff(domain.rootsOfUnity[i], z) + when earlyReturnOnZero: # Split computation in 2 phases + for i in 0 ..< N: + rootsMinusZ[i].diff(domain.rootsOfUnity[i], z) + if rootsMinusZ[i].isZero().bool(): + return i - if rootsMinusZ[i].isZero().bool(): - index0 = i - invRootsMinusZ[i].setZero() - continue + for i in 0 ..< N: + when not earlyReturnOnZero: # Fused substraction and batch inversion + rootsMinusZ[i].diff(domain.rootsOfUnity[i], z) + if rootsMinusZ[i].isZero().bool(): + index0 = i + invRootsMinusZ[i].setZero() + continue invRootsMinusZ[i] = accInv accInv *= rootsMinusZ[i] diff --git a/tests/t_ethereum_eip4844_deneb_kzg.nim b/tests/t_ethereum_eip4844_deneb_kzg.nim index 972a02eb..72a7561f 100644 --- a/tests/t_ethereum_eip4844_deneb_kzg.nim +++ b/tests/t_ethereum_eip4844_deneb_kzg.nim @@ -160,6 +160,21 @@ testGen(compute_blob_kzg_proof, testVector): else: doAssert testVector["output"].content == "null" +testGen(verify_blob_kzg_proof, testVector): + parseAssign(blob, 32*4096, testVector["input"]["blob"].content) + parseAssign(commitment, 48, testVector["input"]["commitment"].content) + parseAssign(proof, 48, testVector["input"]["proof"].content) + + let status = verify_blob_kzg_proof(ctx, blob[].addr, commitment[], proof[]) + stdout.write "[" & $status & "]\n" + + if status == cttEthKZG_Success: + doAssert testVector["output"].content == "true" + elif status == cttEthKZG_VerificationFailure: + doAssert testVector["output"].content == "false" + else: + doAssert testVector["output"].content == "null" + block: suite "Ethereum Deneb Hardfork / EIP-4844 / Proto-Danksharding / KZG Polynomial Commitments": let ctx = load_ethereum_kzg_test_trusted_setup_mainnet() @@ -176,4 +191,7 @@ block: test "compute_blob_kzg_proof(proof: var array[48, byte], blob: ptr array[4096, byte], commitment: array[48, byte])": ctx.test_compute_blob_kzg_proof() + test "verify_blob_kzg_proof(blob: ptr array[4096, byte], commitment: array[48, byte], proof: var array[48, byte])": + ctx.test_verify_blob_kzg_proof() + ctx.delete()