Skip to content
9 changes: 2 additions & 7 deletions frontend/cs/r1cs/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,14 +281,9 @@ func (system *r1cs) Xor(_a, _b frontend.Variable) frontend.Variable {
system.AssertIsBoolean(a)
system.AssertIsBoolean(b)

// the formulation used is for easing up the conversion to sparse r1cs
res := system.newInternalVariable()
t := system.Mul(2, system.Mul(_a, _b))
res := system.Sub(system.Add(_a, _b), t)
system.MarkBoolean(res)
c := system.Neg(res).(compiled.LinearExpression)
c = append(c, a...)
c = append(c, b...)
aa := system.Mul(a, 2)
system.addConstraint(newR1C(aa, b, c))

return res
}
Expand Down
5 changes: 5 additions & 0 deletions frontend/cs/r1cs/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,11 @@ func (system *r1cs) reduce(l compiled.LinearExpression) compiled.LinearExpressio
for i := 1; i < len(l); i++ {
pcID, pvID, pVis := l[i-1].Unpack()
ccID, cvID, cVis := l[i].Unpack()
// if the coefficient is zero, we remove it
if ccID == compiled.CoeffIdZero {
l = append(l[:i], l[i+1:]...)
continue
}
if pVis == cVis && pvID == cvID {
// we have redundancy
c.Add(&system.st.Coeffs[pcID], &system.st.Coeffs[ccID])
Expand Down
14 changes: 9 additions & 5 deletions frontend/cs/scs/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ func (system *scs) FromBinary(b ...frontend.Variable) frontend.Variable {
// Xor returns a ^ b
// a and b must be 0 or 1
func (system *scs) Xor(a, b frontend.Variable) frontend.Variable {

system.AssertIsBoolean(a)
system.AssertIsBoolean(b)
_a, aConstant := system.ConstantValue(a)
Expand All @@ -204,6 +205,7 @@ func (system *scs) Xor(a, b frontend.Variable) frontend.Variable {
}

res := system.newInternalVariable()
system.MarkBoolean(res)
if aConstant {
a, b = b, a
bConstant = aConstant
Expand All @@ -212,10 +214,9 @@ func (system *scs) Xor(a, b frontend.Variable) frontend.Variable {
if bConstant {
l := a.(compiled.Term)
r := l
one := big.NewInt(1)
_b.Lsh(_b, 1).Sub(_b, one)
idl := system.st.CoeffID(_b)
system.addPlonkConstraint(l, r, res, idl, compiled.CoeffIdZero, compiled.CoeffIdZero, compiled.CoeffIdZero, compiled.CoeffIdOne, compiled.CoeffIdZero)
oneMinusTwoB := big.NewInt(1)
oneMinusTwoB.Sub(oneMinusTwoB, _b).Sub(oneMinusTwoB, _b)
system.addPlonkConstraint(l, r, res, system.st.CoeffID(oneMinusTwoB), compiled.CoeffIdZero, compiled.CoeffIdZero, compiled.CoeffIdZero, compiled.CoeffIdMinusOne, system.st.CoeffID(_b))
return res
}
l := a.(compiled.Term)
Expand All @@ -239,6 +240,7 @@ func (system *scs) Or(a, b frontend.Variable) frontend.Variable {
return _a
}
res := system.newInternalVariable()
system.MarkBoolean(res)
if aConstant {
a, b = b, a
_b = _a
Expand All @@ -265,7 +267,9 @@ func (system *scs) Or(a, b frontend.Variable) frontend.Variable {
func (system *scs) And(a, b frontend.Variable) frontend.Variable {
system.AssertIsBoolean(a)
system.AssertIsBoolean(b)
return system.Mul(a, b)
res := system.Mul(a, b)
system.MarkBoolean(res)
return res
}

// ---------------------------------------------------------------------------------------------
Expand Down
1 change: 0 additions & 1 deletion integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ func TestIntegrationAPI(t *testing.T) {
}, fmt.Sprintf("invalid-%d", i))
}
}, name)

}

}
108 changes: 80 additions & 28 deletions internal/backend/circuits/xor.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,58 @@ import (
"github.com/consensys/gnark/frontend"
)

// one input is constant
type xorCircuitVarCst struct {
Op frontend.Variable
XorOne frontend.Variable `gnark:",public"`
XorZero frontend.Variable `gnark:",public"`
}

func (circuit *xorCircuitVarCst) Define(api frontend.API) error {
a := api.Xor(circuit.Op, 1)
b := api.Xor(circuit.Op, 0)
c := api.Xor(1, circuit.Op)
d := api.Xor(0, circuit.Op)
api.AssertIsEqual(a, circuit.XorOne)
api.AssertIsEqual(b, circuit.XorZero)
api.AssertIsEqual(c, circuit.XorOne)
api.AssertIsEqual(d, circuit.XorZero)
return nil
}

func init() {

good := []frontend.Circuit{
&xorCircuitVarCst{
Op: 1,
XorOne: 0,
XorZero: 1,
},
&xorCircuitVarCst{
Op: (0),
XorOne: (1),
XorZero: (0),
},
}

bad := []frontend.Circuit{
&xorCircuitVarCst{
Op: 0,
XorOne: 0,
XorZero: 1,
},
&xorCircuitVarCst{
Op: (1),
XorOne: (1),
XorZero: (0),
},
}

addNewEntry("xorCstVar", &xorCircuitVarCst{}, good, bad, gnark.Curves())

}

// both inputs are variable
type xorCircuit struct {
Op1, Op2, Res frontend.Variable
}
Expand All @@ -20,56 +72,56 @@ func init() {

good := []frontend.Circuit{
&xorCircuit{
Op1: (1),
Op2: (1),
Res: (0),
Op1: 1,
Op2: 1,
Res: 0,
},
&xorCircuit{
Op1: (1),
Op2: (0),
Res: (1),
Op1: 1,
Op2: 0,
Res: 1,
},
&xorCircuit{
Op1: (0),
Op2: (1),
Res: (1),
Op1: 0,
Op2: 1,
Res: 1,
},
&xorCircuit{
Op1: (0),
Op2: (0),
Res: (0),
Op1: 0,
Op2: 0,
Res: 0,
},
}

bad := []frontend.Circuit{
&xorCircuit{
Op1: (1),
Op2: (1),
Res: (1),
Op1: 1,
Op2: 1,
Res: 1,
},
&xorCircuit{
Op1: (1),
Op2: (0),
Res: (0),
Op1: 1,
Op2: 0,
Res: 0,
},
&xorCircuit{
Op1: (0),
Op2: (1),
Res: (0),
Op1: 0,
Op2: 1,
Res: 0,
},
&xorCircuit{
Op1: (0),
Op2: (0),
Res: (1),
Op1: 0,
Op2: 0,
Res: 1,
},
&xorCircuit{
Op1: (42),
Op2: (1),
Res: (1),
Op2: 1,
Res: 1,
},
&xorCircuit{
Op1: (1),
Op2: (1),
Op1: 1,
Op2: 1,
Res: (42),
},
}
Expand Down