gnark-plonky2-verifier/plonky2_verifier/quadratic_extension.go
plonky2_verifier/quadratic_extension.goRaw
1package plonky2_verifier
2
3import (
4 "fmt"
5 . "gnark-ed25519/field"
6 "math/bits"
7
8 "github.com/consensys/gnark/frontend"
9)
10
11type QuadraticExtensionAPI struct {
12 fieldAPI frontend.API
13
14 W F
15 DTH_ROOT F
16
17 ONE_QE QuadraticExtension
18 ZERO_QE QuadraticExtension
19}
20
21func NewQuadraticExtensionAPI(fieldAPI frontend.API, degreeBits uint64) *QuadraticExtensionAPI {
22 // TODO: Should degreeBits be verified that it fits within the field and that degree is within uint64?
23
24 return &QuadraticExtensionAPI{
25 fieldAPI: fieldAPI,
26
27 W: NewFieldElement(7),
28 DTH_ROOT: NewFieldElement(18446744069414584320),
29
30 ONE_QE: QuadraticExtension{ONE_F, ZERO_F},
31 ZERO_QE: QuadraticExtension{ZERO_F, ZERO_F},
32 }
33}
34
35func (c *QuadraticExtensionAPI) SquareExtension(a QuadraticExtension) QuadraticExtension {
36 return c.MulExtension(a, a)
37}
38
39func (c *QuadraticExtensionAPI) MulExtension(a QuadraticExtension, b QuadraticExtension) QuadraticExtension {
40 c_0 := c.fieldAPI.Add(c.fieldAPI.Mul(a[0], b[0]).(F), c.fieldAPI.Mul(c.W, a[1], b[1])).(F)
41 c_1 := c.fieldAPI.Add(c.fieldAPI.Mul(a[0], b[1]).(F), c.fieldAPI.Mul(a[1], b[0])).(F)
42 return QuadraticExtension{c_0, c_1}
43}
44
45func (c *QuadraticExtensionAPI) AddExtension(a QuadraticExtension, b QuadraticExtension) QuadraticExtension {
46 c_0 := c.fieldAPI.Add(a[0], b[0]).(F)
47 c_1 := c.fieldAPI.Add(a[1], b[1]).(F)
48 return QuadraticExtension{c_0, c_1}
49}
50
51func (c *QuadraticExtensionAPI) SubExtension(a QuadraticExtension, b QuadraticExtension) QuadraticExtension {
52 c_0 := c.fieldAPI.Sub(a[0], b[0]).(F)
53 c_1 := c.fieldAPI.Sub(a[1], b[1]).(F)
54 return QuadraticExtension{c_0, c_1}
55}
56
57func (c *QuadraticExtensionAPI) DivExtension(a QuadraticExtension, b QuadraticExtension) QuadraticExtension {
58 return c.MulExtension(a, c.InverseExtension(b))
59}
60
61func (c *QuadraticExtensionAPI) IsZero(a QuadraticExtension) frontend.Variable {
62 return c.fieldAPI.Mul(c.fieldAPI.IsZero(a[0]), c.fieldAPI.IsZero(a[1]))
63}
64
65// TODO: Instead of calculating the inverse within the circuit, can witness the
66// inverse and assert that a_inverse * a = 1. Should reduce # of constraints.
67func (c *QuadraticExtensionAPI) InverseExtension(a QuadraticExtension) QuadraticExtension {
68 // First assert that a doesn't have 0 value coefficients
69 a0_is_zero := c.fieldAPI.IsZero(a[0])
70 a1_is_zero := c.fieldAPI.IsZero(a[1])
71
72 // assert that a0_is_zero OR a1_is_zero == false
73 c.fieldAPI.AssertIsEqual(c.fieldAPI.Mul(a0_is_zero, a1_is_zero).(F), ZERO_F)
74
75 a_pow_r_minus_1 := QuadraticExtension{a[0], c.fieldAPI.Mul(a[1], c.DTH_ROOT).(F)}
76 a_pow_r := c.MulExtension(a_pow_r_minus_1, a)
77 return c.ScalarMulExtension(a_pow_r_minus_1, c.fieldAPI.Inverse(a_pow_r[0]).(F))
78}
79
80func (c *QuadraticExtensionAPI) ScalarMulExtension(a QuadraticExtension, scalar F) QuadraticExtension {
81 return QuadraticExtension{c.fieldAPI.Mul(a[0], scalar).(F), c.fieldAPI.Mul(a[1], scalar).(F)}
82}
83
84func (c *QuadraticExtensionAPI) FieldToQE(a F) QuadraticExtension {
85 return QuadraticExtension{a, ZERO_F}
86}
87
88// / Exponentiate `base` to the power of a known `exponent`.
89func (c *QuadraticExtensionAPI) ExpU64Extension(a QuadraticExtension, exponent uint64) QuadraticExtension {
90 switch exponent {
91 case 0:
92 return c.ONE_QE
93 case 1:
94 return a
95 case 2:
96 return c.SquareExtension(a)
97 default:
98 }
99
100 current := a
101 product := c.ONE_QE
102
103 for i := 0; i < bits.Len64(exponent); i++ {
104 if i != 0 {
105 current = c.SquareExtension(current)
106 }
107
108 if (exponent >> i & 1) != 0 {
109 product = c.MulExtension(product, current)
110 }
111 }
112
113 return product
114}
115
116func (c *QuadraticExtensionAPI) ReduceWithPowers(terms []QuadraticExtension, scalar QuadraticExtension) QuadraticExtension {
117 sum := c.ZERO_QE
118
119 for i := len(terms) - 1; i >= 0; i-- {
120 sum = c.AddExtension(
121 c.MulExtension(
122 sum,
123 scalar,
124 ),
125 terms[i],
126 )
127 }
128
129 return sum
130}
131
132func (c *QuadraticExtensionAPI) Select(b0 frontend.Variable, qe0, qe1 QuadraticExtension) QuadraticExtension {
133 var retQE QuadraticExtension
134
135 for i := 0; i < 2; i++ {
136 retQE[i] = c.fieldAPI.Select(b0, qe0[i], qe1[i]).(F)
137 }
138
139 return retQE
140}
141
142func (c *QuadraticExtensionAPI) Lookup2(b0 frontend.Variable, b1 frontend.Variable, qe0, qe1, qe2, qe3 QuadraticExtension) QuadraticExtension {
143 var retQE QuadraticExtension
144
145 for i := 0; i < 2; i++ {
146 retQE[i] = c.fieldAPI.Lookup2(b0, b1, qe0[i], qe1[i], qe2[i], qe3[i]).(F)
147 }
148
149 return retQE
150}
151
152func (c *QuadraticExtensionAPI) AssertIsEqual(a, b QuadraticExtension) {
153 for i := 0; i < 2; i++ {
154 c.fieldAPI.AssertIsEqual(a[0], b[0])
155 }
156}
157
158func (c *QuadraticExtensionAPI) Println(a QuadraticExtension) {
159 fmt.Print("Degree 0 coefficient")
160 c.fieldAPI.Println(a[0])
161
162 fmt.Print("Degree 1 coefficient")
163 c.fieldAPI.Println(a[1])
164}