From bf808cceee17b0a9f0274d1dfba7289fc1fdbe2e Mon Sep 17 00:00:00 2001 From: Markku Rossi Date: Thu, 9 May 2024 11:54:27 +0200 Subject: [PATCH] Signed integer division with NewIDivider(). All uses changed. --- apps/garbled/examples/div.mpcl | 8 +- benchmarks.md | 3 +- compiler/circuits/circ_divider.go | 103 +++++++++++++++++++- compiler/mpa/mpint.go | 6 +- compiler/ssa/circuitgen.go | 32 +++++- compiler/ssa/streamer.go | 28 ++++-- compiler/tests/lang/divi.mpcl | 11 +++ compiler/tests/lang/{div.mpcl => divu.mpcl} | 0 8 files changed, 169 insertions(+), 22 deletions(-) create mode 100644 compiler/tests/lang/divi.mpcl rename compiler/tests/lang/{div.mpcl => divu.mpcl} (100%) diff --git a/apps/garbled/examples/div.mpcl b/apps/garbled/examples/div.mpcl index a9d72cdd..25b7085a 100644 --- a/apps/garbled/examples/div.mpcl +++ b/apps/garbled/examples/div.mpcl @@ -3,6 +3,12 @@ package main -func main(a, b int64) int { +import ( + "math" +) + +func main(a, b uint64) uint { return a / b + + //return int64(math.DivUint64(uint64(a), uint64(b))) } diff --git a/benchmarks.md b/benchmarks.md index 2654070d..3a061cd1 100644 --- a/benchmarks.md +++ b/benchmarks.md @@ -687,4 +687,5 @@ Optimized circuits from [pkg/math/](pkg/math/): | MPCL a+b | 251 | 80.2 | 63 | 100.0 | | MPCL a-b | 252 | 80.5 | 65 | 51.6 | | MPCL a*b | 8261 | 85.7 | 4007 | 99.4 | -| MPCL a/b | 24515 | 98.8 | 8194 | 160.4 | +| MPCL int a/b | 25274 | 101.8 | 8574 | 167.8 | +| MPCL uint a/b | 24515 | 98.8 | 8194 | 160.4 | diff --git a/compiler/circuits/circ_divider.go b/compiler/circuits/circ_divider.go index 75ad5479..cb709a0f 100644 --- a/compiler/circuits/circ_divider.go +++ b/compiler/circuits/circ_divider.go @@ -1,13 +1,14 @@ // -// Copyright (c) 2019-2023 Markku Rossi +// Copyright (c) 2019-2024 Markku Rossi // // All rights reserved. // package circuits -// NewDivider creates a division circuit computing r=a/b, q=a%b. -func NewDivider(cc *Compiler, a, b, q, r []*Wire) error { +// NewUDivider creates an unsigned integer division circuit computing +// r=a/b, q=a%b. +func NewUDivider(cc *Compiler, a, b, q, r []*Wire) error { a, b = cc.ZeroPad(a, b) rIn := make([]*Wire, len(b)+1) @@ -84,3 +85,99 @@ func NewDivider(cc *Compiler, a, b, q, r []*Wire) error { return nil } + +// NewIDivider creates a signed integer division circuit computing +// r=a/b, q=a%b. +func NewIDivider(cc *Compiler, a, b, q, r []*Wire) error { + a, b = cc.ZeroPad(a, b) + + zero := []*Wire{cc.ZeroWire()} + neg0 := cc.ZeroWire() + + // If a is negative, set neg=!neg, a=-a. + + neg1 := cc.Calloc.Wire() + cc.INV(neg0, neg1) + + a1 := make([]*Wire, len(a)) + for i := 0; i < len(a1); i++ { + a1[i] = cc.Calloc.Wire() + } + err := NewSubtractor(cc, zero, a, a1) + if err != nil { + return err + } + + neg2 := cc.Calloc.Wire() + err = NewMUX(cc, a[len(a)-1:], []*Wire{neg1}, []*Wire{neg0}, []*Wire{neg2}) + if err != nil { + return err + } + + a2 := make([]*Wire, len(a)) + for i := 0; i < len(a2); i++ { + a2[i] = cc.Calloc.Wire() + } + + err = NewMUX(cc, a[len(a)-1:], a1, a, a2) + if err != nil { + return err + } + + // If b is negative, set neg=!neg, b=-b. + + neg3 := cc.Calloc.Wire() + cc.INV(neg2, neg3) + + b1 := make([]*Wire, len(b)) + for i := 0; i < len(b1); i++ { + b1[i] = cc.Calloc.Wire() + } + err = NewSubtractor(cc, zero, b, b1) + if err != nil { + return err + } + + neg4 := cc.Calloc.Wire() + err = NewMUX(cc, b[len(b)-1:], []*Wire{neg3}, []*Wire{neg2}, []*Wire{neg4}) + if err != nil { + return err + } + + b2 := make([]*Wire, len(b)) + for i := 0; i < len(a2); i++ { + b2[i] = cc.Calloc.Wire() + } + + err = NewMUX(cc, b[len(b)-1:], b1, b, b2) + if err != nil { + return err + } + + if len(q) == 0 { + // Modulo operation. + return NewUDivider(cc, a2, b2, q, r) + } + + // If neg is set, set q=-q + + q0 := make([]*Wire, len(q)) + for i := 0; i < len(q0); i++ { + q0[i] = cc.Calloc.Wire() + } + err = NewUDivider(cc, a2, b2, q0, r) + if err != nil { + return err + } + + q1 := make([]*Wire, len(q)) + for i := 0; i < len(q1); i++ { + q1[i] = cc.Calloc.Wire() + } + err = NewSubtractor(cc, zero, q0, q1) + if err != nil { + return err + } + + return NewMUX(cc, []*Wire{neg4}, q1, q0, q) +} diff --git a/compiler/mpa/mpint.go b/compiler/mpa/mpint.go index 2df83c94..70c1bb7e 100644 --- a/compiler/mpa/mpint.go +++ b/compiler/mpa/mpint.go @@ -1,5 +1,5 @@ // -// Copyright (c) 2023 Markku Rossi +// Copyright (c) 2023-2024 Markku Rossi // // All rights reserved. // @@ -257,7 +257,7 @@ func (z *Int) Div(x, y *Int) *Int { panic(err) } - err = circuits.NewDivider(cc, i0w, i1w, o0w, o1w) + err = circuits.NewIDivider(cc, i0w, i1w, o0w, o1w) if err != nil { panic(err) } @@ -337,7 +337,7 @@ func (z *Int) Mod(x, y *Int) *Int { panic(err) } - err = circuits.NewDivider(cc, i0w, i1w, o0w, o1w) + err = circuits.NewIDivider(cc, i0w, i1w, o0w, o1w) if err != nil { panic(err) } diff --git a/compiler/ssa/circuitgen.go b/compiler/ssa/circuitgen.go index 200d42f4..6c5595fc 100644 --- a/compiler/ssa/circuitgen.go +++ b/compiler/ssa/circuitgen.go @@ -1,5 +1,5 @@ // -// Copyright (c) 2020-2023 Markku Rossi +// Copyright (c) 2020-2024 Markku Rossi // // All rights reserved. // @@ -145,24 +145,46 @@ func (prog *Program) Circuit(cc *circuits.Compiler) error { return err } - case Idiv, Udiv: + case Idiv: o, err := prog.walloc.Wires(*instr.Out, instr.Out.Type.Bits) if err != nil { return err } - err = circuits.NewDivider(cc, wires[0], wires[1], o, nil) + err = circuits.NewIDivider(cc, wires[0], wires[1], o, nil) if err != nil { return err } - case Imod, Umod: + case Udiv: o, err := prog.walloc.Wires(*instr.Out, instr.Out.Type.Bits) if err != nil { return err } - err = circuits.NewDivider(cc, wires[0], wires[1], nil, o) + err = circuits.NewUDivider(cc, wires[0], wires[1], o, nil) + if err != nil { + return err + } + + case Imod: + o, err := prog.walloc.Wires(*instr.Out, instr.Out.Type.Bits) + if err != nil { + return err + } + + err = circuits.NewIDivider(cc, wires[0], wires[1], nil, o) + if err != nil { + return err + } + + case Umod: + o, err := prog.walloc.Wires(*instr.Out, instr.Out.Type.Bits) + if err != nil { + return err + } + + err = circuits.NewUDivider(cc, wires[0], wires[1], nil, o) if err != nil { return err } diff --git a/compiler/ssa/streamer.go b/compiler/ssa/streamer.go index 7a3a3231..61e37044 100644 --- a/compiler/ssa/streamer.go +++ b/compiler/ssa/streamer.go @@ -1,5 +1,5 @@ // -// Copyright (c) 2020-2023 Markku Rossi +// Copyright (c) 2020-2024 Markku Rossi // // All rights reserved. // @@ -860,14 +860,24 @@ func newMultiplier(cc *circuits.Compiler, instr Instr, in [][]*circuits.Wire, in[0], in[1], out) } -func newDivider(cc *circuits.Compiler, instr Instr, in [][]*circuits.Wire, +func newIDivider(cc *circuits.Compiler, instr Instr, in [][]*circuits.Wire, out []*circuits.Wire) (bool, error) { - return true, circuits.NewDivider(cc, in[0], in[1], out, nil) + return true, circuits.NewIDivider(cc, in[0], in[1], out, nil) } -func newModulo(cc *circuits.Compiler, instr Instr, in [][]*circuits.Wire, +func newUDivider(cc *circuits.Compiler, instr Instr, in [][]*circuits.Wire, out []*circuits.Wire) (bool, error) { - return true, circuits.NewDivider(cc, in[0], in[1], nil, out) + return true, circuits.NewUDivider(cc, in[0], in[1], out, nil) +} + +func newIModulo(cc *circuits.Compiler, instr Instr, in [][]*circuits.Wire, + out []*circuits.Wire) (bool, error) { + return true, circuits.NewIDivider(cc, in[0], in[1], nil, out) +} + +func newUModulo(cc *circuits.Compiler, instr Instr, in [][]*circuits.Wire, + out []*circuits.Wire) (bool, error) { + return true, circuits.NewUDivider(cc, in[0], in[1], nil, out) } func newIndex(cc *circuits.Compiler, instr Instr, in [][]*circuits.Wire, @@ -896,10 +906,10 @@ var circuitGenerators = map[Operand]NewCircuit{ Usub: newBinary(circuits.NewSubtractor), Imult: newMultiplier, Umult: newMultiplier, - Idiv: newDivider, - Udiv: newDivider, - Imod: newModulo, - Umod: newModulo, + Idiv: newIDivider, + Udiv: newUDivider, + Imod: newIModulo, + Umod: newUModulo, Index: newIndex, Ilt: newBinary(circuits.NewLtComparator), Ult: newBinary(circuits.NewLtComparator), diff --git a/compiler/tests/lang/divi.mpcl b/compiler/tests/lang/divi.mpcl new file mode 100644 index 00000000..2dfcfb08 --- /dev/null +++ b/compiler/tests/lang/divi.mpcl @@ -0,0 +1,11 @@ +// -*- go -*- + +package main + +// @Test 43 4 = 10 +// @Test -43 4 = -10 +// @Test 43 -4 = -10 +// @Test -43 -4 = 10 +func main(a, b int64) int64 { + return a / b +} diff --git a/compiler/tests/lang/div.mpcl b/compiler/tests/lang/divu.mpcl similarity index 100% rename from compiler/tests/lang/div.mpcl rename to compiler/tests/lang/divu.mpcl