Skip to content

Commit a88771d

Browse files
committed
Merge branch 'develop'
2 parents 00a8dce + 91d463f commit a88771d

File tree

113 files changed

+6490
-4459
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

113 files changed

+6490
-4459
lines changed

CHANGELOG.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,49 @@
1+
<a name="v0.6.4"></a>
2+
3+
## [v0.6.4] - 2022-02-15
4+
5+
### Build
6+
7+
- update to gnark-crpto v0.6.1
8+
9+
### Feat
10+
11+
- Constraint system solvers (Groth16 and PlonK) now run in parallel
12+
13+
### Fix
14+
15+
- `api.DivUnchecked` with PlonK between 2 constants was incorrect
16+
17+
### Perf
18+
19+
- **EdDSA:** `std/algebra/twistededwards` takes ~2K less constraints (Groth16). Bandersnatch benefits from same improvments.
20+
21+
22+
### Pull Requests
23+
24+
- Merge pull request [#259](https://github.com/consensys/gnark/issues/259) from ConsenSys/perf-parallel-solver
25+
- Merge pull request [#261](https://github.com/consensys/gnark/issues/261) from ConsenSys/feat/kzg_updated
26+
- Merge pull request [#257](https://github.com/consensys/gnark/issues/257) from ConsenSys/perf/EdDSA
27+
- Merge pull request [#253](https://github.com/consensys/gnark/issues/253) from ConsenSys/feat/fft_cosets
28+
129
<a name="v0.6.3"></a>
230

331
## [v0.6.3] - 2022-02-13
432

533
### Feat
34+
635
- MiMC changes: api doesn't take a "seed" parameter. MiMC impl matches Ethereum one.
736

837
### Fix
38+
939
- fixes [#255](https://github.com/consensys/gnark/issues/255) variable visibility inheritance regression
1040
- counter was set with PLONK backend ID in R1CS
1141
- R1CS Solver was incorrectly calling a "MulByCoeff" instead of "DivByCoeff" (no impact, coeff was always 1 or -1)
1242
- SparseR1CS cbor unmarshal failed [#247](https://github.com/consensys/gnark/issues/247) for compiled.Term
1343

1444

1545
### Pull Requests
46+
1647
- Merge pull request [#256](https://github.com/consensys/gnark/issues/256) from ConsenSys/fix-bug-compile-visibility
1748
- Merge pull request [#249](https://github.com/consensys/gnark/issues/249) from ConsenSys/perf-ccs-hint
1849
- Merge pull request [#248](https://github.com/consensys/gnark/issues/248) from ConsenSys/perf-ccs-solver
@@ -24,9 +55,11 @@
2455
## [v0.6.1] - 2022-01-28
2556

2657
### Build
58+
2759
- go version dependency bumped from 1.16 to 1.17
2860

2961
### Feat
62+
3063
- added witness.MarshalJSON and witness.MarshalBinary
3164
- added `ccs.GetSchema()` - the schema of a circuit is required for witness json (de)serialization
3265
- added `ccs.GetConstraints()` - returns a list of human-readable constraints
@@ -35,18 +68,21 @@
3568
- addition of `Cmp` in the circuit API
3669

3770
### Refactor
71+
3872
- compiled.Visbility -> schema.Visibiility
3973
- witness.WriteSequence -> schema.WriteSequence
4074
- killed `ReadAndProve` and `ReadAndVerify` (plonk)
4175
- killed `ReadAndProve` and `ReadAndVerify` (groth16)
4276
- remove embbed struct tag for frontend.Variable fields
4377

4478
### Docs
79+
4580
- **backend:** unify documentation for options
4681
- **frontend:** unify docs for options
4782
- **test:** unify documentation for options
4883

4984
### Pull Requests
85+
5086
- Merge pull request [#244](https://github.com/consensys/gnark/issues/244) from ConsenSys/plonk-human-readable
5187
- Merge pull request [#237](https://github.com/consensys/gnark/issues/237) from ConsenSys/ccs-get-constraints
5288
- Merge pull request [#233](https://github.com/consensys/gnark/issues/233) from ConsenSys/feat/api_cmp

debug_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,16 @@ func TestPrintln(t *testing.T) {
4747
expected.WriteString("debug_test.go:27 26 42\n")
4848
expected.WriteString("debug_test.go:29 bits 1\n")
4949
expected.WriteString("debug_test.go:30 circuit {A: 2, B: 11}\n")
50-
expected.WriteString("debug_test.go:34 m <unsolved>\n")
50+
expected.WriteString("debug_test.go:34 m .*\n")
5151

5252
{
5353
trace, _ := getGroth16Trace(&circuit, &witness)
54-
assert.Equal(expected.String(), trace)
54+
assert.Regexp(expected.String(), trace)
5555
}
5656

5757
{
5858
trace, _ := getPlonkTrace(&circuit, &witness)
59-
assert.Equal(expected.String(), trace)
59+
assert.Regexp(expected.String(), trace)
6060
}
6161
}
6262

examples/rollup/account.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import (
2525

2626
var (
2727
// SizeAccount byte size of a serialized account (5*32bytes)
28-
// index || nonce || balance || pubkeyX || pubkeyY, each chunk is 32 bytes
28+
// index nonce balance pubkeyX pubkeyY, each chunk is 32 bytes
2929
SizeAccount = 160
3030
)
3131

@@ -48,7 +48,7 @@ func (ac *Account) Reset() {
4848

4949
// Serialize serializes the account as a concatenation of 5 chunks of 256 bits
5050
// one chunk per field (pubKey has 2 chunks), except index and nonce that are concatenated in a single 256 bits chunk
51-
// index || nonce || balance || pubkeyX || pubkeyY, each chunk is 256 bits
51+
// index nonce balance pubkeyX pubkeyY, each chunk is 256 bits
5252
func (ac *Account) Serialize() []byte {
5353

5454
//var buffer bytes.Buffer

examples/rollup/circuit.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ func (circuit *Circuit) Define(api frontend.API) error {
159159
// verifySignatureTransfer ensures that the signature of the transfer is valid
160160
func verifyTransferSignature(api frontend.API, t TransferConstraints, hFunc mimc.MiMC) error {
161161

162-
// the signature is on h(nonce || amount || senderpubKey (x&y) || receiverPubkey(x&y))
162+
// the signature is on h(nonce amount senderpubKey (x&y) receiverPubkey(x&y))
163163
hFunc.Write(t.Nonce, t.Amount, t.SenderPubKey.A.X, t.SenderPubKey.A.Y, t.ReceiverPubKey.A.X, t.ReceiverPubKey.A.Y)
164164
htransfer := hFunc.Sum()
165165

examples/rollup/operator.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ func NewQueue(batchSize int) Queue {
4646

4747
// Operator represents a rollup operator
4848
type Operator struct {
49-
State []byte // list of accounts: index || nonce || balance || pubkeyX || pubkeyY, each chunk is 256 bits
50-
HashState []byte // Hashed version of the state, each chunk is 256bits: ... || H(index || nonce || balance || pubkeyX || pubkeyY)) || ...
49+
State []byte // list of accounts: index nonce balance pubkeyX pubkeyY, each chunk is 256 bits
50+
HashState []byte // Hashed version of the state, each chunk is 256bits: ... H(index nonce balance pubkeyX pubkeyY)) ...
5151
AccountMap map[string]uint64 // hashmap of all available accounts (the key is the account.pubkey.X), the value is the index of the account in the state
5252
nbAccounts int // number of accounts managed by this operator
5353
h hash.Hash // hash function used to build the Merkle Tree
@@ -178,7 +178,7 @@ func (o *Operator) updateState(t Transfer, numTransfer int) error {
178178
o.witnesses.Transfers[numTransfer].Signature.S = t.signature.S[:]
179179

180180
// verifying the signature. The msg is the hash (o.h) of the transfer
181-
// nonce || amount || senderpubKey(x&y) || receiverPubkey(x&y)
181+
// nonce amount senderpubKey(x&y) receiverPubkey(x&y)
182182
resSig, err := t.Verify(o.h)
183183
if err != nil {
184184
return err

examples/rollup/transfer.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ func (t *Transfer) Sign(priv eddsa.PrivateKey, h hash.Hash) (eddsa.Signature, er
5252
//var frNonce, msg fr.Element
5353
var frNonce fr.Element
5454

55-
// serializing transfer. The signature is on h(nonce || amount || senderpubKey (x&y) || receiverPubkey(x&y))
55+
// serializing transfer. The signature is on h(nonce amount senderpubKey (x&y) receiverPubkey(x&y))
5656
// (each pubkey consist of 2 chunks of 256bits)
5757
frNonce.SetUint64(t.nonce)
5858
b := frNonce.Bytes()
@@ -91,7 +91,7 @@ func (t *Transfer) Verify(h hash.Hash) (bool, error) {
9191
var frNonce fr.Element
9292

9393
// serializing transfer. The msg to sign is
94-
// nonce || amount || senderpubKey(x&y) || receiverPubkey(x&y)
94+
// nonce amount senderpubKey(x&y) receiverPubkey(x&y)
9595
// (each pubkey consist of 2 chunks of 256bits)
9696
frNonce.SetUint64(t.nonce)
9797
b := frNonce.Bytes()

frontend/api.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ type API interface {
101101
// AssertIsDifferent fails if i1 == i2
102102
AssertIsDifferent(i1, i2 Variable)
103103

104-
// AssertIsBoolean fails if v != 0 || v != 1
104+
// AssertIsBoolean fails if v != 0 v != 1
105105
AssertIsBoolean(i1 Variable)
106106

107107
// AssertIsLessOrEqual fails if v > bound

frontend/compile.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ type NewBuilder func(ecc.ID) (Builder, error)
4242
// from the declarative code
4343
//
4444
// 3. finally, it converts that to a ConstraintSystem.
45-
// if zkpID == backend.GROTH16 --> R1CS
46-
// if zkpID == backend.PLONK --> SparseR1CS
45+
// if zkpID == backend.GROTH16 R1CS
46+
// if zkpID == backend.PLONK SparseR1CS
4747
//
4848
// initialCapacity is an optional parameter that reserves memory in slices
4949
// it should be set to the estimated number of constraints in the circuit, if known.

frontend/cs/plonk/api.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ func (system *sparseR1CS) DivUnchecked(i1, i2 frontend.Variable) frontend.Variab
120120
q := system.CurveID.Info().Fr.Modulus()
121121
return r.ModInverse(&r, q).
122122
Mul(&l, &r).
123-
Mod(&l, q)
123+
Mod(&r, q)
124124
}
125125
if system.IsConstant(i2) {
126126
c := utils.FromInterface(i2)

frontend/cs/plonk/assertions.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ func (system *sparseR1CS) AssertIsDifferent(i1, i2 frontend.Variable) {
6363
system.Inverse(system.Sub(i1, i2))
6464
}
6565

66-
// AssertIsBoolean fails if v != 0 || v != 1
66+
// AssertIsBoolean fails if v != 0 v != 1
6767
func (system *sparseR1CS) AssertIsBoolean(i1 frontend.Variable) {
6868
if system.IsConstant(i1) {
6969
c := utils.FromInterface(i1)
@@ -125,7 +125,7 @@ func (system *sparseR1CS) mustBeLessOrEqVar(a compiled.Term, bound compiled.Term
125125
l := system.Sub(1, t, aBits[i])
126126

127127
// note if bound[i] == 1, this constraint is (1 - ai) * ai == 0
128-
// --> this is a boolean constraint
128+
// this is a boolean constraint
129129
// if bound[i] == 0, t must be 0 or 1, thus ai must be 0 or 1 too
130130
system.markBoolean(aBits[i].(compiled.Term)) // this does not create a constraint
131131

@@ -172,7 +172,7 @@ func (system *sparseR1CS) mustBeLessOrEqCst(a compiled.Term, bound big.Int) {
172172
}
173173

174174
p := make([]frontend.Variable, nbBits+1)
175-
// p[i] == 1 --> a[j] == c[j] for all j >= i
175+
// p[i] == 1 a[j] == c[j] for all j i
176176
p[nbBits] = 1
177177

178178
for i := nbBits - 1; i >= t; i-- {

frontend/cs/plonk/conversion.go

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,9 @@ HINTLOOP:
116116
}
117117
res.MHints = shiftedMap
118118

119+
// build levels
120+
res.Levels = buildLevels(res)
121+
119122
switch cs.CurveID {
120123
case ecc.BLS12_377:
121124
return bls12377r1cs.NewSparseR1CS(res, cs.Coeffs), nil
@@ -138,3 +141,103 @@ HINTLOOP:
138141
func (cs *sparseR1CS) SetSchema(s *schema.Schema) {
139142
cs.Schema = s
140143
}
144+
145+
func buildLevels(ccs compiled.SparseR1CS) [][]int {
146+
147+
b := levelBuilder{
148+
mWireToNode: make(map[int]int, ccs.NbInternalVariables), // at which node we resolved which wire
149+
nodeLevels: make([]int, len(ccs.Constraints)), // level of a node
150+
mLevels: make(map[int]int), // level counts
151+
ccs: ccs,
152+
nbInputs: ccs.NbPublicVariables + ccs.NbSecretVariables,
153+
}
154+
155+
// for each constraint, we're going to find its direct dependencies
156+
// that is, wires (solved by previous constraints) on which it depends
157+
// each of these dependencies is tagged with a level
158+
// current constraint will be tagged with max(level) + 1
159+
for cID, c := range ccs.Constraints {
160+
161+
b.nodeLevel = 0
162+
163+
b.processTerm(c.L, cID)
164+
b.processTerm(c.R, cID)
165+
b.processTerm(c.O, cID)
166+
167+
b.nodeLevels[cID] = b.nodeLevel
168+
b.mLevels[b.nodeLevel]++
169+
170+
}
171+
172+
levels := make([][]int, len(b.mLevels))
173+
for i := 0; i < len(levels); i++ {
174+
// allocate memory
175+
levels[i] = make([]int, 0, b.mLevels[i])
176+
}
177+
178+
for n, l := range b.nodeLevels {
179+
levels[l] = append(levels[l], n)
180+
}
181+
182+
return levels
183+
}
184+
185+
type levelBuilder struct {
186+
ccs compiled.SparseR1CS
187+
nbInputs int
188+
189+
mWireToNode map[int]int // at which node we resolved which wire
190+
nodeLevels []int // level per node
191+
mLevels map[int]int // number of constraint per level
192+
193+
nodeLevel int // current level
194+
}
195+
196+
func (b *levelBuilder) processTerm(t compiled.Term, cID int) {
197+
wID := t.WireID()
198+
if wID < b.nbInputs {
199+
// it's a input, we ignore it
200+
return
201+
}
202+
203+
// if we know a which constraint solves this wire, then it's a dependency
204+
n, ok := b.mWireToNode[wID]
205+
if ok {
206+
if n != cID { // can happen with hints...
207+
// we add a dependency, check if we need to increment our current level
208+
if b.nodeLevels[n] >= b.nodeLevel {
209+
b.nodeLevel = b.nodeLevels[n] + 1 // we are at the next level at least since we depend on it
210+
}
211+
}
212+
return
213+
}
214+
215+
// check if it's a hint and mark all the output wires
216+
if h, ok := b.ccs.MHints[wID]; ok {
217+
218+
for _, in := range h.Inputs {
219+
switch t := in.(type) {
220+
case compiled.Variable:
221+
for _, tt := range t.LinExp {
222+
b.processTerm(tt, cID)
223+
}
224+
case compiled.LinearExpression:
225+
for _, tt := range t {
226+
b.processTerm(tt, cID)
227+
}
228+
case compiled.Term:
229+
b.processTerm(t, cID)
230+
}
231+
}
232+
233+
for _, hwid := range h.Wires {
234+
b.mWireToNode[hwid] = cID
235+
}
236+
237+
return
238+
}
239+
240+
// mark this wire solved by current node
241+
b.mWireToNode[wID] = cID
242+
243+
}

frontend/cs/plonk/sparse_r1cs.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ func (system *sparseR1CS) NewSecretVariable(name string) frontend.Variable {
130130

131131
// reduces redundancy in linear expression
132132
// It factorizes Variable that appears multiple times with != coeff Ids
133-
// To ensure the determinism in the compile process, Variables are stored as public||secret||internal||unset
133+
// To ensure the determinism in the compile process, Variables are stored as publicsecretinternalunset
134134
// for each visibility, the Variables are sorted from lowest ID to highest ID
135135
func (system *sparseR1CS) reduce(l compiled.LinearExpression) compiled.LinearExpression {
136136

@@ -268,7 +268,7 @@ func (system *sparseR1CS) CheckVariables() error {
268268
sbb.WriteString(strconv.Itoa(cptHints))
269269
sbb.WriteString(" unconstrained hints")
270270
sbb.WriteByte('\n')
271-
// TODO we may add more debug info here --> idea, in NewHint, take the debug stack, and store in the hint map some
271+
// TODO we may add more debug info here idea, in NewHint, take the debug stack, and store in the hint map some
272272
// debugInfo to find where a hint was declared (and not constrained)
273273
}
274274
return errors.New(sbb.String())

frontend/cs/r1cs/assertions.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ func (system *r1CS) AssertIsDifferent(i1, i2 frontend.Variable) {
4141
system.Inverse(system.Sub(i1, i2))
4242
}
4343

44-
// AssertIsBoolean adds an assertion in the constraint system (v == 0 || v == 1)
44+
// AssertIsBoolean adds an assertion in the constraint system (v == 0 v == 1)
4545
func (system *r1CS) AssertIsBoolean(i1 frontend.Variable) {
4646

4747
vars, _ := system.toVariables(i1)
@@ -69,7 +69,7 @@ func (system *r1CS) AssertIsBoolean(i1 frontend.Variable) {
6969
system.addConstraint(newR1C(v, _v, o), debug)
7070
}
7171

72-
// AssertIsLessOrEqual adds assertion in constraint system (v <= bound)
72+
// AssertIsLessOrEqual adds assertion in constraint system (v bound)
7373
//
7474
// bound can be a constant or a Variable
7575
//
@@ -120,7 +120,7 @@ func (system *r1CS) mustBeLessOrEqVar(a, bound compiled.Variable) {
120120
l = system.Sub(l, t, aBits[i])
121121

122122
// note if bound[i] == 1, this constraint is (1 - ai) * ai == 0
123-
// --> this is a boolean constraint
123+
// this is a boolean constraint
124124
// if bound[i] == 0, t must be 0 or 1, thus ai must be 0 or 1 too
125125
system.markBoolean(aBits[i].(compiled.Variable)) // this does not create a constraint
126126

@@ -158,7 +158,7 @@ func (system *r1CS) mustBeLessOrEqCst(a compiled.Variable, bound big.Int) {
158158
}
159159

160160
p := make([]frontend.Variable, nbBits+1)
161-
// p[i] == 1 --> a[j] == c[j] for all j >= i
161+
// p[i] == 1 a[j] == c[j] for all j i
162162
p[nbBits] = system.constant(1)
163163

164164
for i := nbBits - 1; i >= t; i-- {

0 commit comments

Comments
 (0)