Skip to content

Commit

Permalink
Merge pull request Consensys#1061 from Consensys/perf/ec-arithmetic
Browse files Browse the repository at this point in the history
Perf: optimize EC arithmetic
  • Loading branch information
yelhousni authored Mar 12, 2024
2 parents bb26665 + 9f72d90 commit 781de03
Show file tree
Hide file tree
Showing 13 changed files with 614 additions and 250 deletions.
11 changes: 4 additions & 7 deletions frontend/cs/scs/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -465,14 +465,11 @@ func (builder *builder) Lookup2(b0, b1 frontend.Variable, i0, i1, i2, i3 fronten
// (3) (in2 - in0) * s1 = RES - tmp2 - in0
// the variables tmp1 and tmp2 are new internal variables and the variables
// RES will be the returned result

// TODO check how it can be optimized for PLONK (currently it's a copy
// paste of the r1cs version)
tmp1 := builder.Add(i3, i0)
tmp1 = builder.Sub(tmp1, i2, i1)
tmp1 := builder.Sub(i3, i2)
tmp := builder.Sub(i0, i1)
tmp1 = builder.Add(tmp1, tmp)
tmp1 = builder.Mul(tmp1, b1)
tmp1 = builder.Add(tmp1, i1)
tmp1 = builder.Sub(tmp1, i0) // (1) tmp1 = s1 * (in3 - in2 - in1 + in0) + in1 - in0
tmp1 = builder.Sub(tmp1, tmp) // (1) tmp1 = s1 * (in3 - in2 - in1 + in0) + in1 - in0
tmp2 := builder.Mul(tmp1, b0) // (2) tmp2 = tmp1 * s0
res := builder.Sub(i2, i0)
res = builder.Mul(res, b1)
Expand Down
Binary file modified internal/stats/latest.stats
Binary file not shown.
94 changes: 75 additions & 19 deletions std/algebra/emulated/sw_emulated/hints.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,40 +14,96 @@ func init() {
}

func GetHints() []solver.Hint {
return []solver.Hint{decomposeScalarG1}
return []solver.Hint{decomposeScalarG1, decomposeScalarG1Signs, decomposeScalarG1Subscalars}
}

func decomposeScalarG1Subscalars(mod *big.Int, inputs []*big.Int, outputs []*big.Int) error {
return emulated.UnwrapHint(inputs, outputs, func(field *big.Int, inputs, outputs []*big.Int) error {
if len(inputs) != 2 {
return fmt.Errorf("expecting two inputs")
}
if len(outputs) != 2 {
return fmt.Errorf("expecting two outputs")
}
glvBasis := new(ecc.Lattice)
ecc.PrecomputeLattice(field, inputs[1], glvBasis)
sp := ecc.SplitScalar(inputs[0], glvBasis)
outputs[0].Set(&(sp[0]))
outputs[1].Set(&(sp[1]))
// we need the absolute values for the in-circuit computations,
// otherwise the negative values will be reduced modulo the SNARK scalar
// field and not the emulated field.
// output0 = |s0| mod r
// output1 = |s1| mod r
if outputs[0].Sign() == -1 {
outputs[0].Neg(outputs[0])
}
if outputs[1].Sign() == -1 {
outputs[1].Neg(outputs[1])
}

return nil
})
}

func decomposeScalarG1Signs(mod *big.Int, inputs []*big.Int, outputs []*big.Int) error {
return emulated.UnwrapHintWithNativeOutput(inputs, outputs, func(field *big.Int, inputs, outputs []*big.Int) error {
if len(inputs) != 2 {
return fmt.Errorf("expecting two inputs")
}
if len(outputs) != 2 {
return fmt.Errorf("expecting two outputs")
}
glvBasis := new(ecc.Lattice)
ecc.PrecomputeLattice(field, inputs[1], glvBasis)
sp := ecc.SplitScalar(inputs[0], glvBasis)
outputs[0].SetUint64(0)
if sp[0].Sign() == -1 {
outputs[0].SetUint64(1)
}
outputs[1].SetUint64(0)
if sp[1].Sign() == -1 {
outputs[1].SetUint64(1)
}

return nil
})
}

func decomposeScalarG1(mod *big.Int, inputs []*big.Int, outputs []*big.Int) error {
return emulated.UnwrapHint(inputs, outputs, func(field *big.Int, inputs, outputs []*big.Int) error {
if len(inputs) != 3 {
return fmt.Errorf("expecting three inputs")
return fmt.Errorf("expecting two inputs")
}
if len(outputs) != 5 {
return fmt.Errorf("expecting five outputs")
if len(outputs) != 6 {
return fmt.Errorf("expecting two outputs")
}
glvBasis := new(ecc.Lattice)
ecc.PrecomputeLattice(inputs[2], inputs[1], glvBasis)
sp := ecc.SplitScalar(inputs[0], glvBasis)
outputs[0].Set(&(sp[0]))
outputs[1].Set(&(sp[1]))
// figure out how many times we have overflowed
outputs[1].Set(&(sp[1]))
outputs[2].Mul(outputs[1], inputs[1]).Add(outputs[2], outputs[0])
outputs[2].Sub(outputs[2], inputs[0])
outputs[2].Div(outputs[2], inputs[2])

// return:
// output0 = s0 mod r
// output1 = s1 mod r
// output3 = |s0| mod r
// output4 = |s1| mod r
outputs[3].Set(outputs[0])
// we need the negative values for to check that s0+λ*s1 == s mod r
// output4 = s0 mod r
// output5 = s1 mod r
outputs[4].Set(outputs[0])
outputs[5].Set(outputs[1])
// we need the absolute values for the in-circuit computations,
// otherwise the negative values will be reduced modulo the SNARK scalar
// field and not the emulated field.
// output0 = |s0| mod r
// output1 = |s1| mod r
// output2 = 1 if s0 is positive, 0 if s0 is negative
// output3 = 1 if s1 is positive, 0 if s0 is negative
outputs[2].SetUint64(1)
if outputs[0].Sign() == -1 {
outputs[3].Neg(outputs[0])
outputs[0].Neg(outputs[0])
outputs[2].SetUint64(0)
}
outputs[4].Set(outputs[1])
outputs[3].SetUint64(1)
if outputs[1].Sign() == -1 {
outputs[4].Neg(outputs[1])
outputs[1].Neg(outputs[1])
outputs[3].SetUint64(0)
}

return nil
Expand Down
Loading

0 comments on commit 781de03

Please sign in to comment.