Skip to content

Commit bb1f0bd

Browse files
committed
fix(blobs): bind emulated values to canonical bn254 scalars
1 parent a8ecf96 commit bb1f0bd

2 files changed

Lines changed: 19 additions & 12 deletions

File tree

crypto/blobs/evaluation.go

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"fmt"
3131
"math/big"
3232

33+
"github.com/consensys/gnark-crypto/ecc"
3334
"github.com/consensys/gnark/frontend"
3435
"github.com/consensys/gnark/std/math/emulated"
3536
)
@@ -38,6 +39,8 @@ const (
3839
N = 1 << 12 // 4096 evaluation points
3940
)
4041

42+
var maxCanonicalBN254Scalar = emulated.ValueOf[FE](new(big.Int).Sub(ecc.BN254.ScalarField(), big.NewInt(1)))
43+
4144
// FE is type modulus for BLS12‑381 Fr.
4245
type FE = emulated.BLS12381Fr
4346

@@ -175,22 +178,18 @@ func VerifyFullBlobEvaluationBN254(
175178
// Convert all native scalars => emulated via the hint
176179
var blobEmu [N]emulated.Element[FE]
177180
for i := range N {
178-
e, err := hintNativeToEmu(api, fr, blob[i])
181+
e, err := liftNativeBN254ToEmulated(api, fr, blob[i])
179182
if err != nil {
180183
return err
181184
}
182185
blobEmu[i] = *e
183-
// verify that the native input matches the emulated one created by the hint
184-
api.AssertIsEqual(emulatedToNative(api, &blobEmu[i]), blob[i])
185186
}
186187

187188
// Convert the native evaluation point z => emulated
188-
zEmu, err := hintNativeToEmu(api, fr, z)
189+
zEmu, err := liftNativeBN254ToEmulated(api, fr, z)
189190
if err != nil {
190191
return err
191192
}
192-
// verify that the native input matches the emulated one created by the hint
193-
api.AssertIsEqual(emulatedToNative(api, zEmu), z)
194193

195194
// Verify the barycentric evaluation (does NOT check KZG commitment/proof)
196195
if err := VerifyBarycentricEvaluation(api, zEmu, y, blobEmu); err != nil {
@@ -201,8 +200,20 @@ func VerifyFullBlobEvaluationBN254(
201200
return VerifyKZGProof(api, commitment, proof, *zEmu, *y)
202201
}
203202

203+
// liftNativeBN254ToEmulated lifts a native BN254 scalar into the emulated
204+
// field, constraining the witness to the canonical BN254 scalar range [0, pBN254)
205+
// and proving it recomposes back to the original native input.
206+
func liftNativeBN254ToEmulated(api frontend.API, fr *emulated.Field[FE], native frontend.Variable) (*emulated.Element[FE], error) {
207+
emu, err := hintNativeToEmu(fr, native)
208+
if err != nil {
209+
return nil, err
210+
}
211+
fr.AssertIsLessOrEqual(emu, &maxCanonicalBN254Scalar)
212+
api.AssertIsEqual(emulatedToNative(api, emu), native)
213+
return emu, nil
214+
}
215+
204216
// emulatedToNative converts an emulated element to a native BN254 variable.
205-
// This is used to ensure that the native input matches the emulated output.
206217
func emulatedToNative(api frontend.API, e *emulated.Element[FE]) frontend.Variable {
207218
nbBits := FE{}.BitsPerLimb()
208219
acc := frontend.Variable(0)

crypto/blobs/hints.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,7 @@ func splitNativeHint(_ *big.Int, nativeIn, emuOut []*big.Int) error {
8686

8787
// hintNativeToEmu converts a native BN254 variable to an emulated element
8888
// using the copyNativeToEmu hint.
89-
// It is important to verify that the native input matches the emulated output
90-
// to ensure soundness, in the circuit.
91-
func hintNativeToEmu(_ frontend.API, fr *emulated.Field[FE],
92-
vNat frontend.Variable,
93-
) (*emulated.Element[FE], error) {
89+
func hintNativeToEmu(fr *emulated.Field[FE], vNat frontend.Variable) (*emulated.Element[FE], error) {
9490
emu, err := fr.NewHintWithNativeInput(copyNativeToEmu, 1, vNat)
9591
if err != nil {
9692
return nil, err

0 commit comments

Comments
 (0)