2020-11-05 20:55:25 +00:00
|
|
|
import {expect} from "chai";
|
2022-04-14 17:16:06 +00:00
|
|
|
import {Buffer} from "buffer";
|
|
|
|
import {IBls, PointFormat} from "../../src/types.js";
|
|
|
|
import {getN, randomMessage} from "../util.js";
|
2022-04-11 15:08:15 +00:00
|
|
|
import {hexToBytes} from "../../src/helpers/index.js";
|
|
|
|
import {maliciousVerifyMultipleSignaturesData} from "../data/malicious-signature-test-data.js";
|
2020-11-19 14:41:45 +00:00
|
|
|
|
2020-11-20 19:35:32 +00:00
|
|
|
export function runIndexTests(bls: IBls): void {
|
2020-11-20 12:27:30 +00:00
|
|
|
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
2020-11-19 14:41:45 +00:00
|
|
|
function getRandomData() {
|
2020-11-30 18:01:13 +00:00
|
|
|
const sk = bls.SecretKey.fromKeygen();
|
2020-11-19 14:41:45 +00:00
|
|
|
const pk = sk.toPublicKey();
|
|
|
|
const msg = randomMessage();
|
2020-11-25 16:09:44 +00:00
|
|
|
const sig = sk.sign(msg);
|
2020-11-19 14:41:45 +00:00
|
|
|
return {sk, pk, msg, sig};
|
|
|
|
}
|
|
|
|
|
2021-09-22 05:35:53 +00:00
|
|
|
describe("signature", () => {
|
|
|
|
it("should fail loading an invalid signature point (not in G2)", () => {
|
|
|
|
/* eslint-disable max-len */
|
|
|
|
const POINT_NOT_IN_G2 = Buffer.from(
|
|
|
|
"8123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
|
|
|
|
"hex"
|
|
|
|
);
|
|
|
|
let sig;
|
|
|
|
try {
|
|
|
|
sig = bls.Signature.fromBytes(POINT_NOT_IN_G2, undefined, true);
|
|
|
|
} catch {
|
|
|
|
/* eslint-disable no-empty */
|
|
|
|
}
|
|
|
|
expect(sig === undefined).to.be.true;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2020-11-19 14:41:45 +00:00
|
|
|
describe("verify", () => {
|
2019-09-17 20:03:24 +00:00
|
|
|
it("should verify signature", () => {
|
2020-11-19 14:41:45 +00:00
|
|
|
const {pk, msg, sig} = getRandomData();
|
|
|
|
const pkHex = pk.toHex();
|
|
|
|
const isValid = bls.verify(pk.toBytes(), msg, sig.toBytes());
|
|
|
|
expect(isValid, "fail verify").to.be.true;
|
2019-08-05 15:48:26 +00:00
|
|
|
|
2020-11-19 14:41:45 +00:00
|
|
|
// Make sure to not modify original pubkey when verifying
|
|
|
|
expect(pk.toHex()).to.be.equal(pkHex, "pubkey modified when verifying");
|
2019-08-05 15:48:26 +00:00
|
|
|
});
|
|
|
|
|
2019-09-17 20:03:24 +00:00
|
|
|
it("should fail verify empty signature", () => {
|
2020-11-19 14:41:45 +00:00
|
|
|
const {pk, msg} = getRandomData();
|
|
|
|
const emptySig = Buffer.alloc(96);
|
|
|
|
const isValid = bls.verify(pk.toBytes(), msg, emptySig);
|
|
|
|
expect(isValid).to.be.false;
|
2019-08-05 15:48:26 +00:00
|
|
|
});
|
|
|
|
|
2019-09-17 20:03:24 +00:00
|
|
|
it("should fail verify signature of different message", () => {
|
2020-11-19 14:41:45 +00:00
|
|
|
const {pk, sig} = getRandomData();
|
|
|
|
const msg2 = randomMessage();
|
|
|
|
const isValid = bls.verify(pk.toBytes(), msg2, sig.toBytes());
|
|
|
|
expect(isValid).to.be.false;
|
2019-08-05 15:48:26 +00:00
|
|
|
});
|
|
|
|
|
2019-09-17 20:03:24 +00:00
|
|
|
it("should fail verify signature signed by different key", () => {
|
2020-11-19 14:41:45 +00:00
|
|
|
const {msg, sig} = getRandomData();
|
|
|
|
const {pk: pk2} = getRandomData();
|
|
|
|
const isValid = bls.verify(pk2.toBytes(), msg, sig.toBytes());
|
|
|
|
expect(isValid).to.be.false;
|
2019-08-05 15:48:26 +00:00
|
|
|
});
|
2022-10-07 16:05:58 +00:00
|
|
|
|
|
|
|
it("should fail verify empty message", () => {
|
|
|
|
const emptyMsg = new Uint8Array(0);
|
|
|
|
const {pk, sig} = getRandomData();
|
|
|
|
const isValid = sig.verify(pk, emptyMsg);
|
|
|
|
expect(isValid).equals(false);
|
|
|
|
});
|
2019-08-05 15:48:26 +00:00
|
|
|
});
|
|
|
|
|
2020-11-19 14:41:45 +00:00
|
|
|
describe("verify multiple", () => {
|
2020-11-20 12:27:30 +00:00
|
|
|
it("should verify aggregated signatures", () => {
|
2020-11-30 18:01:13 +00:00
|
|
|
const sks = getN(4, () => bls.SecretKey.fromKeygen());
|
2020-11-19 14:41:45 +00:00
|
|
|
const msgs = getN(2, () => randomMessage());
|
|
|
|
const pks = sks.map((sk) => sk.toPublicKey());
|
2019-08-05 15:48:26 +00:00
|
|
|
|
2020-11-25 16:09:44 +00:00
|
|
|
const sigs = [sks[0].sign(msgs[0]), sks[1].sign(msgs[0]), sks[2].sign(msgs[1]), sks[3].sign(msgs[1])];
|
2019-08-05 15:48:26 +00:00
|
|
|
|
2020-11-19 14:41:45 +00:00
|
|
|
const aggPubkeys = [
|
2020-11-30 18:01:13 +00:00
|
|
|
bls.aggregatePublicKeys([pks[0], pks[1]].map((pk) => pk.toBytes())),
|
|
|
|
bls.aggregatePublicKeys([pks[2], pks[3]].map((pk) => pk.toBytes())),
|
2020-11-19 14:41:45 +00:00
|
|
|
];
|
2019-08-05 15:48:26 +00:00
|
|
|
|
2020-11-19 14:41:45 +00:00
|
|
|
const aggSig = bls.aggregateSignatures(sigs.map((sig) => sig.toBytes()));
|
2019-08-05 15:48:26 +00:00
|
|
|
|
2020-11-19 14:41:45 +00:00
|
|
|
expect(bls.verifyMultiple(aggPubkeys, msgs, aggSig), "should be valid").to.be.true;
|
|
|
|
expect(bls.verifyMultiple(aggPubkeys.reverse(), msgs, aggSig), "should fail - swaped pubkeys").to.be.false;
|
|
|
|
});
|
2019-08-05 15:48:26 +00:00
|
|
|
|
2020-11-19 14:41:45 +00:00
|
|
|
it("should verify aggregated signatures - same message", () => {
|
|
|
|
const n = 4;
|
|
|
|
const msg = randomMessage();
|
2020-11-30 18:01:13 +00:00
|
|
|
const sks = getN(n, () => bls.SecretKey.fromKeygen());
|
2020-11-19 14:41:45 +00:00
|
|
|
const pks = sks.map((sk) => sk.toPublicKey());
|
2020-11-25 16:09:44 +00:00
|
|
|
const sigs = sks.map((sk) => sk.sign(msg));
|
2019-08-05 15:48:26 +00:00
|
|
|
|
2020-11-19 14:41:45 +00:00
|
|
|
const aggregateSignature = bls.aggregateSignatures(sigs.map((sig) => sig.toBytes()));
|
2019-08-05 15:48:26 +00:00
|
|
|
|
2020-11-19 14:41:45 +00:00
|
|
|
const isValid = bls.verifyMultiple(
|
|
|
|
pks.map((pk) => pk.toBytes()),
|
|
|
|
getN(4, () => msg), // Same message n times
|
2020-11-19 00:23:34 +00:00
|
|
|
aggregateSignature
|
2019-08-28 13:57:26 +00:00
|
|
|
);
|
2020-11-19 14:41:45 +00:00
|
|
|
expect(isValid).to.be.true;
|
2019-08-05 15:48:26 +00:00
|
|
|
});
|
|
|
|
|
2019-09-17 20:03:24 +00:00
|
|
|
it("should fail to verify aggregated signatures - no public keys", () => {
|
2020-11-19 14:41:45 +00:00
|
|
|
const sig = Buffer.alloc(96);
|
|
|
|
const msg1 = randomMessage();
|
|
|
|
const msg2 = randomMessage();
|
2019-08-05 15:48:26 +00:00
|
|
|
|
2020-11-19 14:41:45 +00:00
|
|
|
const isValid = bls.verifyMultiple([], [msg2, msg1], sig);
|
|
|
|
expect(isValid).to.be.false;
|
2019-08-05 15:48:26 +00:00
|
|
|
});
|
2022-10-07 16:05:58 +00:00
|
|
|
|
|
|
|
it("should fail verify empty message", () => {
|
|
|
|
const sks = getN(2, () => bls.SecretKey.fromKeygen());
|
|
|
|
const msgs = getN(2, () => randomMessage());
|
|
|
|
const pks = sks.map((sk) => sk.toPublicKey());
|
|
|
|
const sigs = [sks[0].sign(msgs[0]), sks[1].sign(msgs[1])];
|
|
|
|
const aggSig = bls.Signature.aggregate(sigs);
|
|
|
|
|
|
|
|
const emptyMsgs = msgs.map(() => new Uint8Array(0));
|
|
|
|
const isValid = aggSig.verifyMultiple(pks, emptyMsgs);
|
|
|
|
expect(isValid).equals(false);
|
|
|
|
});
|
2019-08-05 15:48:26 +00:00
|
|
|
});
|
2020-12-02 23:12:40 +00:00
|
|
|
|
|
|
|
describe("verifyMultipleSignatures", () => {
|
|
|
|
it("Should verify multiple signatures", () => {
|
|
|
|
const n = 4;
|
2021-04-04 23:44:55 +00:00
|
|
|
const sets = getN(n, () => {
|
2020-12-02 23:12:40 +00:00
|
|
|
const sk = bls.SecretKey.fromKeygen();
|
2021-04-04 23:44:55 +00:00
|
|
|
const publicKey = sk.toPublicKey();
|
|
|
|
const message = randomMessage();
|
|
|
|
const signature = sk.sign(message);
|
|
|
|
return {publicKey, message, signature};
|
2020-12-02 23:12:40 +00:00
|
|
|
});
|
|
|
|
|
2021-04-04 23:44:55 +00:00
|
|
|
expect(bls.Signature.verifyMultipleSignatures(sets)).to.equal(true, "class interface failed");
|
2020-12-02 23:32:42 +00:00
|
|
|
|
2020-12-02 23:12:40 +00:00
|
|
|
expect(
|
|
|
|
bls.verifyMultipleSignatures(
|
2021-04-04 23:44:55 +00:00
|
|
|
sets.map((s) => ({
|
|
|
|
publicKey: s.publicKey.toBytes(),
|
|
|
|
message: s.message,
|
|
|
|
signature: s.signature.toBytes(),
|
|
|
|
}))
|
2020-12-02 23:12:40 +00:00
|
|
|
)
|
|
|
|
).to.equal(true, "functional (bytes serialized) interface failed");
|
|
|
|
});
|
|
|
|
|
|
|
|
it("Test fails correctly against a malicous signature", async () => {
|
2020-12-02 23:33:44 +00:00
|
|
|
const pks = maliciousVerifyMultipleSignaturesData.pks.map((pk) => bls.PublicKey.fromHex(pk));
|
2020-12-02 23:15:39 +00:00
|
|
|
const msgs = maliciousVerifyMultipleSignaturesData.msgs.map(hexToBytes);
|
2020-12-02 23:33:44 +00:00
|
|
|
const sigs = maliciousVerifyMultipleSignaturesData.sigs.map((sig) => bls.Signature.fromHex(sig));
|
2020-12-02 23:15:39 +00:00
|
|
|
|
|
|
|
maliciousVerifyMultipleSignaturesData.manipulated.forEach((isManipulated, i) => {
|
2020-12-02 23:32:42 +00:00
|
|
|
expect(sigs[i].verify(pks[i], msgs[i])).to.equal(
|
2020-12-02 23:12:40 +00:00
|
|
|
!isManipulated,
|
|
|
|
isManipulated ? "Manipulated signature should not verify" : "Ok signature should verify"
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
// This method (AggregateVerify in BLS spec lingo) should verify
|
2020-12-02 23:32:42 +00:00
|
|
|
|
|
|
|
const dangerousAggSig = bls.Signature.aggregate(sigs);
|
|
|
|
expect(dangerousAggSig.verifyMultiple(pks, msgs)).to.equal(
|
2020-12-02 23:12:40 +00:00
|
|
|
true,
|
|
|
|
"Malicious signature should be validated with bls.verifyMultiple"
|
|
|
|
);
|
|
|
|
|
2021-04-04 23:44:55 +00:00
|
|
|
const maliciousSets = pks.map((_, i) => ({
|
|
|
|
publicKey: pks[i],
|
|
|
|
message: msgs[i],
|
|
|
|
signature: sigs[i],
|
|
|
|
}));
|
|
|
|
|
2020-12-02 23:12:40 +00:00
|
|
|
// This method is expected to catch the malicious signature and not verify
|
2021-04-04 23:44:55 +00:00
|
|
|
expect(bls.Signature.verifyMultipleSignatures(maliciousSets)).to.equal(
|
2020-12-02 23:12:40 +00:00
|
|
|
false,
|
|
|
|
"Malicous signature should not validate with bls.verifyMultipleSignatures"
|
|
|
|
);
|
|
|
|
});
|
2022-10-07 16:05:58 +00:00
|
|
|
|
|
|
|
it("should fail verify empty message", () => {
|
|
|
|
const n = 4;
|
|
|
|
const sets = getN(n, () => {
|
|
|
|
const sk = bls.SecretKey.fromKeygen();
|
|
|
|
const publicKey = sk.toPublicKey();
|
|
|
|
const message = randomMessage();
|
|
|
|
const signature = sk.sign(message);
|
|
|
|
return {publicKey, message, signature};
|
|
|
|
});
|
|
|
|
|
|
|
|
const setsWithEmptyMsgs = sets.map((set) => ({...set, message: new Uint8Array(0)}));
|
|
|
|
|
|
|
|
const isValid = bls.Signature.verifyMultipleSignatures(setsWithEmptyMsgs);
|
|
|
|
expect(isValid).equals(false);
|
|
|
|
});
|
2020-12-02 23:12:40 +00:00
|
|
|
});
|
2021-04-04 23:44:55 +00:00
|
|
|
|
|
|
|
describe("serialize deserialize", () => {
|
|
|
|
/* eslint-disable max-len */
|
|
|
|
|
|
|
|
const skHex = "0x0101010101010101010101010101010101010101010101010101010101010101";
|
|
|
|
const pkHexCompExpected =
|
|
|
|
"0xaa1a1c26055a329817a5759d877a2795f9499b97d6056edde0eea39512f24e8bc874b4471f0501127abb1ea0d9f68ac1";
|
|
|
|
const pkHexUncompExpected =
|
|
|
|
"0x0a1a1c26055a329817a5759d877a2795f9499b97d6056edde0eea39512f24e8bc874b4471f0501127abb1ea0d9f68ac111392125a1c3750363c2c97d9650fb78696e6428db8ff9efaf0471cbfd20324916ab545746db83756d335e92f9e8c8b8";
|
|
|
|
|
|
|
|
it("Should serialize comp pubkey", () => {
|
2022-04-14 17:16:06 +00:00
|
|
|
const sk = bls.SecretKey.fromBytes(hexToBytes(skHex));
|
2021-04-04 23:44:55 +00:00
|
|
|
const pkHexComp = sk.toPublicKey().toHex(PointFormat.compressed);
|
|
|
|
expect(pkHexComp).to.equal(pkHexCompExpected, "Wrong pkHexComp");
|
|
|
|
});
|
|
|
|
|
|
|
|
it("Should serialize uncomp pubkey", () => {
|
2022-04-14 17:16:06 +00:00
|
|
|
const sk = bls.SecretKey.fromBytes(hexToBytes(skHex));
|
2021-04-04 23:44:55 +00:00
|
|
|
const pkHexUncomp = sk.toPublicKey().toHex(PointFormat.uncompressed);
|
|
|
|
expect(pkHexUncomp).to.equal(pkHexUncompExpected, "Wrong pkHexUncomp");
|
|
|
|
});
|
|
|
|
|
|
|
|
it("Should deserialize comp pubkey", () => {
|
|
|
|
bls.PublicKey.fromHex(pkHexCompExpected);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("Should deserialize uncomp pubkey", () => {
|
|
|
|
bls.PublicKey.fromHex(pkHexUncompExpected);
|
|
|
|
});
|
|
|
|
});
|
2020-11-20 19:03:17 +00:00
|
|
|
}
|