Просмотр исходного кода

[script/research/crypsinous] added crypsinous research notes

mohab 4 лет назад
Родитель
Сommit
f9aa5fb20e
29 измененных файлов с 1094 добавлено и 0 удалено
  1. 7 0
      script/research/crypsinous/README.md
  2. 0 0
      script/research/crypsinous/ouroboros/__init__.py
  3. 0 0
      script/research/crypsinous/ouroboros/ouroboros/__init__.py
  4. 0 0
      script/research/crypsinous/ouroboros/ouroboros/beacon.py
  5. 0 0
      script/research/crypsinous/ouroboros/ouroboros/block.py
  6. 0 0
      script/research/crypsinous/ouroboros/ouroboros/blockchain.py
  7. 0 0
      script/research/crypsinous/ouroboros/ouroboros/clock.py
  8. 0 0
      script/research/crypsinous/ouroboros/ouroboros/consts.py
  9. 0 0
      script/research/crypsinous/ouroboros/ouroboros/data.py
  10. 0 0
      script/research/crypsinous/ouroboros/ouroboros/environment.py
  11. 0 0
      script/research/crypsinous/ouroboros/ouroboros/epoch.py
  12. 0 0
      script/research/crypsinous/ouroboros/ouroboros/hashtree.py
  13. 0 0
      script/research/crypsinous/ouroboros/ouroboros/kes.py
  14. 0 0
      script/research/crypsinous/ouroboros/ouroboros/logger.py
  15. 0 0
      script/research/crypsinous/ouroboros/ouroboros/protocol.tex
  16. 0 0
      script/research/crypsinous/ouroboros/ouroboros/sig_test.py
  17. 0 0
      script/research/crypsinous/ouroboros/ouroboros/stakeholder.py
  18. 0 0
      script/research/crypsinous/ouroboros/ouroboros/utils.py
  19. 0 0
      script/research/crypsinous/ouroboros/ouroboros/vrf.py
  20. 0 0
      script/research/crypsinous/ouroboros/protocol.tex
  21. 0 0
      script/research/crypsinous/ouroboros/sig_test.py
  22. 0 0
      script/research/crypsinous/ouroboros/simulation.py
  23. 0 0
      script/research/crypsinous/ouroboros/vrf_test.py
  24. 21 0
      script/research/crypsinous/zerocash/README.md
  25. BIN
      script/research/crypsinous/zerocash/README.pdf
  26. 338 0
      script/research/crypsinous/zk/plonk-by-hand/Cargo.lock
  27. 11 0
      script/research/crypsinous/zk/plonk-by-hand/Cargo.toml
  28. 334 0
      script/research/crypsinous/zk/plonk-by-hand/plonk.ipynb
  29. 383 0
      script/research/crypsinous/zk/plonk-by-hand/src/main.rs

+ 7 - 0
script/research/crypsinous/README.md

@@ -0,0 +1,7 @@
+this is an effort to break down the building blocks of crypsinous blockchain
+
+# Crypsinous blockchain
+TODO
+
+# Crypsinous leaderelection
+TODO

+ 0 - 0
script/research/dpos/__init__.py → script/research/crypsinous/ouroboros/__init__.py


+ 0 - 0
script/research/dpos/ouroboros/__init__.py → script/research/crypsinous/ouroboros/ouroboros/__init__.py


+ 0 - 0
script/research/dpos/ouroboros/beacon.py → script/research/crypsinous/ouroboros/ouroboros/beacon.py


+ 0 - 0
script/research/dpos/ouroboros/block.py → script/research/crypsinous/ouroboros/ouroboros/block.py


+ 0 - 0
script/research/dpos/ouroboros/blockchain.py → script/research/crypsinous/ouroboros/ouroboros/blockchain.py


+ 0 - 0
script/research/dpos/ouroboros/clock.py → script/research/crypsinous/ouroboros/ouroboros/clock.py


+ 0 - 0
script/research/dpos/ouroboros/consts.py → script/research/crypsinous/ouroboros/ouroboros/consts.py


+ 0 - 0
script/research/dpos/ouroboros/data.py → script/research/crypsinous/ouroboros/ouroboros/data.py


+ 0 - 0
script/research/dpos/ouroboros/environment.py → script/research/crypsinous/ouroboros/ouroboros/environment.py


+ 0 - 0
script/research/dpos/ouroboros/epoch.py → script/research/crypsinous/ouroboros/ouroboros/epoch.py


+ 0 - 0
script/research/dpos/ouroboros/hashtree.py → script/research/crypsinous/ouroboros/ouroboros/hashtree.py


+ 0 - 0
script/research/dpos/ouroboros/kes.py → script/research/crypsinous/ouroboros/ouroboros/kes.py


+ 0 - 0
script/research/dpos/ouroboros/logger.py → script/research/crypsinous/ouroboros/ouroboros/logger.py


+ 0 - 0
script/research/dpos/ouroboros/protocol.tex → script/research/crypsinous/ouroboros/ouroboros/protocol.tex


+ 0 - 0
script/research/dpos/ouroboros/sig_test.py → script/research/crypsinous/ouroboros/ouroboros/sig_test.py


+ 0 - 0
script/research/dpos/ouroboros/stakeholder.py → script/research/crypsinous/ouroboros/ouroboros/stakeholder.py


+ 0 - 0
script/research/dpos/ouroboros/utils.py → script/research/crypsinous/ouroboros/ouroboros/utils.py


+ 0 - 0
script/research/dpos/ouroboros/vrf.py → script/research/crypsinous/ouroboros/ouroboros/vrf.py


+ 0 - 0
script/research/dpos/protocol.tex → script/research/crypsinous/ouroboros/protocol.tex


+ 0 - 0
script/research/dpos/sig_test.py → script/research/crypsinous/ouroboros/sig_test.py


+ 0 - 0
script/research/dpos/simulation.py → script/research/crypsinous/ouroboros/simulation.py


+ 0 - 0
script/research/dpos/vrf_test.py → script/research/crypsinous/ouroboros/vrf_test.py


+ 21 - 0
script/research/crypsinous/zerocash/README.md

@@ -0,0 +1,21 @@
+# zerocash notes, and highlights
+
+## zerocoin drawbacks
+zerocoin isn't used in daily transaction due to performance limitations, but rather for anonymization, or laundrying coins through decentralized mix. performance bottleneck is that redeeming zerocoins requires double-discrete-logarithm proofs of knowledge which have size that exceeds 45kb, and 450ms to verify(at the 128-bit security level), it uses fixed denominations, can't pay in zerocoin directly, provides anonymity for the original address only.
+
+# minting
+minting coin $c := ((a_{pk}, PK_{enc}), v, \rho, r, s, cm)$ is:
+$$tx_{mint}:=(v,k,s,cm)$$
+$$cm :=COMM_{s}(v||k)$$
+$$a_{pk} :=RPF_{a_{sk}}^{addr}(0)$$
+$$k:=COMM_{r}(a_{pk}||\rho)$$
+
+# spending
+Spending the coin c:
+$$tx_{spend}:=(cm,sn,\pi)$$
+$$sn:=PRF_{a_{sk}}^{sn}(\rho)$$
+
+### pouring
+pouring $coin^{old}$ into $coin_1^{new}$, $coin_2^{new}$. with $v^{old}=v_{pub}+v_1^{new}+v_2^{new}$ as follows:
+$$tx_{pour}:=(rt,sn^{old},cm_1^{new},cm_2^{new},\pi_{pour})$$
+$\pi_{pour}$ is the pouring sk-snark proof of the spending/pouring process.

BIN
script/research/crypsinous/zerocash/README.pdf


+ 338 - 0
script/research/crypsinous/zk/plonk-by-hand/Cargo.lock

@@ -0,0 +1,338 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "arrayref"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
+
+[[package]]
+name = "arrayvec"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
+
+[[package]]
+name = "autocfg"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+
+[[package]]
+name = "bitvec"
+version = "0.22.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5237f00a8c86130a0cc317830e558b966dd7850d48a953d998c813f01a41b527"
+dependencies = [
+ "funty",
+ "radium",
+ "tap",
+ "wyz",
+]
+
+[[package]]
+name = "blake2b_simd"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72936ee4afc7f8f736d1c38383b56480b5497b4617b4a77bdbf1d2ababc76127"
+dependencies = [
+ "arrayref",
+ "arrayvec",
+ "constant_time_eq",
+]
+
+[[package]]
+name = "byteorder"
+version = "1.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
+
+[[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.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
+
+[[package]]
+name = "crossbeam-channel"
+version = "0.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53"
+dependencies = [
+ "cfg-if",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-deque"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"
+dependencies = [
+ "cfg-if",
+ "crossbeam-epoch",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-epoch"
+version = "0.9.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c"
+dependencies = [
+ "autocfg",
+ "cfg-if",
+ "crossbeam-utils",
+ "lazy_static",
+ "memoffset",
+ "scopeguard",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38"
+dependencies = [
+ "cfg-if",
+ "lazy_static",
+]
+
+[[package]]
+name = "either"
+version = "1.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
+
+[[package]]
+name = "ff"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2958d04124b9f27f175eaeb9a9f383d026098aa837eadd8ba22c11f13a05b9e"
+dependencies = [
+ "bitvec",
+ "rand_core",
+ "subtle",
+]
+
+[[package]]
+name = "funty"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1847abb9cb65d566acd5942e94aea9c8f547ad02c98e1649326fc0e8910b8b1e"
+
+[[package]]
+name = "getrandom"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
+name = "group"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc5ac374b108929de78460075f3dc439fa66df9d8fc77e8f12caa5165fcf0c89"
+dependencies = [
+ "byteorder",
+ "ff",
+ "rand_core",
+ "subtle",
+]
+
+[[package]]
+name = "halo2"
+version = "0.1.0-beta.1"
+dependencies = [
+ "blake2b_simd",
+ "ff",
+ "group",
+ "pasta_curves",
+ "rand",
+ "rayon",
+]
+
+[[package]]
+name = "hermit-abi"
+version = "0.1.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
+name = "libc"
+version = "0.2.121"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f"
+
+[[package]]
+name = "memoffset"
+version = "0.6.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "num_cpus"
+version = "1.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
+dependencies = [
+ "hermit-abi",
+ "libc",
+]
+
+[[package]]
+name = "pasta_curves"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "82b6fc4f73033f6aa52fdde0c38f1f570e7f2c244f22e441f62a144556891b8c"
+dependencies = [
+ "blake2b_simd",
+ "ff",
+ "group",
+ "lazy_static",
+ "rand",
+ "static_assertions",
+ "subtle",
+]
+
+[[package]]
+name = "plonkbyhand"
+version = "0.1.0"
+dependencies = [
+ "halo2",
+]
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
+
+[[package]]
+name = "radium"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb"
+
+[[package]]
+name = "rand"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
+dependencies = [
+ "libc",
+ "rand_chacha",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "rayon"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90"
+dependencies = [
+ "autocfg",
+ "crossbeam-deque",
+ "either",
+ "rayon-core",
+]
+
+[[package]]
+name = "rayon-core"
+version = "1.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e"
+dependencies = [
+ "crossbeam-channel",
+ "crossbeam-deque",
+ "crossbeam-utils",
+ "lazy_static",
+ "num_cpus",
+]
+
+[[package]]
+name = "scopeguard"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
+
+[[package]]
+name = "static_assertions"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+
+[[package]]
+name = "subtle"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
+
+[[package]]
+name = "tap"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
+
+[[package]]
+name = "wasi"
+version = "0.10.2+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
+
+[[package]]
+name = "wyz"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "129e027ad65ce1453680623c3fb5163cbf7107bfe1aa32257e7d0e63f9ced188"
+dependencies = [
+ "tap",
+]
+
+[[patch.unused]]
+name = "halo2"
+version = "0.1.0-beta.2"
+source = "git+https://github.com/zcash/halo2?branch=main#084ecf185a89827fb68a8e4ef6e0e6a7aaac391f"

+ 11 - 0
script/research/crypsinous/zk/plonk-by-hand/Cargo.toml

@@ -0,0 +1,11 @@
+[package]
+name = "plonkbyhand"
+version = "0.1.0"
+
+edition = "2021"
+
+[dependencies]
+halo2 = { path = "/opt/halo2" }
+
+[patch.crates-io]
+halo2 =  {git = "https://github.com/zcash/halo2", branch = "main"}

+ 334 - 0
script/research/crypsinous/zk/plonk-by-hand/plonk.ipynb

@@ -0,0 +1,334 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# setup \n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 41,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# simple 101 group\n",
+    "F101 = IntegerModRing(101)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 42,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# define elliptic curve with coefficient 0(degree 1), 3(degree 0)\n",
+    "E = EllipticCurve(F101, [0,3])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 43,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# define polynomial ring on F101, then extended in Galois field\n",
+    "R.<X> = PolynomialRing(F101)\n",
+    "K.<X> = GF(101**2, modulus = x^2+2)\n",
+    "E2 = EllipticCurve(K, [0,3])\n",
+    "# EC generator at  (1,2)\n",
+    "G=E2([1,2])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 44,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# the order of G is r=17, the embedding degree it's the smallest k such that r|p^k -1, thus k=2\n",
+    "## if you keep adding G to itself, it would get only 17 unique values r=17\n",
+    "## group base p=101\n",
+    "G2 = E2([36,31*X])\n",
+    "# structured reference string SRS\n",
+    "## in kate commitment, here you create SRS, and release the toxic waste\n",
+    "## for random value rand=2\n",
+    "rand=2\n",
+    "G1_SRS = [(rand**i)*G for i in range(7)]\n",
+    "G2_SRS = [rand**i*G2 for i in range(2)]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 45,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "N=G.order()\n",
+    "F17=Integers(N)\n",
+    "F17.square_roots_of_one()\n",
+    "# witness values for random [1,4,-1,-4]\n",
+    "w = vector(F17, [1,4,-1,-4])\n",
+    "w\n",
+    "k1=2; k2=3\n",
+    "k1*w\n",
+    "k2*w\n",
+    "A = matrix(F17, [[1**i for i in range (4)], [4**i for i in range (4)], [16**i for i in range(4)], [13**i for i in range(4)]])\n",
+    "Ai = A.inverse()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 46,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "s=2\n",
+    "zeta=5\n",
+    "beta=12\n",
+    "gamma=13\n",
+    "vega=12\n",
+    "alpha = 15\n",
+    "ql_coef = [0,0,1,0] # multiplication a1*b1 : q left mulitplication coefficient for l+ r + m + c  = rhs\n",
+    "qr_coef = [0,0,1,0] # multiplication a2*b2'\n",
+    "qm_coef = [1,1,0,0] # addition gate a3+b3\n",
+    "qo_coef = [-1,-1,0,0] # ??\n",
+    "qc_coef = [0,0,-30,0] #??\n",
+    "P.<x> = F17[];x=P.0\n",
+    "ql = P(list(Ai*vector(F17, ql_coef)))\n",
+    "qr = P(list(Ai*vector(F17, qr_coef)))\n",
+    "qm = P(list(Ai*vector(F17, qm_coef)))\n",
+    "qo = P(list(Ai*vector(F17, qo_coef)))\n",
+    "qc = P(list(Ai*vector(F17, qc_coef)))\n",
+    "#public setup polynomials SRS are ql,qr,qm,qo,qc\n",
+    "ql,qr,qm,qo,qc\n",
+    "#\n",
+    "# equality constraints ??\n",
+    "sa = P(list(Ai*vector(F17, [2,3,12,13]))) # ??\n",
+    "sb = P(list(Ai*vector(F17, [1,15,8,9]))) # ??\n",
+    "sc = P(list(Ai*vector(F17, [4,16,14,5]))) # ?? \n",
+    "sa,sb,sc\n",
+    "# blinding values bld1-bld9\n",
+    "bld1=7\n",
+    "bld2=4\n",
+    "bld3=11\n",
+    "bld4=12\n",
+    "bld5=16\n",
+    "bld6=2\n",
+    "bld7=14\n",
+    "bld8=2\n",
+    "bld9=11"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# proving"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 57,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def proving():\n",
+    "        ## for root 3, the following toxic waste coefficient are:\n",
+    "        a_coef = [3,9,27,0] # the left operands: a1,a2,a3,a5 \n",
+    "        b_coef = [3,3,3,0] # the right operands: b1,b2,b3,b5\n",
+    "        c_coef = [9,27,0,0] # the output: c1,c2,c3,c5\n",
+    "        fa = P(list(Ai*vector(F17, a_coef)))\n",
+    "        fb = P(list(Ai*vector(F17, b_coef)))\n",
+    "        fc = P(list(Ai*vector(F17, c_coef)))\n",
+    "        # solution polynomials are fa,fb,fc\n",
+    "        # round 1\n",
+    "        # target polynomial that vanishes at root of unity \n",
+    "        Z = x**4-1\n",
+    "        # random blinding values b1-b9 = [7,4,11,12,16,2]\n",
+    "        a = (bld1*x+bld2)*Z+fa\n",
+    "        b = (bld3*x+bld4)*Z+fb\n",
+    "        c = (bld5*x+bld6)*Z+fc\n",
+    "        ### choose s=2\n",
+    "        a_s = ZZ(a(s))*G\n",
+    "        b_s = ZZ(b(s))*G\n",
+    "        c_s = ZZ(c(s))*G\n",
+    "        p = (a_s,b_s,c_s)\n",
+    "        # round 2\n",
+    "        ### compute permutation challenges (beta,gamma) as hash of the transcript\n",
+    "        #for simplicity\n",
+    "        acc=1 #accumulator\n",
+    "        for i in range(4): #TODO parameterize number of gates\n",
+    "            nominator = ((a(w[i])+beta*w[i]+gamma)*(b(w[i])+beta*k1*w[i]+gamma)*(c(w[i])+beta*k2*w[i]+gamma))\n",
+    "            denominator = ((a(w[i])+beta*sa(w[i])+gamma)*(b(w[i])+beta*sb(w[i])+gamma)*(c(w[i])+beta*sc(w[i])+gamma))\n",
+    "            acc = acc*nominator/denominator\n",
+    "        acc=P(list(Ai*vector(F17,[1,12,10,1]))) #TODO parameterize\n",
+    "        Zx = (bld7*x**bld8+bld9*x+7)*Z+acc\n",
+    "        Z_s = ZZ(Zx(s))*G\n",
+    "        # round 3\n",
+    "        L=P(list(Ai*vector(F17, [1,0,0,0]))) #TODO parameterize\n",
+    "        t1Z = a*b*qm+a*ql+b*qr+c*qo+qc\n",
+    "        t2Z = (a+beta*x+gamma)*(b+k1*beta*x+gamma)*(c+k2*beta*x+gamma)*Zx*alpha\n",
+    "        Zw = Zx(w[1]*x)\n",
+    "        t3Z= -(a+beta*sa+gamma)*(b+beta*sb+gamma)*(c+beta*sc+gamma)*Zw*alpha\n",
+    "        t4Z = (Zx-1)*L*alpha**2\n",
+    "        tZ = t1Z+t2Z+t3Z+t4Z\n",
+    "        ## if everything goes well, then the following should divide without remainders\n",
+    "        t=P(tZ/Z)\n",
+    "        t_list = t.list()\n",
+    "        t_lo=t_list[0:6]\n",
+    "        t_mid=t_list[6:12]\n",
+    "        t_hi=t_list[12:]\n",
+    "        t_lo_s=ZZ(P(t_lo)(s))*G\n",
+    "        t_mid_s=ZZ(P(t_mid)(s))*G\n",
+    "        t_hi_s=ZZ(P(t_hi)(s))*G\n",
+    "        t_lo_s,t_mid_s,t_hi_s\n",
+    "        # Round 4\n",
+    "        a_=a(zeta)\n",
+    "        b_=b(zeta)\n",
+    "        c_=c(zeta)\n",
+    "        sa_=sa(zeta)\n",
+    "        sb_=sb(zeta)\n",
+    "        t_=t(zeta)\n",
+    "        zw_=Zx(zeta*w[1])\n",
+    "        l_=L(zeta)\n",
+    "        r1 = a_*b_*qm+a_*ql+b_*qr+c_*qo+qc\n",
+    "        r2 = ((a_+beta*zeta+gamma)*(b_+beta*k1*zeta+gamma)*(c_+beta*k2*zeta+gamma)*Zx)*alpha\n",
+    "        r3=-(a_+beta*sa_+gamma)*(b_+beta*sb_+gamma)*beta*zw_*sc*alpha\n",
+    "        r4=Zx*l_*alpha**2\n",
+    "        r=r1+r2+r3+r4\n",
+    "        r_=r(zeta)\n",
+    "        # Round 5\n",
+    "        v1 = P(t_lo)\n",
+    "        v2=zeta**6*P(t_mid)\n",
+    "        v3=zeta**12*P(t_hi)\n",
+    "        v4=-t_\n",
+    "        v5 = vega*(r-r_)+vega**2*(a-a_)+vega**3*(b-b_)+vega**4*(c-c_)+vega**5*(sa-sa_)+vega**6*(sb-sb_)\n",
+    "        W=v1+v2+v3+v4+v5\n",
+    "        ## opening proof polynomial\n",
+    "        Wz=W/(x-zeta)\n",
+    "        Wzw=(Zx-zw_)/(x-zeta*w[1])\n",
+    "        Wz_s=ZZ(Wz(s))*G\n",
+    "        Wzw_s=ZZ(Wzw(s))*G\n",
+    "        Wz_s,Wzw_s\n",
+    "        proof = (a_s,b_s,c_s,Z_s,t_lo_s,t_mid_s,t_hi_s,Wz_s,Wzw_s,a_,b_,c_,sa_,sb_,r_,zw_)\n",
+    "        return proof"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 58,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "a_s,b_s,c_s,Z_s,t_lo_s,t_mid_s,t_hi_s,Wz_s,Wzw_s,a_,b_,c_,sa_,sb_,r_,zw_ = proving()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# verification"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 61,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def verify():\n",
+    "    ## TODO (1) verify that all those points are in the curve G1\n",
+    "    ## TODO (2) verify that the bar values are part of Fp^7 group\n",
+    "    ## TODO (3) validate that w_i (roots of unity) are in F_p^l\n",
+    "    ### verifier processed input\n",
+    "    qm_s = ZZ(qm(s))*G\n",
+    "    ql_s = ZZ(ql(s))*G\n",
+    "    qr_s = ZZ(qr(s))*G\n",
+    "    qo_s = ZZ(qo(s))*G\n",
+    "    qc_s = ZZ(qc(s))*G\n",
+    "    sa_s = ZZ(sa(s))*G\n",
+    "    sb_s = ZZ(sb(s))*G\n",
+    "    sc_s = ZZ(sc(s))*G\n",
+    "    ## (4) compute challenges beta, gamma, alpha, zeta, veta, upsilon as in prover description from the common inputs, public input, and elements of zk-snark\n",
+    "    epsilon=4 # only this is missing\n",
+    "    ## (5) ZERO POLYNOMIAL EVALUATION\n",
+    "    Z_z=F17(zeta**4-1)\n",
+    "    ## (6) lagrange polynomial evaluation \n",
+    "    L1_z=F17((zeta**4-1)/(4*(zeta-1)))\n",
+    "    ## TODO(7) public input polynomial evaluation \n",
+    "    ## quotient polynomial evaluation\n",
+    "    t_=(r_-((a_+beta*sa_+gamma)*(b_+beta*sb_+gamma)*(c_+gamma)*zw_)*alpha-L1_z*alpha**2)/Z_z;t_\n",
+    "    ## (9) part of batched opynomimal commitment\n",
+    "    d1=ZZ(a_*b_*vega)*qm_s+ZZ(a_*vega)*ql_s+ZZ(b_*vega)*qr_s+ZZ(c_*vega)*qo_s+vega*qc_s\n",
+    "    d2=ZZ(((a_+beta*zeta+gamma)*(b_+beta*k1*zeta+gamma)*(c_+beta*k2*zeta+gamma)*alpha*vega)+L1_z*alpha**2*vega+F17(epsilon))*Z_s\n",
+    "    d3=-ZZ((a_+beta*sa_+gamma)*(b_+beta*sb_+gamma)*alpha*vega*beta*zw_)*sc_s\n",
+    "    d=d1+d2+d3;d\n",
+    "    ## (10) full batched polynomial commitment [F]1\n",
+    "    f=t_lo_s+zeta**6*t_mid_s+zeta**12*t_hi_s+d+vega**2*a_s+vega**3*b_s+vega**4*c_s+vega**5*sa_s+vega**6*sb_s\n",
+    "    ## (11) group-encoded batch evaluation [E]1\n",
+    "    e=ZZ((t_+vega*r_+vega**2*a_+vega**3*b_+vega**4*c_+vega**5*sa_+vega**6*sb_+epsilon*zw_))*G\n",
+    "    ## (12)\n",
+    "    x1=Wz_s+epsilon*Wzw_s\n",
+    "    x2=s*G2\n",
+    "    y1=zeta*Wz_s+ZZ(epsilon*zeta*w[1])*Wzw_s+f-e\n",
+    "    y2=G2\n",
+    "    x1_=E2(x1)\n",
+    "    x2_=E2(x2)\n",
+    "    y1_=E2(y1)\n",
+    "    y2_=E2(y2)\n",
+    "    return x1_.weil_pairing(x2_,17)==y1_.weil_pairing(y2_,17)\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 62,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "assert(verify())"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### references\n",
+    "[1] https://eprint.iacr.org/2019/953.pdf\n",
+    "\n",
+    "[2] https://research.metastate.dev/plonk-by-hand-part-1/\n",
+    "\n",
+    "[3] https://research.metastate.dev/plonk-by-hand-part-2-the-proof/\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "SageMath 9.3",
+   "language": "sage",
+   "name": "sagemath"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.7.10"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}

+ 383 - 0
script/research/crypsinous/zk/plonk-by-hand/src/main.rs

@@ -0,0 +1,383 @@
+use std::marker::PhantomData;
+
+use halo2::{
+    arithmetic::FieldExt,
+    circuit::{AssignedCell, Chip, Layouter, Region, SimpleFloorPlanner},
+    plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Fixed, Instance, Selector},
+    poly::Rotation,
+};
+
+// ANCHOR: instructions
+trait NumericInstructions<F: FieldExt>: Chip<F> {
+    /// Variable representing a number.
+    type Num;
+
+    /// Loads a number into the circuit as a private input.
+    fn load_private(&self, layouter: impl Layouter<F>, a: Option<F>) -> Result<Self::Num, Error>;
+
+    /// Loads a number into the circuit as a fixed constant.
+    fn load_constant(&self, layouter: impl Layouter<F>, constant: F) -> Result<Self::Num, Error>;
+
+    /// Returns `c = a * b`.
+    fn mul(
+        &self,
+        layouter: impl Layouter<F>,
+        a: Self::Num,
+        b: Self::Num,
+    ) -> Result<Self::Num, Error>;
+
+    /// Returns `c = a + b`.
+    fn add(
+        &self,
+        layouter: impl Layouter<F>,
+        a: Self::Num,
+        b: Self::Num,
+    ) -> Result<Self::Num, Error>;
+
+    /// Exposes a number as a public input to the circuit.
+    fn expose_public(
+        &self,
+        layouter: impl Layouter<F>,
+        num: Self::Num,
+        row: usize,
+    ) -> Result<(), Error>;
+}
+// ANCHOR_END: instructions
+
+// ANCHOR: chip
+/// The chip that will implement our instructions! Chips store their own
+/// config, as well as type markers if necessary.
+struct FieldChip<F: FieldExt> {
+    config: FieldConfig,
+    _marker: PhantomData<F>,
+}
+// ANCHOR_END: chip
+
+// ANCHOR: chip-config
+/// Chip state is stored in a config struct. This is generated by the chip
+/// during configuration, and then stored inside the chip.
+#[derive(Clone, Debug)]
+struct FieldConfig {
+    /// For this chip, we will use two advice columns to implement our instructions.
+    /// These are also the columns through which we communicate with other parts of
+    /// the circuit.
+    advice: [Column<Advice>; 2],
+
+    /// This is the public input (instance) column.
+    instance: Column<Instance>,
+
+    // We need a selector to enable the multiplication gate, so that we aren't placing
+    // any constraints on cells where `NumericInstructions::mul` is not being used.
+    // This is important when building larger circuits, where columns are used by
+    // multiple sets of instructions.
+    s_mul: Selector,
+    s_add: Selector,
+}
+
+impl<F: FieldExt> FieldChip<F> {
+    fn construct(config: <Self as Chip<F>>::Config) -> Self {
+        Self {
+            config,
+            _marker: PhantomData,
+        }
+    }
+
+    fn configure(
+        meta: &mut ConstraintSystem<F>,
+        advice: [Column<Advice>; 2],
+        instance: Column<Instance>,
+        constant: Column<Fixed>,
+    ) -> <Self as Chip<F>>::Config {
+        meta.enable_equality(instance);
+        meta.enable_constant(constant);
+        for column in &advice {
+            meta.enable_equality(*column);
+        }
+        let s_mul = meta.selector();
+        let s_add = meta.selector();
+        // Define our multiplication gate!
+        meta.create_gate("mul", |meta| {
+            // To implement multiplication, we need three advice cells and a selector
+            // cell. We arrange them like so:
+            //
+            // | a0  | a1  | s_mul |
+            // |-----|-----|-------|
+            // | lhs | rhs | s_mul |
+            // | out |     |       |
+            //
+            // Gates may refer to any relative offsets we want, but each distinct
+            // offset adds a cost to the proof. The most common offsets are 0 (the
+            // current row), 1 (the next row), and -1 (the previous row), for which
+            // `Rotation` has specific constructors.
+            let lhs = meta.query_advice(advice[0], Rotation::cur());
+            let rhs = meta.query_advice(advice[1], Rotation::cur());
+            let out = meta.query_advice(advice[0], Rotation::next());
+            let s_mul = meta.query_selector(s_mul);
+
+            // Finally, we return the polynomial expressions that constrain this gate.
+            // For our multiplication gate, we only need a single polynomial constraint.
+            //
+            // The polynomial expressions returned from `create_gate` will be
+            // constrained by the proving system to equal zero. Our expression
+            // has the following properties:
+            // - When s_mul = 0, any value is allowed in lhs, rhs, and out.
+            // - When s_mul != 0, this constrains lhs * rhs = out.
+            vec![s_mul * (lhs * rhs - out)]
+        });
+
+
+        // Define our addition gate!
+        meta.create_gate("add", |meta| {
+            let lhs = meta.query_advice(advice[0], Rotation::cur());
+            let rhs = meta.query_advice(advice[1], Rotation::cur());
+            let out = meta.query_advice(advice[0], Rotation::next());
+            let s_add = meta.query_selector(s_add);
+
+            vec![s_add * (lhs + rhs - out)]
+        });
+
+        FieldConfig {
+            advice,
+            instance,
+            s_mul,
+            s_add,
+        }
+    }
+}
+// ANCHOR_END: chip-config
+
+// ANCHOR: chip-impl
+impl<F: FieldExt> Chip<F> for FieldChip<F> {
+    type Config = FieldConfig;
+    type Loaded = ();
+
+    fn config(&self) -> &Self::Config {
+        &self.config
+    }
+
+    fn loaded(&self) -> &Self::Loaded {
+        &()
+    }
+}
+// ANCHOR_END: chip-impl
+
+// ANCHOR: instructions-impl
+/// A variable representing a number.
+#[derive(Clone)]
+struct Number<F: FieldExt>(AssignedCell<F, F>);
+
+impl<F: FieldExt> NumericInstructions<F> for FieldChip<F> {
+    type Num = Number<F>;
+
+    fn load_private(
+        &self,
+        mut layouter: impl Layouter<F>,
+        value: Option<F>,
+    ) -> Result<Self::Num, Error> {
+        let config = self.config();
+
+        layouter.assign_region(
+            || "load private",
+            |mut region| {
+                region
+                    .assign_advice(
+                        || "private input",
+                        config.advice[0],
+                        0,
+                        || value.ok_or(Error::Synthesis),
+                    )
+                    .map(Number)
+            },
+        )
+    }
+
+    fn load_constant(
+        &self,
+        mut layouter: impl Layouter<F>,
+        constant: F,
+    ) -> Result<Self::Num, Error> {
+        let config = self.config();
+
+        layouter.assign_region(
+            || "load constant",
+            |mut region| {
+                region
+                    .assign_advice_from_constant(|| "constant value", config.advice[0], 0, constant)
+                    .map(Number)
+            },
+        )
+    }
+
+    fn mul(
+        &self,
+        mut layouter: impl Layouter<F>,
+        a: Self::Num,
+        b: Self::Num,
+    ) -> Result<Self::Num, Error> {
+        let config = self.config();
+
+        layouter.assign_region(
+            || "mul",
+            |mut region: Region<'_, F>| {
+                // We only want to use a single multiplication gate in this region,
+                // so we enable it at region offset 0; this means it will constrain
+                // cells at offsets 0 and 1.
+                config.s_mul.enable(&mut region, 0)?;
+
+                // The inputs we've been given could be located anywhere in the circuit,
+                // but we can only rely on relative offsets inside this region. So we
+                // assign new cells inside the region and constrain them to have the
+                // same values as the inputs.
+                a.0.copy_advice(|| "lhs", &mut region, config.advice[0], 0)?;
+                b.0.copy_advice(|| "rhs", &mut region, config.advice[1], 0)?;
+
+                // Now we can assign the multiplication result, which is to be assigned
+                // into the output position.
+                let value = a.0.value().and_then(|a| b.0.value().map(|b| *a * *b));
+
+                // Finally, we do the assignment to the output, returning a
+                // variable to be used in another part of the circuit.
+                region
+                    .assign_advice(
+                        || "lhs * rhs",
+                        config.advice[0],
+                        1,
+                        || value.ok_or(Error::Synthesis),
+                    )
+                    .map(Number)
+            },
+        )
+    }
+
+    fn add(
+        &self,
+        mut layouter: impl Layouter<F>,
+        a: Self::Num,
+        b: Self::Num,
+    ) -> Result<Self::Num, Error> {
+        let config = self.config();
+
+        layouter.assign_region(
+            || "add",
+            |mut region: Region<'_, F>| {
+                // We only want to use a single multiplication gate in this region
+                // so we enable it at region offset 0; this means it will constrain
+                // cells at offsets 0 and 1.
+                config.s_add.enable(&mut region, 0)?;
+
+                //
+                //The inputs we've been given could be located anywhere in the circuit,
+                // but we can only rely on relative offsets inside this region. So we
+                // assign new cells inside the region and constrain them to have the
+                // same values as the inputs.
+                a.0.copy_advice(|| "lhs", &mut region, config.advice[0], 0)?;
+                b.0.copy_advice(|| "rhs", &mut region, config.advice[1], 0)?;
+
+                // Now we can assign the multiplication result, which is to be assigned
+                // into the output position.
+                let value = a.0.value().and_then(|a| b.0.value().map(|b| *a + *b));
+
+                // Finally, we do the assignment to the output, returning a
+                // variable to be used in another part of the circuit.
+                region
+                    .assign_advice(
+                        || "lhs + rhs",
+                        config.advice[0],
+                        1,
+                        || value.ok_or(Error::Synthesis),
+                    )
+                    .map(Number)
+            },
+        )
+    }
+
+    fn expose_public(
+        &self,
+        mut layouter: impl Layouter<F>,
+        num: Self::Num,
+        row: usize,
+    ) -> Result<(), Error> {
+        let config = self.config();
+
+        layouter.constrain_instance(num.0.cell(), config.instance, row)
+    }
+}
+
+#[derive(Default)]
+struct MyCircuit<F: FieldExt> {
+    constant: F,
+    x:Option<F>,
+}
+
+
+impl<F: FieldExt> Circuit<F> for MyCircuit<F> {
+    // Since we are using a single chip for everything, we can just reuse its config.
+    type Config = FieldConfig;
+    type FloorPlanner = SimpleFloorPlanner;
+
+    fn without_witnesses(&self) -> Self {
+        Self::default()
+    }
+
+    fn configure(meta: &mut ConstraintSystem<F>) -> Self::Config {
+        // We create the two advice columns that FieldChip uses for I/O.
+        let advice = [meta.advice_column(), meta.advice_column()];
+
+        // We also need an instance column to store public inputs.
+        let instance = meta.instance_column();
+
+        // Create a fixed column to load constants.
+        let constant = meta.fixed_column();
+
+        FieldChip::configure(meta, advice, instance, constant)
+    }
+
+    fn synthesize(
+        &self,
+        config: Self::Config,
+        mut layouter: impl Layouter<F>,
+    ) -> Result<(), Error> {
+        let field_chip = FieldChip::<F>::construct(config);
+
+        // Load our private values into the circuit.
+        let x = field_chip.load_private(layouter.namespace(|| "load x"), self.x)?;
+
+        // Load the constant factor into the circuit.
+        let constant = field_chip.load_constant(layouter.namespace(|| "load constant"), self.constant)?;
+
+        let x2 = field_chip.mul(layouter.namespace(|| "x * x"), x.clone(), x.clone())?;
+        let x3 = field_chip.mul(layouter.namespace(|| "x * x * x"), x2, x.clone())?;
+        let x3x = field_chip.add(layouter.namespace(|| " x3+x"), x3.clone(), x.clone())?;
+        let c = field_chip.add(layouter.namespace(|| "x3 + x"), constant, x3x)?;
+
+        // Expose the result as a public input to the circuit.
+        field_chip.expose_public(layouter.namespace(|| "expose c"), c, 0)
+    }
+}
+// ANCHOR_END: circuit
+
+fn main() {
+    use halo2::{dev::MockProver, pasta::Fp};
+
+    let k = 4;
+    let x = Fp::from(3);
+    let constant = Fp::from(5);
+    //let c = x*x*x  - constant; // to be x^3+x-5=30 need to implement addition in the chip
+    let c = x*x*x + x + constant; // * constant; // to be x^3+x-5=30 need to implement addition in the chip
+    let circuit = MyCircuit {
+        constant,
+        x: Some(x),
+    };
+
+    // Arrange the public input. We expose the multiplication result in row 0
+    // of the instance column, so we position it there in our public inputs.
+    let mut public_inputs = vec![c];
+
+    // Given the correct public input, our circuit will verify.
+    let prover = MockProver::run(k, &circuit, vec![public_inputs.clone()]).unwrap();
+    assert_eq!(prover.verify(), Ok(()));
+
+    public_inputs[0]  += Fp::one();
+    let prover = MockProver::run(k, &circuit, vec![public_inputs]).unwrap();
+    assert!(prover.verify().is_err());
+}