Compare commits

..

10 Commits

Author SHA1 Message Date
Kobi Gurkan
3478226049 Merge remote-tracking branch 'iden3/master' into feat/audit_fixes 2019-12-11 18:33:31 +02:00
Kobi Gurkan
eeecd07cae Merge remote-tracking branch 'iden3/master' into feat/audit_fixes 2019-12-03 20:26:43 +02:00
Kobi Gurkan
b928421c58 adds comment about baby pbk public key extraction 2019-12-01 15:38:38 +02:00
Kobi Gurkan
8445381431 escalarmulfix uses segments of 246 and adds comments on limits 2019-11-23 22:00:11 +02:00
Kobi Gurkan
42e96c2e1f makes S value in eddsa signatures be 251 bit, uses alias checks with enabled flag and adds eddsamimcsponge test 2019-11-23 21:36:06 +02:00
Kobi Gurkan
5ec0744303 adds alias check for babyjubjub 2019-11-23 21:19:47 +02:00
Kobi Gurkan
451fb51a0d adds comments to binsum 2019-11-23 19:24:02 +02:00
Kobi Gurkan
ba656fefbe mimcsponge: makes the contract hash-only 2019-11-14 17:31:00 +02:00
Kobi Gurkan
5d626852ae Merge remote-tracking branch 'iden3/master' into feat/mimc_constant 2019-11-14 16:25:12 +02:00
Kobi Gurkan
de9c7dda46 mimcsponge: makes rounds constant 2019-11-14 16:24:29 +02:00
31 changed files with 327 additions and 186 deletions

View File

@@ -512,7 +512,7 @@ Implementation of MiMC-7 hash in Fp being... (link to description of the hash)
### mimcsponge ### mimcsponge
- `MiMCSponge(nInputs, nRounds, nOutputs)` - `MiMCSponge(nInputs, nOutputs)`
- DESCRIPTION - DESCRIPTION
- SCHEMA - SCHEMA

View File

@@ -21,7 +21,6 @@ include "compconstant.circom";
template AliasCheck() { template AliasCheck() {
signal input in[254]; signal input in[254];
component compConstant = CompConstant(-1); component compConstant = CompConstant(-1);
@@ -30,3 +29,15 @@ template AliasCheck() {
compConstant.out === 0; compConstant.out === 0;
} }
template AliasCheckBabyJub() {
signal input in[251];
signal input enabled;
component compConstant = CompConstant(2736030358979909402780800718157159386076813972158567259200215660948447373040);
for (var i=0; i<251; i++) in[i] ==> compConstant.in[i];
for (var i=0; i<3; i++) 0 ==> compConstant.in[251+i];
compConstant.out*enabled === 0;
}

View File

@@ -81,7 +81,7 @@ template BabyCheck() {
a*x2 + y2 === 1 + d*x2*y2; a*x2 + y2 === 1 + d*x2*y2;
} }
// Extracts the public key from private key // Extracts the public key from private key, as mentioned in https://tools.ietf.org/html/rfc8032
template BabyPbk() { template BabyPbk() {
signal private input in; signal private input in;
signal output Ax; signal output Ax;

View File

@@ -50,6 +50,7 @@ To waranty binary outputs:
This function calculates the number of extra bits in the output to do the full sum. This function calculates the number of extra bits in the output to do the full sum.
*/ */
/* a must be < Nq/2, where Nq is the number of elements in the scalar field */
function nbits(a) { function nbits(a) {
var n = 1; var n = 1;
var r = 0; var r = 0;
@@ -61,6 +62,7 @@ function nbits(a) {
} }
/* n must be such that (2**(n+1) -2) < Nq/ops, where Nq is the number of bits in the scalar field */
template BinSum(n, ops) { template BinSum(n, ops) {
var nout = nbits((2**n -1)*ops); var nout = nbits((2**n -1)*ops);
signal input in[ops][n]; signal input in[ops][n];

View File

@@ -21,6 +21,7 @@ include "comparators.circom";
include "aliascheck.circom"; include "aliascheck.circom";
/* This doesn't check aliasing, so for n > 253 there are multiple bit strings for each number */
template Num2Bits(n) { template Num2Bits(n) {
signal input in; signal input in;
signal output out[n]; signal output out[n];
@@ -76,6 +77,7 @@ template Bits2Num_strict() {
b2n.out ==> out; b2n.out ==> out;
} }
/* n must not exceed 253 */
template Num2BitsNeg(n) { template Num2BitsNeg(n) {
signal input in; signal input in;
signal output out[n]; signal output out[n];

View File

@@ -17,7 +17,7 @@
along with circom. If not, see <https://www.gnu.org/licenses/>. along with circom. If not, see <https://www.gnu.org/licenses/>.
*/ */
include "compconstant.circom"; include "aliascheck.circom";
include "pointbits.circom"; include "pointbits.circom";
include "pedersen.circom"; include "pedersen.circom";
include "escalarmulany.circom"; include "escalarmulany.circom";
@@ -40,12 +40,15 @@ template EdDSAVerifier(n) {
// Ensure S<Subgroup Order // Ensure S<Subgroup Order
component compConstant = CompConstant(2736030358979909402780800718157159386076813972158567259200215660948447373040); component aliasCheck = AliasCheckBabyJub();
aliasCheck.enabled <== 1;
for (i=0; i<254; i++) { for (i=0; i<251; i++) {
S[i] ==> compConstant.in[i]; S[i] ==> aliasCheck.in[i];
} }
compConstant.out === 0; S[251] === 0;
S[252] === 0;
S[253] === 0;
S[254] === 0; S[254] === 0;
S[255] === 0; S[255] === 0;

View File

@@ -17,7 +17,7 @@
along with circom. If not, see <https://www.gnu.org/licenses/>. along with circom. If not, see <https://www.gnu.org/licenses/>.
*/ */
include "compconstant.circom"; include "aliascheck.circom";
include "pointbits.circom"; include "pointbits.circom";
include "mimc.circom"; include "mimc.circom";
include "bitify.circom"; include "bitify.circom";
@@ -39,16 +39,15 @@ template EdDSAMiMCVerifier() {
// Ensure S<Subgroup Order // Ensure S<Subgroup Order
component snum2bits = Num2Bits(253); component snum2bits = Num2Bits(251);
snum2bits.in <== S; snum2bits.in <== S;
component compConstant = CompConstant(2736030358979909402780800718157159386076813972158567259200215660948447373040); component aliasCheck = AliasCheckBabyJub();
aliasCheck.enabled <== 1;
for (i=0; i<253; i++) { for (i=0; i<251; i++) {
snum2bits.out[i] ==> compConstant.in[i]; snum2bits.out[i] ==> aliasCheck.in[i];
} }
compConstant.in[253] <== 0;
compConstant.out === 0;
// Calculate the h = H(R,A, msg) // Calculate the h = H(R,A, msg)
@@ -104,8 +103,8 @@ template EdDSAMiMCVerifier() {
5299619240641551281634865583518297030282874472190772894086521144482721001553, 5299619240641551281634865583518297030282874472190772894086521144482721001553,
16950150798460657717958625567821834550301663161624707787222815936182638968203 16950150798460657717958625567821834550301663161624707787222815936182638968203
]; ];
component mulFix = EscalarMulFix(253, BASE8); component mulFix = EscalarMulFix(251, BASE8);
for (i=0; i<253; i++) { for (i=0; i<251; i++) {
mulFix.e[i] <== snum2bits.out[i]; mulFix.e[i] <== snum2bits.out[i];
} }

View File

@@ -17,7 +17,7 @@
along with circom. If not, see <https://www.gnu.org/licenses/>. along with circom. If not, see <https://www.gnu.org/licenses/>.
*/ */
include "compconstant.circom"; include "aliascheck.circom";
include "pointbits.circom"; include "pointbits.circom";
include "mimcsponge.circom"; include "mimcsponge.circom";
include "bitify.circom"; include "bitify.circom";
@@ -39,20 +39,19 @@ template EdDSAMiMCSpongeVerifier() {
// Ensure S<Subgroup Order // Ensure S<Subgroup Order
component snum2bits = Num2Bits(253); component snum2bits = Num2Bits(251);
snum2bits.in <== S; snum2bits.in <== S;
component compConstant = CompConstant(2736030358979909402780800718157159386076813972158567259200215660948447373040); component aliasCheck = AliasCheckBabyJub();
aliasCheck.enabled <== 1;
for (i=0; i<253; i++) { for (i=0; i<251; i++) {
snum2bits.out[i] ==> compConstant.in[i]; snum2bits.out[i] ==> aliasCheck.in[i];
} }
compConstant.in[253] <== 0;
compConstant.out === 0;
// Calculate the h = H(R,A, msg) // Calculate the h = H(R,A, msg)
component hash = MiMCSponge(5, 220, 1); component hash = MiMCSponge(5, 1);
hash.ins[0] <== R8x; hash.ins[0] <== R8x;
hash.ins[1] <== R8y; hash.ins[1] <== R8y;
hash.ins[2] <== Ax; hash.ins[2] <== Ax;
@@ -104,8 +103,8 @@ template EdDSAMiMCSpongeVerifier() {
5299619240641551281634865583518297030282874472190772894086521144482721001553, 5299619240641551281634865583518297030282874472190772894086521144482721001553,
16950150798460657717958625567821834550301663161624707787222815936182638968203 16950150798460657717958625567821834550301663161624707787222815936182638968203
]; ];
component mulFix = EscalarMulFix(253, BASE8); component mulFix = EscalarMulFix(251, BASE8);
for (i=0; i<253; i++) { for (i=0; i<251; i++) {
mulFix.e[i] <== snum2bits.out[i]; mulFix.e[i] <== snum2bits.out[i];
} }

View File

@@ -38,16 +38,15 @@ template EdDSAPoseidonVerifier() {
// Ensure S<Subgroup Order // Ensure S<Subgroup Order
component snum2bits = Num2Bits(253); component snum2bits = Num2Bits(251);
snum2bits.in <== S; snum2bits.in <== S;
component compConstant = CompConstant(2736030358979909402780800718157159386076813972158567259200215660948447373040); component aliasCheck = AliasCheckBabyJub();
aliasCheck.enabled <== enabled;
for (i=0; i<253; i++) { for (i=0; i<251; i++) {
snum2bits.out[i] ==> compConstant.in[i]; snum2bits.out[i] ==> aliasCheck.in[i];
} }
compConstant.in[253] <== 0;
compConstant.out*enabled === 0;
// Calculate the h = H(R,A, msg) // Calculate the h = H(R,A, msg)
@@ -103,8 +102,8 @@ template EdDSAPoseidonVerifier() {
5299619240641551281634865583518297030282874472190772894086521144482721001553, 5299619240641551281634865583518297030282874472190772894086521144482721001553,
16950150798460657717958625567821834550301663161624707787222815936182638968203 16950150798460657717958625567821834550301663161624707787222815936182638968203
]; ];
component mulFix = EscalarMulFix(253, BASE8); component mulFix = EscalarMulFix(251, BASE8);
for (i=0; i<253; i++) { for (i=0; i<251; i++) {
mulFix.e[i] <== snum2bits.out[i]; mulFix.e[i] <== snum2bits.out[i];
} }

View File

@@ -44,6 +44,7 @@ include "babyjub.circom";
A good way to see it is that the accumulator input of the adder >= 2^247*B and the other input A good way to see it is that the accumulator input of the adder >= 2^247*B and the other input
is the output of the windows that it's going to be <= 2^246*B is the output of the windows that it's going to be <= 2^246*B
*/ */
/* base must not be the neutral element nor points of small order */
template WindowMulFix() { template WindowMulFix() {
signal input in[3]; signal input in[3];
signal input base[2]; signal input base[2];
@@ -133,11 +134,12 @@ template WindowMulFix() {
/* /*
This component does a multiplication of a escalar times a fix base This component does a multiplication of a escalar times a fix base
nWindows must not exceed 82
Signals: Signals:
e: The scalar in bits e: The scalar in bits
base: the base point in edwards format base: the base point in edwards format
out: The result out: The result
dbl: Point in Edwards to be linked to the next segment. dbl: Point in Montgomery to be linked to the next segment.
*/ */
template SegmentMulFix(nWindows) { template SegmentMulFix(nWindows) {
@@ -236,7 +238,7 @@ template EscalarMulFix(n, BASE) {
signal output out[2]; // Point (Twisted format) signal output out[2]; // Point (Twisted format)
var nsegments = (n-1)\246 +1; // 249 probably would work. But I'm not sure and for security I keep 246 var nsegments = (n-1)\246 +1; // 249 probably would work. But I'm not sure and for security I keep 246
var nlastsegment = n - (nsegments-1)*249; var nlastsegment = n - (nsegments-1)*246;
component segments[nsegments]; component segments[nsegments];
@@ -250,13 +252,13 @@ template EscalarMulFix(n, BASE) {
for (s=0; s<nsegments; s++) { for (s=0; s<nsegments; s++) {
nseg = (s < nsegments-1) ? 249 : nlastsegment; nseg = (s < nsegments-1) ? 246 : nlastsegment;
nWindows = ((nseg - 1)\3)+1; nWindows = ((nseg - 1)\3)+1;
segments[s] = SegmentMulFix(nWindows); segments[s] = SegmentMulFix(nWindows);
for (i=0; i<nseg; i++) { for (i=0; i<nseg; i++) {
segments[s].e[i] <== e[s*249+i]; segments[s].e[i] <== e[s*246+i];
} }
for (i = nseg; i<nWindows*3; i++) { for (i = nseg; i<nWindows*3; i++) {

View File

@@ -1,11 +1,13 @@
// implements MiMC-2n/n as hash using a sponge construction. // implements MiMC-2n/n as hash using a sponge construction.
// log_5(21888242871839275222246405745257275088548364400416034343698204186575808495617) ~= 110 // log_5(21888242871839275222246405745257275088548364400416034343698204186575808495617) ~= 110
// => nRounds should be 220 // => nRounds should be 220
template MiMCSponge(nInputs, nRounds, nOutputs) { template MiMCSponge(nInputs, nOutputs) {
signal input ins[nInputs]; signal input ins[nInputs];
signal input k; signal input k;
signal output outs[nOutputs]; signal output outs[nOutputs];
var nRounds = 220;
// S = R||C // S = R||C
component S[nInputs + nOutputs - 1]; component S[nInputs + nOutputs - 1];

View File

@@ -85,6 +85,7 @@ template Montgomery2Edwards() {
*/ */
/* in1 must be != in2 */
template MontgomeryAdd() { template MontgomeryAdd() {
signal input in1[2]; signal input in1[2];
signal input in2[2]; signal input in2[2];

View File

@@ -108,6 +108,7 @@ template Window4() {
} }
/* nWindows must not exceed 50 */
template Segment(nWindows) { template Segment(nWindows) {
signal input in[nWindows*4]; signal input in[nWindows*4];
signal input base[2]; signal input base[2];

13
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{ {
"name": "circomlib", "name": "circomlib",
"version": "0.0.21", "version": "0.0.20",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@@ -601,9 +601,10 @@
} }
}, },
"circom": { "circom": {
"version": "0.0.35", "version": "0.0.34",
"resolved": "https://registry.npmjs.org/circom/-/circom-0.0.35.tgz", "resolved": "https://registry.npmjs.org/circom/-/circom-0.0.34.tgz",
"integrity": "sha512-MWsJPYPH+s9wN2I5abEHUIAyFVsgTCy+UzJh///WnflXfh3c1tlbv8zt1VV+YHHREpyS+WF5ZBr7TujpaVFu5g==", "integrity": "sha512-R7yNW8PtX2xREtLYWZ/o5cfKHT/qa+CveXsGVAX1ej7mPrTat9mlEMXEy2vX//IuP9/cnYTY/KxJ2SN05PUeGA==",
"dev": true,
"requires": { "requires": {
"big-integer": "^1.6.32", "big-integer": "^1.6.32",
"optimist": "^0.6.1", "optimist": "^0.6.1",
@@ -3862,6 +3863,7 @@
"version": "0.6.1", "version": "0.6.1",
"resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
"integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
"dev": true,
"requires": { "requires": {
"minimist": "~0.0.1", "minimist": "~0.0.1",
"wordwrap": "~0.0.2" "wordwrap": "~0.0.2"
@@ -3870,7 +3872,8 @@
"wordwrap": { "wordwrap": {
"version": "0.0.3", "version": "0.0.3",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
"integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=",
"dev": true
} }
} }
}, },

View File

@@ -1,6 +1,6 @@
{ {
"name": "circomlib", "name": "circomlib",
"version": "0.0.21", "version": "0.0.20",
"description": "Basic circuits library for Circom", "description": "Basic circuits library for Circom",
"main": "index.js", "main": "index.js",
"directories": { "directories": {
@@ -26,12 +26,12 @@
"dependencies": { "dependencies": {
"blake-hash": "^1.1.0", "blake-hash": "^1.1.0",
"blake2b": "^2.1.3", "blake2b": "^2.1.3",
"circom": "0.0.35",
"snarkjs": "^0.1.20", "snarkjs": "^0.1.20",
"typedarray-to-buffer": "^3.1.5", "typedarray-to-buffer": "^3.1.5",
"web3": "^1.0.0-beta.55" "web3": "^1.0.0-beta.55"
}, },
"devDependencies": { "devDependencies": {
"circom": "0.0.35",
"eslint-plugin-mocha": "^5.2.0", "eslint-plugin-mocha": "^5.2.0",
"ganache-cli": "^6.4.4", "ganache-cli": "^6.4.4",
"mocha": "^5.2.0" "mocha": "^5.2.0"

View File

@@ -20,34 +20,29 @@ function createCode(seed, n) {
C.push("0x00"); C.push("0x00");
C.mload(); C.mload();
C.div(); C.div();
C.push("0x3f1a1187"); // MiMCSponge(uint256,uint256,uint256) C.push("0xf47d33b5"); // MiMCSponge(uint256,uint256)
C.eq(); C.eq();
C.jmpi("start"); C.jmpi("start");
C.invalid(); C.invalid();
C.label("start"); C.label("start");
C.push("0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001"); // q C.push("0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001"); // q
C.push("0x44");
C.mload(); // k q
C.push("0x04"); C.push("0x04");
C.mload(); // xL k q C.mload(); // xL q
C.dup(2); // q xL k q C.dup(1); // q xL q
C.push("0x24"); C.push("0x24");
C.mload(); // xR q xL k q C.mload(); // xR q xL q
C.dup(1); // q xR q xL k q C.dup(1); // q xR q xL q
C.dup(0); // q q xR q xL k q C.dup(3); // xL q xR q xL q
C.dup(4); // xL q q xR q xL k q C.dup(1); // q xL q xR q xL q
C.dup(6); // k xL q q xR q xL k q C.dup(0); // q q xL q xR q xL q
C.addmod(); // t=k+xL q xR q xL k q C.dup(2); // xL q q xL q xR q xL q
C.dup(1); // q t q xR q xL k q C.dup(0); // xL xL q q xL q xR q xL q
C.dup(0); // q q t q xR q xL k q C.mulmod(); // b=xL^2 q xL q xR q xL q
C.dup(2); // t q q t q xR q xL k q C.dup(0); // b b q xL q xR q xL q
C.dup(0); // t t q q t q xR q xL k q C.mulmod(); // c=xL^4 xL q xR q xL q
C.mulmod(); // b=t^2 q t q xR q xL k q C.mulmod(); // d=xL^5 xR q xL q
C.dup(0); // b b q t q xR q xL k q C.addmod(); // e=xL^5+xR xL q (for next round: xL xR q)
C.mulmod(); // c=t^4 t q xR q xL k q
C.mulmod(); // d=t^5 xR q xL k q
C.addmod(); // e=t^5+xR xL k q (for next round: xL xR k q)
for (let i=0; i<n-1; i++) { for (let i=0; i<n-1; i++) {
if (i < n-2) { if (i < n-2) {
@@ -55,27 +50,24 @@ function createCode(seed, n) {
} else { } else {
ci = "0x00"; ci = "0x00";
} }
C.swap(1); // xR xL k q C.swap(1); // xR xL q
C.dup(3); // q xR xL k q C.dup(2); // q xR xL q
C.dup(3); // k q xR xL k q C.dup(2); // xL q xR xL q
C.dup(1); // q k q xR xL k q C.push(ci); // ci xL q xR xL q
C.dup(4); // xL q k q xR xL k q C.addmod(); // a=ci+xL xR xL q
C.push(ci); // ci xL q k q xR xL k q C.dup(3); // q a xR xL q
C.addmod(); // a=ci+xL k q xR xL k q C.swap(1); // a q xR xL q
C.addmod(); // t=a+k xR xL k q C.dup(1); // q a q xR xL q
C.dup(4); // q t xR xL k q C.dup(0); // q q a q xR xL q
C.swap(1); // t q xR xL k q C.dup(2); // a q q a q xR xL q
C.dup(1); // q t q xR xL k q C.dup(0); // a a q q a q xR xL q
C.dup(0); // q q t q xR xL k q C.mulmod(); // b=a^2 q a q xR xL q
C.dup(2); // t q q t q xR xL k q C.dup(0); // b b q a q xR xL q
C.dup(0); // t t q q t q xR xL k q C.mulmod(); // c=a^4 a q xR xL q
C.mulmod(); // b=t^2 q t q xR xL k q C.mulmod(); // d=a^5 xR xL q
C.dup(0); // b b q t q xR xL k q C.dup(3); // q d xR xL q
C.mulmod(); // c=t^4 t q xR xL k q C.swap(2); // xR d q xL q
C.mulmod(); // d=t^5 xR xL k q C.addmod(); // e=a^5+xR xL q (for next round: xL xR q)
C.dup(4); // q d xR xL k q
C.swap(2); // xR d q xL k q
C.addmod(); // e=t^5+xR xL k q (for next round: xL xR k q)
} }
C.push("0x20"); C.push("0x20");
@@ -100,10 +92,6 @@ module.exports.abi = [
{ {
"name": "xR_in", "name": "xR_in",
"type": "uint256" "type": "uint256"
},
{
"name": "k",
"type": "uint256"
} }
], ],
"name": "MiMCSponge", "name": "MiMCSponge",

View File

@@ -36,8 +36,6 @@ exports.getMatrix = (t, seed, nRounds) => {
if (typeof seed === "undefined") seed = SEED; if (typeof seed === "undefined") seed = SEED;
if (typeof nRounds === "undefined") nRounds = NROUNDSF + NROUNDSP; if (typeof nRounds === "undefined") nRounds = NROUNDSF + NROUNDSP;
if (typeof t === "undefined") t = T; if (typeof t === "undefined") t = T;
assert(t<=6); // Force the same matrix for all.
t=6;
let nonce = "0000"; let nonce = "0000";
let cmatrix = getPseudoRandom(seed+"_matrix_"+nonce, t*2); let cmatrix = getPseudoRandom(seed+"_matrix_"+nonce, t*2);
while (!allDifferent(cmatrix)) { while (!allDifferent(cmatrix)) {

View File

@@ -121,7 +121,7 @@ function createCode(t, nRoundsF, nRoundsP, seed) {
// We ignore the pointer and the length and just load 6 values to the state // We ignore the pointer and the length and just load 6 values to the state
// (Stack positions 0-5) If the array is shorter, we just set zeros. // (Stack positions 0-5) If the array is shorter, we just set zeros.
for (let i=0; i<t; i++) { for (let i=0; i<t; i++) {
C.push(0x44+(0x20*(t-1-i))); C.push(0x44+(0x20*(5-i)));
C.calldataload(); C.calldataload();
} }

View File

@@ -57,6 +57,7 @@ describe("Aliascheck test", () => {
assert(false); assert(false);
} catch(err) { } catch(err) {
assert(/Constraint\sdoesn't\smatch(.*)1\s!=\s0/.test(err.message) ); assert(/Constraint\sdoesn't\smatch(.*)1\s!=\s0/.test(err.message) );
assert(err.message.indexOf("1 != 0") >= 0);
} }
}); });
@@ -68,6 +69,7 @@ describe("Aliascheck test", () => {
assert(false); assert(false);
} catch(err) { } catch(err) {
assert(/Constraint\sdoesn't\smatch(.*)1\s!=\s0/.test(err.message) ); assert(/Constraint\sdoesn't\smatch(.*)1\s!=\s0/.test(err.message) );
assert(err.message.indexOf("1 != 0") >= 0);
} }
}); });

75
test/aliascheckbabyjub.js Normal file
View File

@@ -0,0 +1,75 @@
const chai = require("chai");
const path = require("path");
const snarkjs = require("snarkjs");
const compiler = require("circom");
const assert = chai.assert;
const bigInt = snarkjs.bigInt;
function print(circuit, w, s) {
console.log(s + ": " + w[circuit.getSignalIdx(s)]);
}
function getBits(v, n) {
const res = [];
for (let i=0; i<n; i++) {
if (v.shr(i).isOdd()) {
res.push(bigInt.one);
} else {
res.push(bigInt.zero);
}
}
return res;
}
const r = bigInt("2736030358979909402780800718157159386076813972158567259200215660948447373041");
describe("Aliascheck test", () => {
let circuit;
before( async() => {
const cirDef = await compiler(path.join(__dirname, "circuits", "aliascheckbabyjub_test.circom"));
circuit = new snarkjs.Circuit(cirDef);
console.log("NConstrains: " + circuit.nConstraints);
});
it("Satisfy the aliastest 0", async () => {
const inp = getBits(bigInt.zero, 251);
circuit.calculateWitness({in: inp});
});
it("Satisfy the aliastest 3", async () => {
const inp = getBits(bigInt(3), 251);
circuit.calculateWitness({in: inp});
});
it("Satisfy the aliastest r-1", async () => {
const inp = getBits(r.sub(bigInt.one), 251);
circuit.calculateWitness({in: inp});
});
it("Nhot not satisfy an input of r", async () => {
const inp = getBits(r, 251);
try {
circuit.calculateWitness({in: inp});
assert(false);
} catch(err) {
assert(err.message.indexOf("Constraint doesn't match") >= 0);
assert(err.message.indexOf("1 != 0") >= 0);
}
});
it("Nhot not satisfy all ones", async () => {
const inp = getBits(bigInt(1).shl(251).sub(bigInt(1)), 251);
try {
circuit.calculateWitness({in: inp});
assert(false);
} catch(err) {
assert(err.message.indexOf("Constraint doesn't match") >= 0);
assert(err.message.indexOf("1 != 0") >= 0);
}
});
});

View File

@@ -101,6 +101,7 @@ describe("Baby Jub test", function () {
assert(false, "Should be a valid point"); assert(false, "Should be a valid point");
} catch(err) { } catch(err) {
assert(/Constraint\sdoesn't\smatch(.*)168700\s!=\s1/.test(err.message) ); assert(/Constraint\sdoesn't\smatch(.*)168700\s!=\s1/.test(err.message) );
assert(err.message.indexOf("168700 != 1") >= 0);
} }
}); });

View File

@@ -0,0 +1,3 @@
include "../../circuits/aliascheck.circom";
component main = AliasCheckBabyJub()

View File

@@ -0,0 +1,3 @@
include "../../circuits/eddsamimcsponge.circom";
component main = EdDSAMiMCSpongeVerifier();

View File

@@ -1,3 +1,3 @@
include "../../circuits/mimcsponge.circom" include "../../circuits/mimcsponge.circom"
component main = MiMCSponge(2, 220, 3); component main = MiMCSponge(2, 3);

View File

@@ -1,3 +0,0 @@
include "../../circuits/poseidon.circom"
component main = Poseidon(2, 3, 8, 57);

99
test/eddsamimcsponge.js Normal file
View File

@@ -0,0 +1,99 @@
const chai = require("chai");
const path = require("path");
const snarkjs = require("snarkjs");
const compiler = require("circom");
const eddsa = require("../src/eddsa.js");
const assert = chai.assert;
const bigInt = snarkjs.bigInt;
describe("EdDSA MiMCSponge test", function () {
let circuit;
this.timeout(100000);
before( async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "eddsamimcsponge_test.circom"));
circuit = new snarkjs.Circuit(cirDef);
console.log("NConstrains EdDSA MiMCSponge: " + circuit.nConstraints);
});
it("Sign a single number", async () => {
const msg = bigInt(1234);
const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex");
const pubKey = eddsa.prv2pub(prvKey);
const signature = eddsa.signMiMCSponge(prvKey, msg);
assert(eddsa.verifyMiMCSponge(msg, signature, pubKey));
const w = circuit.calculateWitness({
enabled: 1,
Ax: pubKey[0],
Ay: pubKey[1],
R8x: signature.R8[0],
R8y: signature.R8[1],
S: signature.S,
M: msg});
assert(circuit.checkWitness(w));
});
it("Detect Invalid signature", async () => {
const msg = bigInt(1234);
const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex");
const pubKey = eddsa.prv2pub(prvKey);
const signature = eddsa.signMiMCSponge(prvKey, msg);
assert(eddsa.verifyMiMCSponge(msg, signature, pubKey));
try {
const w = circuit.calculateWitness({
enabled: 1,
Ax: pubKey[0],
Ay: pubKey[1],
R8x: signature.R8[0].add(bigInt(1)),
R8y: signature.R8[1],
S: signature.S,
M: msg});
assert(false);
} catch(err) {
assert(err.message.indexOf("Constraint doesn't match") >= 0);
assert(err.message.indexOf("1 != 0") >= 0);
}
});
it("Test a dissabled circuit with a bad signature", async () => {
const msg = bigInt(1234);
const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex");
const pubKey = eddsa.prv2pub(prvKey);
const signature = eddsa.signMiMCSponge(prvKey, msg);
assert(eddsa.verifyMiMCSponge(msg, signature, pubKey));
const w = circuit.calculateWitness({
enabled: 0,
Ax: pubKey[0],
Ay: pubKey[1],
R8x: signature.R8[0].add(bigInt(1)),
R8y: signature.R8[1],
S: signature.S,
M: msg});
assert(circuit.checkWitness(w));
});
});

View File

@@ -33,8 +33,8 @@ describe("MiMC Sponge Smart contract test", () => {
}); });
it("Shold calculate the mimc correctly", async () => { it("Shold calculate the mimc correctly", async () => {
const res = await mimc.methods.MiMCSponge(1,2,3).call(); const res = await mimc.methods.MiMCSponge(1,2).call();
const res2 = await mimcjs.hash(1,2,3); const res2 = await mimcjs.hash(1,2, 0);
assert.equal(res.xL.toString(), res2.xL.toString()); assert.equal(res.xL.toString(), res2.xL.toString());
assert.equal(res.xR.toString(), res2.xR.toString()); assert.equal(res.xR.toString(), res2.xR.toString());

View File

@@ -18,74 +18,43 @@ describe("Blake2b version test", function() {
}); });
describe("Poseidon Circuit test", function () { describe("Poseidon Circuit test", function () {
let circuit6; let circuit;
let circuit3;
this.timeout(100000); this.timeout(100000);
before( async () => { before( async () => {
const cirDef6 = await compiler(path.join(__dirname, "circuits", "poseidon6_test.circom")); const cirDef = await compiler(path.join(__dirname, "circuits", "poseidon_test.circom"));
circuit6 = new snarkjs.Circuit(cirDef6);
console.log("Poseidon6 constraints: " + circuit6.nConstraints); circuit = new snarkjs.Circuit(cirDef);
const cirDef3 = await compiler(path.join(__dirname, "circuits", "poseidon3_test.circom"));
circuit3 = new snarkjs.Circuit(cirDef3); console.log("Poseidon constraints: " + circuit.nConstraints);
console.log("Poseidon3 constraints: " + circuit3.nConstraints);
}); });
it("Should check constrain of hash([1, 2]) t=6", async () => { it("Should check constrain of hash([1, 2])", async () => {
const w = circuit6.calculateWitness({inputs: [1, 2]}); const w = circuit.calculateWitness({inputs: [1, 2]});
const res = w[circuit6.getSignalIdx("main.out")]; const res = w[circuit.getSignalIdx("main.out")];
const hash = poseidon.createHash(6, 8, 57); const hash = poseidon.createHash(6, 8, 57);
const res2 = hash([1,2]); const res2 = hash([1,2]);
assert.equal("12242166908188651009877250812424843524687801523336557272219921456462821518061", res2.toString()); assert.equal('12242166908188651009877250812424843524687801523336557272219921456462821518061', res2.toString());
assert.equal(res.toString(), res2.toString()); assert.equal(res.toString(), res2.toString());
assert(circuit6.checkWitness(w)); assert(circuit.checkWitness(w));
}); });
it("Should check constrain of hash([3, 4]) t=6", async () => { it("Should check constrain of hash([3, 4])", async () => {
const w = circuit6.calculateWitness({inputs: [3, 4]}); const w = circuit.calculateWitness({inputs: [3, 4]});
const res = w[circuit6.getSignalIdx("main.out")]; const res = w[circuit.getSignalIdx("main.out")];
const hash = poseidon.createHash(6, 8, 57); const hash = poseidon.createHash(6, 8, 57);
const res2 = hash([3, 4]); const res2 = hash([3, 4]);
assert.equal("17185195740979599334254027721507328033796809509313949281114643312710535000993", res2.toString()); assert.equal('17185195740979599334254027721507328033796809509313949281114643312710535000993', res2.toString());
assert.equal(res.toString(), res2.toString()); assert.equal(res.toString(), res2.toString());
assert(circuit6.checkWitness(w)); assert(circuit.checkWitness(w));
});
it("Should check constrain of hash([1, 2]) t=3", async () => {
const w = circuit3.calculateWitness({inputs: [1, 2]});
const res = w[circuit3.getSignalIdx("main.out")];
const hash = poseidon.createHash(3, 8, 57);
const res2 = hash([1,2]);
assert.equal("2104035019328376391822106787753454168168617545136592089411833517434990977743", res2.toString());
assert.equal(res.toString(), res2.toString());
assert(circuit3.checkWitness(w));
});
it("Should check constrain of hash([3, 4]) t=3", async () => {
const w = circuit3.calculateWitness({inputs: [3, 4]});
const res = w[circuit3.getSignalIdx("main.out")];
const hash = poseidon.createHash(3, 8, 57);
const res2 = hash([3, 4]);
assert.equal("12456141564250880945411182508630957604732712316993112736876413121277158512223", res2.toString());
assert.equal(res.toString(), res2.toString());
assert(circuit3.checkWitness(w));
}); });
}); });

View File

@@ -8,13 +8,13 @@ const bigInt = require("snarkjs").bigInt;
const assert = chai.assert; const assert = chai.assert;
const log = (msg) => { if (process.env.MOCHA_VERBOSE) console.log(msg); }; const log = (msg) => { if (process.env.MOCHA_VERBOSE) console.log(msg); };
describe("Poseidon Smart contract test", function () { const SEED = "mimc";
describe("Poseidon Smart contract test", () => {
let testrpc; let testrpc;
let web3; let web3;
let poseidon6; let mimc;
let poseidon3;
let accounts; let accounts;
this.timeout(100000);
before(async () => { before(async () => {
web3 = new Web3(ganache.provider(), null, { transactionConfirmationBlocks: 1 }); web3 = new Web3(ganache.provider(), null, { transactionConfirmationBlocks: 1 });
@@ -24,23 +24,17 @@ describe("Poseidon Smart contract test", function () {
it("Should deploy the contract", async () => { it("Should deploy the contract", async () => {
const C = new web3.eth.Contract(poseidonGenContract.abi); const C = new web3.eth.Contract(poseidonGenContract.abi);
poseidon6 = await C.deploy({ mimc = await C.deploy({
data: poseidonGenContract.createCode(6) data: poseidonGenContract.createCode()
}).send({
gas: 2500000,
from: accounts[0]
});
poseidon3 = await C.deploy({
data: poseidonGenContract.createCode(3)
}).send({ }).send({
gas: 2500000, gas: 2500000,
from: accounts[0] from: accounts[0]
}); });
}); });
it("Shold calculate the poseidon correctly t=6", async () => { it("Shold calculate the mimic correctly", async () => {
const res = await poseidon6.methods.poseidon([1,2]).call(); const res = await mimc.methods.poseidon([1,2]).call();
// console.log("Cir: " + bigInt(res.toString(16)).toString(16)); // console.log("Cir: " + bigInt(res.toString(16)).toString(16));
@@ -51,19 +45,5 @@ describe("Poseidon Smart contract test", function () {
assert.equal(res.toString(), res2.toString()); assert.equal(res.toString(), res2.toString());
}); });
it("Shold calculate the poseidon correctly t=3", async () => {
const res = await poseidon3.methods.poseidon([1,2]).call();
// console.log("Cir: " + bigInt(res.toString(16)).toString(16));
const hash = Poseidon.createHash(3, 8, 57);
const res2 = hash([1,2]);
// console.log("Ref: " + bigInt(res2).toString(16));
assert.equal(res.toString(), res2.toString());
});
}); });

View File

@@ -80,11 +80,11 @@ describe("SHA256 test", () => {
console.log("Vars: "+circuit.nVars); console.log("Vars: "+circuit.nVars);
console.log("Constraints: "+circuit.nConstraints); console.log("Constraints: "+circuit.nConstraints);
/*
const testStr = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
// const testStr = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; const b = Buffer.from(testStr, 'utf8');
*/
// const b = Buffer.from(testStr, 'utf8');
const b = new Buffer.alloc(64); const b = new Buffer.alloc(64);
for (let i=0; i<64; i++) { for (let i=0; i<64; i++) {
b[i] = i+1; b[i] = i+1;
@@ -95,7 +95,7 @@ describe("SHA256 test", () => {
.digest("hex"); .digest("hex");
const arrIn = buffer2bitArray(b); const arrIn = buffer2bitArray(b);
const witness = circuit.calculateWitness({ "in": arrIn }, {logOutput: false}); const witness = circuit.calculateWitness({ "in": arrIn } /*, {logOutput: true} */);
const arrOut = witness.slice(1, 257); const arrOut = witness.slice(1, 257);
const hash2 = bitArray2buffer(arrOut).toString("hex"); const hash2 = bitArray2buffer(arrOut).toString("hex");
@@ -104,6 +104,7 @@ describe("SHA256 test", () => {
}).timeout(1000000); }).timeout(1000000);
it("Should calculate a hash of 2 compressor", async () => { it("Should calculate a hash of 2 compressor", async () => {
const cirDef = await compiler(path.join(__dirname, "circuits", "sha256_test448.circom"), {reduceConstraints:false} ); const cirDef = await compiler(path.join(__dirname, "circuits", "sha256_test448.circom"), {reduceConstraints:false} );
const circuit = new snarkjs.Circuit(cirDef); const circuit = new snarkjs.Circuit(cirDef);
@@ -111,19 +112,20 @@ describe("SHA256 test", () => {
console.log("Vars: "+circuit.nVars); console.log("Vars: "+circuit.nVars);
console.log("Constraints: "+circuit.nConstraints); console.log("Constraints: "+circuit.nConstraints);
const testStr = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; const testStr = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
const b = Buffer.from(testStr, "utf8"); const b = Buffer.from(testStr, 'utf8');
// for (let i=0; i<64; i++) { for (let i=0; i<64; i++) {
// b[i] = i+1; b[i] = i+1;
// } }
const hash = crypto.createHash("sha256") const hash = crypto.createHash("sha256")
.update(b) .update(b)
.digest("hex"); .digest("hex");
const arrIn = buffer2bitArray(b); const arrIn = buffer2bitArray(b);
const witness = circuit.calculateWitness({ "in": arrIn } , {logOutput: false}); const witness = circuit.calculateWitness({ "in": arrIn } /*, {logOutput: true} */);
const arrOut = witness.slice(1, 257); const arrOut = witness.slice(1, 257);
const hash2 = bitArray2buffer(arrOut).toString("hex"); const hash2 = bitArray2buffer(arrOut).toString("hex");