akosba / jsnark

A Java library for zk-SNARK circuits
MIT License
207 stars 85 forks source link

SHA 256 gadget's output wires have negative id #10

Closed hasinitg closed 5 years ago

hasinitg commented 5 years ago

Hi Ahmed @akosba

I was trying to write a verification circuit using SHA256 gadget using an assert operation. However, assert operation complains that the output wires of SHA256 have negative ids.

When I debugged, I found that the negative ids for the output wires of SHA256 gadget are injected within the 'trimBits' method, which is first invoked at line 158 of SHA256Gadget.java class.

This is because trimBits method returns a VariableWire without an id. Could you please let me know if this is the expected behavior?

Thank you.

akosba commented 5 years ago

Hi @hasinitg

Thanks. I posted a fix for that. Like what the rest of primitive operations do, the assertion op should make sure that the operand wires are in a packed format. This appeared in your use case of SHA256 with assertions, as the output wires of the gadget itself are just bit vectors. Let me know if the fix does not help with your code. I will add a test later to make sure all similar scenarios are covered. Also, will revisit the checks to make them more consistent.

hasinitg commented 5 years ago

Hi @akosba

Thank you very much for the quick reply and also for the quick fix. I appreciate a lot.

My issue get resolved by using your fix as well as by calling 'makeOutputArray' method on the output wires of SHA 256 gadget, before enforcing assertions. Basically, as your fix did, packing the output wires was the key for the solution.

Could you please provide your insights on the following?

As mentioned before, I wrote the following verification circuit (code below) using SHA 256 gadget, to be used by a prover to prove that the prover knows the correct pre-image of a given SHA256-digest. Pre-image is secret input, hence prover witness wires are used for the input.

This circuit runs fine with libsnark. However, since I am planning to write more complex verification circuits using jsnark in the future, I would appreciate a lot if you could please confirm if I have followed the correct approach for writing a verification circuit for the above scenario.

If this is the correct approach and if you think this is a useful example circuit to be added to jsnark, I would be happy to send a pull request, to be reviewed and added to jsnark source code.

`package examples.generators.hash;

import circuit.eval.CircuitEvaluator; import circuit.structure.CircuitGenerator; import circuit.structure.Wire; import examples.gadgets.hash.SHA256Gadget;

import java.math.BigInteger;

public class SHA256VerificationCircuitGenerator extends CircuitGenerator { private Wire[] privateInput; private String inputStr = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl"; private String expectedDigest = "aeacdd7013805404b62e0701cd09aeab2a4994c519d7f1d7cf7a295a5d8201ad";

public SHA256VerificationCircuitGenerator(String circuitName){
    super(circuitName);
}

@Override
protected void buildCircuit() {
    privateInput = createProverWitnessWireArray(64);
    Wire[] digest = new SHA256Gadget(privateInput, 8, 64, false,
            false).getOutputWires();
    makeOutputArray(digest);
    int beginIndex = 0;
    int endIndex = 8;
    for(int i =0; i<8; i++){
        String ss = expectedDigest.substring(beginIndex, endIndex);
        addEqualityAssertion(digest[i], new BigInteger(ss, 16));
        beginIndex +=8;
        endIndex +=8;
    }

}

@Override
public void generateSampleInput(CircuitEvaluator evaluator) {
    for(int i = 0; i < privateInput.length; i++){
        evaluator.setWireValue(privateInput[i], inputStr.charAt(i));
    }
}

public static void main(String[] args) {

    SHA256VerificationCircuitGenerator circuitGenerator = new SHA256VerificationCircuitGenerator("SHA256-V");
    circuitGenerator.generateCircuit();
    circuitGenerator.evalCircuit();
    circuitGenerator.prepFiles();
    circuitGenerator.runLibsnark();
}

} `