Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Perf: optimize EC arithmetic #1061

Merged
merged 45 commits into from
Mar 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
4d71f79
perf(2-chains): save an addition per iteration in ScalarMul
yelhousni Feb 14, 2024
73a7cd6
perf: small optim replacing Sub by Add
yelhousni Feb 15, 2024
b2b96a6
perf(emulated): optimize GLV hint
yelhousni Feb 16, 2024
5cd0913
Revert "perf(2-chains): save an addition per iteration in ScalarMul"
yelhousni Feb 16, 2024
10c242a
perf: small optim in jointScalarMulGLV
yelhousni Feb 16, 2024
1f2d155
perf(2-chains): small optim in varScalarMul and JointScalarMul
yelhousni Feb 16, 2024
56b7937
perf(emulated): big optim scalarMulGLV
yelhousni Feb 16, 2024
8ee1fbc
perf(emulated): big optim jointScalarMulGLV
yelhousni Feb 16, 2024
f7b7d9a
perf: more optim to jointScalarMulGLV
yelhousni Feb 18, 2024
33b31c5
perf: more small optim to jointScalarMulGLV
yelhousni Feb 18, 2024
16990de
perf(emulated): huge optim scalarMulGLV
yelhousni Feb 21, 2024
da9513e
perf(emulated): save 1 add in scalarMulGLV
yelhousni Feb 22, 2024
8bc71b4
perf(2-chain): save 1 add in varScalarMul in G2
yelhousni Feb 22, 2024
4c69e3e
Merge branch 'master' into perf/ec-arithmetic
yelhousni Feb 22, 2024
18d4d10
Merge branch 'master' into perf/ec-arithmetic
yelhousni Feb 22, 2024
7cc8816
perf(emulated): ScalarMulBase with GLV is better
yelhousni Feb 22, 2024
a883c92
perf: save 4 scs in lookup2 api
yelhousni Mar 3, 2024
a354496
Merge branch 'master' into perf/ec-arithmetic
yelhousni Mar 5, 2024
c90e690
perf(2-chain): small scs optim to doubleAndAdd
yelhousni Mar 5, 2024
d6b0320
perf(ecrecover): save 1 MulMod in ecrecover
yelhousni Mar 5, 2024
0fda05c
perf: big optim for JointScalarMulBase
yelhousni Mar 6, 2024
64299a1
chore: update stats
yelhousni Mar 6, 2024
c759df0
fix: JointScalarMulBase without GLV (for ecdsa package)
yelhousni Mar 6, 2024
92b6a8d
perf: save some negs in ec arithmetic
yelhousni Mar 6, 2024
c7d831d
perf: big optim for JointScalarMul and MSM
yelhousni Mar 6, 2024
2f2fadc
fix(emulated/JointScalarMul): edge case where P+Q is maliciously crafted
yelhousni Mar 7, 2024
c35311d
perf: simplify the glv decomposition hint
yelhousni Mar 7, 2024
289413d
fix(emulated/JointScalarMul): avoid malicious hint in decomposeScalar
yelhousni Mar 7, 2024
e992856
Merge branch 'master' into perf/ec-arithmetic
yelhousni Mar 8, 2024
bc1c711
chore: update stats
yelhousni Mar 8, 2024
3c6741c
perf: do not use multiplication for subscalar check
ivokub Mar 8, 2024
cdedeca
feat: add non-native hint with native output
ivokub Mar 8, 2024
2238e16
perf: optimize hint computation with corresponding output field
ivokub Mar 8, 2024
aeb2509
perf: use less outputs from hints
ivokub Mar 8, 2024
a3f25f3
perf: use less outputs (joint)
ivokub Mar 8, 2024
9fa2c4c
fix: incorrect parameter
ivokub Mar 8, 2024
a2f0bdc
fix: edge cases in SM and JSM were inverted + comments
yelhousni Mar 8, 2024
1c35291
Merge branch 'master' into perf/ec-arithmetic
yelhousni Mar 8, 2024
9fc5c14
docs: add comments
yelhousni Mar 9, 2024
1b7c6d0
perf(kzg): remove folding and shrinked scalars options in MSM
yelhousni Mar 9, 2024
5cfccb7
Merge branch 'master' into perf/ec-arithmetic
yelhousni Mar 11, 2024
6709f1b
Revert "feat: add non-native hint with native output"
yelhousni Mar 12, 2024
3ce0ffa
Merge branch 'master' into perf/ec-arithmetic
yelhousni Mar 12, 2024
ce6b81c
Merge branch 'master' into perf/ec-arithmetic
yelhousni Mar 12, 2024
9f72d90
docs: clean comments
yelhousni Mar 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading