Skip to content

Commit

Permalink
Merge pull request #466 from chaosma/revert-the-revert
Browse files Browse the repository at this point in the history
Revert the "topup revert"
  • Loading branch information
chaosma committed Jun 23, 2022
2 parents 04f3597 + 8ef7893 commit 14ee548
Show file tree
Hide file tree
Showing 38 changed files with 1,189 additions and 465 deletions.
32 changes: 17 additions & 15 deletions circuits/circom/hasherPoseidon.circom
Original file line number Diff line number Diff line change
Expand Up @@ -46,31 +46,33 @@ template Hasher5() {
hash <== hasher.out;
}

template Hasher12() {
// Hasher4(
// Hasher5_1(in[0], in[1], in[2], in[3], in[4]),
// Hasher5_2(in[5], in[6], in[7], in[8], in[9])
// in[10],
// in[11]
template Hasher13() {
// Hasher5(
// in[0]
// Hasher5_1(in[1], in[2], in[3], in[4], in[5]),
// Hasher5_2(in[6], in[7], in[8], in[9], in[10])
// in[11],
// in[12]
// )

signal input in[12];
signal input in[13];
signal output hash;

component hasher4 = PoseidonHashT5();
component hasher5 = PoseidonHashT6();
component hasher5_1 = PoseidonHashT6();
component hasher5_2 = PoseidonHashT6();

for (var i = 0; i < 5; i++) {
hasher5_1.inputs[i] <== in[i];
hasher5_2.inputs[i] <== in[i+5];
hasher5_1.inputs[i] <== in[i+1];
hasher5_2.inputs[i] <== in[i+6];
}
hasher4.inputs[0] <== hasher5_1.out;
hasher4.inputs[1] <== hasher5_2.out;
hasher4.inputs[2] <== in[10];
hasher4.inputs[3] <== in[11];
hasher5.inputs[0] <== in[0];
hasher5.inputs[1] <== hasher5_1.out;
hasher5.inputs[2] <== hasher5_2.out;
hasher5.inputs[3] <== in[11];
hasher5.inputs[4] <== in[12];

hash <== hasher4.out;
hash <== hasher5.out;
}

template HashLeftRight() {
Expand Down
10 changes: 5 additions & 5 deletions circuits/circom/messageHasher.circom
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@ pragma circom 2.0.0;
include "./hasherPoseidon.circom";

template MessageHasher() {
signal input in[10];
signal input in[11];
signal input encPubKey[2];
signal output hash;

component hasher = Hasher12();
component hasher = Hasher13();

for (var i = 0; i < 10; i ++) {
for (var i = 0; i < 11; i ++) {
hasher.in[i] <== in[i];
}
hasher.in[10] <== encPubKey[0];
hasher.in[11] <== encPubKey[1];
hasher.in[11] <== encPubKey[0];
hasher.in[12] <== encPubKey[1];

hash <== hasher.hash;
}
6 changes: 3 additions & 3 deletions circuits/circom/messageToCommand.circom
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ template MessageToCommand() {
var PACKED_CMD_LENGTH = 4;
var UNPACKED_CMD_LENGTH = 8;

signal input message[10];
signal input message[11];
signal input encPrivKey;
signal input encPubKey[2];

Expand All @@ -33,8 +33,8 @@ template MessageToCommand() {
decryptor.key[0] <== ecdh.sharedKey[0];
decryptor.key[1] <== ecdh.sharedKey[1];
decryptor.nonce <== 0;
for (var i = 0; i < 10; i++) {
decryptor.ciphertext[i] <== message[i];
for (var i = 1; i < 11; i++) { // the first one is msg type, skip
decryptor.ciphertext[i-1] <== message[i];
}

signal packedCommand[PACKED_CMD_LENGTH];
Expand Down
114 changes: 109 additions & 5 deletions circuits/circom/processMessages.circom
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ include "./privToPubKey.circom";
include "./stateLeafAndBallotTransformer.circom";
include "./trees/incrementalQuinTree.circom";
include "../node_modules/circomlib/circuits/mux1.circom";
include "../node_modules/circomlib/circuits/comparators.circom";

/*
* Proves the correctness of processing a batch of messages.
Expand All @@ -30,7 +31,7 @@ template ProcessMessages(
var TREE_ARITY = 5;
var batchSize = TREE_ARITY ** msgBatchDepth;

var MSG_LENGTH = 10;
var MSG_LENGTH = 11;
var PACKED_CMD_LENGTH = 4;

var STATE_LEAF_LENGTH = 4;
Expand Down Expand Up @@ -90,6 +91,12 @@ template ProcessMessages(
// The state root before it is processed
signal input currentStateRoot;

// topup signals
signal input topupAmounts[batchSize];
signal input topupStateIndexes[batchSize];
signal input topupStateLeaves[batchSize][STATE_LEAF_LENGTH];
signal input topupStateLeavesPathElements[batchSize][stateTreeDepth][TREE_ARITY - 1];

// The state leaves upon which messages are applied.
// transform(currentStateLeaf[4], message5) => newStateLeaf4
// transform(currentStateLeaf[3], message4) => newStateLeaf3
Expand Down Expand Up @@ -258,8 +265,14 @@ template ProcessMessages(

// -----------------------------------------------------------------------
// Process messages in reverse order
component processors[batchSize];
signal tmpStateRoot1[batchSize];
signal tmpStateRoot2[batchSize];
signal tmpBallotRoot1[batchSize];
signal tmpBallotRoot2[batchSize];
component processors[batchSize]; // vote type processor
component processors2[batchSize]; // topup type processor
for (var i = batchSize - 1; i >= 0; i --) {
// process it as vote type message
processors[i] = ProcessOne(stateTreeDepth, voteOptionTreeDepth);

processors[i].numSignUps <== numSignUps;
Expand Down Expand Up @@ -312,8 +325,29 @@ template ProcessMessages(
processors[i].packedCmd[j] <== commands[i].packedCommandOut[j];
}

stateRoots[i] <== processors[i].newStateRoot;
ballotRoots[i] <== processors[i].newBallotRoot;
// --------------------------------------------
// process it as topup type message,
processors2[i] = ProcessTopup(stateTreeDepth);
processors2[i].msgType <== msgs[i][0];
processors2[i].stateTreeIndex <== topupStateIndexes[i];
processors2[i].amount <== topupAmounts[i];
processors2[i].numSignUps <== numSignUps;
for (var j = 0; j < STATE_LEAF_LENGTH; j ++) {
processors2[i].stateLeaf[j] <== topupStateLeaves[i][j];
}
for (var j = 0; j < stateTreeDepth; j ++) {
for (var k = 0; k < TREE_ARITY - 1; k ++) {
processors2[i].stateLeafPathElements[j][k]
<== topupStateLeavesPathElements[i][j][k];
}
}
// pick the correct result by msg type
tmpStateRoot1[i] <== processors[i].newStateRoot * (2-msgs[i][0]);
tmpStateRoot2[i] <== processors2[i].newStateRoot * (msgs[i][0]-1);
tmpBallotRoot1[i] <== processors[i].newBallotRoot * (2-msgs[i][0]);
tmpBallotRoot2[i] <== ballotRoots[i+1] * (msgs[i][0]-1);
stateRoots[i] <== tmpStateRoot1[i] + tmpStateRoot2[i];
ballotRoots[i] <== tmpBallotRoot1[i] + tmpBallotRoot2[i];
}

component sbCommitmentHasher = Hasher3();
Expand All @@ -324,6 +358,76 @@ template ProcessMessages(
sbCommitmentHasher.hash === newSbCommitment;
}

template ProcessTopup(stateTreeDepth) {
var STATE_LEAF_LENGTH = 4;
var MSG_LENGTH = 11;
var TREE_ARITY = 5;

var STATE_LEAF_PUB_X_IDX = 0;
var STATE_LEAF_PUB_Y_IDX = 1;
var STATE_LEAF_VOICE_CREDIT_BALANCE_IDX = 2;
var STATE_LEAF_TIMESTAMP_IDX = 3;

signal input msgType;
signal input stateTreeIndex;
signal input amount;
signal input numSignUps;

signal input stateLeaf[STATE_LEAF_LENGTH];
signal input stateLeafPathElements[stateTreeDepth][TREE_ARITY - 1];

signal output newStateRoot;

// skip several checkings here, because ProcessOne already checks

// check stateIndex, if invalid index, set index and amount to zero
component validStateLeafIndex = LessEqThan(252);
validStateLeafIndex.in[0] <== stateTreeIndex;
validStateLeafIndex.in[1] <== numSignUps;

component indexMux = Mux1();
indexMux.s <== validStateLeafIndex.out;
indexMux.c[0] <== 0;
indexMux.c[1] <== stateTreeIndex;

component amtMux = Mux1();
amtMux.s <== validStateLeafIndex.out;
amtMux.c[0] <== 0;
amtMux.c[1] <== amount;


// check less than field size
// amt = 0 for vote type msg (msgType=1); amt not changed for topup msg (msgType=2)
// this is to avoid possible overflow failure for vote type message here
signal newCreditBalance;
signal amt;
amt <== amtMux.out * (msgType - 1);
component validCreditBalance = LessEqThan(252);
newCreditBalance <== stateLeaf[STATE_LEAF_VOICE_CREDIT_BALANCE_IDX] + amt;
validCreditBalance.in[0] <== stateLeaf[STATE_LEAF_VOICE_CREDIT_BALANCE_IDX];
validCreditBalance.in[1] <== newCreditBalance;

// update credit voice balance
component newStateLeafHasher = Hasher4();
newStateLeafHasher.in[STATE_LEAF_PUB_X_IDX] <== stateLeaf[STATE_LEAF_PUB_X_IDX];
newStateLeafHasher.in[STATE_LEAF_PUB_Y_IDX] <== stateLeaf[STATE_LEAF_PUB_Y_IDX];
newStateLeafHasher.in[STATE_LEAF_VOICE_CREDIT_BALANCE_IDX] <== newCreditBalance;
newStateLeafHasher.in[STATE_LEAF_TIMESTAMP_IDX] <== stateLeaf[STATE_LEAF_TIMESTAMP_IDX];

component stateLeafPathIndices = QuinGeneratePathIndices(stateTreeDepth);
stateLeafPathIndices.in <== indexMux.out;

component newStateLeafQip = QuinTreeInclusionProof(stateTreeDepth);
newStateLeafQip.leaf <== newStateLeafHasher.hash;
for (var i = 0; i < stateTreeDepth; i ++) {
newStateLeafQip.path_index[i] <== stateLeafPathIndices.out[i];
for (var j = 0; j < TREE_ARITY - 1; j++) {
newStateLeafQip.path_elements[i][j] <== stateLeafPathElements[i][j];
}
}
newStateRoot <== newStateLeafQip.root;
}

template ProcessOne(stateTreeDepth, voteOptionTreeDepth) {
/*
transform(currentStateLeaves0, cmd0) -> newStateLeaves0, isValid0
Expand All @@ -333,7 +437,7 @@ template ProcessOne(stateTreeDepth, voteOptionTreeDepth) {
*/
var STATE_LEAF_LENGTH = 4;
var BALLOT_LENGTH = 2;
var MSG_LENGTH = 10;
var MSG_LENGTH = 11;
var PACKED_CMD_LENGTH = 4;
var TREE_ARITY = 5;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pragma circom 2.0.0;
include "../hasherPoseidon.circom";

component main = Hasher12();
component main = Hasher13();
2 changes: 1 addition & 1 deletion circuits/circom/verifySignature.circom
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ template EdDSAPoseidonVerifier_patched() {
var i;

// Ensure S<Subgroup Order
component snum2bits = Num2Bits(253);
component snum2bits = Num2Bits(254);
snum2bits.in <== S;

component compConstant = CompConstant(2736030358979909402780800718157159386076813972158567259200215660948447373040);
Expand Down
16 changes: 8 additions & 8 deletions circuits/ts/__tests__/Hasher.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
} from './utils'

import {
Command,
PCommand,
Keypair,
} from 'maci-domainobjs'

Expand All @@ -14,7 +14,7 @@ import {
genRandomSalt,
sha256Hash,
hashLeftRight,
hash12,
hash13,
hash5,
hash4,
hash3,
Expand Down Expand Up @@ -147,11 +147,11 @@ describe('Poseidon hash circuits', () => {
})
})

describe('Hasher12', () => {
it('correctly hashes 12 random values', async () => {
const circuit = 'hasher12_test'
describe('Hasher13', () => {
it('correctly hashes 13 random values', async () => {
const circuit = 'hasher13_test'
const preImages: any = []
for (let i = 0; i < 12; i++) {
for (let i = 0; i < 13; i++) {
preImages.push(genRandomSalt())
}
const circuitInputs = stringifyBigInts({
Expand All @@ -161,7 +161,7 @@ describe('Poseidon hash circuits', () => {
const witness = await genWitness(circuit, circuitInputs)
const output = await getSignalByName(circuit, witness, 'main.hash')

const outputJS = hash12(preImages)
const outputJS = hash13(preImages)

expect(output.toString()).toEqual(outputJS.toString())
})
Expand Down Expand Up @@ -197,7 +197,7 @@ describe('Poseidon hash circuits', () => {
) & BigInt(genRandomSalt())
}

const command: Command = new Command(
const command: PCommand = new PCommand(
random50bitBigInt(),
k.pubKey,
random50bitBigInt(),
Expand Down
4 changes: 2 additions & 2 deletions circuits/ts/__tests__/MessageToCommand.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {

import {
Keypair,
Command,
PCommand,
} from 'maci-domainobjs'

describe('MessageToCommand circuit', () => {
Expand All @@ -32,7 +32,7 @@ describe('MessageToCommand circuit', () => {
) & BigInt(genRandomSalt())
}

const command: Command = new Command(
const command: PCommand = new PCommand(
random50bitBigInt(),
newPubKey,
random50bitBigInt(),
Expand Down
4 changes: 2 additions & 2 deletions circuits/ts/__tests__/MessageValidator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
} from 'maci-crypto'

import {
Command,
PCommand,
Keypair,
} from 'maci-domainobjs'

Expand All @@ -23,7 +23,7 @@ describe('MessageValidator circuit', () => {
const { privKey, pubKey } = new Keypair()

// Note that the command fields don't matter in this test
const command: Command = new Command(
const command: PCommand = new PCommand(
BigInt(1),
pubKey,
BigInt(2),
Expand Down
Loading

0 comments on commit 14ee548

Please sign in to comment.