Skip to content

Commit c1528db

Browse files
authored
Perf(native/BLS12-377): Torus optimal ate pairing check (#1702)
1 parent 51f3867 commit c1528db

File tree

19 files changed

+975
-30
lines changed

19 files changed

+975
-30
lines changed

internal/stats/latest_stats.csv

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,14 +158,14 @@ pairing_bls12377,bls12_377,groth16,0,0
158158
pairing_bls12377,bls12_381,groth16,0,0
159159
pairing_bls12377,bls24_315,groth16,0,0
160160
pairing_bls12377,bls24_317,groth16,0,0
161-
pairing_bls12377,bw6_761,groth16,11236,11236
161+
pairing_bls12377,bw6_761,groth16,11876,11876
162162
pairing_bls12377,bw6_633,groth16,0,0
163163
pairing_bls12377,bn254,plonk,0,0
164164
pairing_bls12377,bls12_377,plonk,0,0
165165
pairing_bls12377,bls12_381,plonk,0,0
166166
pairing_bls12377,bls24_315,plonk,0,0
167167
pairing_bls12377,bls24_317,plonk,0,0
168-
pairing_bls12377,bw6_761,plonk,51280,51280
168+
pairing_bls12377,bw6_761,plonk,48130,48130
169169
pairing_bls12377,bw6_633,plonk,0,0
170170
pairing_bls12381,bn254,groth16,949313,1570566
171171
pairing_bls12381,bls12_377,groth16,0,0

std/algebra/native/fields_bls12377/e12.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2020-2025 Consensys Software Inc.
1+
// Copyright 2020-2026 Consensys Software Inc.
22
// Licensed under the Apache License, Version 2.0. See the LICENSE file for details.
33

44
package fields_bls12377

std/algebra/native/fields_bls12377/e12_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2020-2025 Consensys Software Inc.
1+
// Copyright 2020-2026 Consensys Software Inc.
22
// Licensed under the Apache License, Version 2.0. See the LICENSE file for details.
33

44
package fields_bls12377

std/algebra/native/fields_bls12377/e2.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2020-2025 Consensys Software Inc.
1+
// Copyright 2020-2026 Consensys Software Inc.
22
// Licensed under the Apache License, Version 2.0. See the LICENSE file for details.
33

44
package fields_bls12377

std/algebra/native/fields_bls12377/e2_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2020-2025 Consensys Software Inc.
1+
// Copyright 2020-2026 Consensys Software Inc.
22
// Licensed under the Apache License, Version 2.0. See the LICENSE file for details.
33

44
package fields_bls12377

std/algebra/native/fields_bls12377/e6.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2020-2025 Consensys Software Inc.
1+
// Copyright 2020-2026 Consensys Software Inc.
22
// Licensed under the Apache License, Version 2.0. See the LICENSE file for details.
33

44
package fields_bls12377

std/algebra/native/fields_bls12377/e6_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2020-2025 Consensys Software Inc.
1+
// Copyright 2020-2026 Consensys Software Inc.
22
// Licensed under the Apache License, Version 2.0. See the LICENSE file for details.
33

44
package fields_bls12377
Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
// Copyright 2020-2026 Consensys Software Inc.
2+
// Licensed under the Apache License, Version 2.0. See the LICENSE file for details.
3+
4+
package fields_bls12377
5+
6+
import (
7+
"github.com/consensys/gnark/frontend"
8+
)
9+
10+
// Torus-based arithmetic for cyclotomic subgroup
11+
// The torus T₆ represents elements of the cyclotomic subgroup of E12 using E6
12+
// For x in cyclotomic subgroup: x = (1 + y·w) / (1 - y·w) where y ∈ E6
13+
14+
// TorusSquare computes the square in torus representation
15+
// Input: y ∈ E6 representing x ∈ T₆
16+
// Output: y' ∈ E6 representing x² ∈ T₆
17+
// Formula: y' = 2y / (1 + y²·v) where v is the cubic non-residue
18+
func TorusSquare(api frontend.API, y E6) E6 {
19+
// Compute numerator: 2y
20+
var num E6
21+
num.Double(api, y)
22+
23+
// Compute y²
24+
var ySq E6
25+
ySq.Square(api, y)
26+
27+
// Compute denominator: 1 + y²·v
28+
var denom E6
29+
denom.MulByNonResidue(api, ySq)
30+
denom.B0.A0 = api.Add(denom.B0.A0, 1)
31+
32+
// Compute result = num / denom (DivUnchecked uses hint internally)
33+
var result E6
34+
result.DivUnchecked(api, num, denom)
35+
36+
return result
37+
}
38+
39+
// TorusMul computes multiplication in torus representation
40+
// Input: y1, y2 ∈ E6 representing x1, x2 ∈ T₆
41+
// Output: y' ∈ E6 representing x1·x2 ∈ T₆
42+
// Formula: y' = (y1 + y2) / (1 + y1·y2·v)
43+
func TorusMul(api frontend.API, y1, y2 E6) E6 {
44+
// Compute numerator: y1 + y2
45+
var num E6
46+
num.Add(api, y1, y2)
47+
48+
// Compute y1·y2
49+
var prod E6
50+
prod.Mul(api, y1, y2)
51+
52+
// Compute denominator: 1 + y1·y2·v
53+
var denom E6
54+
denom.MulByNonResidue(api, prod)
55+
denom.B0.A0 = api.Add(denom.B0.A0, 1)
56+
57+
// Compute result = num / denom (DivUnchecked uses hint internally)
58+
var result E6
59+
result.DivUnchecked(api, num, denom)
60+
61+
return result
62+
}
63+
64+
// TorusMulBy01 computes multiplication by sparse element (l0, l1, 0) in torus
65+
// This is used for line multiplication where the line projects to (-c3, -c4, 0)
66+
// Formula: y' = (y + sparse) / (1 + y·sparse·v)
67+
func TorusMulBy01(api frontend.API, y E6, l0, l1 E2) E6 {
68+
// Sparse element: (l0, l1, 0)
69+
var sparse E6
70+
sparse.B0 = l0
71+
sparse.B1 = l1
72+
// B2 is zero - must be explicit circuit zero
73+
sparse.B2.A0 = 0
74+
sparse.B2.A1 = 0
75+
76+
// Compute numerator: y + sparse
77+
var num E6
78+
num.Add(api, y, sparse)
79+
80+
// Compute y · sparse using MulBy01
81+
prod := y
82+
prod.MulBy01(api, l0, l1)
83+
84+
// Compute denominator: 1 + prod·v
85+
var denom E6
86+
denom.MulByNonResidue(api, prod)
87+
denom.B0.A0 = api.Add(denom.B0.A0, 1)
88+
89+
// Compute result = num / denom (DivUnchecked uses hint internally)
90+
var result E6
91+
result.DivUnchecked(api, num, denom)
92+
93+
return result
94+
}
95+
96+
// TorusDecompress converts torus representation back to E12
97+
// Input: y ∈ E6 representing x ∈ T₆
98+
// Output: x ∈ E12 where x = (1 + y·w) / (1 - y·w)
99+
//
100+
// We compute C0 and C1 such that x = C0 + C1·w
101+
// From (1 + y·w) = (C0 + C1·w)(1 - y·w):
102+
//
103+
// 1 = C0 - C1·y·v => C0 = 1 + C1·y·v
104+
// y = C1 - C0·y => C1 = y + C0·y = y(1 + C0)
105+
//
106+
// Substituting: C1 = y(1 + 1 + C1·y·v) = y(2 + C1·y·v)
107+
// C1 = 2y + C1·y²·v
108+
// C1(1 - y²·v) = 2y
109+
// C1 = 2y / (1 - y²·v)
110+
func TorusDecompress(api frontend.API, y E6) E12 {
111+
// Compute y²
112+
var ySq E6
113+
ySq.Square(api, y)
114+
115+
// Compute y²·v
116+
var ySqV E6
117+
ySqV.MulByNonResidue(api, ySq)
118+
119+
// Compute denominator: 1 - y²·v
120+
var one E6
121+
one.SetOne()
122+
var denom E6
123+
denom.Sub(api, one, ySqV)
124+
125+
// Compute numerator: 2y
126+
var num E6
127+
num.Double(api, y)
128+
129+
// C1 = 2y / (1 - y²·v)
130+
var c1 E6
131+
c1.DivUnchecked(api, num, denom)
132+
133+
// C0 = 1 + C1·y·v
134+
var c1y E6
135+
c1y.Mul(api, c1, y)
136+
var c1yv E6
137+
c1yv.MulByNonResidue(api, c1y)
138+
var c0 E6
139+
c0.Add(api, one, c1yv)
140+
141+
return E12{C0: c0, C1: c1}
142+
}
143+
144+
// FrobeniusTorus computes the Frobenius endomorphism on torus element
145+
// For y ∈ E6 representing W in cyclotomic subgroup via W = (1+y·w)/(1-y·w):
146+
// Frob(W) = (1 + z·w) / (1 - z·w) where z = FrobeniusTorus(y)
147+
// Formula:
148+
//
149+
// z.B0 = Conj(y.B0) · frobw
150+
// z.B1 = Conj(y.B1) · frobvw
151+
// z.B2 = Conj(y.B2) · frobv2w
152+
func FrobeniusTorus(api frontend.API, y E6) E6 {
153+
var z E6
154+
z.B0.Conjugate(api, y.B0).MulByFp(api, z.B0, ext.frobw)
155+
z.B1.Conjugate(api, y.B1).MulByFp(api, z.B1, ext.frobvw)
156+
z.B2.Conjugate(api, y.B2).MulByFp(api, z.B2, ext.frobv2w)
157+
return z
158+
}
159+
160+
// TorusCompress computes compress(x) = C1 / (1 + C0)
161+
// Input: x ∈ E12 in cyclotomic subgroup
162+
// Output: y ∈ E6 such that x = (1 + y·w) / (1 - y·w)
163+
func TorusCompress(api frontend.API, x E12) E6 {
164+
// y = C1 / (1 + C0)
165+
var one E6
166+
one.SetOne()
167+
var c0PlusOne E6
168+
c0PlusOne.Add(api, x.C0, one)
169+
170+
var y E6
171+
y.DivUnchecked(api, x.C1, c0PlusOne)
172+
173+
return y
174+
}
175+
176+
// CompressFrobDivideByScaling computes compress(Frob(W) / s) where W = decompress(y)
177+
// Formula: result = 2·z / (1 + s + z²·v·(1 - s))
178+
// where z = FrobeniusTorus(y)
179+
func CompressFrobDivideByScaling(api frontend.API, y E6, s E6) E6 {
180+
// Compute z = FrobeniusTorus(y)
181+
z := FrobeniusTorus(api, y)
182+
183+
// Compute z²
184+
var zSquare E6
185+
zSquare.Square(api, z)
186+
187+
// Compute z²·v (multiply by non-residue)
188+
var zSquareV E6
189+
zSquareV.MulByNonResidue(api, zSquare)
190+
191+
// Compute (1 - s)
192+
var one E6
193+
one.SetOne()
194+
var oneMinusS E6
195+
oneMinusS.Sub(api, one, s)
196+
197+
// Compute z²·v·(1 - s)
198+
var term E6
199+
term.Mul(api, zSquareV, oneMinusS)
200+
201+
// Compute denominator = 1 + s + z²·v·(1 - s)
202+
var denom E6
203+
denom.Add(api, one, s)
204+
denom.Add(api, denom, term)
205+
206+
// Compute numerator = 2·z
207+
var num E6
208+
num.Double(api, z)
209+
210+
// Compute result = num / denom
211+
var result E6
212+
result.DivUnchecked(api, num, denom)
213+
214+
return result
215+
}

0 commit comments

Comments
 (0)