fix: check bls12-381 point in subgroup#253
Open
lightsing wants to merge 1 commit into
Open
Conversation
lispc
approved these changes
Jun 10, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a BLS12-381 G1 subgroup-membership check for the KZG commitment and proof points consumed by the batch circuit's EIP-4844 point-evaluation. This is the G1 counterpart to #247, which added the equivalent check on the G2 /
extension-field side.
Without this check, a point that lies on the curve but outside the prime-order subgroup G1 would be accepted, which breaks the soundness of the pairing-based KZG verification.
Background
EIP-4844 blob consistency is proven in-circuit via a KZG pairing check (
verify_kzg_proof). The commitment and proof are G1 points supplied through the witness. On-curve validation alone is insufficient:E(Fp)has orderh · r, whereris the G1 subgroup order andhthe cofactor, so a crafted witness could supply an on-curve point in theh-torsion (or a mixed point) that is not in G1. Pairing checks are only sound for subgroup elements, so membership must be enforced.Change
is_in_g1_subgroup(p: &G1Affine) -> bool(blob_consistency/openvm.rs), using the GLV endomorphism (Bowe's fast subgroup test):[-x²]on G1, so for anyP ∈ G1:[x²]P == -φ(P) == (β·Pₓ, -P_y).msm([x²], [P])) plus one Fp multiply and a coordinate comparison — much cheaper in-circuit than cofactor clearing or a full λ-multiplication.build_intrinsic_point) and halo2curves (build_point) constructors (witness.rs).build_pointis on the in-circuit V7 path (BatchInfo::from→BatchInfoBuilderV7::build), so an off-subgroup point causes the builder to fail and no valid proof can be produced.#[cfg(feature = "host")]assertion cross-checks the result against halo2curves' independentis_torsion_free()during host-side witness generation.Constants (
openvm.rs):BETA— nontrivial cube root of unity in Fp (the root for which φ acts as[-x²]on G1).X_SQUARE—x², wherex = -0xd201000000010000is the BLS seed (BLS_X).Tests
test_beta—BETA ≠ 1,BETA³ = 1,BETA² + BETA + 1 = 0(mod p).test_x_square—X_SQUARE == BLS_X²(mod r).test_g1_generator_is_in_subgroup— positive case: the G1 generator is accepted. (Guards against picking the wrong cube root, which would still satisfytest_beta.)test_point_on_curve_but_not_in_subgroup— negative case: a random on-curve, non-torsion-free point is rejected, cross-checked againstis_torsion_free().cargo test -p scroll-zkvm-types-batchpasses with and without--features host.