From 2319593641006dc7a5a5bfffff91672a28956486 Mon Sep 17 00:00:00 2001 From: Wekuz Date: Thu, 3 Apr 2025 22:50:38 +0300 Subject: [PATCH] Initial interactive proof implementation --- .gitignore | 1 + Cargo.lock | 213 ++++++++++++++++++++++ Cargo.toml | 10 + README.md | 4 + example-graphs/graph0.txt | 6 + example-graphs/graph1.txt | 11 ++ example-graphs/graph2.txt | 10 + example-graphs/graph3.txt | 5 + out.dot | 371 ++++++++++++++++++++++++++++++++++++++ src/main.rs | 301 +++++++++++++++++++++++++++++++ 10 files changed, 932 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 README.md create mode 100644 example-graphs/graph0.txt create mode 100644 example-graphs/graph1.txt create mode 100644 example-graphs/graph2.txt create mode 100644 example-graphs/graph3.txt create mode 100644 out.dot create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..b8d4cb7 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,213 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "bitflags" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" + +[[package]] +name = "blake3" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34a796731680be7931955498a16a10b2270c7762963d5d570fdbfe02dcbf314f" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", +] + +[[package]] +name = "cc" +version = "1.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "constant_time_eq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + +[[package]] +name = "dot2" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "855423f2158bcc73798b3b9a666ec4204597a72370dc91dbdb8e7f9519de8cc3" + +[[package]] +name = "getrandom" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.171" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + +[[package]] +name = "rand" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +dependencies = [ + "rand_chacha", + "rand_core", + "zerocopy", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "syn" +version = "2.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "three-coloring-zkp" +version = "0.1.0" +dependencies = [ + "blake3", + "dot2", + "rand", + "rand_chacha", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags", +] + +[[package]] +name = "zerocopy" +version = "0.8.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..d376b4e --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "three-coloring-zkp" +version = "0.1.0" +edition = "2021" + +[dependencies] +blake3 = "1.7.0" +dot2 = "1.0.0" +rand = "0.9.0" +rand_chacha = "0.9.0" diff --git a/README.md b/README.md new file mode 100644 index 0000000..1bae1ba --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +# Resources +- https://youtu.be/Otvcbw6k4eo +- https://blog.cryptographyengineering.com/2014/11/27/zero-knowledge-proofs-illustrated-primer +- https://www.cs.cmu.edu/~goyal/s18/15503/scribe_notes/lecture23.pdf diff --git a/example-graphs/graph0.txt b/example-graphs/graph0.txt new file mode 100644 index 0000000..763063a --- /dev/null +++ b/example-graphs/graph0.txt @@ -0,0 +1,6 @@ +2 1 2 +0 0 2 +1 0 1 3 4 +0 2 5 +2 2 5 +1 3 4 diff --git a/example-graphs/graph1.txt b/example-graphs/graph1.txt new file mode 100644 index 0000000..8b00a38 --- /dev/null +++ b/example-graphs/graph1.txt @@ -0,0 +1,11 @@ +0 1 2 +1 0 2 3 +2 0 1 3 6 +0 1 2 5 +2 5 +1 3 4 +1 2 7 9 +2 6 8 9 +0 7 +0 6 7 10 +2 9 diff --git a/example-graphs/graph2.txt b/example-graphs/graph2.txt new file mode 100644 index 0000000..78fae3d --- /dev/null +++ b/example-graphs/graph2.txt @@ -0,0 +1,10 @@ +0 1 3 5 +2 0 2 8 +1 1 4 7 +2 0 6 7 +0 2 5 6 +2 0 4 9 +1 3 4 8 +0 2 3 9 +0 1 6 9 +1 5 7 8 diff --git a/example-graphs/graph3.txt b/example-graphs/graph3.txt new file mode 100644 index 0000000..7773a96 --- /dev/null +++ b/example-graphs/graph3.txt @@ -0,0 +1,5 @@ +0 1 2 +1 0 3 4 +1 0 3 +0 2 1 4 +2 1 3 diff --git a/out.dot b/out.dot new file mode 100644 index 0000000..98be3cc --- /dev/null +++ b/out.dot @@ -0,0 +1,371 @@ +graph nodes { + N0[label="0"][color="blue"]; + N1[label="1"][color="green"]; + N2[label="2"][color="red"]; + N3[label="3"][color="red"]; + N4[label="4"][color="green"]; + N5[label="5"][color="red"]; + N6[label="6"][color="blue"]; + N7[label="7"][color="blue"]; + N8[label="8"][color="red"]; + N9[label="9"][color="blue"]; + N10[label="10"][color="green"]; + N11[label="11"][color="blue"]; + N12[label="12"][color="green"]; + N13[label="13"][color="green"]; + N14[label="14"][color="blue"]; + N15[label="15"][color="red"]; + N16[label="16"][color="blue"]; + N17[label="17"][color="blue"]; + N18[label="18"][color="green"]; + N19[label="19"][color="red"]; + N20[label="20"][color="red"]; + N21[label="21"][color="red"]; + N22[label="22"][color="green"]; + N23[label="23"][color="red"]; + N24[label="24"][color="green"]; + N25[label="25"][color="green"]; + N26[label="26"][color="blue"]; + N27[label="27"][color="blue"]; + N28[label="28"][color="green"]; + N29[label="29"][color="red"]; + N30[label="30"][color="green"]; + N31[label="31"][color="green"]; + N32[label="32"][color="red"]; + N33[label="33"][color="green"]; + N34[label="34"][color="red"]; + N35[label="35"][color="green"]; + N36[label="36"][color="blue"]; + N37[label="37"][color="blue"]; + N38[label="38"][color="blue"]; + N39[label="39"][color="red"]; + N40[label="40"][color="green"]; + N41[label="41"][color="red"]; + N42[label="42"][color="green"]; + N43[label="43"][color="red"]; + N44[label="44"][color="red"]; + N45[label="45"][color="red"]; + N46[label="46"][color="blue"]; + N47[label="47"][color="red"]; + N48[label="48"][color="green"]; + N49[label="49"][color="red"]; + N50[label="50"][color="green"]; + N51[label="51"][color="red"]; + N52[label="52"][color="blue"]; + N53[label="53"][color="red"]; + N54[label="54"][color="blue"]; + N55[label="55"][color="green"]; + N56[label="56"][color="blue"]; + N57[label="57"][color="green"]; + N58[label="58"][color="blue"]; + N59[label="59"][color="red"]; + N60[label="60"][color="green"]; + N61[label="61"][color="green"]; + N62[label="62"][color="green"]; + N63[label="63"][color="red"]; + N64[label="64"][color="red"]; + N65[label="65"][color="blue"]; + N66[label="66"][color="red"]; + N67[label="67"][color="green"]; + N68[label="68"][color="green"]; + N69[label="69"][color="green"]; + N70[label="70"][color="blue"]; + N71[label="71"][color="green"]; + N72[label="72"][color="blue"]; + N73[label="73"][color="green"]; + N74[label="74"][color="blue"]; + N75[label="75"][color="red"]; + N76[label="76"][color="green"]; + N77[label="77"][color="blue"]; + N78[label="78"][color="blue"]; + N79[label="79"][color="red"]; + N80[label="80"][color="blue"]; + N81[label="81"][color="red"]; + N82[label="82"][color="red"]; + N83[label="83"][color="blue"]; + N84[label="84"][color="blue"]; + N85[label="85"][color="red"]; + N86[label="86"][color="red"]; + N87[label="87"][color="blue"]; + N88[label="88"][color="green"]; + N89[label="89"][color="red"]; + N90[label="90"][color="green"]; + N91[label="91"][color="blue"]; + N92[label="92"][color="green"]; + N93[label="93"][color="red"]; + N94[label="94"][color="red"]; + N95[label="95"][color="red"]; + N96[label="96"][color="green"]; + N97[label="97"][color="green"]; + N98[label="98"][color="green"]; + N99[label="99"][color="green"]; + N0 -- N1[label=""]; + N0 -- N2[label=""]; + N0 -- N3[label=""]; + N0 -- N4[label=""]; + N0 -- N5[label=""]; + N0 -- N8[label=""]; + N0 -- N12[label=""]; + N0 -- N15[label=""]; + N0 -- N19[label=""]; + N0 -- N25[label=""]; + N0 -- N32[label=""]; + N0 -- N35[label=""]; + N0 -- N55[label=""]; + N0 -- N88[label=""]; + N1 -- N6[label=""]; + N1 -- N15[label=""]; + N1 -- N23[label=""]; + N1 -- N37[label=""]; + N1 -- N75[label=""]; + N2 -- N17[label=""]; + N2 -- N48[label=""]; + N2 -- N57[label=""]; + N2 -- N84[label=""]; + N3 -- N30[label=""]; + N3 -- N31[label=""]; + N3 -- N33[label=""]; + N3 -- N38[label=""]; + N3 -- N58[label=""]; + N3 -- N68[label=""]; + N3 -- N90[label=""]; + N4 -- N7[label=""]; + N4 -- N43[label=""]; + N4 -- N54[label=""]; + N4 -- N56[label=""]; + N4 -- N64[label=""]; + N4 -- N66[label=""]; + N5 -- N9[label=""]; + N5 -- N13[label=""]; + N5 -- N42[label=""]; + N5 -- N77[label=""]; + N5 -- N99[label=""]; + N6 -- N10[label=""]; + N6 -- N47[label=""]; + N6 -- N49[label=""]; + N6 -- N53[label=""]; + N6 -- N57[label=""]; + N6 -- N98[label=""]; + N7 -- N22[label=""]; + N7 -- N41[label=""]; + N7 -- N57[label=""]; + N7 -- N88[label=""]; + N7 -- N89[label=""]; + N8 -- N11[label=""]; + N8 -- N18[label=""]; + N8 -- N24[label=""]; + N8 -- N38[label=""]; + N8 -- N97[label=""]; + N9 -- N31[label=""]; + N9 -- N51[label=""]; + N9 -- N60[label=""]; + N9 -- N89[label=""]; + N9 -- N99[label=""]; + N10 -- N21[label=""]; + N10 -- N23[label=""]; + N10 -- N26[label=""]; + N10 -- N34[label=""]; + N10 -- N49[label=""]; + N10 -- N54[label=""]; + N10 -- N78[label=""]; + N11 -- N20[label=""]; + N11 -- N22[label=""]; + N11 -- N32[label=""]; + N11 -- N39[label=""]; + N11 -- N41[label=""]; + N11 -- N42[label=""]; + N12 -- N15[label=""]; + N12 -- N83[label=""]; + N13 -- N14[label=""]; + N13 -- N41[label=""]; + N13 -- N47[label=""]; + N13 -- N79[label=""]; + N14 -- N29[label=""]; + N14 -- N69[label=""]; + N14 -- N75[label=""]; + N14 -- N76[label=""]; + N15 -- N16[label=""]; + N15 -- N35[label=""]; + N15 -- N40[label=""]; + N15 -- N46[label=""]; + N15 -- N60[label=""]; + N15 -- N68[label=""]; + N16 -- N47[label=""]; + N16 -- N81[label=""]; + N16 -- N96[label=""]; + N17 -- N40[label=""]; + N17 -- N41[label=""]; + N17 -- N53[label=""]; + N17 -- N57[label=""]; + N17 -- N59[label=""]; + N17 -- N63[label=""]; + N17 -- N68[label=""]; + N17 -- N95[label=""]; + N18 -- N19[label=""]; + N18 -- N47[label=""]; + N18 -- N54[label=""]; + N18 -- N63[label=""]; + N18 -- N81[label=""]; + N18 -- N87[label=""]; + N19 -- N27[label=""]; + N19 -- N37[label=""]; + N19 -- N52[label=""]; + N19 -- N76[label=""]; + N19 -- N87[label=""]; + N20 -- N24[label=""]; + N20 -- N26[label=""]; + N20 -- N48[label=""]; + N20 -- N74[label=""]; + N21 -- N26[label=""]; + N21 -- N67[label=""]; + N21 -- N96[label=""]; + N22 -- N63[label=""]; + N23 -- N28[label=""]; + N23 -- N40[label=""]; + N23 -- N55[label=""]; + N23 -- N74[label=""]; + N23 -- N97[label=""]; + N23 -- N98[label=""]; + N24 -- N36[label=""]; + N24 -- N45[label=""]; + N24 -- N54[label=""]; + N24 -- N63[label=""]; + N25 -- N38[label=""]; + N25 -- N64[label=""]; + N25 -- N84[label=""]; + N25 -- N86[label=""]; + N26 -- N71[label=""]; + N27 -- N32[label=""]; + N27 -- N81[label=""]; + N27 -- N93[label=""]; + N28 -- N51[label=""]; + N28 -- N72[label=""]; + N28 -- N94[label=""]; + N29 -- N35[label=""]; + N29 -- N84[label=""]; + N30 -- N43[label=""]; + N30 -- N44[label=""]; + N30 -- N81[label=""]; + N30 -- N86[label=""]; + N31 -- N43[label=""]; + N31 -- N51[label=""]; + N31 -- N54[label=""]; + N31 -- N80[label=""]; + N32 -- N50[label=""]; + N32 -- N74[label=""]; + N32 -- N76[label=""]; + N32 -- N88[label=""]; + N32 -- N92[label=""]; + N33 -- N49[label=""]; + N33 -- N54[label=""]; + N33 -- N65[label=""]; + N34 -- N67[label=""]; + N35 -- N47[label=""]; + N35 -- N63[label=""]; + N35 -- N64[label=""]; + N35 -- N75[label=""]; + N35 -- N78[label=""]; + N35 -- N79[label=""]; + N35 -- N89[label=""]; + N35 -- N95[label=""]; + N36 -- N48[label=""]; + N36 -- N59[label=""]; + N36 -- N95[label=""]; + N37 -- N41[label=""]; + N37 -- N51[label=""]; + N37 -- N96[label=""]; + N37 -- N98[label=""]; + N39 -- N52[label=""]; + N39 -- N76[label=""]; + N40 -- N51[label=""]; + N40 -- N75[label=""]; + N41 -- N70[label=""]; + N41 -- N71[label=""]; + N41 -- N72[label=""]; + N41 -- N78[label=""]; + N41 -- N83[label=""]; + N41 -- N87[label=""]; + N42 -- N44[label=""]; + N42 -- N85[label=""]; + N43 -- N48[label=""]; + N43 -- N57[label=""]; + N44 -- N77[label=""]; + N44 -- N98[label=""]; + N45 -- N69[label=""]; + N46 -- N60[label=""]; + N46 -- N96[label=""]; + N48 -- N51[label=""]; + N48 -- N58[label=""]; + N48 -- N59[label=""]; + N48 -- N82[label=""]; + N48 -- N87[label=""]; + N48 -- N94[label=""]; + N49 -- N76[label=""]; + N49 -- N77[label=""]; + N49 -- N83[label=""]; + N49 -- N88[label=""]; + N50 -- N86[label=""]; + N50 -- N91[label=""]; + N51 -- N78[label=""]; + N52 -- N62[label=""]; + N52 -- N73[label=""]; + N52 -- N95[label=""]; + N53 -- N84[label=""]; + N53 -- N99[label=""]; + N54 -- N55[label=""]; + N54 -- N59[label=""]; + N54 -- N63[label=""]; + N54 -- N88[label=""]; + N54 -- N89[label=""]; + N55 -- N65[label=""]; + N56 -- N75[label=""]; + N57 -- N64[label=""]; + N57 -- N86[label=""]; + N57 -- N93[label=""]; + N58 -- N61[label=""]; + N58 -- N76[label=""]; + N59 -- N92[label=""]; + N59 -- N99[label=""]; + N60 -- N80[label=""]; + N60 -- N95[label=""]; + N61 -- N87[label=""]; + N62 -- N85[label=""]; + N63 -- N69[label=""]; + N64 -- N72[label=""]; + N64 -- N76[label=""]; + N64 -- N78[label=""]; + N64 -- N83[label=""]; + N65 -- N75[label=""]; + N65 -- N76[label=""]; + N65 -- N79[label=""]; + N66 -- N78[label=""]; + N67 -- N80[label=""]; + N68 -- N75[label=""]; + N69 -- N75[label=""]; + N69 -- N87[label=""]; + N70 -- N81[label=""]; + N70 -- N86[label=""]; + N70 -- N96[label=""]; + N71 -- N82[label=""]; + N71 -- N93[label=""]; + N72 -- N73[label=""]; + N72 -- N92[label=""]; + N72 -- N96[label=""]; + N74 -- N79[label=""]; + N74 -- N85[label=""]; + N74 -- N86[label=""]; + N74 -- N89[label=""]; + N76 -- N80[label=""]; + N76 -- N89[label=""]; + N79 -- N88[label=""]; + N80 -- N92[label=""]; + N81 -- N92[label=""]; + N83 -- N96[label=""]; + N84 -- N98[label=""]; + N86 -- N92[label=""]; + N87 -- N93[label=""]; + N93 -- N96[label=""]; + N93 -- N99[label=""]; + N94 -- N97[label=""]; + N95 -- N96[label=""]; +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..0bfcb41 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,301 @@ +use std::fs; +use rand::{Rng, SeedableRng}; + +type Graph = Vec>; + +fn gen_graph(num_nodes: &usize, initial_edge_chance: &f64, edge_chance_change: &f64) -> (Graph, Vec) { + let mut graph: Graph = Default::default(); + let mut colors: Vec = vec![]; + let mut rng = rand::rng(); + let colors_selection = (0..=2).collect::>(); + + for i in 0..*num_nodes { + let mut c = rng.random_range(0..=2); + let mut color = colors_selection[c]; + + let mut neighbors: Vec = vec![]; + let mut edge_chance_bonus: f64 = 0.0; + if !graph.is_empty() { + while neighbors.is_empty() { + for (j, n) in graph.iter_mut().enumerate() { + let neighbor = n; + if colors[j] != color && !neighbor.contains(&(i as u64)) && rng.random_bool( + std::cmp::min_by( + *initial_edge_chance + edge_chance_bonus, + 1.0, + |a, b| a.total_cmp(b)) + ) { + neighbor.push(i as u64); + neighbors.push(j as u64); + edge_chance_bonus = 0.0; + } + } + if initial_edge_chance + edge_chance_bonus >= 1.0 && neighbors.is_empty() { + c = (c + 1) % 3; + color = colors_selection[c]; + edge_chance_bonus = 0.0; + continue; + } + edge_chance_bonus += edge_chance_change; + } + } + + graph.push(neighbors); + colors.push(color); + } + + (graph, colors) +} + +type Hash = [u8; 32]; + +fn commit(colors: &[u64], rng: &mut impl rand::Rng) -> (Hash, (Vec, usize, Vec)) { + let mut salts: Vec = Vec::with_capacity(colors.len()); + let mut nodes: Vec = (0..colors.len()).map(|i| { + let mut salt: Hash = [0; 32]; + rng.fill_bytes(&mut salt); + salts.push(salt); + *blake3::keyed_hash(&salt, &colors[i].to_be_bytes()).as_bytes() + }).collect(); + while nodes.len().next_power_of_two() != nodes.len() { + nodes.push(*nodes.last().unwrap()); + } + let num_leaves = nodes.len(); + + let mut level_start = 0; + let mut level_size = num_leaves; + while level_size > 1 { + for i in (0..level_size).step_by(2) { + let left = nodes[level_start + i]; + assert!(i + 1 < level_size, "Number of leaves is not a power of 2"); // Uneven tree + let right = nodes[level_start + i + 1]; + let mut salt: Hash = [0; 32]; + rng.fill_bytes(&mut salt); + salts.push(salt); + let mut hasher = blake3::Hasher::new(); + hasher.update(&left); + hasher.update(&right); + nodes.push(*hasher.finalize().as_bytes()); + } + + level_start += level_size; + level_size = (level_size + 1) / 2; + } + + (*nodes.last().unwrap(), (nodes, num_leaves, salts)) +} + +type ProofMerkle = (((u64, Hash), Vec<(Hash, bool)>), ((u64, Hash), Vec<(Hash, bool)>)); + +fn prove(graph: &Graph, colors: &[u64], nodes: &[Hash], num_leaves: &usize, salts: &[Hash], challange: &(u64, u64)) -> ProofMerkle { + assert!(challange.0 < *num_leaves as u64 && challange.1 < *num_leaves as u64, + "Leaf requested by the challange is out of range"); + assert!(graph[challange.0 as usize].contains(&challange.1) && + graph[challange.1 as usize].contains(&challange.0), + "vertices don't share a edge ({}, {})", challange.0, challange.1); + + let proof: Vec<((u64, Hash), Vec<(Hash, bool)>)> = (0..=1).map(|ci| { + let leaf_idx: usize = if ci == 0 { + challange.0 as usize + } else { + challange.1 as usize + }; + let mut path = vec![]; + + let mut current_index = leaf_idx; + let mut level_start = 0; + let mut level_size = *num_leaves; + while level_size > 1 { + let sibling_index = if current_index % 2 == 0 { + current_index + 1 + } else { + current_index - 1 + }; + + if sibling_index < level_start + level_size { + let sibling_hash = nodes[sibling_index]; + let direction = if current_index % 2 == 0 { + true // right + } else { + false // left + }; + path.push((sibling_hash, direction)); + } + + current_index = level_start + level_size + current_index / 2 - level_start / 2; + level_start += level_size; + level_size = (level_size + 1) / 2; + } + + ((colors[leaf_idx], salts[leaf_idx]), path) + }).collect(); + + (proof.first().unwrap().to_owned(), proof.last().unwrap().to_owned()) +} + +fn challange(graph: &Graph, rng: &mut impl rand::Rng) -> (u64, u64) { + let v0 = rng.random_range(0..graph.len()); + let v0_edges = &graph[v0]; + let v1 = v0_edges[rng.random_range(0..v0_edges.len())].to_owned(); + (v0 as u64, v1) +} + +fn verify(commitment: &Hash, proof: &ProofMerkle) -> bool { + if proof.0.0.0 == proof.1.0.0 { + return false; + } + + for v in 0..1 { + let cur_proof = if v == 0 { + &proof.0 + } else { + &proof.1 + }; + let mut current_hash = *blake3::keyed_hash(&cur_proof.0.1, &cur_proof.0.0.to_be_bytes()).as_bytes(); + for (sibling_hash, direction) in &cur_proof.1 { + let mut hasher = blake3::Hasher::new(); + match direction { + false => { // left + hasher.update(sibling_hash); + hasher.update(¤t_hash); + }, + true => { // right + hasher.update(¤t_hash); + hasher.update(sibling_hash); + } + }; + current_hash = *hasher.finalize().to_owned().as_bytes(); + } + if ¤t_hash != commitment { + return false; + } + } + + true +} + +fn parse_graph(data: &str) -> (Graph, Vec) { + let mut graph: Graph = Default::default(); + let mut colors: Vec = vec![]; + for v in data.split('\n') { + if v.is_empty() { continue; } + let (color, edges) = v.split_once(' ').unwrap(); + graph.push(vec![]); + colors.push(color.parse::().unwrap()); + for e in edges.split(' ') { + graph.last_mut().unwrap().push(e.parse::().unwrap()); + } + } + + (graph, colors) +} + +type Nd = usize; +type Ed<'a> = &'a (usize, usize); + +#[derive(Debug, Clone)] +struct DotGraph { + nodes: Vec<(usize, u64)>, + edges: Vec<(usize, usize)>, +} + +impl<'a> dot2::Labeller<'a> for DotGraph { + type Node = Nd; + type Edge = Ed<'a>; + type Subgraph = (); + + fn kind(&self) -> dot2::Kind { + dot2::Kind::Graph + } + + fn graph_id(&'a self) -> dot2::Result> { + dot2::Id::new("nodes") + } + + fn node_id(&'a self, n: &Nd) -> dot2::Result> { + dot2::Id::new(format!("N{}", n)) + } + + fn node_label<'b>(&'b self, n: &Nd) -> dot2::Result> { + Ok(dot2::label::Text::LabelStr((self.nodes[*n].0.to_string()).into())) + } + + fn node_color(&'a self, n: &Nd) -> Option> { + match self.nodes[*n].1 { + 0 => Some(dot2::label::Text::label("red")), + 1 => Some(dot2::label::Text::label("blue")), + 2 => Some(dot2::label::Text::label("green")), + _ => None + } + } +} + +impl<'a> dot2::GraphWalk<'a> for DotGraph { + type Node = Nd; + type Edge = Ed<'a>; + type Subgraph = (); + + fn nodes(&self) -> dot2::Nodes<'a,Nd> { + (0..self.nodes.len()).collect() + } + + fn edges(&'a self) -> dot2::Edges<'a,Ed<'a>> { + self.edges.iter().collect() + } + + fn source(&self, e: &Ed) -> Nd { + let & &(s,_) = e; + s + } + + fn target(&self, e: &Ed) -> Nd { + let & &(_,t) = e; + t + } +} + +pub fn save_graph(graph: &Graph, colors: &[u64], output: &mut W) -> dot2::Result { + let nodes: Vec<(usize, u64)> = graph.iter().enumerate().map(|node| { + (node.0, colors[node.0]) + }).collect(); + let edges: Vec<(usize, usize)> = graph.iter().enumerate().flat_map(|node| { + node.1.iter().map(|neighbor| { + (node.0, *neighbor as usize) + }).collect::>() + }).filter(|e| e.0 < e.1).collect(); + let graph = DotGraph { nodes, edges }; + + dot2::render(&graph, output) +} + +fn main() { + let (graph, colors) = gen_graph(&100, &0.08, &0.01); + // parse_graph(&fs::read_to_string("example-graphs/graph3.txt") + // .expect("Unable to read graph data")); + println!("{:?}", graph); + + let mut rng = rand_chacha::ChaCha8Rng::from_os_rng(); + let rounds = graph.len().pow(2); + let mut successes: u64 = 0; + use std::time::Instant; + let now = Instant::now(); + for _ in 0..rounds { + let commitment = commit(&colors, &mut rng); + let challange = challange(&graph, &mut rng); + let proof = prove(&graph, &colors, &commitment.1.0, &commitment.1.1, &commitment.1.2, &challange); + let success = verify(&commitment.0, &proof); + println!("Egress: {} Ingress: {}", size_of_val(&commitment.0) + size_of_val(&proof), size_of_val(&challange)); + if success { + successes += 1; + } + else { + println!("Failed challange: {:?}", challange); + } + } + let elapsed = now.elapsed(); + println!("Verified in {:.2?}", elapsed); + println!("Success rate: {:.2}% ({} / {})", successes as f64 / rounds as f64 * 100_f64, successes, rounds); + + let mut f = std::fs::File::create("out.dot").unwrap(); + _ = save_graph(&graph, &colors, &mut f); +}