Skip to content

Commit 781de03

Browse files
authored
Merge pull request #1061 from Consensys/perf/ec-arithmetic
Perf: optimize EC arithmetic
2 parents bb26665 + 9f72d90 commit 781de03

File tree

13 files changed

+614
-250
lines changed

13 files changed

+614
-250
lines changed

frontend/cs/scs/api.go

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -465,14 +465,11 @@ func (builder *builder) Lookup2(b0, b1 frontend.Variable, i0, i1, i2, i3 fronten
465465
// (3) (in2 - in0) * s1 = RES - tmp2 - in0
466466
// the variables tmp1 and tmp2 are new internal variables and the variables
467467
// RES will be the returned result
468-
469-
// TODO check how it can be optimized for PLONK (currently it's a copy
470-
// paste of the r1cs version)
471-
tmp1 := builder.Add(i3, i0)
472-
tmp1 = builder.Sub(tmp1, i2, i1)
468+
tmp1 := builder.Sub(i3, i2)
469+
tmp := builder.Sub(i0, i1)
470+
tmp1 = builder.Add(tmp1, tmp)
473471
tmp1 = builder.Mul(tmp1, b1)
474-
tmp1 = builder.Add(tmp1, i1)
475-
tmp1 = builder.Sub(tmp1, i0) // (1) tmp1 = s1 * (in3 - in2 - in1 + in0) + in1 - in0
472+
tmp1 = builder.Sub(tmp1, tmp) // (1) tmp1 = s1 * (in3 - in2 - in1 + in0) + in1 - in0
476473
tmp2 := builder.Mul(tmp1, b0) // (2) tmp2 = tmp1 * s0
477474
res := builder.Sub(i2, i0)
478475
res = builder.Mul(res, b1)

internal/stats/latest.stats

0 Bytes
Binary file not shown.

std/algebra/emulated/sw_emulated/hints.go

Lines changed: 75 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,40 +14,96 @@ func init() {
1414
}
1515

1616
func GetHints() []solver.Hint {
17-
return []solver.Hint{decomposeScalarG1}
17+
return []solver.Hint{decomposeScalarG1, decomposeScalarG1Signs, decomposeScalarG1Subscalars}
18+
}
19+
20+
func decomposeScalarG1Subscalars(mod *big.Int, inputs []*big.Int, outputs []*big.Int) error {
21+
return emulated.UnwrapHint(inputs, outputs, func(field *big.Int, inputs, outputs []*big.Int) error {
22+
if len(inputs) != 2 {
23+
return fmt.Errorf("expecting two inputs")
24+
}
25+
if len(outputs) != 2 {
26+
return fmt.Errorf("expecting two outputs")
27+
}
28+
glvBasis := new(ecc.Lattice)
29+
ecc.PrecomputeLattice(field, inputs[1], glvBasis)
30+
sp := ecc.SplitScalar(inputs[0], glvBasis)
31+
outputs[0].Set(&(sp[0]))
32+
outputs[1].Set(&(sp[1]))
33+
// we need the absolute values for the in-circuit computations,
34+
// otherwise the negative values will be reduced modulo the SNARK scalar
35+
// field and not the emulated field.
36+
// output0 = |s0| mod r
37+
// output1 = |s1| mod r
38+
if outputs[0].Sign() == -1 {
39+
outputs[0].Neg(outputs[0])
40+
}
41+
if outputs[1].Sign() == -1 {
42+
outputs[1].Neg(outputs[1])
43+
}
44+
45+
return nil
46+
})
47+
}
48+
49+
func decomposeScalarG1Signs(mod *big.Int, inputs []*big.Int, outputs []*big.Int) error {
50+
return emulated.UnwrapHintWithNativeOutput(inputs, outputs, func(field *big.Int, inputs, outputs []*big.Int) error {
51+
if len(inputs) != 2 {
52+
return fmt.Errorf("expecting two inputs")
53+
}
54+
if len(outputs) != 2 {
55+
return fmt.Errorf("expecting two outputs")
56+
}
57+
glvBasis := new(ecc.Lattice)
58+
ecc.PrecomputeLattice(field, inputs[1], glvBasis)
59+
sp := ecc.SplitScalar(inputs[0], glvBasis)
60+
outputs[0].SetUint64(0)
61+
if sp[0].Sign() == -1 {
62+
outputs[0].SetUint64(1)
63+
}
64+
outputs[1].SetUint64(0)
65+
if sp[1].Sign() == -1 {
66+
outputs[1].SetUint64(1)
67+
}
68+
69+
return nil
70+
})
1871
}
1972

2073
func decomposeScalarG1(mod *big.Int, inputs []*big.Int, outputs []*big.Int) error {
2174
return emulated.UnwrapHint(inputs, outputs, func(field *big.Int, inputs, outputs []*big.Int) error {
2275
if len(inputs) != 3 {
23-
return fmt.Errorf("expecting three inputs")
76+
return fmt.Errorf("expecting two inputs")
2477
}
25-
if len(outputs) != 5 {
26-
return fmt.Errorf("expecting five outputs")
78+
if len(outputs) != 6 {
79+
return fmt.Errorf("expecting two outputs")
2780
}
2881
glvBasis := new(ecc.Lattice)
2982
ecc.PrecomputeLattice(inputs[2], inputs[1], glvBasis)
3083
sp := ecc.SplitScalar(inputs[0], glvBasis)
3184
outputs[0].Set(&(sp[0]))
3285
outputs[1].Set(&(sp[1]))
33-
// figure out how many times we have overflowed
34-
outputs[1].Set(&(sp[1]))
35-
outputs[2].Mul(outputs[1], inputs[1]).Add(outputs[2], outputs[0])
36-
outputs[2].Sub(outputs[2], inputs[0])
37-
outputs[2].Div(outputs[2], inputs[2])
38-
39-
// return:
40-
// output0 = s0 mod r
41-
// output1 = s1 mod r
42-
// output3 = |s0| mod r
43-
// output4 = |s1| mod r
44-
outputs[3].Set(outputs[0])
86+
// we need the negative values for to check that s0+λ*s1 == s mod r
87+
// output4 = s0 mod r
88+
// output5 = s1 mod r
89+
outputs[4].Set(outputs[0])
90+
outputs[5].Set(outputs[1])
91+
// we need the absolute values for the in-circuit computations,
92+
// otherwise the negative values will be reduced modulo the SNARK scalar
93+
// field and not the emulated field.
94+
// output0 = |s0| mod r
95+
// output1 = |s1| mod r
96+
// output2 = 1 if s0 is positive, 0 if s0 is negative
97+
// output3 = 1 if s1 is positive, 0 if s0 is negative
98+
outputs[2].SetUint64(1)
4599
if outputs[0].Sign() == -1 {
46-
outputs[3].Neg(outputs[0])
100+
outputs[0].Neg(outputs[0])
101+
outputs[2].SetUint64(0)
47102
}
48-
outputs[4].Set(outputs[1])
103+
outputs[3].SetUint64(1)
49104
if outputs[1].Sign() == -1 {
50-
outputs[4].Neg(outputs[1])
105+
outputs[1].Neg(outputs[1])
106+
outputs[3].SetUint64(0)
51107
}
52108

53109
return nil

0 commit comments

Comments
 (0)