Skip to content
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
2 changes: 1 addition & 1 deletion .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ permissions:
contents: read

env:
GO_VERSION: 1.25.x # NB! when updating also update matrix, we cannot refer to env variables in the matrix
GO_VERSION: 1.26.x # NB! when updating also update matrix, we cannot refer to env variables in the matrix
GOLANGCI_LINT_VERSION: v2.10.1

jobs:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ permissions:
contents: read

env:
GO_VERSION: 1.25.x # NB! when updating also update matrix, we cannot refer to env variables in the matrix
GO_VERSION: 1.26.x # NB! when updating also update matrix, we cannot refer to env variables in the matrix
GOLANGCI_LINT_VERSION: v2.10.1

jobs:
Expand Down Expand Up @@ -48,7 +48,7 @@ jobs:
test:
strategy:
matrix:
go-version: [1.25.x]
go-version: [1.26.x]
os:
[
gha-runner-scale-set-ubuntu-24-amd64-xxl,
Expand Down
31 changes: 31 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,34 @@

<a name="v0.22.0"></a>
## [v0.22.0] - 2026-10-02
### Breaking
- BLS12-381/Jubjub: correct the twisted-Edwards generator; regenerate keys and signatures derived from the previous generator ([#821](https://github.com/Consensys/gnark-crypto/pull/821))
- BLS12-381/Bandersnatch EdDSA now uses Bandersnatch rather than Jubjub; regenerate keys and signatures ([#882](https://github.com/Consensys/gnark-crypto/pull/882))
- MamaBear Poseidon2 uses its derived `R_F = 8`, `R_P = 32` round schedule; existing MamaBear Poseidon2 outputs are incompatible ([#900](https://github.com/Consensys/gnark-crypto/pull/900))

### Security
- ecdsa: reject identity and small-subgroup public keys during key deserialization ([#889](https://github.com/Consensys/gnark-crypto/pull/889))
- kzg MPC setup: restore the omitted verifying-key G1 generator when reading a setup, preserving opening-proof binding ([#891](https://github.com/Consensys/gnark-crypto/pull/891))
- Vortex: reject malformed opening proofs that could make an invalid evaluation claim verify (KoalaBear [#896](https://github.com/Consensys/gnark-crypto/pull/896); MamaBear)
- shplonk and fflonk: reject malformed proof shapes rather than panicking in `BatchVerify` ([#892](https://github.com/Consensys/gnark-crypto/pull/892))
- fft: reject invalid serialized domain cardinalities before panic or excessive allocation ([#893](https://github.com/Consensys/gnark-crypto/pull/893))
- field vectors: reject lengths exceeding a knowable remaining input before allocating ([#878](https://github.com/Consensys/gnark-crypto/pull/878))

### Feat
- add the 49-bit MamaBear field, degree-3 extensions, FFT, Poseidon2, SIS, IOP, and experimental Vortex commitment scheme with AVX-512 IFMA acceleration ([#887](https://github.com/Consensys/gnark-crypto/pull/887))
- kzg: add the `Committer` interface plus `OpenWithCommitter` and `BatchOpenSinglePointWithCommitter` for externally accelerated quotient commitments ([#879](https://github.com/Consensys/gnark-crypto/pull/879))

### Perf
- MamaBear AVX-512 IFMA vector arithmetic and FFT acceleration; optimized E3 arithmetic and Poseidon2 ([#887](https://github.com/Consensys/gnark-crypto/pull/887))

### Fix
- reject uncompressed all-zero point encodings whose infinity bit is clear ([#897](https://github.com/Consensys/gnark-crypto/pull/897))
- correct MamaBear Poseidon2 parameters for 128-bit security ([#900](https://github.com/Consensys/gnark-crypto/pull/900))

### Build
- require Go 1.26.8 and update CI to Go 1.26.x
- **deps:** update direct and tool dependencies

<a name="v0.21.0"></a>
## [v0.21.0] - 2026-08-10
### Breaking
Expand Down Expand Up @@ -2289,6 +2319,7 @@
- Merge pull request [#2](https://github.com/Consensys/gnark-crypto/issues/2) from ConsenSys/develop
<a name="v0.0.1"></a>
## v0.0.1 - 2020-03-23
[v0.22.0]: https://github.com/Consensys/gnark-crypto/compare/v0.21.0...v0.22.0
[v0.21.0]: https://github.com/Consensys/gnark-crypto/compare/v0.20.1...v0.21.0
[v0.20.1]: https://github.com/Consensys/gnark-crypto/compare/v0.20.0...v0.20.1
[v0.20.0]: https://github.com/Consensys/gnark-crypto/compare/v0.19.2...v0.20.0
Expand Down
8 changes: 4 additions & 4 deletions CITATION.bib
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
@software{gnark-crypto-v0.20,
@software{gnark-crypto-v0.22,
author = {Gautam Botrel and
Thomas Piellard and
Youssef El Housni and
Arya Tabaie and
Gus Gutoski and
Ivo Kubjas and
Yao J. Galteland},
title = {Consensys/gnark-crypto: v0.20.0},
month = mar,
title = {Consensys/gnark-crypto: v0.22.0},
month = oct,
year = 2026,
publisher = {Zenodo},
version = {v0.20.0},
version = {v0.22.0},
doi = {10.5281/zenodo.5815453},
url = {https://doi.org/10.5281/zenodo.5815453}
}
23 changes: 14 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,18 @@ It is actively developed and maintained by the team (<gnark@consensys.com> | [Ha
* [`bls12-377`] / [`bw6-761`]
* [`bls24-315`] / [`bw6-633`]

Each of these curves has a [`twistededwards`] sub-package with its companion curve, which allows efficient elliptic curve cryptography inside zkSNARK circuits.
Each pairing-friendly curve has a [`twistededwards`] companion sub-package for efficient elliptic-curve cryptography in zkSNARK circuits. BLS12-381 also has the [`bandersnatch`] companion curve.

Additional (non pairing-friendly) curves: [`secp256r1`] (P-256), [`secp256k1`], [`grumpkin`], [`stark-curve`].
Additional non-pairing-friendly curves: [`secp256r1`] (P-256), [`secp256k1`], [`grumpkin`], [`stark-curve`].

### Small fields

Small prime fields for STARK-style provers:

* [`koalabear`], [`babybear`] (31-bit, with AVX-512 and NEON vector kernels), [`goldilocks`] (64-bit)
* Each with `extensions` (degree 2/4/6), `fft`, `poseidon2`, `sis` (Ring-SIS) and `iop` sub-packages
* [`koalabear`] and [`babybear`] — 31-bit fields with AVX-512 and NEON vector kernels; degree-2/4/6 extensions
* [`mamabear`] — 49-bit field with AVX-512 IFMA kernels; a degree-3 extension
* [`goldilocks`] — 64-bit field; a degree-2 extension
* Each field includes `fft`, `poseidon2`, `sis` (Ring-SIS) and `iop`; KoalaBear and MamaBear additionally provide the experimental [`vortex`] commitment scheme

### Signatures & hashing

Expand Down Expand Up @@ -68,7 +70,7 @@ See [list of audits for `gnark` and `gnark-crypto`](https://github.com/Consensys

### Go version

`gnark-crypto` requires Go 1.25 or newer (see `go.mod`); CI tests against Go 1.25.x.
`gnark-crypto` requires Go 1.26 or newer (see `go.mod`); CI tests against Go 1.26.x.

### Install `gnark-crypto`

Expand Down Expand Up @@ -105,19 +107,19 @@ If you use `gnark-crypto` in your research a citation would be appreciated.
Please use the following BibTeX to cite the most recent release.

```bib
@software{gnark-crypto-v0.21,
@software{gnark-crypto-v0.22,
author = {Gautam Botrel and
Thomas Piellard and
Youssef El Housni and
Arya Tabaie and
Gus Gutoski and
Ivo Kubjas and
Yao J. Galteland},
title = {Consensys/gnark-crypto: v0.21.0},
month = aug,
title = {Consensys/gnark-crypto: v0.22.0},
month = oct,
year = 2026,
publisher = {Zenodo},
version = {v0.21.0},
version = {v0.22.0},
doi = {10.5281/zenodo.5815453},
url = {https://doi.org/10.5281/zenodo.5815453}
}
Expand All @@ -144,6 +146,7 @@ This project is licensed under the Apache 2 License - see the [LICENSE](LICENSE)
[`grumpkin`]: https://pkg.go.dev/github.com/consensys/gnark-crypto/ecc/grumpkin
[`stark-curve`]: https://pkg.go.dev/github.com/consensys/gnark-crypto/ecc/stark-curve
[`twistededwards`]: https://pkg.go.dev/github.com/consensys/gnark-crypto/ecc/bn254/twistededwards
[`bandersnatch`]: https://pkg.go.dev/github.com/consensys/gnark-crypto/ecc/bls12-381/bandersnatch
[`eddsa`]: https://pkg.go.dev/github.com/consensys/gnark-crypto/signature/eddsa
[`ecdsa`]: https://pkg.go.dev/github.com/consensys/gnark-crypto/signature/ecdsa
[`fft`]: https://pkg.go.dev/github.com/consensys/gnark-crypto/ecc/bn254/fr/fft
Expand All @@ -161,6 +164,8 @@ This project is licensed under the Apache 2 License - see the [LICENSE](LICENSE)
[`koalabear`]: https://pkg.go.dev/github.com/consensys/gnark-crypto/field/koalabear
[`babybear`]: https://pkg.go.dev/github.com/consensys/gnark-crypto/field/babybear
[`goldilocks`]: https://pkg.go.dev/github.com/consensys/gnark-crypto/field/goldilocks
[`mamabear`]: https://pkg.go.dev/github.com/consensys/gnark-crypto/field/mamabear
[`vortex`]: https://pkg.go.dev/github.com/consensys/gnark-crypto/field/koalabear/vortex
[`merkletree`]: https://pkg.go.dev/github.com/consensys/gnark-crypto/accumulator/merkletree
[`eisenstein`]: https://pkg.go.dev/github.com/consensys/gnark-crypto/algebra/eisenstein
[`lattice`]: https://pkg.go.dev/github.com/consensys/gnark-crypto/algebra/lattice
197 changes: 197 additions & 0 deletions field/mamabear/vortex/prover_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,203 @@ func runTest(t *testing.T, tc *testcaseVortex) {
}
}

// An unchecked suffix changes the polynomial evaluated at x without changing
// the Reed-Solomon codeword or any opened column.
func TestVerifyRejectsOversizedUAlpha(t *testing.T) {
const numColumns, numRows = 4, 4
sisParams, err := sis.NewRSis(0, 9, 16, numRows)
require.NoError(t, err)
params, err := NewParams(numColumns, numRows, sisParams, 2, 1)
require.NoError(t, err)

matrix := make([][]mamabear.Element, numRows)
for row := range matrix {
matrix[row] = make([]mamabear.Element, numColumns)
for col := range matrix[row] {
matrix[row][col] = mamabear.NewElement(uint64(100 + 10*row + col))
}
}
x := fext.E3{
A0: mamabear.NewElement(123),
A1: mamabear.NewElement(456),
A2: mamabear.NewElement(789),
}
alpha := fext.E3{
A0: mamabear.NewElement(17),
A1: mamabear.NewElement(19),
A2: mamabear.NewElement(23),
}
claims := make([]fext.E3, numRows)
for row := range matrix {
claims[row], err = EvalBasePolyLagrange(matrix[row], x)
require.NoError(t, err)
}
state, err := Commit(params, matrix)
require.NoError(t, err)
state.OpenLinComb(alpha)
proof, err := state.OpenColumns([]int{0})
require.NoError(t, err)
input := VerifierInput{
Proof: proof, MerkleRoot: state.GetCommitment(), ClaimedValues: claims,
EvaluationPoint: x, Alpha: alpha, SelectedColumns: []int{0},
}
require.NoError(t, params.Verify(input))
input.Proof = nil
require.Error(t, params.Verify(input), "missing proof must be rejected")
short := *proof
short.UAlpha = short.UAlpha[:len(short.UAlpha)-1]
input.Proof = &short
require.Error(t, params.Verify(input), "short codeword must be rejected without panicking")
input.Proof = proof

falseClaims := append([]fext.E3(nil), claims...)
var one fext.E3
one.SetOne()
falseClaims[0].Add(&falseClaims[0], &one)
input.ClaimedValues = falseClaims
require.Error(t, params.Verify(input))

n := params.SizeCodeWord()
forged := *proof
forged.UAlpha = make([]fext.E3, 2*n)
copy(forged.UAlpha, proof.UAlpha)
forged.UAlpha[n] = EvalBasePolyHorner(forged.OpenedColumns[0], alpha)
prefixValue, err := EvalFextPolyLagrange(forged.UAlpha, x)
require.NoError(t, err)
target := EvalFextPolyHorner(falseClaims, alpha)
var correction fext.E3
correction.Sub(&target, &prefixValue)
corrected := false
for index := n + 1; index < len(forged.UAlpha); index++ {
basis := make([]fext.E3, len(forged.UAlpha))
basis[index].SetOne()
weight, evalErr := EvalFextPolyLagrange(basis, x)
require.NoError(t, evalErr)
if weight.IsZero() {
continue
}
var inverse fext.E3
inverse.Inverse(&weight)
forged.UAlpha[index].Mul(&correction, &inverse)
corrected = true
break
}
require.True(t, corrected, "no nonzero suffix Lagrange coordinate")
input.Proof = &forged
require.Error(t, params.Verify(input), "forged false claim must be rejected")
}

func TestVerifyRejectsMalformedOpening(t *testing.T) {
const numColumns, numRows = 4, 4
sisParams, err := sis.NewRSis(0, 9, 16, numRows)
require.NoError(t, err)
params, err := NewParams(numColumns, numRows, sisParams, 2, 1)
require.NoError(t, err)
matrix := make([][]mamabear.Element, numRows)
for i := range matrix {
matrix[i] = make([]mamabear.Element, numColumns)
matrix[i][0] = mamabear.NewElement(uint64(i + 1))
}
var x, alpha fext.E3
x.A0 = mamabear.NewElement(123)
alpha.A0 = mamabear.NewElement(17)
claims := make([]fext.E3, numRows)
for i := range matrix {
claims[i], err = EvalBasePolyLagrange(matrix[i], x)
require.NoError(t, err)
}
state, err := Commit(params, matrix)
require.NoError(t, err)
state.OpenLinComb(alpha)
proof, err := state.OpenColumns([]int{0})
require.NoError(t, err)
input := VerifierInput{
Proof: proof, MerkleRoot: state.GetCommitment(), ClaimedValues: claims,
EvaluationPoint: x, Alpha: alpha, SelectedColumns: []int{0},
}
require.NoError(t, params.Verify(input))

t.Run("missing selection permits an unbound claim", func(t *testing.T) {
bad := input
bad.SelectedColumns = nil
bad.Proof = &Proof{UAlpha: make([]fext.E3, params.SizeCodeWord())}
bad.ClaimedValues = make([]fext.E3, numRows)
require.Error(t, params.Verify(bad))
})
t.Run("missing opened column", func(t *testing.T) {
bad := *proof
bad.OpenedColumns = nil
input.Proof = &bad
require.Error(t, params.Verify(input))
})
t.Run("missing merkle proof", func(t *testing.T) {
bad := *proof
bad.MerkleProofOpenedColumns = nil
input.Proof = &bad
require.Error(t, params.Verify(input))
})
t.Run("short opened column", func(t *testing.T) {
bad := *proof
bad.OpenedColumns = [][]mamabear.Element{proof.OpenedColumns[0][:numRows-1]}
input.Proof = &bad
require.Error(t, params.Verify(input))
})
t.Run("oversized opened column", func(t *testing.T) {
bad := *proof
bad.OpenedColumns = [][]mamabear.Element{append(append([]mamabear.Element(nil), proof.OpenedColumns[0]...), mamabear.Element{})}
input.Proof = &bad
require.Error(t, params.Verify(input))
})
t.Run("out of range Merkle alias", func(t *testing.T) {
bad := input
bad.Proof = proof
bad.SelectedColumns = []int{params.SizeCodeWord()}
require.Error(t, params.Verify(bad))
})
t.Run("negative column", func(t *testing.T) {
bad := input
bad.Proof = proof
bad.SelectedColumns = []int{-1}
require.Error(t, params.Verify(bad))
})
t.Run("missing claims", func(t *testing.T) {
bad := input
bad.Proof = proof
bad.ClaimedValues = nil
require.Error(t, params.Verify(bad))
})
t.Run("extra claims", func(t *testing.T) {
bad := input
bad.Proof = proof
bad.ClaimedValues = append(append([]fext.E3(nil), claims...), fext.E3{})
require.Error(t, params.Verify(bad))
})
t.Run("extra opened column", func(t *testing.T) {
bad := *proof
bad.OpenedColumns = append(append([][]mamabear.Element(nil), proof.OpenedColumns...), proof.OpenedColumns[0])
input.Proof = &bad
require.Error(t, params.Verify(input))
})
t.Run("extra Merkle proof", func(t *testing.T) {
bad := *proof
bad.MerkleProofOpenedColumns = append(append([]MerkleProof(nil), proof.MerkleProofOpenedColumns...), proof.MerkleProofOpenedColumns[0])
input.Proof = &bad
require.Error(t, params.Verify(input))
})
t.Run("missing Merkle sibling", func(t *testing.T) {
bad := *proof
bad.MerkleProofOpenedColumns = []MerkleProof{proof.MerkleProofOpenedColumns[0][:0]}
input.Proof = &bad
require.Error(t, params.Verify(input))
})
t.Run("extra Merkle sibling", func(t *testing.T) {
bad := *proof
bad.MerkleProofOpenedColumns = []MerkleProof{append(append(MerkleProof(nil), proof.MerkleProofOpenedColumns[0]...), Hash{})}
input.Proof = &bad
require.Error(t, params.Verify(input))
})
}

func FuzzVortex(f *testing.F) {
const (
sisLog2Degree = 4
Expand Down
4 changes: 3 additions & 1 deletion field/mamabear/vortex/reedsolomon.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,9 @@ func (p *Params) encodeReedSolomonCosets(input, res []mamabear.Element) {

// IsReedSolomonCodewords returns true iff the argument is a correct codeword.
func (p *Params) IsReedSolomonCodewords(codeword []fext.E3) bool {

if len(codeword) != p.SizeCodeWord() {
return false
}
coeffs := make([]mamabear.Element, p.SizeCodeWord())

for i := range coeffs {
Expand Down
Loading
Loading