ZKP Implementation details
The Circom Circuit powering the application
pragma circom 2.0.0;
include "../../node_modules/circomlib/circuits/poseidon.circom";
template CommitmentHasher(){
signal input nullifier;
signal input secret;
signal input nonce;
signal output commitment;
signal output paymentIntent;
component commitmentHasher = Poseidon(2);
component nullifierHasher = Poseidon(2);
commitmentHasher.inputs[0] <== nullifier;
commitmentHasher.inputs[1] <== secret;
commitment <==commitmentHasher.out;
nullifierHasher.inputs[0] <== nullifier;
nullifierHasher.inputs[1] <== nonce;
paymentIntent <== nullifierHasher.out;
}
template DirectDebit(){
signal input paymentIntent;
signal input commitmentHash;
signal input payee;
// The max amount that can be debited with the proof
signal input maxDebitAmount;
// The amount of times this proof can be used ti withdraw max amount
signal input debitTimes;
// The time that needs to pass before the proof can be used to debit an account again
signal input debitInterval;
// Private inputs!
signal input secret;
// A nonce for the nullifier so the note is reusable!
signal input nonce;
// The nullifier is used to calculate the secret with the commitment
// And also the payment intent with the nonce!
signal input nullifier;
//Hidden signals to verify inputs
signal payeeSquare;
signal maxDebitAmountSquare;
signal debitTimesSquare;
signal debitIntervalSquare;
// Hashing the commitment and the nullifier
component commitmentHasher = CommitmentHasher();
commitmentHasher.nullifier <== nullifier;
commitmentHasher.secret <== secret;
commitmentHasher.nonce <== nonce;
commitmentHasher.paymentIntent === paymentIntent;
commitmentHasher.commitment === commitmentHash;
payeeSquare <== payee * payee;
maxDebitAmountSquare <== maxDebitAmount * maxDebitAmount;
debitTimesSquare <== debitTimes * debitTimes;
debitIntervalSquare <==debitInterval * debitInterval;
}
component main {public [paymentIntent,commitmentHash, payee, maxDebitAmount, debitTimes,debitInterval]} = DirectDebit();
The direct debit implementation is powered by this zkp circuit.
Let me explain what is going on, 🤔
Commitment Hasher
The hasher takes a nullifier, a secret and a nonce which are BigIntegers and outputs Poseidon Hashes Commitment and PaymentIntent
Nullifier is a random generated number created when the Debit Account is created
Secret is a random generated number created when the Debit Account is created
Nonce is a random generated number created when a payment intent is created to allow reusing the Nullifier!
The Commitment hash is the identifier of the Account. It is the poseidon hash of the nullifier and the secret
The PaymentIntent hash is the identifier of the PaymentIntent that is used to nullify it and it's created by hashing the nullifier with the nonce!
Direct Debit Template
The template contains public, private and hidden signals. The public signals need to be available when the proof is verified in the smart contract, the private signals are kept secret and the hidden signals are used to verify parameters of the subscription so they can't be altered! Private Inputs, These are provided only when the ZKP is created
Secret, nonce, nullifier
Public Inputs:
paymentIntent - Used to verify the creator knows the nullifier and the nonce without revealing it
commitment - Used to verify the creator knows the secret and the nullifier that created the commitment hash
payee, maxDebitAmount,debitTimes, debitInterval - These are arguments to the smart contract function and they are used to verify they were not tampared with, this is done using hidden signals!
Last updated