diff --git a/tooling/README.md b/tooling/README.md
new file mode 100644
index 00000000..67ac035e
--- /dev/null
+++ b/tooling/README.md
@@ -0,0 +1,10 @@
+
+Plonky2 external tooling
+------------------------
+
+Some experimental tooling to visualize, analyze and debug Plonky2 circuits.
+
+For example using `prove_with_options` you can export the witness and visualize
+it with html/javascript.
+
+
diff --git a/tooling/web/README.md b/tooling/web/README.md
new file mode 100644
index 00000000..d1179fdb
--- /dev/null
+++ b/tooling/web/README.md
@@ -0,0 +1,20 @@
+
+Web based witness visualization
+-------------------------------
+
+### Quickstart
+
+With `node.js`:
+
+ $ npx http-server
+ $ open http://127.0.0.1:8080
+
+Or with `python3`:
+
+ $ python3 -m http.server
+ $ open http://127.0.0.1:8000
+
+### Caching
+
+As web-browser like to cache stuff, for now just use `ctrl-shift-r`
+(or `cmd-shift-r` on mac) to reload the page after changes.
diff --git a/tooling/web/fibonacci_witness.json b/tooling/web/fibonacci_witness.json
new file mode 100644
index 00000000..2f405ca5
--- /dev/null
+++ b/tooling/web/fibonacci_witness.json
@@ -0,0 +1 @@
+{"gates":["ConstantGate:2","PublicInputGate","ArithmeticGate:20","PoseidonGate:12"],"selector_vector":[2,2,2,2,2,3,1,0],"matrix":[[0,6765,102334155,1548008755920,23416728348467685,0,8416658900775745054,0],[1,1,1,1,1,1,12574228347150446423,1],[1,10946,165580141,2504730781961,37889062373143906,3736710860384812976,9629056739760131473,0],[1,17711,267914296,4052739537881,61305790721611591,0,3119289788404190010,0],[1,10946,165580141,2504730781961,37889062373143906,0,0,0],[1,1,1,1,1,0,0,0],[1,17711,267914296,4052739537881,61305790721611591,0,0,0],[2,28657,433494437,6557470319842,99194853094755497,0,0,0],[1,17711,267914296,4052739537881,61305790721611591,0,0,0],[1,1,1,1,1,0,0,0],[2,28657,433494437,6557470319842,99194853094755497,0,0,0],[3,46368,701408733,10610209857723,160500643816367088,0,0,0],[2,28657,433494437,6557470319842,99194853094755497,8416658900775745054,0,0],[1,1,1,1,1,12574228347150446423,0,0],[3,46368,701408733,10610209857723,160500643816367088,9629056739760131473,0,0],[5,75025,1134903170,17167680177565,259695496911122585,3119289788404190010,0,0],[3,46368,701408733,10610209857723,160500643816367088,14861960955103405647,0,0],[1,1,1,1,1,372802127489869527,0,0],[5,75025,1134903170,17167680177565,259695496911122585,17949976003686161308,0,0],[8,121393,1836311903,27777890035288,420196140727489673,1857324986026215171,0,0],[5,75025,1134903170,17167680177565,259695496911122585,5971167677106193079,0,0],[1,1,1,1,1,11693818845587106938,0,0],[8,121393,1836311903,27777890035288,420196140727489673,2069952246609707872,0,0],[13,196418,2971215073,44945570212853,679891637638612258,217879661521314238,0,0],[8,121393,1836311903,27777890035288,420196140727489673,0,0,0],[1,1,1,1,1,0,0,0],[13,196418,2971215073,44945570212853,679891637638612258,0,0,0],[21,317811,4807526976,72723460248141,1100087778366101931,0,0,0],[13,196418,2971215073,44945570212853,679891637638612258,0,0,0],[1,1,1,1,1,10040222711290671429,0,0],[21,317811,4807526976,72723460248141,1100087778366101931,14620731031104971238,0,0],[34,514229,7778742049,117669030460994,1779979416004714189,17044025898016030703,0,0],[21,317811,4807526976,72723460248141,1100087778366101931,7238567237932994928,0,0],[1,1,1,1,1,15906345692884439372,0,0],[34,514229,7778742049,117669030460994,1779979416004714189,5144700563978952905,0,0],[55,832040,12586269025,190392490709135,2880067194370816120,8166204101423404765,0,0],[34,514229,7778742049,117669030460994,1779979416004714189,477486086501229569,0,0],[1,1,1,1,1,9608939408992013865,0,0],[55,832040,12586269025,190392490709135,2880067194370816120,3967372222851101859,0,0],[89,1346269,20365011074,308061521170129,4660046610375530309,6747904536878816765,0,0],[55,832040,12586269025,190392490709135,2880067194370816120,10676707001551177325,0,0],[1,1,1,1,1,15582639502207228120,0,0],[89,1346269,20365011074,308061521170129,4660046610375530309,13686409820604502173,0,0],[144,2178309,32951280099,498454011879264,7540113804746346429,1567790829695590004,0,0],[89,1346269,20365011074,308061521170129,4660046610375530309,17435189342848201979,0,0],[1,1,1,1,1,6880593622141894941,0,0],[144,2178309,32951280099,498454011879264,7540113804746346429,8426833217377909941,0,0],[233,3524578,53316291173,806515533049393,12200160415121876738,1750952861857697999,0,0],[144,2178309,32951280099,498454011879264,7540113804746346429,7363947565712320428,0,0],[1,1,1,1,1,3124824639148633302,0,0],[233,3524578,53316291173,806515533049393,12200160415121876738,9815057002508797666,0,0],[377,5702887,86267571272,1304969544928657,1293530150453638846,8800225758791566091,0,0],[233,3524578,53316291173,806515533049393,12200160415121876738,15770247867912269728,0,0],[1,1,1,1,1,3135653937829880960,0,0],[377,5702887,86267571272,1304969544928657,1293530150453638846,15779646663237235129,0,0],[610,9227465,139583862445,2111485077978050,13493690565575515584,6797675489104882722,0,0],[377,5702887,86267571272,1304969544928657,1293530150453638846,2449041418020548842,0,0],[1,1,1,1,1,7190423305376289408,0,0],[610,9227465,139583862445,2111485077978050,13493690565575515584,17337800908067952557,0,0],[987,14930352,225851433717,3416454622906707,14787220716029154430,5830228614653198906,0,0],[610,9227465,139583862445,2111485077978050,13493690565575515584,8884464056103704513,0,0],[1,1,1,1,1,5363825021791947577,0,0],[987,14930352,225851433717,3416454622906707,14787220716029154430,15220052284474590997,0,0],[1597,24157817,365435296162,5527939700884757,9834167212190085693,8505277843539538987,0,0],[987,14930352,225851433717,3416454622906707,14787220716029154430,9904213084008489739,0,0],[1,1,1,1,1,16267234471440708648,0,0],[1597,24157817,365435296162,5527939700884757,9834167212190085693,7397784185928096775,0,0],[2584,39088169,591286729879,8944394323791464,6174643858804655802,18428755921504058133,0,0],[1597,24157817,365435296162,5527939700884757,9834167212190085693,3337122630204711140,0,0],[1,1,1,1,1,16198616623652854046,0,0],[2584,39088169,591286729879,8944394323791464,6174643858804655802,15666646868790223685,0,0],[4181,63245986,956722026041,14472334024676221,16008811070994741495,8026155603046169528,0,0],[2584,39088169,591286729879,8944394323791464,6174643858804655802,8469751101646333747,0,0],[1,1,1,1,1,9164013103097068803,0,0],[4181,63245986,956722026041,14472334024676221,16008811070994741495,12400986561189304806,0,0],[6765,102334155,1548008755920,23416728348467685,3736710860384812976,16077058258931765567,0,0],[4181,63245986,956722026041,14472334024676221,0,11379947257449814103,0,0],[1,1,1,1,0,15535488051570816465,0,0],[6765,102334155,1548008755920,23416728348467685,0,15881106855513562765,0,0],[10946,165580141,2504730781961,37889062373143906,0,7781013937409781090,0,0],[0,0,0,0,0,1225792993053954782,0,0],[0,0,0,0,0,17643850961762156539,0,0],[0,0,0,0,0,4033881532651059650,0,0],[0,0,0,0,0,10550305237523993157,0,0],[0,0,0,0,0,8184211280336425828,0,0],[0,0,0,0,0,562906072670039007,0,0],[0,0,0,0,0,6362129067496863546,0,0],[0,0,0,0,0,6526337289101062663,0,0],[0,0,0,0,0,6490233936458245575,0,0],[0,0,0,0,0,12891963448702135799,0,0],[0,0,0,0,0,17760427698633916708,0,0],[0,0,0,0,0,6497795749681618804,0,0],[0,0,0,0,0,12827959275124201763,0,0],[0,0,0,0,0,11113378605033148767,0,0],[0,0,0,0,0,6569703523987102558,0,0],[0,0,0,0,0,7995489224595613381,0,0],[0,0,0,0,0,13387871631798397469,0,0],[0,0,0,0,0,10659905477666838737,0,0],[0,0,0,0,0,1840186988953944109,0,0],[0,0,0,0,0,15890763427816250250,0,0],[0,0,0,0,0,1029740517934924290,0,0],[0,0,0,0,0,7078942175277198294,0,0],[0,0,0,0,0,8493243431220293997,0,0],[0,0,0,0,0,15522877625405579026,0,0],[0,0,0,0,0,16496651246651191648,0,0],[0,0,0,0,0,4444069363249625691,0,0],[0,0,0,0,0,14026344929456590691,0,0],[0,0,0,0,0,15722697891119137492,0,0],[0,0,0,0,0,7060126015483727731,0,0],[0,0,0,0,0,10519195180224552510,0,0],[0,0,0,0,0,13821269625316219387,0,0],[0,0,0,0,0,10658689852821575241,0,0],[0,0,0,0,0,2174261422963674768,0,0],[0,0,0,0,0,11010238115484875126,0,0],[0,0,0,0,0,3344493737477086936,0,0],[0,0,0,0,0,3169819264478121565,0,0],[0,0,0,0,0,10548892680228605962,0,0],[0,0,0,0,0,8054855812681440344,0,0],[0,0,0,0,0,2292458712761356147,0,0],[0,0,0,0,0,5641640176540904214,0,0],[0,0,0,0,0,6920691066608171985,0,0],[0,0,0,0,0,14203798936975626124,0,0],[0,0,0,0,0,5973321330466181466,0,0],[0,0,0,0,0,1089446532694553977,0,0],[0,0,0,0,0,8112981925793197878,0,0],[0,0,0,0,0,6317657525109977570,0,0],[0,0,0,0,0,8259326469873680154,0,0],[0,0,0,0,0,18293467284009711799,0,0],[0,0,0,0,0,8616308775836730292,0,0],[0,0,0,0,0,2919873196638644821,0,0],[0,0,0,0,0,3445369750894310746,0,0],[0,0,0,0,0,976214721355428342,0,0],[0,0,0,0,0,4717957757685036884,0,0],[0,0,0,0,0,4723399287518688581,0,0],[0,0,0,0,0,11331936104580144288,0,0]]}
\ No newline at end of file
diff --git a/tooling/web/index.html b/tooling/web/index.html
new file mode 100644
index 00000000..5cfebed7
--- /dev/null
+++ b/tooling/web/index.html
@@ -0,0 +1,76 @@
+
+
+
+
+
+ witness visualizer
+
+
+
+
+
+
+
+
+
+
+
+ Plonky2 witness visualizer
+
+
+ file name:
+
+
+
+
+
+
+
+
+ | index |
+ gate type |
+
+
+
+
+
+
+
+
+ | property | value (hover!) |
+ | row | |
+ | column | |
+ | value | |
+ | gate | |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ratio of non-empty cells:
+
+
+
+
diff --git a/tooling/web/styles.css b/tooling/web/styles.css
new file mode 100644
index 00000000..8cbaa99b
--- /dev/null
+++ b/tooling/web/styles.css
@@ -0,0 +1,17 @@
+table, th, td {
+ border-collapse: collapse;
+ border: 2px solid black;
+ font-family: sans-serif;
+ font-size: 0.8rem;
+ letter-spacing: 1px;
+}
+
+th, td {
+ padding: 5px;
+}
+
+#left, #middle, #right {
+ display: inline-block;
+ *display: inline;
+ vertical-align: top;
+}
\ No newline at end of file
diff --git a/tooling/web/witness_view.js b/tooling/web/witness_view.js
new file mode 100644
index 00000000..d1e5903a
--- /dev/null
+++ b/tooling/web/witness_view.js
@@ -0,0 +1,166 @@
+
+const the_supported_gates =
+ [ "UnknownGate"
+ , "ArithmeticGate"
+ , "ArithmeticExtensionGate"
+ , "BaseSumGate"
+ , "ConstantGate"
+ , "CosetInterpolationGate"
+ , "ExponentiationGate"
+ , "LookupGate"
+ , "LookupTableGate"
+ , "MultiplicationExtensionGate"
+ , "NoopGate"
+ , "PoseidonGate"
+ , "PoseidonMdsGate"
+ , "PublicInputGate"
+ , "RandomAccessGate"
+ , "ReducingGate"
+ , "ReducingExtensionGate"
+ ];
+
+const the_gate_colors =
+ [ "#800000" // UnknownGate -> dark red
+ , "#c0c0c0" // ArithmeticGate -> light grey
+ , "#808080" // ArithmeticExtensionGate -> medium grey
+ , "#60c0c0" // BaseSumGate -> medium cyan
+ , "#f0f080" // ConstantGate -> yellow
+ , "#b0b0f0" // CosetInterpolationGate -> light blue
+ , "#80f080" // ExponentiationGate -> cyan
+ , "#80f080" // LookupGate -> light green
+ , "#60c060" // LookupTableGate -> medium green
+ , "#8080c0" // MultiplicationExtensionGate -> dark blue
+ , "#ffffff" // NoopGate -> white
+ , "#f07070" // PoseidonGate -> light red
+ , "#c06060" // PoseidonMdsGate -> medium red
+ , "#a0ffa0" // PublicInputGate -> ligth green
+ , "#8080f0" // RandomAccessGate -> blue
+ , "#f080f0" // ReducingGate -> light purple
+ , "#c060c0" // ReducingExtensionGate -> medium purple
+ ];
+
+function findGateIndex(gate) {
+ let k = the_supported_gates.indexOf(gate);
+ return ((k<0) ? 0 : k);
+}
+
+function add_table_row(table, idx, text, color) {
+ let tr = document.createElement("tr");
+ tr.style.background = (color)?color:"#fffff";
+
+ let td1 = document.createElement("td"); td1.innerHTML = idx.toString();
+ let td2 = document.createElement("td"); td2.innerHTML = text;
+
+ tr.appendChild(td1);
+ tr.appendChild(td2);
+ table.appendChild(tr);
+}
+
+/*
+function test_fill_gates() {
+ let el = document.getElementById("gates");
+ for(let i=0; i
+ let cell = document.createElementNS("http://www.w3.org/2000/svg", "rect");
+ cell.setAttribute('width' ,10);
+ cell.setAttribute('height',10);
+ cell.setAttribute('x',10*j);
+ cell.setAttribute('y',10*i);
+ cell.setAttribute('style',"stroke-width:1;stroke:black;");
+ cell.setAttribute('fill',col);
+ let hover_call = "cell_hover(" + i.toString() + "," + j.toString() + ")";
+ cell.setAttribute('onmouseover', hover_call );
+ el_svg.appendChild(cell);
+ }
+ }
+
+ el_ratio = document.getElementById("nonempty-ratio");
+ let ratio = Math.round( 100 * (ncells - empty_counter) / ncells);
+ el_ratio.value = ratio.toString() + "%";
+}
+
+function handle_error(res) {
+ if (!res.ok) {
+ throw new Error(`HTTP error! Status: ${res.status}`);
+ }
+ return res.json();
+}
+
+function load_witness(fname) {
+ fetch(fname).then( err => handle_error(err) ).then( data => initialize_from_witness(fname,data) ).catch();
+}
+