Skip to content

Commit

Permalink
test(domainobjs): implement unit tests for the domainobjs package
Browse files Browse the repository at this point in the history
  • Loading branch information
ctrlc03 committed Jan 2, 2024
1 parent ded1724 commit f71a56a
Show file tree
Hide file tree
Showing 8 changed files with 895 additions and 276 deletions.
106 changes: 93 additions & 13 deletions domainobjs/ts/__tests__/ballot.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,102 @@ import { expect } from "chai";
import { Ballot } from "..";

describe("Ballot", () => {
it("should create a new ballot and hash it", () => {
const b = new Ballot(0, 2);
const h = b.hash();
expect(h).to.not.eq(null);
describe("constructor", () => {
it("should create an empty ballot", () => {
const b = new Ballot(0, 2);
expect(b.votes.length).to.eq(0);
});

it("should create a ballot with 1 vote", () => {
const b = new Ballot(1, 2);
expect(b.votes.length).to.eq(1);
expect(b.votes[0]).to.eq(BigInt(0));
});
});

describe("hash", () => {
it("should produce an hash of the ballot", () => {
const b = new Ballot(0, 2);
const h = b.hash();
expect(h).to.not.eq(null);
});
});

describe("copy", () => {
it("should produce a deep copy", () => {
const b1 = Ballot.genRandomBallot(2, 2);
const b2 = b1.copy();
expect(b1.equals(b2)).to.eq(true);
});
});

describe("asCircuitInputs", () => {
it("should produce an array", () => {
const len = 2;
const b1 = Ballot.genRandomBallot(len, 2);
const arr = b1.asCircuitInputs();
expect(arr).to.be.instanceOf(Array);
expect(arr.length).to.eq(len);
});
});

it("copy should produce a deep copy", () => {
const b1 = Ballot.genRandomBallot(2, 2);
const b2 = b1.copy();
expect(b1.equals(b2)).to.eq(true);
describe("isEqual", () => {
it("should return false for ballots that are not equal", () => {
const b1 = Ballot.genRandomBallot(2, 2);
const b2 = Ballot.genRandomBallot(2, 3);
expect(b1.equals(b2)).to.eq(false);
});
it("should return true for ballots that are equal", () => {
const b1 = new Ballot(0, 2);
const b2 = new Ballot(0, 2);
expect(b1.equals(b2)).to.eq(true);
});
});

it("asCircuitInputs should produce an array", () => {
const b1 = Ballot.genRandomBallot(2, 2);
const arr = b1.asCircuitInputs();
expect(arr).to.be.instanceOf(Array);
expect(arr.length).to.eq(2);
describe("asArray", () => {
it("should produce a valid result", () => {
const b1 = Ballot.genRandomBallot(2, 2);
const arr = b1.asArray();
expect(arr[0]).to.eq(b1.nonce);
});
});

describe("genRandomBallot", () => {
it("should generate a ballot with a random nonce", () => {
const b1 = Ballot.genRandomBallot(2, 2);
const b2 = Ballot.genRandomBallot(2, 2);
expect(b1.nonce).to.not.eq(b2.nonce);
});
});

describe("genBlankBallot", () => {
it("should generate a ballot with all votes set to 0", () => {
const b1 = Ballot.genBlankBallot(2, 2);
expect(b1.votes.every((v) => v === BigInt(0))).to.eq(true);
});
});

describe("serialization/deserialization", () => {
describe("toJSON", () => {
it("toJSON should produce a JSON object representing the ballot", () => {
const b1 = Ballot.genBlankBallot(2, 2);
const json = b1.toJSON();
expect(json).to.have.property("votes");
expect(json).to.have.property("nonce");
expect(json).to.have.property("voteOptionTreeDepth");
expect(json.votes.length).to.eq(b1.votes.length);
expect(json.nonce).to.eq(b1.nonce.toString());
expect(json.voteOptionTreeDepth).to.eq(b1.voteOptionTreeDepth.toString());
});
});

describe("fromJSON", () => {
it("should create a ballot from a JSON object", () => {
const b1 = Ballot.genBlankBallot(2, 2);
const json = b1.toJSON();
const b2 = Ballot.fromJSON(json);
expect(b1.equals(b2)).to.eq(true);
});
});
});
});
222 changes: 131 additions & 91 deletions domainobjs/ts/__tests__/commands.test.ts
Original file line number Diff line number Diff line change
@@ -1,120 +1,160 @@
import { expect } from "chai";
import { genRandomSalt } from "maci-crypto";

import { Keypair, Message, PCommand, TCommand } from "..";
import { PCommand, Keypair, TCommand } from "..";

describe("Commands & Messages", () => {
describe("Commands", () => {
const { privKey, pubKey } = new Keypair();
const k = new Keypair();

const pubKey1 = k.pubKey;

const newPubKey = k.pubKey;

const ecdhSharedKey = Keypair.genEcdhSharedKey(privKey, pubKey1);
// eslint-disable-next-line no-bitwise
const random50bitBigInt = (): bigint => ((BigInt(1) << BigInt(50)) - BigInt(1)) & BigInt(genRandomSalt().toString());
const command: PCommand = new PCommand(
random50bitBigInt(),
newPubKey,
random50bitBigInt(),
random50bitBigInt(),
random50bitBigInt(),
random50bitBigInt(),
genRandomSalt(),
);
const signature = command.sign(privKey);
const message = command.encrypt(signature, ecdhSharedKey);
const decrypted = PCommand.decrypt(message, ecdhSharedKey);

it("command.sign() should produce a valid signature", () => {
expect(command.verifySignature(signature, pubKey)).to.eq(true);

describe("constructor", () => {
it("should create a PCommand", () => {
const command: PCommand = new PCommand(
random50bitBigInt(),
newPubKey,
random50bitBigInt(),
random50bitBigInt(),
random50bitBigInt(),
random50bitBigInt(),
genRandomSalt(),
);
expect(command).to.not.eq(null);
});
it("should create a TCommand", () => {
const command: TCommand = new TCommand(random50bitBigInt(), random50bitBigInt(), random50bitBigInt());
expect(command).to.not.eq(null);
});
});

it("decrypted message should match the original command", () => {
expect(decrypted.command.equals(command)).to.eq(true);
expect(decrypted.signature.R8[0].toString()).to.eq(signature.R8[0].toString());
expect(decrypted.signature.R8[1].toString()).to.eq(signature.R8[1].toString());
expect(decrypted.signature.S.toString()).to.eq(signature.S.toString());
describe("signature", () => {
const command: PCommand = new PCommand(
random50bitBigInt(),
newPubKey,
random50bitBigInt(),
random50bitBigInt(),
random50bitBigInt(),
random50bitBigInt(),
genRandomSalt(),
);
it("should produce a valid signature", () => {
const signature = command.sign(privKey);
expect(command.verifySignature(signature, pubKey)).to.eq(true);
});
});

it("decrypted message should have a valid signature", () => {
const isValid = decrypted.command.verifySignature(decrypted.signature, pubKey);
expect(isValid).to.eq(true);
describe("encryption", () => {
const command: PCommand = new PCommand(
random50bitBigInt(),
newPubKey,
random50bitBigInt(),
random50bitBigInt(),
random50bitBigInt(),
random50bitBigInt(),
genRandomSalt(),
);

const signature = command.sign(privKey);

describe("encrypt", () => {
it("should encrypt a command", () => {
const message = command.encrypt(signature, ecdhSharedKey);
expect(message).to.not.eq(null);
});
});

describe("decrypt", () => {
const message = command.encrypt(signature, ecdhSharedKey);

const decrypted = PCommand.decrypt(message, ecdhSharedKey);

it("should decrypt a message and keep the correct values", () => {
expect(decrypted).to.not.eq(null);
expect(decrypted.command.equals(command)).to.eq(true);
expect(decrypted.signature.R8[0].toString()).to.eq(signature.R8[0].toString());
expect(decrypted.signature.R8[1].toString()).to.eq(signature.R8[1].toString());
expect(decrypted.signature.S.toString()).to.eq(signature.S.toString());
});
it("should have a valid signature after decryption", () => {
const isValid = decrypted.command.verifySignature(decrypted.signature, pubKey);
expect(isValid).to.eq(true);
});
});
});

it("Command.copy() should produce a deep copy", () => {
const c1: PCommand = new PCommand(BigInt(10), newPubKey, BigInt(0), BigInt(9), BigInt(1), BigInt(123));
describe("copy", () => {
it("should produce a deep copy for PCommand", () => {
const c1: PCommand = new PCommand(BigInt(10), newPubKey, BigInt(0), BigInt(9), BigInt(1), BigInt(123));

// shallow copy
const c2 = c1;
c1.nonce = BigInt(9999);
expect(c1.nonce.toString()).to.eq(c2.nonce.toString());
// shallow copy
const c2 = c1;
c1.nonce = BigInt(9999);
expect(c1.nonce.toString()).to.eq(c2.nonce.toString());

// deep copy
const c3 = c1.copy();
c1.nonce = BigInt(8888);
// deep copy
const c3 = c1.copy();
c1.nonce = BigInt(8888);

expect(c1.nonce.toString()).not.to.eq(c3.nonce.toString());
});
expect(c1.nonce.toString()).not.to.eq(c3.nonce.toString());
});

it("message.copy() should produce a deep copy", () => {
const m1 = new Message(BigInt(1), [
BigInt(2),
BigInt(3),
BigInt(4),
BigInt(5),
BigInt(6),
BigInt(7),
BigInt(8),
BigInt(9),
BigInt(10),
BigInt(11),
]);

const m2 = m1.copy();
expect(m2.equals(m1)).to.eq(true);
});
it("should produce a deep copy for TCommand", () => {
const c1: TCommand = new TCommand(BigInt(10), BigInt(0), BigInt(9));

it("message.asCircuitInputs() should return a array", () => {
const m1 = new Message(BigInt(1), [
BigInt(2),
BigInt(3),
BigInt(4),
BigInt(5),
BigInt(6),
BigInt(7),
BigInt(8),
BigInt(9),
BigInt(10),
BigInt(11),
]);

const arr = m1.asCircuitInputs();
expect(arr.length).to.eq(11);
expect(arr[0]).to.eq(BigInt(1));
expect(arr[1]).to.eq(BigInt(2));
expect(arr[2]).to.eq(BigInt(3));
expect(arr[3]).to.eq(BigInt(4));
expect(arr[4]).to.eq(BigInt(5));
expect(arr[5]).to.eq(BigInt(6));
expect(arr[6]).to.eq(BigInt(7));
expect(arr[7]).to.eq(BigInt(8));
expect(arr[8]).to.eq(BigInt(9));
expect(arr[9]).to.eq(BigInt(10));
expect(arr[10]).to.eq(BigInt(11));
expect(arr).to.be.instanceOf(Array);
// shallow copy
const c2 = c1;
c1.amount = BigInt(9999);
expect(c1.amount.toString()).to.eq(c2.amount.toString());

// deep copy
const c3 = c1.copy();
c1.amount = BigInt(8888);

expect(c1.amount.toString()).not.to.eq(c3.amount.toString());
});
});

describe("TCommand", () => {
const stateIndex = BigInt(0);
const amount = BigInt(100);
const pollId = BigInt(1);
const tCommand = new TCommand(stateIndex, amount, pollId);
describe("deserialization/serialization", () => {
describe("toJSON", () => {
it("should produce a JSON object with valid values", () => {
const c1: TCommand = new TCommand(BigInt(10), BigInt(0), BigInt(9));
const json = c1.toJSON();
expect(json).to.not.eq(null);
expect(json.stateIndex).to.eq("10");
expect(json.amount).to.eq("0");
expect(json.pollId).to.eq("9");
});
it("should produce a JSON object with valid values", () => {
const c1: PCommand = new PCommand(BigInt(10), newPubKey, BigInt(0), BigInt(9), BigInt(1), BigInt(123));
const json = c1.toJSON();
expect(json).to.not.eq(null);
expect(json.stateIndex).to.eq("10");
expect(json.voteOptionIndex).to.eq("0");
expect(json.newVoteWeight).to.eq("9");
expect(json.nonce).to.eq("1");
expect(json.pollId).to.eq("123");
expect(json.cmdType).to.eq("1");
});
});

it("copy should produce a deep copy", () => {
const c = tCommand.copy();
expect(c.equals(tCommand)).to.eq(true);
describe("fromJSON", () => {
it("should produce a TCommand from a JSON object", () => {
const c1: TCommand = new TCommand(BigInt(10), BigInt(0), BigInt(9));
const json = c1.toJSON();
const c2 = TCommand.fromJSON(json);
expect(c2.equals(c1)).to.eq(true);
});
it("should produce a PCommand from a JSON object", () => {
const c1: PCommand = new PCommand(BigInt(10), newPubKey, BigInt(0), BigInt(9), BigInt(1), BigInt(123));
const json = c1.toJSON();
const c2 = PCommand.fromJSON(json);
expect(c2.equals(c1)).to.eq(true);
});
});
});
});
Loading

0 comments on commit f71a56a

Please sign in to comment.