Consensys / gnark

gnark is a fast zk-SNARK library that offers a high-level API to design circuits. The library is open source and developed under the Apache 2.0 license
https://hackmd.io/@gnark
Apache License 2.0
1.41k stars 361 forks source link

Bug: `std/algebra/twistededwards` unable to verify SchnorrProof #103

Closed SherLzp closed 3 years ago

SherLzp commented 3 years ago

I want to use twisted edwards bn254 to verify schnorr proof(to prove $pk = g^{sk}$, and the verification process is: $g^z == A pk^c$), but some errors occur. Here is my code:

type SchnorrProofCircuit struct {
    G  Point
    A  Point
    Pk Point
    E  Point
    Z  frontend.Variable
    C  frontend.Variable
}

func (circuit *SchnorrProofCircuit) Define(curveID ecc.ID, cs *frontend.ConstraintSystem) error {
    // get edwards curve params
    params, err := NewEdCurve(curveID)
    if err != nil {
        return err
    }

    l := circuit.G.ScalarMulFixedBase(cs, params.BaseX, params.BaseY, circuit.Z, params)
    pkc := circuit.G.ScalarMulNonFixedBase(cs, &circuit.Pk, circuit.C, params)
    r := circuit.A.AddGeneric(cs, &circuit.A, pkc, params)

    cs.AssertIsEqual(l.X, circuit.E.X)
    cs.AssertIsEqual(l.Y, circuit.E.Y)
    cs.AssertIsEqual(r.X, circuit.E.X)
    cs.AssertIsEqual(r.Y, circuit.E.Y)

    return nil
}

func TestSchnorrProof(t *testing.T) {
    assert := groth16.NewAssert(t)

    var circuit, witness SchnorrProofCircuit
    r1cs, err := frontend.Compile(ecc.BN254, backend.GROTH16, &circuit)
    if err != nil {
        t.Fatal(err)
    }
    // generate witness data
    witness.G.X.Assign("9671717474070082183213120605117400219616337014328744928644933853176787189663")
    witness.G.Y.Assign("16950150798460657717958625567821834550301663161624707787222815936182638968203")
    witness.A.X.Assign("1805826214268140062109789454888545380426720994127895546120718277293486808528")
    witness.A.Y.Assign("1992424522915255363820795818666870149715470888958691910097484002003697548446")
    witness.Pk.X.Assign("20062244510347148272446781100879286480638585431533684331180269070589632792928")
    witness.Pk.Y.Assign("1270552922097600254906946530389401056931473037205902458907582592439177824778")
    witness.E.X.Assign("13267298554170076447200931779952958551554919355570507175724056086686427997337")
    witness.E.Y.Assign("91546535213534860287538445389844078149478740933762505141585402403269006816")
    z, _ := new(big.Int).SetString("56457306562257122565246154685424300206626160564298072980723270873916373234", 10)
    c, _ := new(big.Int).SetString("12570305820242045194614329830538401576680239494304591206526835130365207477516", 10)
    witness.Z.Assign(z)
    witness.C.Assign(c)

    assert.SolvingSucceeded(r1cs, &witness)

}

I can confirm that the witness is right. And something strange is that, when I change the code for Define as these two ways, it works: First:

func (circuit *SchnorrProofCircuit) Define(curveID ecc.ID, cs *frontend.ConstraintSystem) error {
    // get edwards curve params
    params, err := NewEdCurve(curveID)
    if err != nil {
        return err
    }

    l := circuit.G.ScalarMulFixedBase(cs, params.BaseX, params.BaseY, circuit.Z, params)
    //pkc := circuit.G.ScalarMulNonFixedBase(cs, &circuit.Pk, circuit.C, params)
    //r := circuit.A.AddGeneric(cs, &circuit.A, pkc, params)

    cs.AssertIsEqual(l.X, circuit.E.X)
    cs.AssertIsEqual(l.Y, circuit.E.Y)
    //cs.AssertIsEqual(r.X, circuit.E.X)
    //cs.AssertIsEqual(r.Y, circuit.E.Y)

    return nil
}

Second:

func (circuit *SchnorrProofCircuit) Define(curveID ecc.ID, cs *frontend.ConstraintSystem) error {
    // get edwards curve params
    params, err := NewEdCurve(curveID)
    if err != nil {
        return err
    }

    //l := circuit.G.ScalarMulFixedBase(cs, params.BaseX, params.BaseY, circuit.Z, params)
    pkc := circuit.G.ScalarMulNonFixedBase(cs, &circuit.Pk, circuit.C, params)
    r := circuit.A.AddGeneric(cs, &circuit.A, pkc, params)

    //cs.AssertIsEqual(l.X, circuit.E.X)
    //cs.AssertIsEqual(l.Y, circuit.E.Y)
    cs.AssertIsEqual(r.X, circuit.E.X)
    cs.AssertIsEqual(r.Y, circuit.E.Y)

    return nil
}

I think that's something wrong with the AssertIsEqual. Could you help me solve that?

SherLzp commented 3 years ago

When I change Define to this(change A to G), it works:

func (circuit *SchnorrProofCircuit) Define(curveID ecc.ID, cs *frontend.ConstraintSystem) error {
    // get edwards curve params
    params, err := NewEdCurve(curveID)
    if err != nil {
        return err
    }

    l := circuit.G.ScalarMulFixedBase(cs, params.BaseX, params.BaseY, circuit.Z, params)
    pkc := circuit.G.ScalarMulNonFixedBase(cs, &circuit.Pk, circuit.C, params)
    r := circuit.G.AddGeneric(cs, &circuit.A, pkc, params)

    cs.AssertIsEqual(l.X, circuit.E.X)
    cs.AssertIsEqual(l.Y, circuit.E.Y)
    cs.AssertIsEqual(r.X, circuit.E.X)
    cs.AssertIsEqual(r.Y, circuit.E.Y)

    return nil
}
gbotrel commented 3 years ago

hi, did reproduce, but I believe your issue comes from the fact that circuit.G.ScalarMulFixedBase and circuit.G. circuit.G.ScalarMulNonFixedBase mutates the caller.

So doing this works:

    l := circuit.G.ScalarMulFixedBase(cs, params.BaseX, params.BaseY, circuit.Z, params)
    cs.AssertIsEqual(l.X, circuit.E.X)
    cs.AssertIsEqual(l.Y, circuit.E.Y)

    pkc := circuit.G.ScalarMulNonFixedBase(cs, &circuit.Pk, circuit.C, params)
    r := circuit.A.AddGeneric(cs, &circuit.A, pkc, params)

    cs.AssertIsEqual(r.X, circuit.E.X)
    cs.AssertIsEqual(r.Y, circuit.E.Y)

or

    l := Point{
        X: cs.Constant(circuit.G.X),
        Y: cs.Constant(circuit.G.Y),
    }

    l.ScalarMulFixedBase(cs, params.BaseX, params.BaseY, circuit.Z, params)

    pkc := circuit.G.ScalarMulNonFixedBase(cs, &circuit.Pk, circuit.C, params)
    r := circuit.A.AddGeneric(cs, &circuit.A, pkc, params)
    cs.AssertIsEqual(l.X, circuit.E.X)
    cs.AssertIsEqual(l.Y, circuit.E.Y)
    cs.AssertIsEqual(r.X, circuit.E.X)
    cs.AssertIsEqual(r.Y, circuit.E.Y)
SherLzp commented 3 years ago

it works again. Thanks.