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

Revert "removed old crypto stuff from /src and /bin"

This reverts commit 7e9d853cae125e3beb4aaafec96a7d438f6fe4a0.
lunar-mining 4 лет назад
Родитель
Сommit
f50d677612

+ 99 - 0
src/bin/jubjub.rs

@@ -0,0 +1,99 @@
+use bls12_381::Scalar;
+use drk::{BlsStringConversion, Decodable, Encodable, ZkContract, ZkProof};
+use std::fs::File;
+use std::time::Instant;
+
+type Result<T> = std::result::Result<T, failure::Error>;
+
+fn main() -> Result<()> {
+    {
+        // Load the contract from file
+
+        let start = Instant::now();
+        let file = File::open("jubjub.zcd")?;
+        let mut contract = ZkContract::decode(file)?;
+        println!(
+            "Loaded contract '{}': [{:?}]",
+            contract.name,
+            start.elapsed()
+        );
+
+        println!("Stats:");
+        println!("    Constants: {}", contract.vm.constants.len());
+        println!("    Alloc: {}", contract.vm.alloc.len());
+        println!("    Operations: {}", contract.vm.ops.len());
+        println!(
+            "    Constraint Instructions: {}",
+            contract.vm.constraints.len()
+        );
+
+        // Do the trusted setup
+
+        contract.setup("jubjub.zts")?;
+    }
+
+    // Load the contract from file
+
+    let start = Instant::now();
+    let file = File::open("jubjub.zcd")?;
+    let mut contract = ZkContract::decode(file)?;
+    println!(
+        "Loaded contract '{}': [{:?}]",
+        contract.name,
+        start.elapsed()
+    );
+
+    contract.load_setup("jubjub.zts")?;
+
+    {
+        // Put in our input parameters
+
+        contract.set_param(
+            "a_u",
+            Scalar::from_string("15a36d1f0f390d8852a35a8c1908dd87a361ee3fd48fdf77b9819dc82d90607e"),
+        )?;
+        contract.set_param(
+            "a_v",
+            Scalar::from_string("015d8c7f5b43fe33f7891142c001d9251f3abeeb98fad3e87b0dc53c4ebf1891"),
+        )?;
+        contract.set_param(
+            "b_u",
+            Scalar::from_string("15a36d1f0f390d8852a35a8c1908dd87a361ee3fd48fdf77b9819dc82d90607e"),
+        )?;
+        contract.set_param(
+            "b_v",
+            Scalar::from_string("015d8c7f5b43fe33f7891142c001d9251f3abeeb98fad3e87b0dc53c4ebf1891"),
+        )?;
+
+        // Generate the ZK proof
+
+        let proof = contract.prove()?;
+
+        // Test and show our output values
+
+        assert_eq!(proof.public.len(), 2);
+        // 0x66ced46f14e5616d12b993f60a6e66558d6b6afe4c321ed212e0b9cfbd81061a
+        assert_eq!(
+            *proof.public.get("result_u").unwrap(),
+            Scalar::from_string("66ced46f14e5616d12b993f60a6e66558d6b6afe4c321ed212e0b9cfbd81061a")
+        );
+        // 0x4731570fdd57cf280eadc8946fa00df81112502e44e497e794ab9a221f1bcca
+        assert_eq!(
+            *proof.public.get("result_v").unwrap(),
+            Scalar::from_string("04731570fdd57cf280eadc8946fa00df81112502e44e497e794ab9a221f1bcca")
+        );
+        println!("u = {:?}", proof.public.get("result_u").unwrap());
+        println!("v = {:?}", proof.public.get("result_v").unwrap());
+
+        let mut file = File::create("jubjub.prf")?;
+        proof.encode(&mut file)?;
+    }
+
+    // Verify the proof
+
+    let file = File::open("jubjub.prf")?;
+    let proof = ZkProof::decode(file)?;
+    assert!(contract.verify(&proof));
+
+    Ok(())
+}

+ 123 - 0
src/bin/mimc.rs

@@ -0,0 +1,123 @@
+use bls12_381::Scalar;
+use ff::Field;
+use drk::{Decodable, ZkContract};
+use std::fs::File;
+use std::ops::{Add, AddAssign, MulAssign, Neg, SubAssign};
+use std::time::Instant;
+
+type Result<T> = std::result::Result<T, failure::Error>;
+
+mod mimc_constants;
+use mimc_constants::mimc_constants;
+
+const MIMC_ROUNDS: usize = 322;
+
+fn mimc(mut xl: Scalar, mut xr: Scalar, constants: &[Scalar]) -> Scalar {
+    assert_eq!(constants.len(), MIMC_ROUNDS);
+
+    for i in 0..MIMC_ROUNDS {
+        let mut tmp1 = xl;
+        tmp1.add_assign(&constants[i]);
+        let mut tmp2 = tmp1.square();
+        tmp2.mul_assign(&tmp1);
+        tmp2.add_assign(&xr);
+        xr = xl;
+        xl = tmp2;
+    }
+
+    xl
+}
+
+macro_rules! from_slice {
+    ($data:expr, $len:literal) => {{
+        let mut array = [0; $len];
+        // panics if not enough data
+        let bytes = &$data[..array.len()];
+        assert_eq!(bytes.len(), array.len());
+        for (a, b) in array.iter_mut().rev().zip(bytes.iter()) {
+            *a = *b;
+        }
+        //array.copy_from_slice(bytes.iter().rev());
+        array
+    }};
+}
+
+fn main() -> Result<()> {
+    /////////////////////////////////
+    // Initialize our MiMC constants
+    let mut constants = Vec::new();
+    for const_str in mimc_constants() {
+        let bytes = from_slice!(&hex::decode(const_str).unwrap(), 32);
+        assert_eq!(bytes.len(), 32);
+        let constant = Scalar::from_bytes(&bytes).unwrap();
+
+        constants.push(constant);
+    }
+    /////////////////////////////////
+
+    // Load the contract from file
+
+    let start = Instant::now();
+    let file = File::open("mimc.zcd")?;
+    let mut contract = ZkContract::decode(file)?;
+    println!(
+        "Loaded contract '{}': [{:?}]",
+        contract.name,
+        start.elapsed()
+    );
+
+    println!("Stats:");
+    println!("    Constants: {}", contract.vm.constants.len());
+    println!("    Alloc: {}", contract.vm.alloc.len());
+    println!("    Operations: {}", contract.vm.ops.len());
+    println!(
+        "    Constraint Instructions: {}",
+        contract.vm.constraints.len()
+    );
+
+    // Do the trusted setup
+
+    contract.setup("mimc.zts");
+
+    // Put in our input parameters
+
+    let left = Scalar::from_raw([
+        0xb981_9dc8_2d90_607e,
+        0xa361_ee3f_d48f_df77,
+        0x52a3_5a8c_1908_dd87,
+        0x15a3_6d1f_0f39_0d88,
+    ]);
+    let right = Scalar::from_raw([
+        0x7b0d_c53c_4ebf_1891,
+        0x1f3a_beeb_98fa_d3e8,
+        0xf789_1142_c001_d925,
+        0x015d_8c7f_5b43_fe33,
+    ]);
+
+    println!("----> {:?}", left);
+    println!("----> {:?}", right);
+    
+    contract.set_param("left_0", left.clone())?;
+    contract.set_param("right", right.clone())?;
+
+    // Generate the ZK proof
+
+    let proof = contract.prove()?;
+
+    // Test and show our output values
+
+    let mimc_hash = mimc(left, right, &constants);
+    assert_eq!(proof.public.len(), 1);
+    // 0x66ced46f14e5616d12b993f60a6e66558d6b6afe4c321ed212e0b9cfbd81061a
+    assert_eq!(*proof.public.get("hash_result").unwrap(), mimc_hash);
+    println!(
+        "hash result = {:?}",
+        proof.public.get("hash_result").unwrap()
+    );
+
+    // Verify the proof
+
+    assert!(contract.verify(&proof));
+
+    Ok(())
+}

+ 328 - 0
src/bin/mimc_constants.rs

@@ -0,0 +1,328 @@
+pub fn mimc_constants() -> Vec<&'static str> {
+    vec![
+        "4699afdd3f9ce9916eaffcfbef597c5009ae9d3209c3b15feb6928a4a8d4b59e",
+        "41e2431761fee4a40b468524d91b3d64590b3c242de10d18f55f0c5e3883ef02",
+        "5a04a1ea758bf1cc1140fcec1ce2c9d68da53d6cf7ee8dfeedfb2ee45db08c27",
+        "2e4b930078e93e73581d7b71120a8e8b9627955a0aabf139bbfa5feceaab2e3b",
+        "6a9db69e4fd0a3f94402cf22076bd18300c344c69bf665542129ad887f0030ab",
+        "4458f2de4e16ce2ead3fe9dd164cca36d2b70a25e71f55cf0c51ca553a4f83ad",
+        "04f539ab6ea2d344049219c720a16c4e6033f8360b124519fdbb6d441428143b",
+        "6b9c7b12a4b3cf92e2f2b386426058709573f9abdf1bcc5411dacd7ea0eaf8f3",
+        "4375e3120921697155b3ea15c32b9412adce3a8ff8e28e1b8c95935cc71ad853",
+        "041854bb643e9e5e5d8aa6e828dc4c732c8fa24192a160f40da85737372c5d0c",
+        "65d9cc7ab2a2060d198d66310a902bddeeb7f5150173190036d2fae68de1c2b9",
+        "1e7d2b472c6a40254a228b0543aff318084e7f6152617a6cf7fc405d917bfc37",
+        "35293381012ebaf649d8c6db4e4d5e594bd114c99c234ddff7b9b5f6f8a9ec36",
+        "3a50794418ac54a1467578ed61e34d8be5d52c5f188f42955fe8d5e257ad3e89",
+        "446d905f60110dbd51129896a63a0e34bb0502101ad6311998ad2dfd74818277",
+        "3eee70356bab144c54b5fc1095f9bce59c727a57a5582dcbbd5c3afc3c61ceca",
+        "40b08ae056833e12c82f7e15e2dc72febc15d3275b51ec70afaffa6ce8bbb3d0",
+        "205923e6eb137869a552b4857bb64f946c912f3335a94291ebb8b29ecd3e6034",
+        "2a6aebced756f7e33c466bca2169ba24c471a088c8363fe0a966a223fd3b59ea",
+        "566efaf4e022036a8e073fd9812376888ac9f37c794daebe3fa77b1a87bf109e",
+        "1ee814f2660e7272712d588477e458c06f8f06950402e97c542d3682ad5f9aed",
+        "257fe0ace4965622be247dba9185f108707f4ab16c910c03c565afab43b0fb4f",
+        "43e156f0cad02ff6b763645c97663ab72229bb0a34f975681359797ccd58093c",
+        "317f43b78cc26f0332a3ec3ec187332d4de0f2baf04f62fe76bee9b11256130b",
+        "076ca6cd23830e3b3ece767b774e1b2243408098a7c5b816e7c616cb88f6b916",
+        "14e30a644f034c72cf40b1bc790200c2e8ab3e750e38f3fb0160188e817e4560",
+        "02eb02bfbac795a497a0882d66b718bb23de64f9fe7644179ddd3241cc407942",
+        "644f175cf6f2268d451e5188e467c508bc91d870646de9297911be2aedf26daf",
+        "14aef8f4f5499a0387e521a1c6064094590f149c52fb99e37b583434ca6bd46c",
+        "2ddc7c6bba8895913f3deee128bc63b5e34797274de80da775c4a0c810ac60e6",
+        "46adc33428a63a20459699183272b14797a5a7d1d66079701d214bced9a4be71",
+        "552847d9a2a5b03f726b277ba01ad61c0e28114667e7a9e11229b83224f74349",
+        "624921e44f5811f76c06ab74a11ad56e5241e4c597e9d172ee3c862bf6d4b1fd",
+        "506af906fab5f9407ee71824d72dfcd99115c5a2eb53b55a1d5877910a645282",
+        "514ddde7e75b27ae6f31efb7375bc209dcdd0ab4c277ee0f8b362cb5211def31",
+        "2e3be2e2a10f8e24b411902d9578d44e2a4a5042036ecc397e1cc5ab88e76329",
+        "61755a2f6a9729a3bd8d21aea98f4cf885aa1751a714e251a517395711674bf5",
+        "68f8f91713d81c2a6d601411447e944c27f7a1862855b940ef3521cbf4074e96",
+        "32e6b3dfaa0162846620ace97838a93f48999b5bbc078964687c795a9e5b71a0",
+        "3c783bf0caa35bd381603b9e3aa5dbcc4ed4fc93b03d69a49fa15286a6374f8d",
+        "4a3f322f033de27244d79dd5c6c2f34d84c24c917ce95cfb6458d72124280e70",
+        "3ee0abb7af79168e05566994017fade2d69bdb55c4253f996362b73d49f3f70e",
+        "15498a06e80c6060320e9a01292ee1a805c2aafd7b92f76b5f5e8be515e0a3b3",
+        "02424410de65455350831f5b1c3554626f6bbf373ed0f627b42f0d3ec2fdd487",
+        "5886da407f6014665272b45d213cb388987503398d407732f278c9a35267622d",
+        "15f6180f287d2ef5d9d057dc18eb7df732d97632bfb31e93ac065dcf0c67fd40",
+        "65f5dc85c9660f184a09ee768ae9af0f62911af31920d3b5c49ac0360d261441",
+        "65751a6bbccb0ea7fd79fe7231d03d2f14ec6a24c5d9c4a77d1a86acf3d027a9",
+        "4c21c6990442cb96b2ca684c9d427dc41090447248378f50b4de15b616f1f133",
+        "34cde97ef5c2459e29dbad8324fbefa5097f744f737cc59ad2681e49dfa43f99",
+        "5df3e3787510f9e2b32beb2fdf76fc6d646b3fb94d4ede65309762fc515ffb55",
+        "30394778b396dd8191e78cb7627636eb82b15b0de788c1e2db2788b05caedd8b",
+        "695a64cc6953c658f40c1c2666715790410e302d3d902fcb809924896c2d1f4e",
+        "6a4fe5863990f4b4d588841b0e52c4dc7a8c4644edfec7c721ab66b162ec5de9",
+        "62e4428cb1856ae809589806e5e7869ab0fb818d6c0a696d94ee616fe549400e",
+        "0b1e8a6d6581c13b6888d0bd9816bda3695f917d03510d9b42452f3501e3d55a",
+        "5e5a2b767f853d0f0bf0e3cae872fb942065db112cb48a12dbce3ce4da28aa87",
+        "2c1c59e21a9741edbaf1e5a275c573bbeb395c6a79abdd0e532e000298dc8c00",
+        "25d648572388935cac47095b4f38b3ebe6519766a0d03bf7de9b4368b7bc1b58",
+        "475a00fdc58c8a7092cae8942af520dd5e0f476dc469f0c3e908da68be55e6ff",
+        "3fe62baf8e0a5286b0055e16e712ad06d233fa71fb374557d4c3d585e33dd37b",
+        "54d74923f593c55659f92b34bf5c05a400187e143850173786c8a1dd2f3a1283",
+        "6aa3afe84262b6c5bc8994a2c0e66a64a534904efcf47ead067fa09cd2d58a6a",
+        "2069d079cd963cec28ccac413172576ace57da0b4ab502c11289fff6ff2de6eb",
+        "364b3a05a8b1271aa61d5894b51a445c5896e86a535869b70e56e1e0f7f49f42",
+        "1c904753197233afda76661025e67f6a8e7a5c209292e151a7f34119397c281f",
+        "45f6d1ed8bc4395ccc6cfc90a1cf5f636248e966d82d040d795014f5d184b3ac",
+        "1bdbb396d84fe4c8b5b230e1c925e9f0f5f88faea9b713b319c7c11c307cbdbe",
+        "347c35497a65e93d8f4ec06c1546991841fd680868e145849195e38ef783d1a4",
+        "1d9c23cb0d4a20c384d629c6e706ebaf12fe0fc4eb0860c8175e687742e941cc",
+        "59378cc30bc5948d66a6f1671e84e2e9ef342e0e3dd682015d93f96a68159f3a",
+        "59992c34faff2238e03be3d6e87086a427e6eef2c5647a690363a9ddc0c82d67",
+        "60b13d9cae9b2504ca982c50b14ee5a628d40832bab95108e6640b9a8ef8a853",
+        "4cea35b5ebf7d7956c0c592d4238051c37bdb8bcb4c08fa29239ffaff00793bf",
+        "25344d0db88e9df26d216c287ddc36a958ba1e4d4c05a9cd59715de870d47e36",
+        "19a1c0a1f3aa80db57b014a2dad65eecf645fcd442a09b97e78d044a50ba58c3",
+        "32a6b9ba275d0204fd0e3de5fed3eac823aa8ce0ef5eca627fe92030e4506fe3",
+        "4e4f1056e9e3b8861117ba8bba1a1c37e784ef9e1358473aa55156e3b1523dff",
+        "710f51f9f3866ab261df0fad6ad3986f75d9990bf7776f4e4775f9c8f95045c2",
+        "48623d21c816d6a47a6339d9bda7ff31f2b32b8491c72967b93f2734ec37f64d",
+        "69aae3a126e0625c52d05e8c98ea912f56a582419cef7f13f31be66ec14bd43c",
+        "2f7264fc97a0ff9188c506d5df4bf3d4f28cb1d12fa2767e18d023f8a7e907b0",
+        "54bf8632b89211a06bbf9c0ee5ba2328b1f2cbc1892b76282599c0fb432d761d",
+        "0deb44dd3e20b34cfb473944f4f8f07b4d337da0fc18021777c983bf3e4e7f44",
+        "37a108a7b9e612231e21f0b4c7186163e3cc59325cbb17a39e1e25b4c4345dba",
+        "317515ddac6dcb33a4ac68d4c02c6d93d147b61cd892474292258ebceaf5ce83",
+        "38e225b4f524fa89f414976687473eb4c5f3edfe983dbdd07d3e8486f3b93c0a",
+        "636b27e505a14fb8362beb2e436582db991e3089e6edaeb9aaba3d67f58c8c60",
+        "28fd1afb8cf1e9c7594b5b8d6b50ff1f81aa19f211c5c271f2181836158bb625",
+        "1a8cf4f8569d80ca7d878d7a76d959956ac5e7edb37fbcfd2f5d130e3841dbc0",
+        "2cfbffcc25a0a01ab7cd1e700030d0e363ac170dd000397fa83d107a6d12bd54",
+        "325355d6824f71f550b102c6fa6c8c129de58d325174c5981c562e606a58c55f",
+        "1716f66b4ad2388a23ce111dd5ff7c04d4478dd81930050fdf0c4a90fcd6d381",
+        "02992cefec8ee9bef9602858d51c87a2c4180d9fe0c02e6c6003531010793572",
+        "2132b3fd309dd69a9f3c39b450534d857721dd5a2bcb23b479a29b08e8f8551e",
+        "369986658b8e7e4f990fd6fc09b99a056d81ee47c7a9e46b4109d8af0956678c",
+        "25e00309f0c3097a6500df9ed5587ec128b20a97379814b4a0522f7e775a4548",
+        "529a8ecdddfb500c68b664f7303dad768da802c29a933801b2199cf74a3470f5",
+        "3cf98a6dc8290785ede38da9455dbd28a64a1bda35a48d6c6b1b35ba6df3268b",
+        "127401f379aa992d492782910baee0fb331b3e9c1a66492c9b002a37999f356a",
+        "449dabe3e12e7b495e0421de157acbd4b3852cb824bba7171c8e3da565e3f95e",
+        "410d1d4fb041736101f5468ebdfd9380f2066593534339bc419f35d530c92cd7",
+        "09747f87db187d67e7881e1b64345754ec9bc9ec353e9b055bc377f1618ef17e",
+        "5fec471449175525c56b18200dd8ab96b2f9ee383849545628f0ceff76f631d8",
+        "0c7e402c723170d5dc5f15e229f4bacc5eb50b34dbfb6129215ee662288e159c",
+        "158896654586f5c3a34808ef7ab93def61fc9257d5b7631ed6869259a45d1d01",
+        "57ab3eab90ec38cfb23625e7110948e4b56e38a1ccc2cfffc344876d28aceddd",
+        "08d08f8650f5ca7bf03aad9a80ae09c697327a131827a9c2aec67d1d9f58064e",
+        "273607089f1e9c2b99812e032dfb62c359438c76556a15692a3de02b8c13df4d",
+        "55bf5cd5a1a89d7e3d1d274cc5b1b765e42a9eab5cfd32148c1633550ecfffce",
+        "5c4f6e0acb889fbb573583767535e95bc537641769c35063c0bd3a65812ade57",
+        "581faa1d0a57ef947001fd8e57eee26e645d15eebedb7ebb1d85581968544ca6",
+        "48b77ab45f5fb6d615bd759a6661097bb8a3b5c27ba35f1b127d2ee12f043bc4",
+        "590618389009da43c679b6254ae4cc86dbfa397981f4dff30e064e07bfdc9eab",
+        "3ef9bd95ccaa3c577ab98d3fad87fe69953bbbba6c8bbca0301a6c88e9bed8e6",
+        "2bc1dd87795feb2a5e8d98759371592ba7147ee4c2a3473d18c496ebe3721216",
+        "620ba5be31e353f1f3c72a4380f32c016f0746f5446f9e1743fb01fe6994051e",
+        "151d0bcf972db311553ef8da672b1c861d118e9b78da632d24c49d4a0fa177b7",
+        "01f1bda7ed65ad241d6fa13d8c5cb40cc335a0b2a31b433f2c65cb01e8dad5bc",
+        "4aec58578fdfd5e59d18063bdcc69086dae303518f5155facdc2824878862c53",
+        "1ca2d39cd13b6c690faf2be3da4d4517e28244fbf9ca0f8f4d80565205fb86f2",
+        "72432f39b454d6457ffae81f2e843df03c1526920384c50136beca0627f9054a",
+        "1910c2e6bb35a12e22ec46cd0db6185f352bf3581cf46d2f9c494daf8d94b993",
+        "4e47d6f9080e682d34ae07d5886c29869d16324c468782bea9c62334b583251f",
+        "3240024a0dd08da0c135caf8114ea8d333ab181e94a3a01edabb760a64adcee4",
+        "1669aabbd01c4541575f150981af0cf9a196e0b98908af53ea14b81734ecce5a",
+        "316aa08fd611919a73b60dc2b3175b3843f17035d71b9edf2f72c32850629574",
+        "4919d1e48c28eb1d36a689d8a5826c4ae4cd4e84a8347a9c9238b825a0b53a8e",
+        "4572211d4d1c8257d142ff2335eea65ccbf3177a982fed00931410f3bdf08c19",
+        "5d2d04f110bb9a50adf25427b232870f2be2307685f19df47f9b2f1bae984a04",
+        "472609c977c6854de75985c9154f70a7fda1843a38f10dd4985ab8dc353ad5a7",
+        "5c2ba4f8bec80b52e65afbe7b2ff41ad73542275e40acba8730403e9e33c7697",
+        "267614d22d526f429346fb2e9dcc4930880971780e85ef44a199feabe2b48227",
+        "1110d3da8ece3e4eda99c2d63f6724779af505b9527f0b191b34b5bfabbf5584",
+        "68fc77023c046909572d302630c6508922cbc03e6c6d9a05108bc8db71e045ff",
+        "1b6630a5ab959106f3951689fcbc6a757c97511d08a3d4652b8ee7eab820d575",
+        "2e34a9c19201971c6cffc366e7955b33d0b7dc59fbaf87cadeb8d0c099cfb541",
+        "060bd11957a053af7aec4b2c2caf7e227512d9e856552e5cf6f4ed4b04753bec",
+        "0d8a6987303d76b12f97eaeacfd783401ffef6ac2e994182eaa93843300385ae",
+        "0e9b15bfa73141c59edc9d11ec4ee316525ba53c4b91e4f1a8adb8d372e91dff",
+        "55215d958a6afccf90247026efb61dd9bae318cd31ad27746b227de8873add8c",
+        "4ccb674b94da03efd3404a424a422d42fd4f3a8b9f73de3aa7377e728400e797",
+        "256f31bdb0e0cad47ec44da9bdd1fc146d0284f1d71c596e12b0c690e202d1c4",
+        "60797d9977e8cf8484240c0ac4d3703818c096db8d61ca640bab83ea4e675919",
+        "57fd867a56f6fba130d5cd80d1aa2562ca3bdb6956892c0f66e8d9bbe1fe49e7",
+        "09115f248d518063beb8d89c11115a6b53ac2927b2eeb0c50b50b3e82c314e5e",
+        "6a10f8ecb4e14465b19148ae366be2452b809596eec80f4913a2240e5e89c98d",
+        "0399008978536884058e8b36c86b622d5da6cde04ceabb591fe8057153f6c7b2",
+        "2c7ba50ad84ce603d8206950a09277dbf59da814c5b5119763a208953d946812",
+        "02a697c90f23766d5fde4b61101665b865375243f1bde57522bcb4bcda33804d",
+        "3bba46c732127685e3a7c6963ec063f961bfa23dce70af06fbbdba02d295aa8a",
+        "206c47de6dfd8600586a42f98aea1284742671c605e7a274a306e188015e031d",
+        "608a94a91f8e4e1b0adf94c1af4992b0176fc84d8d79b881ec02d2613f4d9083",
+        "28f906b6e3e6d01ac90251789b81001bb5d96ec2f55be04354b37bd7211c8731",
+        "25c66f7f7c9db885d9f7d7b64bd555f7e2e939878a6f1f1056c0c5af008949a7",
+        "4992f08ef5816859cd16e02a367e55fb073cc08ba19fce061e83288caba6e308",
+        "432fd05cdbd6ce762396cc6b88f6db33f0e6daa1e4faf602a599575fe797979d",
+        "4961bcdf4ad6da150ed71fe78f84c9faaa28e63e378af83aedd33870e337c362",
+        "4d1025421a43054ecb8eab1d4ed666a8cfc7b3e1d3f5243bd945032b7ae19a1b",
+        "0eb68c99851461def5baf569dff154f8ac4591e8ad194f641dc5fcfbc157c07d",
+        "256cd6ef41e108838bc52d51af281be02ad6c5d2a3e6f49f2cb864bcf2397447",
+        "0df82b76b04d8813711f92ed2bc6dda5f32e4778b5f1b328bd3b2a3b82928645",
+        "73397a58cf55ae9d2b14647125725f053dc0a9d5d5599f67955b8b8ceb8c43d8",
+        "352a6762b6764cd234a5e7e24e1beaed50618b691be9e40d4b15813d6023439a",
+        "4ebe36c93f3561edd31170f6775e38889598f0b40a3a2967882b60c6bcf8d6f6",
+        "4af798462ebca10935795dcb09770d98e2a93bc25a99af876c1f080fdf04047e",
+        "6f9acbad33e5d972376f1f67457fb5565582c0cc233006fe51942c48479a3c9f",
+        "395558ce9453ad4999a1d87585bc88b08731882ae0ffbbec886db1cc3fc7ee62",
+        "17b48a7db220b2b4e4a3e9139168f050056e71049e4080ded3949222d3915dd2",
+        "13266faaffcb6e011f73a4065bb1f7bdc373571d1b9c0210674f4f9d18cdbf3f",
+        "0edbbed85597c4beb59685811f7f3c0ce807083c032e6c71e5869004bb37c93d",
+        "64a7409e0e833df31fb574e1c12f764ecf0e3d335cc53afcdc22ac13d7a81da8",
+        "730fbba0d85d06eabf3f517d4826457bacb2fa8c2f24168c1b026ada9eca5bf5",
+        "1ffdde6d216f269f8d25efca3b28590416ea7340d92df2c02d111e30302ba020",
+        "6551f0ba88e2b256f61e052c2ed98e5253fb7791614da7f7f10f9db1dbace96f",
+        "5a40abaaa2542543cd1710bab187798b01f6c7d93395e3a1cdaed5b8866018e9",
+        "7021fa2631484663ef5e14124c49b3078b460d77c9972b9f3aa8fe7bed79bed6",
+        "28e1b47a74ed1328c9cf0188bcce0e6bc8e32d808ad91d62d747382141e7c439",
+        "267bb1817a59e83c9cb67f740cb31fccde2ae0f6dc49745f826267f78136bc5a",
+        "6f2a6bdaf2152c1368e51b4d1ae3ce48bb8a62e00d92f2f9f21393c691243aee",
+        "00cd4b3d36b639b44a828c3dfe8e8da68a7cccaf7063fa92877683c0e5080869",
+        "3e8e056dee60929e925fdcd2395a9959202ef71b82a638fd1e3decba9051d016",
+        "651baeb3fea106c59cefec6a9c8973347a481a75b04f547d8d2f63a1ced57161",
+        "1e6ea48da02249378957d446d9603e4a1e0efd343426933d0cf5a1400148f654",
+        "5eb2faa76b282614614ae97db1e0bb722146ac8230739cf9abb35058ae7f6363",
+        "6400a9ba34a8ce081b7755a5241338c78c10c07ff6cc97ac94f29b23775922f3",
+        "5c475b1284568d5c55fae4840fd5bf9b9f8041fb4c75f3fd902681d97d4b09d2",
+        "037e3fa79fcab75541fe4ceed6404d2a89228694646835e0422fb558477fb128",
+        "39186a11b8693a21684796f4dd227523ac2782d6d23330d8287d77e19f106923",
+        "44b4264d680b2bfa7081436798dce5bc3b20bedf250dfb2103abdde5b3f24eb2",
+        "01fd3211afd7ab17103dd5a181b91982d83e69f9df9568ed132db65c23bfba2d",
+        "66bd19f66bf63ef557cd87c638d6a97f2853a284307ff04392e61b7a68e56b12",
+        "09e3ea8c3c87110454cb0045179ac850f74285652c6854351682cd1706b54f88",
+        "22b7ffce8814457850e403085d0f725dc72396144565f4542d5bf826f4627106",
+        "255b1285cd235b83bbdc8032f637a74bc8b33a798e2751969ebe67c593b578bb",
+        "5b568413938daa1acec17d776af723451fc067e63ed8a24d58cefc27ef7feca9",
+        "4fc38e950b447f3040484e58a7d106386da69400c9292640014886e33eb7596f",
+        "044e95a76627fade400c813061a56bd38ae137734ac1b7b11fce4a12eed6bb68",
+        "129d3939b05352392ee46921665e027d3cb9c9857f0b2f161bb1f0fdd58a74bf",
+        "327b98a9fc847d6b6d54a175aaed3678172d615d37cf1c4448c9d4588a2eb7c7",
+        "63675e996ad78bc6725b923b4cbeacf40f7d4b85bf38fd8b5ed0f63424779ab5",
+        "7374af204d7432c7954dbbd12ed973b79fd0a6d7109061ffd10ecb2f6942d5fd",
+        "0fdf70b408b29ce4bb3ef9a02c333ba7789fffbf2b17dc2ef4dce8714ada06a8",
+        "4373b306976a59fbd07f82bb44c4ee4e4a11806801960c5c18f32f7679321d3c",
+        "1b218fbc57953d8d44ab45c19993b223939a121a1e6bf87b4ca549e06699880a",
+        "09b95f647fc4e11ed6a4757be6287d3f4d6bbdc6da8173da072d7a5d046862b1",
+        "1def7155ba82eebd07611e2dd694a49dac9085004c1b4e9de2b4f0bf40c063fd",
+        "38921799f2fae22e5dc387e3b63a8d4d2210ad60690f61cce190bad2a304c035",
+        "2cfc11979ac028eea6636015cd2241a9ca2b9256bcdbae2f89df853751f63589",
+        "21e602b39eade2ce622e3da4c76124a5f9b2580296037a33f88044895aa8562c",
+        "25c9a818e3691a8d36cc881eed8513110fbcd2c855270ae265cc4a53283e2f4e",
+        "6d17e4bdef0620c74ce13ee9b219e49bf2c8ac57cb1882bca03c64ec7c7c69fc",
+        "2285fe01b02e1cb4331c2e86272f10d7e7daeac3d368b914e9115d832aab4e12",
+        "3fb801cc1a5264babd7f35a65091d15eb9b47a6f06ab9422defafaee4cd35a84",
+        "5b2ae60ec46971d3b3535743c3ab4d99f07ee2f551bfb2212ecfc7120169c8eb",
+        "5322e28426199923aab00dcb5aa2c0c92690628e69ddbeaa8a9e0b92e4d84aa4",
+        "1db225ddf28a651a6f809533078dfc8a006d4b76b59afde3d3356c7f26bf1ac2",
+        "600fcc0f370b76ed88186364efc8d0435ba4efe84abd6b2573e87e213cb405dc",
+        "007c21ae6a4471fb33141d353cb73f3769ee63d78cbc5d7e6a8c1bdb7cf3eb4f",
+        "17520db9848586770ced86adfca305209a0884592720f70eb91f9e3a22c23a94",
+        "3db8aeed94f87b37fc9cfee7a7c027605bec03af4965b840a8942b89fef39ecf",
+        "10b3102359b66388bf079dd2f30d8131ec4da41bf159fae392838a9708e1cfc9",
+        "0c9f537a5a0efc930019893a3fbd46c5e2a85b78b22b4bb60c0c1ec2da334a07",
+        "165f9cb0313efaf5a0636141f39c3ff22089c0f9c494ebc40e9e8060b84f149f",
+        "001879a49e2e539bf9e9c713416f517ee14f6e510a9cafb9a321fef9ca23ed49",
+        "32e53a1e65305675144ebd5bb49bdcf81879daab30fff361eba5cfef952184a3",
+        "51b4edb20a2bbb2daf144d4ab3b72a5a4cc956d9bd9e2ba5017c2163928118c3",
+        "140c9db4c384a0e3757a41ae5005b2557148cb3c190ab7101059053039d655ed",
+        "1737e47c806e74be09d8f7daf7c9d12ede33929f5152eda6c8c008064cfc1be3",
+        "23f3501123499df44f5cd31b08fa1338be61194a023c9101a41ce7518acddcdd",
+        "68dcbacbeb6727e3b47ef3a6291421496a78d81a645f2451c2cd89818715329b",
+        "2f1dd4d3ce3e7b49d67a4bca9ba8b5b64ee37a20496ddbc302aa8c1bed9b2fbf",
+        "2b5427a54294793e926c0ed030eff8b5020801ae8a46b1d7cecc49d01d2cd4a1",
+        "1bcdebbdce2545485d5db25d9776f7bdc31dc799c61cb726e20e0071e939e4c4",
+        "6021616995863e2b6fb9015892f2f361b60656bf1998239aa471d4c698564e9f",
+        "4816704f77b55fba8188d9424143ffd7b015587467072992b2482e9bacd4f072",
+        "60aad5cbecde71eae3fb3e8355137d5890f2947227093bacd23291a731720e79",
+        "5bff651adb907adde66b4a4810173bb8cc0cc618e6698e236979750865b68466",
+        "4dc639d5986ad912fc2632704ad03b039c6982fccad820b16ce2e519de54dcb0",
+        "1780c0f66f7afefb6b32a019956b2a209224b9eeba8a643a222f7355214be300",
+        "6d23740f70b21671e66d9bb35d7387b017dd56c78b65973db44e5479567c27a0",
+        "1784ada0fe2211721dff5b63c46ddbd0cc2a7161e42f24b26b10cf0a807398c9",
+        "3721b5cbdc714dc02db737a41bac0ad9dfd640229e4ef73c780f2abc7907a101",
+        "6777e0e8612172897bde7e5e4d7edafdfac32f855d07b645ef0a2c2b6815d7bd",
+        "5430480105f06250a915e429d5436268eeff94a54606848883d84eece231db3a",
+        "5b06f0578c8e419abaf9365b1e0e4605a270d831b886b1310c2b30830f70aa05",
+        "064faf1daa9415f3bf666dccf10e96a660e3c3e08945cecfad74bcf656a09b63",
+        "5a7cf453cdc309e004ac0d4b161686c9497ddd5333302ce1ac689d3cd3f15fe8",
+        "3d1cdaba6330736b0b9c17a27d3f31b58ea7b0aa1a46faa5cbc191faef9e41ef",
+        "59c894b434302a88c78f3438263ff4a3f82f27af2f086958497b75ba9ede3267",
+        "4f96eab2814accfe7cc529624df63fd4d9d3932ecace112a52d488ebd64f86a9",
+        "5c3395a99f651f587c1e9f88fb32ffde50f312874219daec0f67f604ba56f55a",
+        "10bc86369a85dae2cbcb60d1a110675555b1f29f01af909d0b0a452fd6f8aa0a",
+        "025c11c9d5846be858ed85b2706718d0859b14b5e6afafc50e5b7cab9390e88d",
+        "6a0df7099df32bbf845516682d8b2c40d5b238bab4493508146ec7da5280b31d",
+        "15dee1455b9289a97a4fb4561cd05cc4eaac7f45e2098e6db369c4e38780a898",
+        "6b00cd849365b050f85b3bcb73dc91ae063ed60360b053ccecd4ea226f5d3480",
+        "36ba01e51f6cce897b12718e2947d0ded1b43f1ad65045d9e80792cc0d2afbcf",
+        "705ec3f8f1bdd15381e69d0241b37349e11963b509f73dde27e4d00f7173e9d2",
+        "00259c2c2a277983602c80547343f0037a7a3c7edfdf98a1ffd16bea20204aa2",
+        "07ba65993dc66a3359f96e202f8408f9367d24e37a83164c622f682ef4d113d0",
+        "56324ef5c5a36793bc76d0c2a38e6ae35916ab04bc072325036d9e832981518d",
+        "3cdc6e8fc9101d4e6be6b5fb368a3911ac13c4090ea7da9f345cd5f7ae7b1e6c",
+        "3fe62a321b08da7f8f6cd2080867b98b6c9f54bf910bac77db5a71da68b18270",
+        "53915ca5503403181327eea9143a99782e31f1636a324a946882376fb9d07681",
+        "45ec1e9c297bdd973aec556197b1168f8a55b0d7bb0519b5db479f95d11cd045",
+        "7310ab366f789b5264f16fd563b6dd31462f3e352a92fbb5e2357a9fbb9a1f16",
+        "739ebe2484fabba7b18d7f3a213bb9d3bb2d78a8c05f41515aa20533b933cc2e",
+        "048f8d7f23612a95c09d90137f7a4d87e340a1e83ec3c94284d6784ea8006423",
+        "49a59faf4bbf57ee29b5e186bb0008a4ec74c8fdb7ea8fe7e1aa46bc40873b50",
+        "5cf260d13f5da4870855a40e71d4effda202f310a955db2d140e9317e4238998",
+        "38c2eba027b51ab146dc61e33b7403789b63641a5cba018829e3dfc9336cbcb8",
+        "1f90a83ada4e0d548c8beea8f902f4bdd8466948161fe2760a0127f44a0edea8",
+        "6b65cc39e2d766f83e8f6f59fd5e40290bf8b887c99da8c166417d5a9cae1444",
+        "1da9f1f317f97e9c6132dc6808def44d32daa0c2dbcffe580d8f35b85400ccc3",
+        "3df94f558d1e935080d48183a3e742f6be2992f5aea51387f01c90219e980fa2",
+        "59974c89246e978cbee6e84478252843235f550eb7ba45324d4a7ea572ca7e2b",
+        "094be891b94edbc55530775ac31dd8f5ac0d1e2462579c158ce2f28843a2e9b2",
+        "02c997879aff55f85e9e19e36a32758b868a0504ff0cb4a704fabdb897f308bd",
+        "090a6946efff80828d498845e43aebaf02f19cc8a5459db7b12952e4924e1fd1",
+        "3cf7d767a121eb81462c2731ee18da4f5579e007ed7e198ed9c74d0e4122d247",
+        "4dafcb7ed415b248c5f169092d29b0f5d213e599e2bf15ade507d9ae2c9d764d",
+        "5204fb985e7a86bb77fd705bf71787c4a09b97e7729318e6828a422f70aabcea",
+        "0e1b38375d5ded933a6c9d7512ade1e96679651be670f381f875dd62c7279827",
+        "6b612638db66a469241a60b7222956ca0364f2d77ea8849aeb99fad2a0b5637f",
+        "3626c1544bd18d8a9bde32d6210aa6179839b1ebefb87fdb914d3735db50f92e",
+        "222fd118f0cc69ef015f43fdd95a4db3fc08eec734f4cd3fce78e73348373e03",
+        "369885b7348e2be8c21dce937e248cc6c390c703a09dddbb88b39bbfb3fa2943",
+        "0794753806f2502ff43f7b8c4990e446c37677a49f78e0a8e38622a23c34eb60",
+        "4b9b69b8b54c2ba38a23c409263b2ea543ba2082b6fded12c3c9b9dc754c4202",
+        "06fae323404cc19a099fb298803a76737720c25913e21f38a75f1c8e63a96b9c",
+        "50461e3977f12ec2de486071fc3924cd1aef82a6bc9fbde215eaddee6780de1d",
+        "5ff12618767830d17a759dadc62c40221cc848ef84da8cd91b76e5ca59ccaa37",
+        "6b7bdeac8d4dc989219510a928aa2e2a8995f4aba16e9f59d85e88ae3f6f5f5f",
+        "5fbc48469f2e94eaee4ce3cc7af5c45f27a6532f0b7d8aaad76e61091a319ecd",
+        "024ec0f964b1ce01b08352c231662c238c623cd66a2da4ef330debc7323dba8e",
+        "0dfd978f5c1e804bd89e9d579edb44c49335296cd5948420d7650775cf88fc0c",
+        "57ecafcf80a257780a9bbac3793c3e772fde0c88d6ce8e39399c7eb0a7e76d6a",
+        "705b423e84afdccba45b0286397d1a29896cc1dc3fb41721e9e14942a2c13db6",
+        "61efd69d156931b397d7aebd87d6c7599f6a5e2925cb7d8891fd751b7757c486",
+        "5b0a8e0bc9d55850e65cb119b6b43abd5eda13de38ffd6e45130a6b2c7184251",
+        "2ee9eb134a2f83e93bb4b09c71da3e7810d9a2bd01acaacf70fc7b43ccc2fec6",
+        "136a3734420b9a29249f23e3292d871653540c3a86fdfbdbb655596aac99d0ce",
+        "11ea5a840d53c0f0eaa111e6f43d953cdadcddedd8b7658d82266fd0897cd71a",
+        "51a4d6a93c09813a72f272b043ef5cf88fe27eeadb2065cb75c95620874ea281",
+        "00b698d1b30b8486b7fb7cafdae54bb93ac182be3623f1feffa7edc12486d4e8",
+        "22386f894f2a9326c7ab4cfbceae435cb69f3e359ee49946dc566f242f4238de",
+        "636d98aea6cb6afe50fd1e96bb8bfdf18a9d54a87e66fd79e3dff80abda98c18",
+        "067a4de70930459165ff7d84a0dc375adb145ac07e67eb0e1fadebd4e2610eeb",
+        "64721850463f2d1dfe148e429e472914d67d9867409de6c39150225106d4d425",
+        "6c87827aa64247be6bb132c49e271a6e23c54c8334f2c3eca5551b4ae5260f05",
+        "65cbbc751ea4f5e7956628b8645708187b37f2d65c6c297a5854355256de476e",
+        "6bf24b343856b4066e2835b1fe3e5d16496a36f41386c2afd44d001ba886fdc7",
+        "41d82825d409ab7c996773b516f6720e34cbfdebdc9c069fa579dcea11ef44f6",
+        "45f741f2e9481a85b86467ab30d363fd0328e33d53fce6b39286c2494ee7bd28",
+        "6c06f72d4e071f9c1ddca4f9ea231853f6d8c5e9b7418e9c564c995912d19c18",
+        "154f9ecfb65370a8b59a12cd736348aead2e59a7e3701d20a669bec15363fe62",
+        "0c4d910fbd3b57be6d6680e8d2db47c1454712b240b78468cb764702be5c1aec",
+        "0e1ac575e1125f5ee86da3342018bc4f3c1e2310148043d5074eb4ee22fc55b6",
+        "273531c7d0d03d8f97b722ef1f0c324dac39f804e0222202f7502946647ef332",
+        "101464d19cf380958e5aef1084736db89f4cb131033ae670f6de0a5cf9d92b73",
+        "597cdd384abdad1beccc73fb39f74a18eb44d056951d602c2ef6ef6448fc5626",
+    ]
+}
+
+fn main() {}

+ 39 - 0
src/bin/mint-classic.rs

@@ -0,0 +1,39 @@
+use ff::Field;
+use group::Group;
+
+use drk::crypto::{
+    create_mint_proof, load_params, save_params, setup_mint_prover, verify_mint_proof,
+};
+
+fn main() {
+    use rand::rngs::OsRng;
+
+    let public = jubjub::SubgroupPoint::random(&mut OsRng);
+
+    let value = 110;
+    let asset_id = 1;
+    let randomness_value: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
+    let randomness_asset: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
+
+    let serial: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
+    let randomness_coin: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
+
+    {
+        let params = setup_mint_prover();
+        save_params("mint.params", &params).unwrap();
+    }
+    let (params, pvk) = load_params("mint.params").expect("params should load");
+
+    let (proof, revealed) = create_mint_proof(
+        &params,
+        value,
+        asset_id,
+        randomness_value,
+        randomness_asset,
+        serial,
+        randomness_coin,
+        public,
+    );
+
+    assert!(verify_mint_proof(&pvk, &proof, &revealed));
+}

+ 213 - 0
src/bin/old/dfi.rs

@@ -0,0 +1,213 @@
+extern crate clap;
+use async_executor::Executor;
+use drk::rpc::adapter::RpcAdapter;
+use drk::rpc::jsonserver;
+use drk::rpc::options::ProgramOptions;
+use drk::Result;
+use easy_parallel::Parallel;
+use std::sync::Arc;
+
+/*
+async fn start2(executor: Arc<Executor<'_>>, options: ProgramOptions) -> Result<()> {
+    let connections = Arc::new(Mutex::new(HashMap::new()));
+
+    let stored_addrs = Arc::new(Mutex::new(Vec::new()));
+
+    let executor2 = executor.clone();
+    let stored_addrs2 = stored_addrs.clone();
+
+    let mut server_task = None;
+    if let Some(accept_addr) = options.accept_addr {
+        let accept_addr = accept_addr.clone();
+
+        let protocol = ServerProtocol::new(connections.clone(), accept_addr, stored_addrs2);
+        server_task = Some(executor.spawn(async move {
+            protocol.start(executor2).await?;
+            Ok::<(), drk::Error>(())
+        }));
+//    }
+
+    let mut seed_protocols = Vec::with_capacity(options.seed_addrs.len());
+
+    // Normally we query this from a server
+    let accept_addr = options.accept_addr.clone();
+
+    for seed_addr in options.seed_addrs.iter() {
+        let protocol = SeedProtocol::new(seed_addr.clone(), accept_addr, stored_addrs.clone());
+        protocol.clone().start(executor.clone()).await;
+        seed_protocols.push(protocol);
+    }
+
+    debug!("Waiting for seed node queries to finish...");
+
+    for seed_protocol in seed_protocols {
+        seed_protocol.await_finish().await;
+    }
+
+    debug!("Seed nodes queried.");
+
+    let mut client_slots = vec![];
+    for i in 0..options.connection_slots {
+        debug!("Starting connection slot {}", i);
+
+        let client = Channel::new(
+            connections.clone(),
+            accept_addr.clone(),
+            stored_addrs.clone(),
+        );
+        client.clone().start(executor.clone()).await;
+        client_slots.push(client);
+    }
+
+    for remote_addr in options.manual_connects {
+        debug!("Starting connection (manual) to {}", remote_addr);
+
+        let client = Channel::new(
+            connections.clone(),
+            accept_addr.clone(),
+            stored_addrs.clone(),
+        );
+        client
+            .clone()
+            .start_manual(remote_addr, executor.clone())
+            .await;
+        client_slots.push(client);
+    }
+
+    let rpc = RpcInterface::new();
+    let http = listen(
+        executor.clone(),
+        rpc.clone(),
+        Async::<TcpListener>::bind(([127, 0, 0, 1], 8000))?,
+        None,
+    );
+
+    let http_task = executor.spawn(http);
+
+    rpc.stop_recv.recv().await?;
+
+    http_task.cancel().await;
+
+    match server_task {
+        None => {}
+        Some(server_task) => {
+            server_task.cancel().await;
+        }
+    }
+    Ok(())
+}
+*/
+
+//struct ProgramOptions {
+//    network_settings: net::Settings,
+//    log_path: Box<std::path::PathBuf>,
+//    rpc_port: u16,
+//}
+//
+//impl ProgramOptions {
+//    fn load() -> Result<ProgramOptions> {
+//        let app = clap_app!(dfi =>
+//            (version: "0.1.0")
+//            (author: "Amir Taaki <amir@dyne.org>")
+//            (about: "Dark node")
+//            (@arg ACCEPT: -a --accept +takes_value "Accept address")
+//            (@arg SEED_NODES: -s --seeds ... "Seed nodes")
+//            (@arg CONNECTS: -c --connect ... "Manual connections")
+//            (@arg CONNECT_SLOTS: --slots +takes_value "Connection slots")
+//            (@arg LOG_PATH: --log +takes_value "Logfile path")
+//            (@arg RPC_PORT: -r --rpc +takes_value "RPC port")
+//        )
+//        .get_matches();
+//
+//        let accept_addr = if let Some(accept_addr) = app.value_of("ACCEPT") {
+//            Some(accept_addr.parse()?)
+//        } else {
+//            None
+//        };
+//
+//        let mut seed_addrs: Vec<SocketAddr> = vec![];
+//        if let Some(seeds) = app.values_of("SEED_NODES") {
+//            for seed in seeds {
+//                seed_addrs.push(seed.parse()?);
+//            }
+//        }
+//
+//        let mut manual_connects: Vec<SocketAddr> = vec![];
+//        if let Some(connections) = app.values_of("CONNECTS") {
+//            for connect in connections {
+//                manual_connects.push(connect.parse()?);
+//            }
+//        }
+//
+//        let connection_slots = if let Some(connection_slots) =
+// app.value_of("CONNECT_SLOTS") {            connection_slots.parse()?
+//        } else {
+//            0
+//        };
+//
+//        let log_path = Box::new(
+//            if let Some(log_path) = app.value_of("LOG_PATH") {
+//                std::path::Path::new(log_path)
+//            } else {
+//                std::path::Path::new("/tmp/darkfid.log")
+//            }
+//            .to_path_buf(),
+//        );
+//
+//        let rpc_port = if let Some(rpc_port) = app.value_of("RPC_PORT") {
+//            rpc_port.parse()?
+//        } else {
+//            8000
+//        };
+//
+//        Ok(ProgramOptions {
+//            network_settings: net::Settings {
+//                inbound: accept_addr,
+//                outbound_connections: connection_slots,
+//                external_addr: accept_addr,
+//                peers: manual_connects,
+//                seeds: seed_addrs,
+//                ..Default::default()
+//            },
+//            log_path,
+//            rpc_port,
+//        })
+//    }
+//}
+
+fn main() -> Result<()> {
+    use simplelog::*;
+
+    let options = ProgramOptions::load()?;
+
+    let logger_config = ConfigBuilder::new().set_time_format_str("%T%.6f").build();
+
+    CombinedLogger::init(vec![
+        TermLogger::new(LevelFilter::Debug, logger_config, TerminalMode::Mixed).unwrap(),
+        WriteLogger::new(
+            LevelFilter::Debug,
+            Config::default(),
+            std::fs::File::create(options.log_path.as_path()).unwrap(),
+        ),
+    ])
+    .unwrap();
+
+    let adapter = RpcAdapter::new("wallet.db")?;
+    let ex = Arc::new(Executor::new());
+    let (signal, shutdown) = async_channel::unbounded::<()>();
+    let ex2 = ex.clone();
+
+    let (_, result) = Parallel::new()
+        // Run four executor threads.
+        .each(0..3, |_| smol::future::block_on(ex.run(shutdown.recv())))
+        // Run the main future on the current thread.
+        .finish(|| {
+            smol::future::block_on(async move {
+                jsonserver::start(ex2, options, adapter).await?;
+                drop(signal);
+                Ok::<(), drk::Error>(())
+            })
+        });
+
+    result
+}

+ 117 - 0
src/bin/solana-poc

@@ -0,0 +1,117 @@
+// $ cargo run --features sol --bin solana-poc
+// $ solana transfer 10 $pubkey
+use futures::{SinkExt, StreamExt};
+use rand::rngs::OsRng;
+use serde::Serialize;
+use serde_json::{json, Value};
+use solana_client::{blockhash_query::BlockhashQuery, rpc_client::RpcClient};
+use solana_sdk::{
+    native_token::lamports_to_sol, pubkey::Pubkey, signature::Signer, signer::keypair::Keypair,
+    system_instruction, transaction::Transaction,
+};
+use std::sync::{Arc, Mutex};
+use tokio_tungstenite::{connect_async, tungstenite::protocol::Message};
+
+use drk::rpc::{jsonrpc, jsonrpc::JsonResult};
+
+//const RPC_SERVER: &'static str = "https://api.mainnet-beta.solana.com";
+//const WSS_SERVER: &'static str = "wss://api.mainnet-beta.solana.com";
+//const RPC_SERVER: &'static str = "https://api.devnet.solana.com";
+//const WSS_SERVER: &'static str = "wss://api.devnet.solana.com";
+const RPC_SERVER: &'static str = "http://localhost:8899";
+const WSS_SERVER: &'static str = "ws://localhost:8900";
+
+// https://docs.solana.com/developing/clients/jsonrpc-api#accountsubscribe
+#[derive(Serialize)]
+struct SubscribeParams {
+    encoding: Value,
+    commitment: Value,
+}
+
+// Example function to show how to transfer `amount` lamports
+fn transfer_lamports(from: &Keypair, to: &Pubkey, amount: u64) {
+    let rpc = RpcClient::new(RPC_SERVER.to_string());
+    let instruction = system_instruction::transfer(&from.pubkey(), to, amount);
+
+    let mut tx = Transaction::new_with_payer(&[instruction], Some(&from.pubkey()));
+    let bhq = BlockhashQuery::default();
+    match bhq.get_blockhash_and_fee_calculator(&rpc, rpc.commitment()) {
+        Err(_) => panic!("Couldn't connect to RPC"),
+        Ok(v) => tx.sign(&[from], v.0),
+    }
+
+    let _signature = rpc.send_and_confirm_transaction(&tx);
+}
+
+#[tokio::main]
+async fn main() -> Result<(), &'static str> {
+    let keypair = Keypair::generate(&mut OsRng);
+    println!("Pubkey: {:?}", keypair.pubkey());
+
+    let rpc = RpcClient::new(RPC_SERVER.to_string());
+    let balance = rpc.get_balance(&keypair.pubkey()).unwrap();
+    let account_bal = Arc::new(Mutex::new(balance));
+
+    // Parameters for subscription to events related to `pubkey`.
+    let sub_params = SubscribeParams {
+        encoding: json!("jsonParsed"),
+        // XXX: Use "finalized" for 100% certainty.
+        commitment: json!("confirmed"),
+    };
+
+    let sub_msg = jsonrpc::request(
+        json!("accountSubscribe"),
+        json!([json!(keypair.pubkey().to_string()), json!(sub_params)]),
+    );
+
+    // WebSocket handshake/connect
+    let (ws_stream, _) = connect_async(WSS_SERVER)
+        .await
+        .expect("Failed to connect to WebSocket server");
+
+    let (mut write, read) = ws_stream.split();
+
+    // Send the subscription request
+    write
+        .send(Message::Text(serde_json::to_string(&sub_msg).unwrap()))
+        .await
+        .unwrap();
+    println!("Subscribed to events for {:?}", keypair.pubkey());
+
+    // Subscription ID so we can map our notifications to our pubkey
+    // when we do multiple subscriptions and also do `accountUnsubscribe`.
+    let sub_id = Arc::new(Mutex::new(0));
+
+    let read_future = read.for_each(|message| async {
+        let data = message.unwrap().into_text().unwrap();
+        let v: JsonResult = serde_json::from_str(&data).unwrap();
+        match v {
+            JsonResult::Resp(r) => {
+                println!(
+                    "Successfully subscribed with ID: {:?}",
+                    r.result.as_i64().unwrap()
+                );
+                *sub_id.lock().unwrap() = r.result.as_i64().unwrap();
+            }
+
+            JsonResult::Err(e) => {
+                println!("Error on subscription: {:?}", e.error.message.to_string());
+            }
+
+            JsonResult::Notif(n) => {
+                println!("Got WebSocket notification: {:?}", n);
+                println!(
+                    "Old balance: {:?} SOL",
+                    lamports_to_sol(*account_bal.lock().unwrap())
+                );
+                let new_bal = n.params["result"]["value"]["lamports"].as_u64().unwrap();
+                *account_bal.lock().unwrap() = new_bal;
+                println!("New balance: {:?} SOL", lamports_to_sol(new_bal));
+            }
+        }
+    });
+
+    read_future.await;
+
+    Ok(())
+}

+ 215 - 0
src/bin/spend-classic.rs

@@ -0,0 +1,215 @@
+use bellman::gadgets::multipack;
+use bitvec::{order::Lsb0, view::AsBits};
+use blake2s_simd::Params as Blake2sParams;
+use ff::{Field, PrimeField};
+use group::{Curve, GroupEncoding};
+
+use drk::crypto::{
+    create_spend_proof, load_params, merkle_node::SAPLING_COMMITMENT_TREE_DEPTH, save_params,
+    setup_spend_prover, verify_spend_proof,
+};
+
+// This thing is nasty lol
+pub fn merkle_hash(
+    depth: usize,
+    lhs: &bls12_381::Scalar,
+    rhs: &bls12_381::Scalar,
+) -> bls12_381::Scalar {
+    let lhs = {
+        let mut tmp = [false; 256];
+        for (a, b) in tmp.iter_mut().zip(lhs.to_repr().as_bits::<Lsb0>()) {
+            *a = *b;
+        }
+        tmp
+    };
+
+    let rhs = {
+        let mut tmp = [false; 256];
+        for (a, b) in tmp.iter_mut().zip(rhs.to_repr().as_bits::<Lsb0>()) {
+            *a = *b;
+        }
+        tmp
+    };
+
+    jubjub::ExtendedPoint::from(zcash_primitives::pedersen_hash::pedersen_hash(
+        zcash_primitives::pedersen_hash::Personalization::MerkleTree(depth),
+        lhs.iter()
+            .copied()
+            .take(bls12_381::Scalar::NUM_BITS as usize)
+            .chain(
+                rhs.iter()
+                    .copied()
+                    .take(bls12_381::Scalar::NUM_BITS as usize),
+            ),
+    ))
+    .to_affine()
+    .get_u()
+}
+
+struct SpendRevealedValues {
+    value_commit: jubjub::SubgroupPoint,
+    nullifier: [u8; 32],
+    // This should not be here, we just have it for debugging
+    //coin: [u8; 32],
+    merkle_root: bls12_381::Scalar,
+}
+
+#[allow(dead_code)]
+impl SpendRevealedValues {
+    fn compute(
+        value: u64,
+        asset_id: u64,
+        randomness_value: &jubjub::Fr,
+        serial: &jubjub::Fr,
+        randomness_coin: &jubjub::Fr,
+        secret: &jubjub::Fr,
+        merkle_path: &[(bls12_381::Scalar, bool)],
+    ) -> Self {
+        let value_commit = (zcash_primitives::constants::VALUE_COMMITMENT_VALUE_GENERATOR
+            * jubjub::Fr::from(value))
+            + (zcash_primitives::constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR
+                * randomness_value);
+
+        let mut nullifier = [0; 32];
+        nullifier.copy_from_slice(
+            Blake2sParams::new()
+                .hash_length(32)
+                .personal(zcash_primitives::constants::PRF_NF_PERSONALIZATION)
+                .to_state()
+                .update(&secret.to_bytes())
+                .update(&serial.to_bytes())
+                .finalize()
+                .as_bytes(),
+        );
+
+        let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret;
+
+        let mut coin = [0; 32];
+        coin.copy_from_slice(
+            Blake2sParams::new()
+                .hash_length(32)
+                .personal(zcash_primitives::constants::CRH_IVK_PERSONALIZATION)
+                .to_state()
+                .update(&public.to_bytes())
+                .update(&value.to_le_bytes())
+                .update(&asset_id.to_le_bytes())
+                .update(&serial.to_bytes())
+                .update(&randomness_coin.to_bytes())
+                .finalize()
+                .as_bytes(),
+        );
+
+        let merkle_root =
+            jubjub::ExtendedPoint::from(zcash_primitives::pedersen_hash::pedersen_hash(
+                zcash_primitives::pedersen_hash::Personalization::NoteCommitment,
+                multipack::bytes_to_bits_le(&coin),
+            ));
+        let affine = merkle_root.to_affine();
+        let mut merkle_root = affine.get_u();
+
+        for (i, (right, is_right)) in merkle_path.iter().enumerate() {
+            if *is_right {
+                merkle_root = merkle_hash(i, &right, &merkle_root);
+            } else {
+                merkle_root = merkle_hash(i, &merkle_root, &right);
+            }
+        }
+
+        SpendRevealedValues {
+            value_commit,
+            nullifier,
+            merkle_root,
+        }
+    }
+
+    fn make_outputs(&self) -> [bls12_381::Scalar; 5] {
+        let mut public_input = [bls12_381::Scalar::zero(); 5];
+
+        // CV
+        {
+            let result = jubjub::ExtendedPoint::from(self.value_commit);
+            let affine = result.to_affine();
+            //let (u, v) = (affine.get_u(), affine.get_v());
+            let u = affine.get_u();
+            let v = affine.get_v();
+            public_input[0] = u;
+            public_input[1] = v;
+        }
+
+        // NF
+        {
+            // Pack the hash as inputs for proof verification.
+            let hash = multipack::bytes_to_bits_le(&self.nullifier);
+            let hash = multipack::compute_multipacking(&hash);
+
+            // There are 2 chunks for a blake hash
+            assert_eq!(hash.len(), 2);
+
+            public_input[2] = hash[0];
+            public_input[3] = hash[1];
+        }
+
+        // Not revealed. We leave this code here for debug
+        // Coin
+        /*{
+            // Pack the hash as inputs for proof verification.
+            let hash = multipack::bytes_to_bits_le(&self.coin);
+            let hash = multipack::compute_multipacking(&hash);
+
+            // There are 2 chunks for a blake hash
+            assert_eq!(hash.len(), 2);
+
+            public_input[4] = hash[0];
+            public_input[5] = hash[1];
+        }*/
+
+        public_input[4] = self.merkle_root;
+
+        public_input
+    }
+}
+
+fn main() {
+    use rand::rngs::OsRng;
+
+    let value = 110;
+    let asset_id = 1;
+    let randomness_value: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
+    let randomness_asset: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
+
+    let serial: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
+    let randomness_coin: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
+    let secret: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
+    let signature_secret: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
+
+    let mut merkle_path = vec![true, false];
+    merkle_path.resize(SAPLING_COMMITMENT_TREE_DEPTH, true);
+    let merkle_path = merkle_path
+        .into_iter()
+        .map(|x| (bls12_381::Scalar::random(&mut OsRng), x))
+        .collect();
+
+    {
+        let params = setup_spend_prover();
+        save_params("spend.params", &params).unwrap();
+    }
+    let (params, pvk) = load_params("spend.params").expect("params should load");
+
+    let signature_public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * signature_secret;
+
+    let (proof, revealed) = create_spend_proof(
+        &params,
+        value,
+        asset_id,
+        randomness_value,
+        randomness_asset,
+        serial,
+        randomness_coin,
+        secret,
+        merkle_path,
+        signature_secret,
+    );
+
+    assert!(verify_spend_proof(&pvk, &proof, &revealed));
+    assert_eq!(revealed.signature_public, signature_public);
+}

+ 86 - 0
src/bin/tutorial.rs

@@ -0,0 +1,86 @@
+// This tutorial example corresponds to the VM proof in proofs/tutorial.psm
+// It encodes the same function as the one in zk-explainer document.
+use bls12_381::Scalar;
+use drk::{BlsStringConversion, Decodable, Encodable, ZkContract, ZkProof};
+use std::fs::File;
+use std::time::Instant;
+
+type Result<T> = std::result::Result<T, failure::Error>;
+
+fn main() -> Result<()> {
+    {
+        // Load the contract from file
+
+        let start = Instant::now();
+        let file = File::open("tutorial.zcd")?;
+        let mut contract = ZkContract::decode(file)?;
+        println!(
+            "Loaded contract '{}': [{:?}]",
+            contract.name,
+            start.elapsed()
+        );
+
+        println!("Stats:");
+        println!("    Constants: {}", contract.vm.constants.len());
+        println!("    Alloc: {}", contract.vm.alloc.len());
+        println!("    Operations: {}", contract.vm.ops.len());
+        println!(
+            "    Constraint Instructions: {}",
+            contract.vm.constraints.len()
+        );
+
+        // Do the trusted setup
+
+        contract.setup("tutorial.zts")?;
+    }
+
+    // Load the contract from file
+
+    let start = Instant::now();
+    let file = File::open("tutorial.zcd")?;
+    let mut contract = ZkContract::decode(file)?;
+    println!(
+        "Loaded contract '{}': [{:?}]",
+        contract.name,
+        start.elapsed()
+    );
+
+    contract.load_setup("tutorial.zts")?;
+
+    {
+        // Put in our input parameters
+
+        contract.set_param(
+            "w",
+            Scalar::from_string("0000000000000000000000000000000000000000000000000000000000000001"),
+        )?;
+        contract.set_param(
+            "a",
+            Scalar::from_string("0000000000000000000000000000000000000000000000000000000000000001"),
+        )?;
+        contract.set_param(
+            "b",
+            Scalar::from_string("0000000000000000000000000000000000000000000000000000000000000004"),
+        )?;
+
+        // Generate the ZK proof
+
+        let proof = contract.prove()?;
+
+        // Test and show our output values
+
+        assert_eq!(proof.public.len(), 1);
+        println!("v = {:?}", proof.public.get("v").unwrap());
+
+        let mut file = File::create("tutorial.prf")?;
+        proof.encode(&mut file)?;
+    }
+
+    // Verify the proof
+
+    let file = File::open("tutorial.prf")?;
+    let proof = ZkProof::decode(file)?;
+    assert!(contract.verify(&proof));
+
+    Ok(())
+}

+ 300 - 0
src/bin/tx.rs

@@ -0,0 +1,300 @@
+use bellman::groth16;
+use bls12_381::Bls12;
+use ff::{Field, PrimeField};
+use rand::rngs::OsRng;
+use std::path::Path;
+
+use drk::crypto::{
+    coin::Coin,
+    load_params,
+    merkle::{CommitmentTree, IncrementalWitness},
+    merkle_node::MerkleNode,
+    note::{EncryptedNote, Note},
+    nullifier::Nullifier,
+    save_params, setup_mint_prover, setup_spend_prover,
+};
+use drk::serial::{Decodable, Encodable};
+use drk::state::{state_transition, ProgramState, StateUpdate};
+use drk::tx;
+
+struct MemoryState {
+    // The entire merkle tree state
+    tree: CommitmentTree<MerkleNode>,
+    // List of all previous and the current merkle roots
+    // This is the hashed value of all the children.
+    merkle_roots: Vec<MerkleNode>,
+    // Nullifiers prevent double spending
+    nullifiers: Vec<Nullifier>,
+    // All received coins
+    // NOTE: we need maybe a flag to keep track of which ones are spent
+    // Maybe the spend field links to a tx hash:input index
+    // We should also keep track of the tx hash:output index where this
+    // coin was received
+    own_coins: Vec<(Coin, Note, jubjub::Fr, IncrementalWitness<MerkleNode>)>,
+
+    // Mint verifying key used by ZK
+    mint_pvk: groth16::PreparedVerifyingKey<Bls12>,
+    // Spend verifying key used by ZK
+    spend_pvk: groth16::PreparedVerifyingKey<Bls12>,
+
+    // Public key of the cashier
+    cashier_public: jubjub::SubgroupPoint,
+    // List of all our secret keys
+    secrets: Vec<jubjub::Fr>,
+}
+
+impl ProgramState for MemoryState {
+    fn is_valid_cashier_public_key(&self, public: &jubjub::SubgroupPoint) -> bool {
+        public == &self.cashier_public
+    }
+    fn is_valid_merkle(&self, merkle_root: &MerkleNode) -> bool {
+        self.merkle_roots.iter().any(|m| *m == *merkle_root)
+    }
+    fn nullifier_exists(&self, nullifier: &Nullifier) -> bool {
+        self.nullifiers.iter().any(|n| n.repr == nullifier.repr)
+    }
+
+    fn mint_pvk(&self) -> &groth16::PreparedVerifyingKey<Bls12> {
+        &self.mint_pvk
+    }
+    fn spend_pvk(&self) -> &groth16::PreparedVerifyingKey<Bls12> {
+        &self.spend_pvk
+    }
+}
+
+impl MemoryState {
+    fn apply(&mut self, mut update: StateUpdate) {
+        // Extend our list of nullifiers with the ones from the update
+        self.nullifiers.append(&mut update.nullifiers);
+
+        // Update merkle tree and witnesses
+        for (coin, enc_note) in update.coins.into_iter().zip(update.enc_notes.into_iter()) {
+            // Add the new coins to the merkle tree
+            let node = MerkleNode::from_coin(&coin);
+            self.tree.append(node).expect("Append to merkle tree");
+
+            // Keep track of all merkle roots that have existed
+            self.merkle_roots.push(self.tree.root());
+
+            // Also update all the coin witnesses
+            for (_, _, _, witness) in self.own_coins.iter_mut() {
+                witness.append(node).expect("append to witness");
+            }
+
+            if let Some((note, secret)) = self.try_decrypt_note(enc_note) {
+                // We need to keep track of the witness for this coin.
+                // This allows us to prove inclusion of the coin in the merkle tree with ZK.
+                // Just as we update the merkle tree with every new coin, so we do the same with
+                // the witness.
+
+                // Derive the current witness from the current tree.
+                // This is done right after we add our coin to the tree (but before any other
+                // coins are added)
+
+                // Make a new witness for this coin
+                let witness = IncrementalWitness::from_tree(&self.tree);
+                self.own_coins.push((coin, note, secret, witness));
+            }
+        }
+    }
+
+    fn try_decrypt_note(&self, ciphertext: EncryptedNote) -> Option<(Note, jubjub::Fr)> {
+        // Loop through all our secret keys...
+        for secret in &self.secrets {
+            // ... attempt to decrypt the note ...
+            match ciphertext.decrypt(secret) {
+                Ok(note) => {
+                    // ... and return the decrypted note for this coin.
+                    return Some((note, secret.clone()));
+                }
+                Err(_) => {}
+            }
+        }
+        // We weren't able to decrypt the note with any of our keys.
+        None
+    }
+}
+
+fn main() {
+    // Auto create trusted ceremony parameters if they don't exist
+    if !Path::new("mint.params").exists() {
+        let params = setup_mint_prover();
+        save_params("mint.params", &params).unwrap();
+    }
+    if !Path::new("spend.params").exists() {
+        let params = setup_spend_prover();
+        save_params("spend.params", &params).unwrap();
+    }
+
+    // Load trusted setup parameters
+    let (mint_params, mint_pvk) = load_params("mint.params").expect("params should load");
+    let (spend_params, spend_pvk) = load_params("spend.params").expect("params should load");
+
+    // Cashier creates a secret key
+    let cashier_secret = jubjub::Fr::random(&mut OsRng);
+    // This is their public key
+    let cashier_public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * cashier_secret;
+
+    // Wallet 1 creates a secret key
+    let secret = jubjub::Fr::random(&mut OsRng);
+    // This is their public key
+    let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret;
+
+    let mut state = MemoryState {
+        tree: CommitmentTree::empty(),
+        merkle_roots: vec![],
+        nullifiers: vec![],
+        own_coins: vec![],
+        mint_pvk,
+        spend_pvk,
+        cashier_public,
+        secrets: vec![secret.clone()],
+    };
+
+    // Step 1: Cashier deposits to wallet1's address
+
+    // Create the deposit for 110 BTC
+    // Clear inputs are visible to everyone on the network
+    let builder = tx::TransactionBuilder {
+        clear_inputs: vec![tx::TransactionBuilderClearInputInfo {
+            value: 110,
+            asset_id: 1,
+            signature_secret: cashier_secret,
+        }],
+        inputs: vec![],
+        outputs: vec![tx::TransactionBuilderOutputInfo {
+            value: 110,
+            asset_id: 1,
+            public,
+        }],
+    };
+
+    // We will 'compile' the tx, and then serialize it to this Vec<u8>
+    let mut tx_data = vec![];
+    {
+        // Build the tx
+        let tx = builder.build(&mint_params, &spend_params);
+        // Now serialize it
+        tx.encode(&mut tx_data).expect("encode tx");
+    }
+
+    // Step 1 is completed.
+    // Tx data is posted to the blockchain
+
+    // Step 2: wallet1 receive's payment from the cashier
+
+    // Wallet1 is receiving tx, and for every new coin it finds, it adds to its
+    // merkle tree
+    {
+        // Here we simulate 5 fake random coins, adding them to our tree.
+        let tree = &mut state.tree;
+        for _i in 0..5 {
+            // Don't worry about any of the code in this block
+            // We're just filling the tree with fake coins
+            let cmu = MerkleNode::new(bls12_381::Scalar::random(&mut OsRng).to_repr());
+            tree.append(cmu).unwrap();
+
+            let root = tree.root();
+            state.merkle_roots.push(root.into());
+        }
+    }
+
+    // Now we receive the tx data
+    {
+        let tx = tx::Transaction::decode(&tx_data[..]).unwrap();
+
+        let update = state_transition(&state, tx).expect("step 2 state transition failed");
+        // Our state impl is memory online for this demo
+        // but in the real version, this function will be async
+        // and using the databases.
+        state.apply(update);
+    }
+
+    // Wallet1 has received payment from the cashier.
+    // Step 2 is complete.
+    assert_eq!(state.own_coins.len(), 1);
+    //let (coin, note, secret, witness) = &mut state.own_coins[0];
+
+    let merkle_path = {
+        let tree = &mut state.tree;
+        let (coin, _, _, witness) = &mut state.own_coins[0];
+        // Check this is the 6th coin we added
+        assert_eq!(witness.position(), 5);
+        assert_eq!(tree.root(), witness.root());
+
+        // Add some more random coins in
+        for _i in 0..10 {
+            // Don't worry about any of the code in this block
+            // We're just filling the tree with fake coins
+            let cmu = MerkleNode::new(bls12_381::Scalar::random(&mut OsRng).to_repr());
+            tree.append(cmu).unwrap();
+            witness.append(cmu).unwrap();
+            assert_eq!(tree.root(), witness.root());
+
+            let root = tree.root();
+            state.merkle_roots.push(root.into());
+        }
+
+        assert_eq!(state.merkle_roots.len(), 16);
+
+        // This is the value we need to spend the coin
+        // We use the witness and the merkle root (both in sync with each other)
+        // to prove our coin exists inside the tree.
+        // The coin is not revealed publicly but is proved to exist inside
+        // a merkle tree. Only the root will be revealed, and then the
+        // verifier checks that merkle root actually existed before.
+        let merkle_path = witness.path().unwrap();
+
+        // Just test the path is good because we just added a bunch of fake coins
+        let node = MerkleNode::from_coin(&coin);
+        let root = tree.root();
+        drop(tree);
+        drop(witness);
+        assert_eq!(merkle_path.root(node), root);
+        let root = root.into();
+        assert!(state.is_valid_merkle(&root));
+
+        merkle_path
+    };
+
+    // Step 3: wallet1 sends payment to wallet2
+
+    // Wallet1 now wishes to send the coin to wallet2
+
+    // The receiving wallet has a secret key
+    let secret2 = jubjub::Fr::random(&mut OsRng);
+    // This is their public key to receive payment
+    let public2 = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret2;
+
+    // Make a spend tx
+
+    // Construct a new tx spending the coin
+    // We need the decrypted note and our private key
+    let builder = tx::TransactionBuilder {
+        clear_inputs: vec![],
+        inputs: vec![tx::TransactionBuilderInputInfo {
+            merkle_path,
+            secret: secret.clone(),
+            note: state.own_coins[0].1.clone(),
+        }],
+        // We can add more outputs to this list.
+        // The only constraint is that sum(value in) == sum(value out)
+        outputs: vec![tx::TransactionBuilderOutputInfo {
+            value: 110,
+            asset_id: 1,
+            public: public2,
+        }],
+    };
+    // Build the tx
+    let mut tx_data = vec![];
+    {
+        let tx = builder.build(&mint_params, &spend_params);
+        tx.encode(&mut tx_data).expect("encode tx");
+    }
+    // Verify it's valid
+    {
+        let tx = tx::Transaction::decode(&tx_data[..]).unwrap();
+        let update = state_transition(&state, tx).expect("step 3 state transition failed");
+        state.apply(update);
+    }
+}

+ 113 - 0
src/old/basic_minimal.rs

@@ -0,0 +1,113 @@
+use bellman::{
+    gadgets::{
+        Assignment,
+    },
+    groth16, Circuit, ConstraintSystem, SynthesisError,
+};
+use bls12_381::Bls12;
+
+use ff::{Field};
+
+use rand::rngs::OsRng;
+
+
+pub const CRH_IVK_PERSONALIZATION: &[u8; 8] = b"Zcashivk";
+
+struct MyCircuit {
+    aux: Vec<Option<bls12_381::Scalar>>,
+}
+
+impl Circuit<bls12_381::Scalar> for MyCircuit {
+    fn synthesize<CS: ConstraintSystem<bls12_381::Scalar>>(
+        self,
+        cs: &mut CS,
+    ) -> Result<(), SynthesisError> {
+        //let x = num::AllocatedNum::alloc(cs.namespace(|| "conditional anchor"), || {
+        //    Ok(*self.aux_values[0].get()?)
+        //})?;
+
+        //let x2 = x.mul(cs.namespace(|| "x2"), &x)?;
+        //let x3 = x.mul(cs.namespace(|| "x2"), &x2)?;
+        //x3.inputize(cs.namespace(|| "pubx2"))?;
+
+        // ------------------
+
+        // x
+        let x_var = cs.alloc(|| "num", || Ok(*self.aux[0].get()?))?;
+
+        // x2 = x * x
+
+        let x2_var = cs.alloc(|| "product num", || Ok(*self.aux[1].get()?))?;
+
+        let x3_var = cs.alloc(|| "product num", || Ok(*self.aux[2].get()?))?;
+
+        let input = cs.alloc_input(|| "input variable", || Ok(*self.aux[2].get()?))?;
+
+        let coeff = bls12_381::Scalar::one();
+        let lc0 = bellman::LinearCombination::zero() + (coeff, x_var);
+        let lc1 = bellman::LinearCombination::zero() + (coeff, x_var);
+        let lc2 = bellman::LinearCombination::zero() + (coeff, x2_var);
+
+        cs.enforce(|| "multiplication constraint", |_| lc0, |_| lc1, |_| lc2);
+
+        // x3 = x2 * x
+
+        let coeff = bls12_381::Scalar::one();
+        let lc0 = bellman::LinearCombination::zero() + (coeff, x2_var);
+        let lc1 = bellman::LinearCombination::zero() + (coeff, x_var);
+        let lc2 = bellman::LinearCombination::zero() + (coeff, x3_var);
+
+        cs.enforce(|| "multiplication constraint", |_| lc0, |_| lc1, |_| lc2);
+
+        // inputize values
+
+        let coeff = bls12_381::Scalar::one();
+        let lc0 = bellman::LinearCombination::zero() + (coeff, input);
+        let lc1 = bellman::LinearCombination::zero() + (coeff, CS::one());
+        let lc2 = bellman::LinearCombination::zero() + (coeff, x3_var);
+
+        cs.enforce(|| "enforce input is correct", |_| lc0, |_| lc1, |_| lc2);
+
+        Ok(())
+    }
+}
+
+fn main() {
+    use std::time::Instant;
+
+    let start = Instant::now();
+    // Create parameters for our circuit. In a production deployment these would
+    // be generated securely using a multiparty computation.
+    let params = {
+        let c = MyCircuit { aux: vec![None] };
+        groth16::generate_random_parameters::<Bls12, _, _>(c, &mut OsRng).unwrap()
+    };
+    println!("Setup: [{:?}]", start.elapsed());
+
+    // Prepare the verification key (for proof verification).
+    let pvk = groth16::prepare_verifying_key(&params.vk);
+
+    // Pick a preimage and compute its hash.
+    let quantity = bls12_381::Scalar::from(3);
+
+    // Create an instance of our circuit (with the preimage as a witness).
+    let c = MyCircuit {
+        aux: vec![
+            Some(quantity),
+            Some(quantity * quantity),
+            Some(quantity * quantity * quantity),
+        ],
+    };
+
+    let start = Instant::now();
+    // Create a Groth16 proof with our parameters.
+    let proof = groth16::create_random_proof(c, &params, &mut OsRng).unwrap();
+    println!("Prove: [{:?}]", start.elapsed());
+
+    let public_input = vec![bls12_381::Scalar::from(27)];
+
+    let start = Instant::now();
+    // Check the proof!
+    assert!(groth16::verify_proof(&pvk, &proof, &public_input).is_ok());
+    println!("Verify: [{:?}]", start.elapsed());
+}

+ 31 - 0
src/old/bits.rs

@@ -0,0 +1,31 @@
+use bls12_381::Scalar;
+
+mod bits_contract;
+mod vm;
+use bits_contract::load_zkvm;
+
+fn main() -> std::result::Result<(), vm::ZkVmError> {
+    let mut vm = load_zkvm();
+
+    vm.setup();
+
+    let params = vec![(
+        0,
+        Scalar::from_raw([
+            0xb981_9dc8_2d90_607e,
+            0xa361_ee3f_d48f_df77,
+            0x52a3_5a8c_1908_dd87,
+            0x15a3_6d1f_0f39_0d88,
+        ]),
+    )];
+    vm.initialize(&params)?;
+
+    let proof = vm.prove();
+
+    let public = vm.public();
+
+    assert_eq!(public.len(), 0);
+
+    assert!(vm.verify(&proof, &public));
+    Ok(())
+}

+ 118 - 0
src/old/blake.rs

@@ -0,0 +1,118 @@
+use bellman::{
+    gadgets::{
+        blake2s,
+        boolean::{AllocatedBit, Boolean},
+        multipack,
+    },
+    groth16, Circuit, ConstraintSystem, SynthesisError,
+};
+use bls12_381::Bls12;
+use ff::PrimeField;
+use rand::rngs::OsRng;
+
+pub const CRH_IVK_PERSONALIZATION: &[u8; 8] = b"Zcashivk";
+
+struct MyCircuit {
+    /// The input to SHA-256d we are proving that we know. Set to `None` when we
+    /// are verifying a proof (and do not have the witness data).
+    preimage: Option<[u8; 80]>,
+}
+
+impl<Scalar: PrimeField> Circuit<Scalar> for MyCircuit {
+    fn synthesize<CS: ConstraintSystem<Scalar>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
+        // Compute the values for the bits of the preimage. If we are verifying a proof,
+        // we still need to create the same constraints, so we return an equivalent-size
+        // Vec of None (indicating that the value of each bit is unknown).
+        let bit_values = if let Some(preimage) = self.preimage {
+            preimage
+                .iter()
+                .map(|byte| (0..8).map(move |i| (byte >> i) & 1u8 == 1u8))
+                .flatten()
+                .map(|b| Some(b))
+                .collect()
+        } else {
+            vec![None; 80 * 8]
+        };
+        assert_eq!(bit_values.len(), 80 * 8);
+
+        // Witness the bits of the preimage.
+        let preimage_bits = bit_values
+            .into_iter()
+            .enumerate()
+            // Allocate each bit.
+            .map(|(i, b)| AllocatedBit::alloc(cs.namespace(|| format!("preimage bit {}", i)), b))
+            // Convert the AllocatedBits into Booleans (required for the sha256 gadget).
+            .map(|b| b.map(Boolean::from))
+            .collect::<Result<Vec<_>, _>>()?;
+
+        let hash = blake2s::blake2s(
+            cs.namespace(|| "computation of ivk"),
+            &preimage_bits,
+            CRH_IVK_PERSONALIZATION,
+        )?;
+
+        // Expose the vector of 32 boolean variables as compact public inputs.
+        multipack::pack_into_inputs(cs.namespace(|| "pack hash"), &hash)
+    }
+}
+
+fn main() {
+    use blake2s_simd::Params as Blake2sParams;
+    use std::time::Instant;
+
+    let start = Instant::now();
+    println!("Starting...");
+    // Create parameters for our circuit. In a production deployment these would
+    // be generated securely using a multiparty computation.
+    let params = {
+        let c = MyCircuit { preimage: None };
+        groth16::generate_random_parameters::<Bls12, _, _>(c, &mut OsRng).unwrap()
+    };
+    println!("Generated random params. [{:?}]", start.elapsed());
+
+    let start = Instant::now();
+    // Prepare the verification key (for proof verification).
+    let pvk = groth16::prepare_verifying_key(&params.vk);
+    println!("Prepared verify key [{:?}]", start.elapsed());
+
+    let start = Instant::now();
+    // Pick a preimage and compute its hash.
+    let preimage = [42; 80];
+    //let hash = Sha256::digest(&Sha256::digest(&preimage));
+    println!(
+        "Computed blake2s(preimage) witness data [{:?}]",
+        start.elapsed()
+    );
+
+    // Create an instance of our circuit (with the preimage as a witness).
+    let c = MyCircuit {
+        preimage: Some(preimage),
+    };
+
+    let start = Instant::now();
+    // Create a Groth16 proof with our parameters.
+    let proof = groth16::create_random_proof(c, &params, &mut OsRng).unwrap();
+    println!("Generated random proof [{:?}]", start.elapsed());
+
+    let start = Instant::now();
+
+    let hash_result = {
+        let mut h = Blake2sParams::new()
+            .hash_length(32)
+            .personal(CRH_IVK_PERSONALIZATION)
+            .to_state();
+        h.update(&preimage);
+        h.finalize()
+    };
+
+    // Pack the hash as inputs for proof verification.
+    let hash_bits = multipack::bytes_to_bits_le(hash_result.as_bytes());
+    let inputs = multipack::compute_multipacking(&hash_bits);
+
+    println!("Packed data and verifying proof... [{:?}]", start.elapsed());
+
+    let start = Instant::now();
+    // Check the proof!
+    assert!(groth16::verify_proof(&pvk, &proof, &inputs).is_ok());
+    println!("Done! [{:?}]", start.elapsed());
+}

+ 152 - 0
src/old/eq.rs

@@ -0,0 +1,152 @@
+use bellman::{
+    gadgets::{
+        boolean::{AllocatedBit, Boolean},
+        multipack, num, Assignment,
+    },
+    groth16, Circuit, ConstraintSystem, SynthesisError,
+};
+use bls12_381::Bls12;
+use bls12_381::Scalar;
+use ff::{Field, PrimeField};
+use group::Curve;
+use rand::rngs::OsRng;
+use std::ops::{Neg, SubAssign};
+
+pub const CRH_IVK_PERSONALIZATION: &[u8; 8] = b"Zcashivk";
+
+struct MyCircuit {
+    quantity: Option<bls12_381::Scalar>,
+    multiplier: Option<bls12_381::Scalar>,
+    entry_price: Option<bls12_381::Scalar>,
+    exit_price: Option<bls12_381::Scalar>,
+}
+
+impl Circuit<bls12_381::Scalar> for MyCircuit {
+    fn synthesize<CS: ConstraintSystem<bls12_381::Scalar>>(
+        self,
+        cs: &mut CS,
+    ) -> Result<(), SynthesisError> {
+        // Witness variables
+        let quantity = num::AllocatedNum::alloc(cs.namespace(|| "conditional anchor"), || {
+            Ok(*self.quantity.get()?)
+        })?;
+        let multiplier = num::AllocatedNum::alloc(cs.namespace(|| "conditional anchor"), || {
+            Ok(*self.multiplier.get()?)
+        })?;
+        let entry_price = num::AllocatedNum::alloc(cs.namespace(|| "conditional anchor"), || {
+            Ok(*self.entry_price.get()?)
+        })?;
+        let exit_price = num::AllocatedNum::alloc(cs.namespace(|| "conditional anchor"), || {
+            Ok(*self.exit_price.get()?)
+        })?;
+
+        // P = mN (1 - 1/R)
+        //   = mN - mN/R
+        //   = mN - mN * S_0 * S_T^-1
+
+        // initial_margin = mN
+        let initial_margin = multiplier.mul(cs.namespace(|| "initial margin"), &quantity)?;
+
+        // S_T_inv = S_T^-1
+        let exit_price_inv =
+            num::AllocatedNum::alloc(cs.namespace(|| "exit price inverse"), || {
+                let tmp = *exit_price.get_value().get()?;
+
+                if tmp.is_zero() {
+                    Err(SynthesisError::DivisionByZero)
+                } else {
+                    let inv = tmp.invert().unwrap();
+                    Ok(inv)
+                }
+            })?;
+
+        // assert S_T * S_T_inv = 1
+        cs.enforce(
+            || "constraint inverse exit price",
+            |lc| lc + exit_price.get_variable(),
+            |lc| lc + exit_price_inv.get_variable(),
+            |lc| lc + CS::one(),
+        );
+
+        // ungained = initial_margin * S_0 * S_T_inv
+        let ungained = initial_margin.mul(cs.namespace(|| "ungained 1"), &entry_price)?;
+        let ungained = ungained.mul(cs.namespace(|| "ungained 2"), &exit_price_inv)?;
+
+        // pnl = initial_margin - ungained
+        let pnl = num::AllocatedNum::alloc(cs.namespace(|| "exit price inverse"), || {
+            let mut tmp = *initial_margin.get_value().get()?;
+
+            tmp.sub_assign(ungained.get_value().get()?);
+
+            Ok(tmp)
+        })?;
+
+        cs.enforce(
+            || "constraint pnl calc",
+            |lc| lc + initial_margin.get_variable() - ungained.get_variable(),
+            |lc| lc + CS::one(),
+            |lc| lc + pnl.get_variable(),
+        );
+
+        // Apply clamp:
+        //
+        //   if pnl < -initial_margin:
+        //       pnl = -initial_margin
+        //   if pnl > initial_margin:
+        //       pnl = initial_margin
+
+        Ok(())
+    }
+}
+
+fn main() {
+    let x = Scalar::from(2);
+    println!("{:?}", x.invert().unwrap());
+
+    use std::time::Instant;
+
+    let start = Instant::now();
+    // Create parameters for our circuit. In a production deployment these would
+    // be generated securely using a multiparty computation.
+    let params = {
+        let c = MyCircuit {
+            quantity: None,
+            multiplier: None,
+            entry_price: None,
+            exit_price: None,
+        };
+        groth16::generate_random_parameters::<Bls12, _, _>(c, &mut OsRng).unwrap()
+    };
+    println!("Setup: [{:?}]", start.elapsed());
+
+    // Prepare the verification key (for proof verification).
+    let pvk = groth16::prepare_verifying_key(&params.vk);
+
+    // Pick a preimage and compute its hash.
+    let quantity = bls12_381::Scalar::from(1);
+    let multiplier = bls12_381::Scalar::from(1);
+    let entry_price = bls12_381::Scalar::from(100);
+    let exit_price = bls12_381::Scalar::from(200);
+
+    // Create an instance of our circuit (with the preimage as a witness).
+    let c = MyCircuit {
+        quantity: Some(quantity),
+        multiplier: Some(multiplier),
+        entry_price: Some(entry_price),
+        exit_price: Some(exit_price),
+    };
+
+    let start = Instant::now();
+    // Create a Groth16 proof with our parameters.
+    let proof = groth16::create_random_proof(c, &params, &mut OsRng).unwrap();
+    println!("Prove: [{:?}]", start.elapsed());
+
+    let start = Instant::now();
+
+    let mut public_input = [bls12_381::Scalar::zero(); 0];
+
+    let start = Instant::now();
+    // Check the proof!
+    assert!(groth16::verify_proof(&pvk, &proof, &public_input).is_ok());
+    println!("Verify: [{:?}]", start.elapsed());
+}

+ 61 - 0
src/old/jubjub.rs

@@ -0,0 +1,61 @@
+use bls12_381::Scalar;
+use ff::PrimeField;
+use group::Group;
+use jubjub::SubgroupPoint;
+
+const EDWARDS_D: Scalar = Scalar::from_raw([
+    0x0106_5fd6_d634_3eb1,
+    0x292d_7f6d_3757_9d26,
+    0xf5fd_9207_e6bd_7fd4,
+    0x2a93_18e7_4bfa_2b48,
+]);
+
+fn print_generators() {
+    use group::{Curve, Group, GroupEncoding};
+    use zcash_primitives::constants::*;
+
+    let x = jubjub::ExtendedPoint::from(VALUE_COMMITMENT_RANDOMNESS_GENERATOR.clone()).to_affine();
+    println!("G_VCR: {:?}", x);
+    let x = jubjub::ExtendedPoint::from(VALUE_COMMITMENT_VALUE_GENERATOR.clone()).to_affine();
+    println!("G_VCV: {:?}", x);
+}
+
+fn main() {
+    print_generators();
+
+    let g = SubgroupPoint::from_raw_unchecked(
+        bls12_381::Scalar::from_raw([
+            0xb981_9dc8_2d90_607e,
+            0xa361_ee3f_d48f_df77,
+            0x52a3_5a8c_1908_dd87,
+            0x15a3_6d1f_0f39_0d88,
+        ]),
+        bls12_381::Scalar::from_raw([
+            0x7b0d_c53c_4ebf_1891,
+            0x1f3a_beeb_98fa_d3e8,
+            0xf789_1142_c001_d925,
+            0x015d_8c7f_5b43_fe33,
+        ]),
+    );
+    let x = g + g;
+    let x = jubjub::AffinePoint::from(jubjub::ExtendedPoint::from(x));
+    println!("{:?}", x);
+
+    let one = Scalar::from_bytes(&[
+        0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00,
+    ])
+    .unwrap();
+    assert_eq!(Scalar::one(), one);
+
+    // Scalar stuff
+    println!("-Scalar::one: {:?}", -Scalar::one());
+    let bits = (-Scalar::one()).to_le_bits();
+    for b in bits.iter() {
+        print!("{}", if *b { 1 } else { 0 });
+    }
+    println!("");
+
+    println!("Edwards d: {:?}", EDWARDS_D);
+}

+ 271 - 0
src/old/mimc.rs

@@ -0,0 +1,271 @@
+// For randomness (during paramgen and proof generation)
+//use rand::thread_rng;
+
+// For benchmarking
+use std::time::{Duration, Instant};
+
+// from string scalar
+use drk::bls_extensions::BlsStringConversion;
+
+// Bring in some tools for using finite fiels
+use ff::PrimeField;
+
+// mimc constants
+//mod mimc_constants;
+//use mimc_constants::mimc_constants;
+
+// We're going to use the BLS12-381 pairing-friendly elliptic curve.
+use bls12_381::Bls12;
+
+// We'll use these interfaces to construct our circuit.
+use bellman::{Circuit, ConstraintSystem, SynthesisError};
+
+// We're going to use the Groth16 proving system.
+use bellman::groth16::{
+    create_random_proof, generate_random_parameters, prepare_verifying_key, verify_proof, Proof,
+};
+
+const MIMC_ROUNDS: usize = 322;
+
+/// This is an implementation of MiMC, specifically a
+/// variant named `LongsightF322p3` for BLS12-381.
+/// See http://eprint.iacr.org/2016/492 for more
+/// information about this construction.
+///
+/// ```
+/// function LongsightF322p3(xL ⦂ Fp, xR ⦂ Fp) {
+///     for i from 0 up to 321 {
+///         xL, xR := xR + (xL + Ci)^3, xL
+///     }
+///     return xL
+/// }
+/// ```
+fn mimc<Scalar: PrimeField>(mut xl: Scalar, mut xr: Scalar, constants: &[Scalar]) -> Scalar {
+    assert_eq!(constants.len(), MIMC_ROUNDS);
+
+    for i in 0..MIMC_ROUNDS {
+        let mut tmp1 = xl;
+        tmp1.add_assign(&constants[i]);
+        let mut tmp2 = tmp1.square();
+        tmp2.mul_assign(&tmp1);
+        tmp2.add_assign(&xr);
+        xr = xl;
+        xl = tmp2;
+    }
+
+    xl
+}
+
+//macro_rules! from_slice {
+//    ($data:expr, $len:literal) => {{
+//        let mut array = [0; $len];
+//        // panics if not enough data
+//        let bytes = &$data[..array.len()];
+//        assert_eq!(bytes.len(), array.len());
+//        for (a, b) in array.iter_mut().rev().zip(bytes.iter()) {
+//            *a = *b;
+//        }
+//        //array.copy_from_slice(bytes.iter().rev());
+//        array
+//    }};
+//}
+
+/// This is our demo circuit for proving knowledge of the
+/// preimage of a MiMC hash invocation.
+struct MiMCDemo<'a, Scalar: PrimeField> {
+    xl: Option<Scalar>,
+    xr: Option<Scalar>,
+    constants: &'a [Scalar],
+}
+
+/// Our demo circuit implements this `Circuit` trait which
+/// is used during paramgen and proving in order to
+/// synthesize the constraint system.
+impl<'a, Scalar: PrimeField> Circuit<Scalar> for MiMCDemo<'a, Scalar> {
+    fn synthesize<CS: ConstraintSystem<Scalar>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
+        assert_eq!(self.constants.len(), MIMC_ROUNDS);
+
+        // Allocate the first component of the preimage.
+        let mut xl_value = self.xl;
+        let mut xl = cs.alloc(
+            || "preimage xl",
+            || xl_value.ok_or(SynthesisError::AssignmentMissing),
+        )?;
+
+        // Allocate the second component of the preimage.
+        let mut xr_value = self.xr;
+        let mut xr = cs.alloc(
+            || "preimage xr",
+            || xr_value.ok_or(SynthesisError::AssignmentMissing),
+        )?;
+
+        for i in 0..MIMC_ROUNDS {
+            // xL, xR := xR + (xL + Ci)^3, xL
+            let cs = &mut cs.namespace(|| format!("round {}", i));
+
+            // tmp = (xL + Ci)^2
+            let tmp_value = xl_value.map(|mut e| {
+                println!("{:?}", e);
+                e.add_assign(&self.constants[i]);
+                e.square()
+            });
+
+            // println!("tmp_value {:?} {:?}", self.constants[i], tmp_value);
+
+            let tmp = cs.alloc(
+                || "tmp",
+                || tmp_value.ok_or(SynthesisError::AssignmentMissing),
+            )?;
+
+            cs.enforce(
+                || "tmp = (xL + Ci)^2",
+                |lc| lc + xl + (self.constants[i], CS::one()),
+                |lc| lc + xl + (self.constants[i], CS::one()),
+                |lc| lc + tmp,
+            );
+
+            // new_xL = xR + (xL + Ci)^3
+            // new_xL = xR + tmp * (xL + Ci)
+            // new_xL - xR = tmp * (xL + Ci)
+            let new_xl_value = xl_value.map(|mut e| {
+                e.add_assign(&self.constants[i]);
+                e.mul_assign(&tmp_value.unwrap());
+                e.add_assign(&xr_value.unwrap());
+                e
+            });
+
+            let new_xl = if i == (MIMC_ROUNDS - 1) {
+                // This is the last round, xL is our image and so
+                // we allocate a public input.
+                cs.alloc_input(
+                    || "image",
+                    || new_xl_value.ok_or(SynthesisError::AssignmentMissing),
+                )?
+            } else {
+                cs.alloc(
+                    || "new_xl",
+                    || new_xl_value.ok_or(SynthesisError::AssignmentMissing),
+                )?
+            };
+
+            cs.enforce(
+                || "new_xL = xR + (xL + Ci)^3",
+                |lc| lc + tmp,
+                |lc| lc + xl + (self.constants[i], CS::one()),
+                |lc| lc + new_xl - xr,
+            );
+
+            println!("{:?}", i);
+            println!("{:?} {:?}", xl_value, xr_value);
+            println!("{:?}", new_xl_value);
+
+            // xR = xL
+            xr = xl;
+            xr_value = xl_value;
+
+            // xL = new_xL
+            xl = new_xl;
+            xl_value = new_xl_value;
+        }
+
+        Ok(())
+    }
+}
+
+fn main() {
+    use rand::rngs::OsRng;
+
+    // // Generate the MiMC round constants
+    // let constants = (0..MIMC_ROUNDS)
+    //     .map(|_| Scalar::random(&mut OsRng))
+    //     .collect::<Vec<_>>();
+
+    let constants = Vec::new();
+    /*
+    for const_str in mimc_constants() {
+        let bytes = from_slice!(&hex::decode(const_str).unwrap(), 32);
+        assert_eq!(bytes.len(), 32);
+        let constant = Scalar::from_bytes(&bytes).unwrap();
+
+        constants.push(constant);
+    }
+    */
+
+    println!("Creating parameters...");
+
+    // Create parameters for our circuit
+    let params = {
+        let c = MiMCDemo {
+            xl: None,
+            xr: None,
+            constants: &constants,
+        };
+
+        generate_random_parameters::<Bls12, _, _>(c, &mut OsRng).unwrap()
+    };
+
+    // Prepare the verification key (for proof verification)
+    let pvk = prepare_verifying_key(&params.vk);
+
+    println!("Creating proofs...");
+
+    // Let's benchmark stuff!
+    const SAMPLES: u32 = 1;
+    let mut total_proving = Duration::new(0, 0);
+    let mut total_verifying = Duration::new(0, 0);
+
+    // Just a place to put the proof data, so we can
+    // benchmark deserialization.
+    let mut proof_vec = vec![];
+
+    for _ in 0..SAMPLES {
+        // Generate a random preimage and compute the image
+        // let xl = Scalar::random(&mut OsRng);
+        // let xr = Scalar::random(&mut OsRng);
+        let xl = bls12_381::Scalar::from_string(
+            "15a36d1f0f390d8852a35a8c1908dd87a361ee3fd48fdf77b9819dc82d90607e",
+        );
+        let xr = bls12_381::Scalar::from_string(
+            "015d8c7f5b43fe33f7891142c001d9251f3abeeb98fad3e87b0dc53c4ebf1891",
+        );
+        let image = mimc(xl, xr, &constants);
+
+        proof_vec.truncate(0);
+
+        let start = Instant::now();
+        {
+            // Create an instance of our circuit (with the
+            // witness)
+            let c = MiMCDemo {
+                xl: Some(xl),
+                xr: Some(xr),
+                constants: &constants,
+            };
+
+            // Create a groth16 proof with our parameters.
+            let proof = create_random_proof(c, &params, &mut OsRng).unwrap();
+
+            proof.write(&mut proof_vec).unwrap();
+        }
+
+        total_proving += start.elapsed();
+
+        let start = Instant::now();
+        let proof = Proof::read(&proof_vec[..]).unwrap();
+        // Check the proof
+        assert!(verify_proof(&pvk, &proof, &[image]).is_ok());
+        total_verifying += start.elapsed();
+    }
+    let proving_avg = total_proving / SAMPLES;
+    //let proving_avg =
+    //    proving_avg.subsec_nanos() as f64 / 1_000_000_000f64 +
+    // (proving_avg.as_secs() as f64);
+
+    let verifying_avg = total_verifying / SAMPLES;
+    //let verifying_avg =
+    //    verifying_avg.subsec_nanos() as f64 / 1_000_000_000f64 +
+    // (verifying_avg.as_secs() as f64);
+
+    println!("Average proving time: {:?} seconds", proving_avg);
+    println!("Average verifying time: {:?} seconds", verifying_avg);
+}

+ 108 - 0
src/old/mint2.rs

@@ -0,0 +1,108 @@
+use bls12_381::Scalar;
+use ff::{Field, PrimeField};
+use group::{Curve, Group, GroupEncoding};
+
+mod mint2_contract;
+mod vm;
+use mint2_contract::{load_params, load_zkvm};
+
+fn unpack<F: PrimeField>(value: F) -> Vec<Scalar> {
+    let mut bits = Vec::new();
+    print!("Unpack: ");
+    for (i, bit) in value.to_le_bits().into_iter().cloned().enumerate() {
+        match bit {
+            true => bits.push(Scalar::one()),
+            false => bits.push(Scalar::zero()),
+        }
+        print!("{}", if bit { 1 } else { 0 });
+    }
+    println!("");
+    bits
+}
+
+fn unpack_u64(value: u64) -> Vec<Scalar> {
+    let mut result = Vec::with_capacity(64);
+
+    for i in 0..64 {
+        if (value >> i) & 1 == 1 {
+            result.push(Scalar::one());
+        } else {
+            result.push(Scalar::zero());
+        }
+    }
+
+    result
+}
+
+fn do_vcr_test(value: &jubjub::Fr) {
+    let mut curbase = zcash_primitives::constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR;
+    let mut result = jubjub::SubgroupPoint::identity();
+    //let value = jubjub::Fr::from(7);
+    for (i, bit) in value.to_le_bits().into_iter().cloned().enumerate() {
+        let thisbase = if bit {
+            curbase.clone()
+        } else {
+            jubjub::SubgroupPoint::identity()
+        };
+        result += thisbase;
+        curbase = curbase.double();
+        print!("{}", if bit { 1 } else { 0 });
+    }
+    println!("");
+    let result = jubjub::ExtendedPoint::from(result).to_affine();
+    println!("cvr1: {:?}", result);
+    let randomness_commit =
+        zcash_primitives::constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR * value;
+    let randomness_commit = jubjub::ExtendedPoint::from(randomness_commit).to_affine();
+    println!("cvr2: {:?}", randomness_commit);
+}
+
+fn main() -> std::result::Result<(), vm::ZkVmError> {
+    use rand::rngs::OsRng;
+    let public_point = jubjub::ExtendedPoint::from(jubjub::SubgroupPoint::random(&mut OsRng));
+    let public_affine = public_point.to_affine();
+
+    let value = 110;
+    let randomness_value: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
+    //let randomness_value = jubjub::Fr::from(7);
+    let value_commit = (zcash_primitives::constants::VALUE_COMMITMENT_VALUE_GENERATOR
+        * jubjub::Fr::from(value))
+        + (zcash_primitives::constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR * randomness_value);
+
+    /////
+    let randomness_commit =
+        zcash_primitives::constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR * randomness_value;
+    /////
+    do_vcr_test(&randomness_value);
+
+    let mut vm = load_zkvm();
+
+    vm.setup();
+
+    let mut params = vec![public_affine.get_u(), public_affine.get_v()];
+    for x in unpack(randomness_value) {
+        params.push(x);
+    }
+    let params = load_params(params);
+    println!("Size of params: {}", params.len());
+    vm.initialize(&params)?;
+
+    let proof = vm.prove();
+
+    let public = vm.public();
+
+    assert_eq!(public.len(), 2);
+
+    // Use this code for testing point doubling
+    let dbl = public_point.double().to_affine();
+    println!("{:?}", dbl.get_u());
+    println!("{:?}", public[0]);
+    println!("{:?}", dbl.get_v());
+    println!("{:?}", public[1]);
+    //assert_eq!(public.len(), 2);
+    //assert_eq!(public[0], dbl.get_u());
+    //assert_eq!(public[1], dbl.get_v());
+
+    assert!(vm.verify(&proof, &public));
+    Ok(())
+}

+ 136 - 0
src/old/pedersen_hash.rs

@@ -0,0 +1,136 @@
+use bellman::{
+    gadgets::{
+        boolean::{AllocatedBit, Boolean},
+        multipack,
+    },
+    groth16, Circuit, ConstraintSystem, SynthesisError,
+};
+use bls12_381::Bls12;
+use group::Curve;
+use rand::rngs::OsRng;
+
+pub const CRH_IVK_PERSONALIZATION: &[u8; 8] = b"Zcashivk";
+
+struct MyCircuit {
+    /// The input to SHA-256d we are proving that we know. Set to `None` when we
+    /// are verifying a proof (and do not have the witness data).
+    preimage: Option<[u8; 80]>,
+}
+
+impl Circuit<bls12_381::Scalar> for MyCircuit {
+    fn synthesize<CS: ConstraintSystem<bls12_381::Scalar>>(
+        self,
+        cs: &mut CS,
+    ) -> Result<(), SynthesisError> {
+        // Compute the values for the bits of the preimage. If we are verifying a proof,
+        // we still need to create the same constraints, so we return an equivalent-size
+        // Vec of None (indicating that the value of each bit is unknown).
+        let bit_values = if let Some(preimage) = self.preimage {
+            preimage
+                .iter()
+                .map(|byte| (0..8).map(move |i| (byte >> i) & 1u8 == 1u8))
+                .flatten()
+                .map(|b| Some(b))
+                .collect()
+        } else {
+            vec![None; 80 * 8]
+        };
+        assert_eq!(bit_values.len(), 80 * 8);
+
+        // Witness the bits of the preimage.
+        let preimage_bits = bit_values
+            .into_iter()
+            .enumerate()
+            // Allocate each bit.
+            .map(|(i, b)| AllocatedBit::alloc(cs.namespace(|| format!("preimage bit {}", i)), b))
+            // Convert the AllocatedBits into Booleans (required for the sha256 gadget).
+            .map(|b| b.map(Boolean::from))
+            .collect::<Result<Vec<_>, _>>()?;
+
+        let hash = zcash_proofs::circuit::pedersen_hash::pedersen_hash(
+            cs.namespace(|| "computation of ivk"),
+            zcash_primitives::pedersen_hash::Personalization::MerkleTree(0),
+            &preimage_bits,
+        )?;
+
+        hash.get_u().inputize(cs.namespace(|| "commitment"))?;
+
+        Ok(())
+    }
+}
+
+fn main() {
+    use std::time::Instant;
+
+    let start = Instant::now();
+    println!("Starting...");
+    // Create parameters for our circuit. In a production deployment these would
+    // be generated securely using a multiparty computation.
+    let params = {
+        let c = MyCircuit { preimage: None };
+        groth16::generate_random_parameters::<Bls12, _, _>(c, &mut OsRng).unwrap()
+    };
+    println!("Generated random params. [{:?}]", start.elapsed());
+
+    let start = Instant::now();
+    // Prepare the verification key (for proof verification).
+    let pvk = groth16::prepare_verifying_key(&params.vk);
+    println!("Prepared verify key [{:?}]", start.elapsed());
+
+    let start = Instant::now();
+    // Pick a preimage and compute its hash.
+    let preimage = [42; 80];
+    //let hash = Sha256::digest(&Sha256::digest(&preimage));
+    println!(
+        "Computed pedersen_hash(preimage) witness data [{:?}]",
+        start.elapsed()
+    );
+
+    // Create an instance of our circuit (with the preimage as a witness).
+    let test_c = MyCircuit {
+        preimage: Some(preimage.clone()),
+    };
+
+    let mut cs = bellman::gadgets::test::TestConstraintSystem::new();
+    test_c.synthesize(&mut cs).unwrap();
+    assert!(cs.is_satisfied());
+    println!("Constraints: {}", cs.num_constraints());
+
+    let c = MyCircuit {
+        preimage: Some(preimage),
+    };
+
+    let start = Instant::now();
+    // Create a Groth16 proof with our parameters.
+    let proof = groth16::create_random_proof(c, &params, &mut OsRng).unwrap();
+    println!("Generated random proof [{:?}]", start.elapsed());
+
+    let start = Instant::now();
+
+    let input_bools: Vec<bool> = preimage
+        .iter()
+        .map(|byte| (0..8).map(move |i| (byte >> i) & 1u8 == 1u8))
+        .flatten()
+        .collect();
+    let hash_result = jubjub::ExtendedPoint::from(zcash_primitives::pedersen_hash::pedersen_hash(
+        zcash_primitives::pedersen_hash::Personalization::MerkleTree(0),
+        input_bools.into_iter(),
+    ));
+
+    let mut public_input = [bls12_381::Scalar::zero(); 1];
+    {
+        let affine = hash_result.to_affine();
+        //let (u, v) = (affine.get_u(), affine.get_v());
+        let u = affine.get_u();
+        public_input[0] = u;
+    }
+
+    // Pack the hash as inputs for proof verification.
+
+    println!("Packed data and verifying proof... [{:?}]", start.elapsed());
+
+    let start = Instant::now();
+    // Check the proof!
+    assert!(groth16::verify_proof(&pvk, &proof, &public_input).is_ok());
+    println!("Done! [{:?}]", start.elapsed());
+}

+ 138 - 0
src/old/sha256.rs

@@ -0,0 +1,138 @@
+// Say we want to write a circuit that proves we know the preimage to some hash computed
+// using SHA-256d (calling SHA-256 twice). The preimage must have a fixed length known in
+// advance (because the circuit parameters will depend on it), but can otherwise have any value.
+// We take the following strategy:
+//
+// * Witness each bit of the preimage.
+// * Compute hash = SHA-256d(preimage) inside the circuit.
+// * Expose hash as a public input using multiscalar packing.
+//
+use bellman::{
+    gadgets::{
+        boolean::{AllocatedBit, Boolean},
+        multipack,
+        sha256::sha256,
+    },
+    groth16, Circuit, ConstraintSystem, SynthesisError,
+};
+use bls12_381::Bls12;
+use ff::PrimeField;
+use rand::rngs::OsRng;
+use sha2::{Digest, Sha256};
+
+/// Our own SHA-256d gadget. Input and output are in little-endian bit order.
+fn sha256d<Scalar: PrimeField, CS: ConstraintSystem<Scalar>>(
+    mut cs: CS,
+    data: &[Boolean],
+) -> Result<Vec<Boolean>, SynthesisError> {
+    // Flip endianness of each input byte
+    // NOTE: data is a vec of Bool so it is iterating over 8 'bits' at a time
+    // This is needed because Rust sha256 and ZC sha256 have different endianness.
+    let input: Vec<_> = data
+        .chunks(8)
+        .map(|c| c.iter().rev())
+        .flatten()
+        .cloned()
+        .collect();
+
+    let mid = sha256(cs.namespace(|| "SHA-256(input)"), &input)?;
+    let res = sha256(cs.namespace(|| "SHA-256(mid)"), &mid)?;
+
+    // Flip endianness of each output byte
+    Ok(res
+        .chunks(8)
+        .map(|c| c.iter().rev())
+        .flatten()
+        .cloned()
+        .collect())
+}
+
+struct MyCircuit {
+    /// The input to SHA-256d we are proving that we know. Set to `None` when we
+    /// are verifying a proof (and do not have the witness data).
+    preimage: Option<[u8; 80]>,
+}
+
+impl<Scalar: PrimeField> Circuit<Scalar> for MyCircuit {
+    fn synthesize<CS: ConstraintSystem<Scalar>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
+        // Compute the values for the bits of the preimage. If we are verifying a proof,
+        // we still need to create the same constraints, so we return an equivalent-size
+        // Vec of None (indicating that the value of each bit is unknown).
+        let bit_values = if let Some(preimage) = self.preimage {
+            preimage
+                .iter()
+                .map(|byte| (0..8).map(move |i| (byte >> i) & 1u8 == 1u8))
+                .flatten()
+                .map(|b| Some(b))
+                .collect()
+        } else {
+            vec![None; 80 * 8]
+        };
+        assert_eq!(bit_values.len(), 80 * 8);
+
+        // Witness the bits of the preimage.
+        let preimage_bits = bit_values
+            .into_iter()
+            .enumerate()
+            // Allocate each bit.
+            .map(|(i, b)| AllocatedBit::alloc(cs.namespace(|| format!("preimage bit {}", i)), b))
+            // Convert the AllocatedBits into Booleans (required for the sha256 gadget).
+            .map(|b| b.map(Boolean::from))
+            .collect::<Result<Vec<_>, _>>()?;
+
+        // Compute hash = SHA-256d(preimage).
+        let hash = sha256d(cs.namespace(|| "SHA-256d(preimage)"), &preimage_bits)?;
+
+        // Expose the vector of 32 boolean variables as compact public inputs.
+        multipack::pack_into_inputs(cs.namespace(|| "pack hash"), &hash)
+    }
+}
+
+fn main() {
+    use std::time::Instant;
+
+    let start = Instant::now();
+    println!("Starting...");
+    // Create parameters for our circuit. In a production deployment these would
+    // be generated securely using a multiparty computation.
+    let params = {
+        let c = MyCircuit { preimage: None };
+        groth16::generate_random_parameters::<Bls12, _, _>(c, &mut OsRng).unwrap()
+    };
+    println!("Generated random params. [{:?}]", start.elapsed());
+
+    let start = Instant::now();
+    // Prepare the verification key (for proof verification).
+    let pvk = groth16::prepare_verifying_key(&params.vk);
+    println!("Prepared verify key [{:?}]", start.elapsed());
+
+    let start = Instant::now();
+    // Pick a preimage and compute its hash.
+    let preimage = [42; 80];
+    let hash = Sha256::digest(&Sha256::digest(&preimage));
+    println!(
+        "Computed sha256(sha256(preimage)) witness data [{:?}]",
+        start.elapsed()
+    );
+
+    // Create an instance of our circuit (with the preimage as a witness).
+    let c = MyCircuit {
+        preimage: Some(preimage),
+    };
+
+    let start = Instant::now();
+    // Create a Groth16 proof with our parameters.
+    let proof = groth16::create_random_proof(c, &params, &mut OsRng).unwrap();
+    println!("Generated random proof [{:?}]", start.elapsed());
+
+    let start = Instant::now();
+    // Pack the hash as inputs for proof verification.
+    let hash_bits = multipack::bytes_to_bits_le(&hash);
+    let inputs = multipack::compute_multipacking(&hash_bits);
+    println!("Packed data and verifying proof... [{:?}]", start.elapsed());
+
+    let start = Instant::now();
+    // Check the proof!
+    assert!(groth16::verify_proof(&pvk, &proof, &inputs).is_ok());
+    println!("Done! [{:?}]", start.elapsed());
+}

+ 81 - 0
src/old/simple.rs

@@ -0,0 +1,81 @@
+use bellman::gadgets::multipack;
+use bellman::groth16;
+use blake2s_simd::Params as Blake2sParams;
+use bls12_381::Bls12;
+use ff::Field;
+use group::{Curve, Group, GroupEncoding};
+
+mod simple_circuit;
+use simple_circuit::InputSpend;
+
+fn main() {
+    use rand::rngs::OsRng;
+
+    let ak = jubjub::SubgroupPoint::random(&mut OsRng);
+
+    let secret: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
+    let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret + ak;
+
+    let params = {
+        let c = InputSpend {
+            secret: None,
+            ak: None,
+            value: None,
+            is_cool: None,
+            path: None,
+        };
+        groth16::generate_random_parameters::<Bls12, _, _>(c, &mut OsRng).unwrap()
+    };
+    let pvk = groth16::prepare_verifying_key(&params.vk);
+
+    let c = InputSpend {
+        secret: Some(secret),
+        ak: Some(ak),
+        value: Some(110),
+        is_cool: Some(true),
+        path: Some(bls12_381::Scalar::one()),
+    };
+
+    let proof = groth16::create_random_proof(c, &params, &mut OsRng).unwrap();
+
+    let mut public_input = [bls12_381::Scalar::zero(); 4];
+    {
+        let result = jubjub::ExtendedPoint::from(public);
+        let affine = result.to_affine();
+        //let (u, v) = (affine.get_u(), affine.get_v());
+        let u = affine.get_u();
+        let v = affine.get_v();
+        public_input[0] = u;
+        public_input[1] = v;
+    }
+
+    {
+        const CRH_IVK_PERSONALIZATION: &[u8; 8] = b"Zcashivk";
+        let preimage = [42; 80];
+        let hash_result = {
+            let mut hash = [0; 32];
+            hash.copy_from_slice(
+                Blake2sParams::new()
+                    .hash_length(32)
+                    .personal(CRH_IVK_PERSONALIZATION)
+                    .to_state()
+                    .update(&ak.to_bytes())
+                    .finalize()
+                    .as_bytes(),
+            );
+            hash
+        };
+
+        // Pack the hash as inputs for proof verification.
+        let hash = multipack::bytes_to_bits_le(&hash_result);
+        let hash = multipack::compute_multipacking(&hash);
+
+        // There are 2 chunks for a blake hash
+        assert_eq!(hash.len(), 2);
+
+        public_input[2] = hash[0];
+        public_input[3] = hash[1];
+    }
+
+    assert!(groth16::verify_proof(&pvk, &proof, &public_input).is_ok());
+}

+ 63 - 0
src/old/vmtest.rs

@@ -0,0 +1,63 @@
+use bls12_381::Scalar;
+
+mod vm;
+mod vm_load;
+use vm_load::load_zkvm;
+
+fn main() {
+    let mut vm = load_zkvm();
+
+    vm.setup();
+
+    let params = vec![
+        (
+            0,
+            Scalar::from_raw([
+                0xb981_9dc8_2d90_607e,
+                0xa361_ee3f_d48f_df77,
+                0x52a3_5a8c_1908_dd87,
+                0x15a3_6d1f_0f39_0d88,
+            ]),
+        ),
+        (
+            1,
+            Scalar::from_raw([
+                0x7b0d_c53c_4ebf_1891,
+                0x1f3a_beeb_98fa_d3e8,
+                0xf789_1142_c001_d925,
+                0x015d_8c7f_5b43_fe33,
+            ]),
+        ),
+        (
+            2,
+            Scalar::from_raw([
+                0xb981_9dc8_2d90_607e,
+                0xa361_ee3f_d48f_df77,
+                0x52a3_5a8c_1908_dd87,
+                0x15a3_6d1f_0f39_0d88,
+            ]),
+        ),
+        (
+            3,
+            Scalar::from_raw([
+                0x7b0d_c53c_4ebf_1891,
+                0x1f3a_beeb_98fa_d3e8,
+                0xf789_1142_c001_d925,
+                0x015d_8c7f_5b43_fe33,
+            ]),
+        ),
+    ];
+    vm.initialize(&params);
+
+    let proof = vm.prove();
+
+    let public = vm.public();
+
+    assert_eq!(public.len(), 2);
+    // 0x66ced46f14e5616d12b993f60a6e66558d6b6afe4c321ed212e0b9cfbd81061a
+    // 0x4731570fdd57cf280eadc8946fa00df81112502e44e497e794ab9a221f1bcca
+    println!("u = {:?}", public[0]);
+    println!("v = {:?}", public[1]);
+
+    assert!(vm.verify(&proof, &public));
+}

+ 271 - 0
src/old/zec.rs

@@ -0,0 +1,271 @@
+use bellman::groth16::*;
+use bls12_381::Bls12;
+use ff::{Field, PrimeField};
+use rand::rngs::OsRng;
+use rand_core::RngCore;
+use std::fs::File;
+use std::time::Instant;
+use zcash_primitives::{
+    merkle_tree::{CommitmentTree, IncrementalWitness},
+    note_encryption::{Memo, SaplingNoteEncryption},
+    primitives::{Diversifier, Note, ProofGenerationKey, Rseed, ValueCommitment},
+    redjubjub::PrivateKey,
+    sapling::{spend_sig, Node},
+    transaction::components::{Amount, GROTH_PROOF_SIZE},
+    zip32::{ChildIndex, ExtendedFullViewingKey, ExtendedSpendingKey},
+};
+use zcash_proofs::{
+    circuit::sapling::{Output, Spend},
+    sapling::{SaplingProvingContext, SaplingVerificationContext},
+};
+
+const TREE_DEPTH: usize = 32;
+
+type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
+
+fn generate_params() -> Result<()> {
+    let mut rng = OsRng;
+
+    println!("Creating spend parameters...");
+    let start = Instant::now();
+    let spend_params = generate_random_parameters::<Bls12, _, _>(
+        Spend {
+            value_commitment: None,
+            proof_generation_key: None,
+            payment_address: None,
+            commitment_randomness: None,
+            ar: None,
+            auth_path: vec![None; TREE_DEPTH],
+            anchor: None,
+        },
+        &mut rng,
+    )
+    .unwrap();
+    let buffer = File::create("spend.params")?;
+    spend_params.write(buffer)?;
+    println!("Finished spend paramgen [{:?}]", start.elapsed());
+
+    println!("Creating output parameters...");
+    let start = Instant::now();
+    let output_params = generate_random_parameters::<Bls12, _, _>(
+        Output {
+            value_commitment: None,
+            payment_address: None,
+            commitment_randomness: None,
+            esk: None,
+        },
+        &mut rng,
+    )
+    .unwrap();
+    let buffer = File::create("output.params")?;
+    output_params.write(buffer)?;
+    println!("Finished output paramgen [{:?}]", start.elapsed());
+
+    Ok(())
+}
+
+fn main() -> Result<()> {
+    //generate_params()?;
+
+    let mut rng = OsRng;
+
+    println!("Reading output parameters from file...");
+    let start = Instant::now();
+    let buffer = File::open("output.params")?;
+    let output_params = Parameters::<Bls12>::read(buffer, false)?;
+    let output_vk = prepare_verifying_key(&output_params.vk);
+    println!("Finished load output params [{:?}]", start.elapsed());
+
+    let mut ctx = SaplingProvingContext::new();
+
+    let start = Instant::now();
+
+    let seed = [0; 32];
+    let xsk_m = ExtendedSpendingKey::master(&seed);
+    //let xfvk_m = ExtendedFullViewingKey::from(&xsk_m);
+
+    let i_5h = ChildIndex::Hardened(5);
+    let secret_key = xsk_m.derive_child(i_5h);
+    let viewing_key = ExtendedFullViewingKey::from(&secret_key);
+
+    let (diversifier, payment_address) = viewing_key.default_address().unwrap();
+    let ovk = viewing_key.fvk.ovk;
+
+    let g_d = payment_address.g_d().expect("invalid address");
+    let mut buffer = [0u8; 32];
+    &rng.fill_bytes(&mut buffer);
+    let rseed = Rseed::AfterZip212(buffer);
+
+    let note = Note {
+        g_d,
+        pk_d: payment_address.pk_d().clone(),
+        value: 10,
+        rseed,
+    };
+
+    println!("Now we made the output [{:?}]", start.elapsed());
+    // Ok(SaplingOutput {
+    //     ovk,
+    //     to,
+    //     note,
+    //     memo
+    // })
+
+    let start = Instant::now();
+
+    let memo = Default::default();
+
+    let encryptor =
+        SaplingNoteEncryption::new(ovk, note.clone(), payment_address.clone(), memo, &mut rng);
+
+    let esk = encryptor.esk().clone();
+    let rcm = note.rcm();
+    let value = note.value;
+    let (proof_output, cv_output) =
+        ctx.output_proof(esk, payment_address.clone(), rcm, value, &output_params);
+
+    let mut zkproof = [0u8; GROTH_PROOF_SIZE];
+    proof_output
+        .write(&mut zkproof[..])
+        .expect("should be able to serialize a proof");
+
+    let cmu = note.cmu();
+
+    let enc_ciphertext = encryptor.encrypt_note_plaintext();
+    let out_ciphertext = encryptor.encrypt_outgoing_plaintext(&cv_output, &cmu);
+
+    let ephemeral_key: jubjub::ExtendedPoint = encryptor.epk().clone().into();
+
+    println!("Output description completed [{:?}]", start.elapsed());
+    // OutputDescription {
+    //     cv,
+    //     cmu,
+    //     ephemeral_key,
+    //     enc_ciphertext,
+    //     out_ciphertext,
+    //     zkproof,
+    // }
+
+    println!("Reading spend parameters from file...");
+    let start = Instant::now();
+    let buffer = File::open("spend.params")?;
+    let spend_params = Parameters::<Bls12>::read(buffer, false)?;
+    let spend_vk = prepare_verifying_key(&spend_params.vk);
+    println!("Finished spend paramgen [{:?}]", start.elapsed());
+
+    let start = Instant::now();
+
+    let cmu1 = Node::new(note.cmu().to_repr());
+    let mut tree = CommitmentTree::new();
+    tree.append(cmu1).unwrap();
+    let witness = IncrementalWitness::from_tree(&tree);
+
+    let alpha = jubjub::Fr::random(&mut rng);
+
+    // Now we have the spend
+    // SpendDescriptionInfo {
+    //     extsk,
+    //     diversifier,
+    //     note,
+    //     alpha,
+    //     merkle_path,
+    // }
+
+    // We will spend the address from above
+    // Leaving these here for reference.
+    //let extsk = ExtendedSpendingKey::master(&[]);
+    //let extfvk = ExtendedFullViewingKey::from(&extsk);
+    //let to_address = extfvk.default_address().unwrap().1;
+
+    let proof_generation_key = secret_key.expsk.proof_generation_key();
+
+    let merkle_path = witness.path().unwrap();
+
+    let cmu = Node::new(note.cmu().into());
+    let anchor = merkle_path.root(cmu).into();
+
+    let mut nullifier = [0u8; 32];
+    nullifier
+        .copy_from_slice(&note.nf(&proof_generation_key.to_viewing_key(), merkle_path.position));
+
+    let (proof_spend, cv_spend, rk) = ctx
+        .spend_proof(
+            proof_generation_key,
+            payment_address.diversifier().clone(),
+            rseed,
+            alpha,
+            value,
+            anchor,
+            merkle_path,
+            &spend_params,
+            &spend_vk,
+        )
+        .expect("Making proof failed");
+
+    let mut zkproof = [0u8; GROTH_PROOF_SIZE];
+    proof_spend
+        .write(&mut zkproof[..])
+        .expect("should be able to serialize a proof");
+
+    // Now we have a shielded spend
+    // SpendDescription {
+    //     cv,
+    //     anchor,
+    //     nullifier,
+    //     rk,
+    //     zkproof,
+    //     spend_auth_sig: None,
+    // }
+
+    // Now for each spend in the tx, we create a signature
+    // spendAuthSig
+    // Signature of the entire transaction
+
+    // Transaction hash into sighash. Just like in Bitcoin
+    // Contains our SpendDescriptions and OutputDescriptions
+    let mut sighash = [0u8; 32];
+    let spend_auth_sig = spend_sig(PrivateKey(secret_key.expsk.ask), alpha, &sighash, &mut rng);
+
+    // And now use the sighash value (since it's signed by all inputs) to create a new key
+    // which is used to sign the balance commitments.
+    let amount = Amount::from_u64(0).unwrap();
+    let binding_sig = ctx
+        .binding_sig(amount, &sighash)
+        .expect("sighash binding sig failed");
+
+    ////////////////////////////////////////
+
+    // Now lets verify the tx
+
+    let mut ctx = SaplingVerificationContext::new();
+
+    let success = ctx.check_output(
+        cv_output,
+        note.cmu(),
+        ephemeral_key,
+        proof_output,
+        &output_vk,
+    );
+    assert!(success);
+
+    let success = ctx.check_spend(
+        cv_spend,
+        anchor,
+        &nullifier,
+        rk,
+        &sighash,
+        spend_auth_sig,
+        proof_spend,
+        &spend_vk,
+    );
+    assert!(success);
+
+    let success = ctx.final_check(amount, &sighash, binding_sig);
+    assert!(success);
+
+    // The anchor must be a valid merkle root from some past block header
+    // The nullifier must not already exist
+    // And the amount is the 'fee' for the block.
+
+    Ok(())
+}

+ 94 - 0
src/old/zkmimc.rs

@@ -0,0 +1,94 @@
+use bls12_381::Scalar;
+use ff::{Field, PrimeField};
+use std::ops::{Add, AddAssign, MulAssign, Neg, SubAssign};
+
+mod vm;
+mod zkmimc_contract;
+use zkmimc_contract::load_zkvm;
+mod mimc_constants;
+use mimc_constants::mimc_constants;
+
+const MIMC_ROUNDS: usize = 322;
+
+fn mimc(mut xl: Scalar, mut xr: Scalar, constants: &[Scalar]) -> Scalar {
+    assert_eq!(constants.len(), MIMC_ROUNDS);
+
+    for i in 0..MIMC_ROUNDS {
+        let mut tmp1 = xl;
+        tmp1.add_assign(&constants[i]);
+        let mut tmp2 = tmp1.square();
+        tmp2.mul_assign(&tmp1);
+        tmp2.add_assign(&xr);
+        xr = xl;
+        xl = tmp2;
+    }
+
+    xl
+}
+
+macro_rules! from_slice {
+    ($data:expr, $len:literal) => {{
+        let mut array = [0; $len];
+        // panics if not enough data
+        let bytes = &$data[..array.len()];
+        assert_eq!(bytes.len(), array.len());
+        for (a, b) in array.iter_mut().rev().zip(bytes.iter()) {
+            *a = *b;
+        }
+        //array.copy_from_slice(bytes.iter().rev());
+        array
+    }};
+}
+
+fn main() -> std::result::Result<(), vm::ZkVmError> {
+    use rand::rngs::OsRng;
+
+    /////////////////////////////////
+    // Initialize our MiMC constants
+    let mut constants = Vec::new();
+    for const_str in mimc_constants() {
+        let bytes = from_slice!(&hex::decode(const_str).unwrap(), 32);
+        assert_eq!(bytes.len(), 32);
+        let constant = Scalar::from_bytes(&bytes).unwrap();
+
+        constants.push(constant);
+    }
+    /////////////////////////////////
+
+    let mut vm = load_zkvm();
+
+    vm.setup();
+
+    let params = vec![
+        (
+            0,
+            Scalar::from_raw([
+                0xb981_9dc8_2d90_607e,
+                0xa361_ee3f_d48f_df77,
+                0x52a3_5a8c_1908_dd87,
+                0x15a3_6d1f_0f39_0d88,
+            ]),
+        ),
+        (
+            1,
+            Scalar::from_raw([
+                0x7b0d_c53c_4ebf_1891,
+                0x1f3a_beeb_98fa_d3e8,
+                0xf789_1142_c001_d925,
+                0x015d_8c7f_5b43_fe33,
+            ]),
+        ),
+    ];
+    vm.initialize(&params)?;
+
+    let proof = vm.prove();
+
+    let public = vm.public();
+
+    let mimc_hash = mimc(params[0].1.clone(), params[1].1.clone(), &constants);
+    assert_eq!(public.len(), 1);
+    assert_eq!(public[0], mimc_hash);
+
+    assert!(vm.verify(&proof, &public));
+    Ok(())
+}

+ 443 - 0
src/vm.rs

@@ -0,0 +1,443 @@
+use bellman::{gadgets::Assignment, groth16, Circuit, ConstraintSystem, SynthesisError};
+use bls12_381::Bls12;
+use bls12_381::Scalar;
+use ff::{Field, PrimeField};
+use rand::rngs::OsRng;
+use std::ops::{AddAssign, MulAssign, SubAssign};
+use std::time::Instant;
+
+use crate::error::Result;
+
+pub struct ZkVirtualMachine {
+    pub constants: Vec<Scalar>,
+    pub alloc: Vec<(AllocType, VariableIndex)>,
+    pub ops: Vec<CryptoOperation>,
+    pub constraints: Vec<ConstraintInstruction>,
+
+    pub aux: Vec<Scalar>,
+
+    pub params: Option<groth16::Parameters<Bls12>>,
+    pub verifying_key: Option<groth16::PreparedVerifyingKey<Bls12>>,
+}
+
+pub type VariableIndex = usize;
+
+pub enum VariableRef {
+    Aux(VariableIndex),
+    Local(VariableIndex),
+}
+
+pub enum CryptoOperation {
+    Set(VariableRef, VariableRef),
+    Mul(VariableRef, VariableRef),
+    Add(VariableRef, VariableRef),
+    Sub(VariableRef, VariableRef),
+    Load(VariableRef, VariableIndex),
+    Divide(VariableRef, VariableRef),
+    Double(VariableRef),
+    Square(VariableRef),
+    Invert(VariableRef),
+    UnpackBits(VariableRef, VariableRef, VariableRef),
+    Local,
+    Debug(String, VariableRef),
+    DumpAlloc,
+    DumpLocal,
+}
+
+#[derive(Clone)]
+pub enum AllocType {
+    Private,
+    Public,
+}
+
+#[derive(Debug, Clone)]
+pub enum ConstraintInstruction {
+    Lc0Add(VariableIndex),
+    Lc1Add(VariableIndex),
+    Lc2Add(VariableIndex),
+    Lc0Sub(VariableIndex),
+    Lc1Sub(VariableIndex),
+    Lc2Sub(VariableIndex),
+    Lc0AddOne,
+    Lc1AddOne,
+    Lc2AddOne,
+    Lc0SubOne,
+    Lc1SubOne,
+    Lc2SubOne,
+    Lc0AddCoeff(VariableIndex, VariableIndex),
+    Lc1AddCoeff(VariableIndex, VariableIndex),
+    Lc2AddCoeff(VariableIndex, VariableIndex),
+    Lc0AddConstant(VariableIndex),
+    Lc1AddConstant(VariableIndex),
+    Lc2AddConstant(VariableIndex),
+    Enforce,
+    LcCoeffReset,
+    LcCoeffDouble,
+}
+
+#[derive(Debug)]
+pub enum ZkVmError {
+    DivisionByZero,
+    MalformedRange,
+}
+
+impl ZkVirtualMachine {
+    pub fn initialize(
+        &mut self,
+        params: &Vec<(VariableIndex, Scalar)>,
+    ) -> std::result::Result<(), ZkVmError> {
+        // Resize array
+        self.aux = vec![Scalar::zero(); self.alloc.len()];
+
+        // Copy over the parameters
+        for (index, value) in params {
+            //println!("Setting {} to {:?}", index, value);
+            self.aux[*index] = *value;
+        }
+
+        let mut local_stack: Vec<Scalar> = Vec::new();
+
+        for op in &self.ops {
+            match op {
+                CryptoOperation::Set(self_, other) => {
+                    let other = match other {
+                        VariableRef::Aux(index) => self.aux[*index].clone(),
+                        VariableRef::Local(index) => local_stack[*index].clone(),
+                    };
+                    let self_ = match self_ {
+                        VariableRef::Aux(index) => &mut self.aux[*index],
+                        VariableRef::Local(index) => &mut local_stack[*index],
+                    };
+                    *self_ = other;
+                }
+                CryptoOperation::Mul(self_, other) => {
+                    let other = match other {
+                        VariableRef::Aux(index) => self.aux[*index].clone(),
+                        VariableRef::Local(index) => local_stack[*index].clone(),
+                    };
+                    let self_ = match self_ {
+                        VariableRef::Aux(index) => &mut self.aux[*index],
+                        VariableRef::Local(index) => &mut local_stack[*index],
+                    };
+                    self_.mul_assign(other);
+                }
+                CryptoOperation::Add(self_, other) => {
+                    let other = match other {
+                        VariableRef::Aux(index) => self.aux[*index].clone(),
+                        VariableRef::Local(index) => local_stack[*index].clone(),
+                    };
+                    let self_ = match self_ {
+                        VariableRef::Aux(index) => &mut self.aux[*index],
+                        VariableRef::Local(index) => &mut local_stack[*index],
+                    };
+                    self_.add_assign(other);
+                }
+                CryptoOperation::Sub(self_, other) => {
+                    let other = match other {
+                        VariableRef::Aux(index) => self.aux[*index].clone(),
+                        VariableRef::Local(index) => local_stack[*index].clone(),
+                    };
+                    let self_ = match self_ {
+                        VariableRef::Aux(index) => &mut self.aux[*index],
+                        VariableRef::Local(index) => &mut local_stack[*index],
+                    };
+                    self_.sub_assign(other);
+                }
+                CryptoOperation::Load(self_, const_index) => {
+                    let self_ = match self_ {
+                        VariableRef::Aux(index) => &mut self.aux[*index],
+                        VariableRef::Local(index) => &mut local_stack[*index],
+                    };
+                    *self_ = self.constants[*const_index];
+                }
+                CryptoOperation::Divide(self_, other) => {
+                    let other = match other {
+                        VariableRef::Aux(index) => self.aux[*index].clone(),
+                        VariableRef::Local(index) => local_stack[*index].clone(),
+                    };
+                    let self_ = match self_ {
+                        VariableRef::Aux(index) => &mut self.aux[*index],
+                        VariableRef::Local(index) => &mut local_stack[*index],
+                    };
+                    let ret = other.invert().map(|other| *self_ * other);
+                    if bool::from(ret.is_some()) {
+                        *self_ = ret.unwrap();
+                    } else {
+                        return Err(ZkVmError::DivisionByZero);
+                    }
+                }
+                CryptoOperation::Double(self_) => {
+                    let self_ = match self_ {
+                        VariableRef::Aux(index) => &mut self.aux[*index],
+                        VariableRef::Local(index) => &mut local_stack[*index],
+                    };
+                    *self_ = self_.double();
+                }
+                CryptoOperation::Square(self_) => {
+                    let self_ = match self_ {
+                        VariableRef::Aux(index) => &mut self.aux[*index],
+                        VariableRef::Local(index) => &mut local_stack[*index],
+                    };
+                    *self_ = self_.square();
+                }
+                CryptoOperation::Invert(self_) => {
+                    let self_ = match self_ {
+                        VariableRef::Aux(index) => &mut self.aux[*index],
+                        VariableRef::Local(index) => &mut local_stack[*index],
+                    };
+                    if self_.is_zero() {
+                        return Err(ZkVmError::DivisionByZero);
+                    } else {
+                        *self_ = self_.invert().unwrap();
+                    }
+                }
+                CryptoOperation::UnpackBits(value, start, end) => {
+                    let value = match value {
+                        VariableRef::Aux(index) => self.aux[*index].clone(),
+                        VariableRef::Local(index) => local_stack[*index].clone(),
+                    };
+                    let (self_, start_index, end_index) = match start {
+                        VariableRef::Aux(start_index) => match end {
+                            VariableRef::Aux(end_index) => (&mut self.aux, start_index, end_index),
+                            VariableRef::Local(_) => {
+                                return Err(ZkVmError::MalformedRange);
+                            }
+                        },
+                        VariableRef::Local(start_index) => match end {
+                            VariableRef::Aux(_) => {
+                                return Err(ZkVmError::MalformedRange);
+                            }
+                            VariableRef::Local(end_index) => {
+                                (&mut local_stack, start_index, end_index)
+                            }
+                        },
+                    };
+                    if start_index > end_index {
+                        return Err(ZkVmError::MalformedRange);
+                    }
+                    if (end_index + 1) - start_index != 256 {
+                        return Err(ZkVmError::MalformedRange);
+                    }
+                    if *end_index >= self_.len() {
+                        return Err(ZkVmError::MalformedRange);
+                    }
+
+                    for (i, bit) in value.to_le_bits().into_iter().cloned().enumerate() {
+                        match bit {
+                            true => self_[start_index + i] = Scalar::one(),
+                            false => self_[start_index + i] = Scalar::zero(),
+                        }
+                    }
+                }
+                CryptoOperation::Local => {
+                    local_stack.push(Scalar::zero());
+                }
+                CryptoOperation::Debug(debug_str, self_) => {
+                    let self_ = match self_ {
+                        VariableRef::Aux(index) => &mut self.aux[*index],
+                        VariableRef::Local(index) => &mut local_stack[*index],
+                    };
+                    println!("{}", debug_str);
+                    println!("value = {:?}", self_);
+                }
+                CryptoOperation::DumpAlloc => {
+                    println!("-------------------");
+                    println!("alloc");
+                    println!("-------------------");
+                    for (i, value) in self.aux.iter().enumerate() {
+                        println!("{}: {:?}", i, value);
+                    }
+                    println!("-------------------");
+                }
+                CryptoOperation::DumpLocal => {
+                    println!("-------------------");
+                    println!("local");
+                    println!("-------------------");
+                    for (i, value) in local_stack.iter().enumerate() {
+                        println!("{}: {:?}", i, value);
+                    }
+                    println!("-------------------");
+                }
+            }
+        }
+
+        Ok(())
+    }
+
+    pub fn public(&self) -> Vec<(VariableIndex, Scalar)> {
+        let mut publics = Vec::new();
+        for (alloc_type, index) in &self.alloc {
+            match alloc_type {
+                AllocType::Private => {}
+                AllocType::Public => {
+                    let scalar = self.aux[*index].clone();
+                    publics.push((*index, scalar));
+                }
+            }
+        }
+        publics
+    }
+
+    pub fn setup(&mut self) -> Result<()> {
+        let start = Instant::now();
+        // Create parameters for our circuit. In a production deployment these would
+        // be generated securely using a multiparty computation.
+        self.params = Some({
+            let circuit = ZkVmCircuit {
+                aux: vec![None; self.aux.len()],
+                alloc: self.alloc.clone(),
+                constraints: self.constraints.clone(),
+                constants: self.constants.clone(),
+            };
+            groth16::generate_random_parameters::<Bls12, _, _>(circuit, &mut OsRng)?
+        });
+
+        println!("Setup: [{:?}]", start.elapsed());
+
+        self.verifying_key = Some(groth16::prepare_verifying_key(
+            &self.params.as_ref().unwrap().vk,
+        ));
+        Ok(())
+    }
+
+    pub fn prove(&self) -> groth16::Proof<Bls12> {
+        let aux = self.aux.iter().map(|scalar| Some(scalar.clone())).collect();
+        // Create an instance of our circuit (with the preimage as a witness).
+        let circuit = ZkVmCircuit {
+            aux,
+            alloc: self.alloc.clone(),
+            constraints: self.constraints.clone(),
+            constants: self.constants.clone(),
+        };
+
+        let start = Instant::now();
+        // Create a Groth16 proof with our parameters.
+        let proof =
+            groth16::create_random_proof(circuit, self.params.as_ref().unwrap(), &mut OsRng)
+                .unwrap();
+        println!("Prove: [{:?}]", start.elapsed());
+        proof
+    }
+
+    pub fn verify(&self, proof: &groth16::Proof<Bls12>, public_values: &Vec<Scalar>) -> bool {
+        let start = Instant::now();
+        let is_passed =
+            groth16::verify_proof(self.verifying_key.as_ref().unwrap(), proof, public_values)
+                .is_ok();
+        println!("Verify: [{:?}]", start.elapsed());
+        is_passed
+    }
+}
+
+pub struct ZkVmCircuit {
+    aux: Vec<Option<bls12_381::Scalar>>,
+    alloc: Vec<(AllocType, VariableIndex)>,
+    constraints: Vec<ConstraintInstruction>,
+    constants: Vec<Scalar>,
+}
+
+impl Circuit<bls12_381::Scalar> for ZkVmCircuit {
+    fn synthesize<CS: ConstraintSystem<bls12_381::Scalar>>(
+        self,
+        cs: &mut CS,
+    ) -> std::result::Result<(), SynthesisError> {
+        let mut variables = Vec::new();
+
+        for (alloc_type, index) in &self.alloc {
+            match alloc_type {
+                AllocType::Private => {
+                    let var = cs.alloc(|| "private alloc", || Ok(*self.aux[*index].get()?))?;
+                    variables.push(var);
+                }
+                AllocType::Public => {
+                    let var = cs.alloc_input(|| "public alloc", || Ok(*self.aux[*index].get()?))?;
+                    variables.push(var);
+                }
+            }
+        }
+
+        let mut coeff = bls12_381::Scalar::one();
+        let mut lc0 = bellman::LinearCombination::<Scalar>::zero();
+        let mut lc1 = bellman::LinearCombination::<Scalar>::zero();
+        let mut lc2 = bellman::LinearCombination::<Scalar>::zero();
+
+        for constraint in self.constraints {
+            match constraint {
+                ConstraintInstruction::Lc0Add(index) => {
+                    lc0 = lc0 + (coeff, variables[index]);
+                }
+                ConstraintInstruction::Lc1Add(index) => {
+                    lc1 = lc1 + (coeff, variables[index]);
+                }
+                ConstraintInstruction::Lc2Add(index) => {
+                    lc2 = lc2 + (coeff, variables[index]);
+                }
+                ConstraintInstruction::Lc0Sub(index) => {
+                    lc0 = lc0 - (coeff, variables[index]);
+                }
+                ConstraintInstruction::Lc1Sub(index) => {
+                    lc1 = lc1 - (coeff, variables[index]);
+                }
+                ConstraintInstruction::Lc2Sub(index) => {
+                    lc2 = lc2 - (coeff, variables[index]);
+                }
+                ConstraintInstruction::Lc0AddOne => {
+                    lc0 = lc0 + CS::one();
+                }
+                ConstraintInstruction::Lc1AddOne => {
+                    lc1 = lc1 + CS::one();
+                }
+                ConstraintInstruction::Lc2AddOne => {
+                    lc2 = lc2 + CS::one();
+                }
+                ConstraintInstruction::Lc0SubOne => {
+                    lc0 = lc0 - CS::one();
+                }
+                ConstraintInstruction::Lc1SubOne => {
+                    lc1 = lc1 - CS::one();
+                }
+                ConstraintInstruction::Lc2SubOne => {
+                    lc2 = lc2 - CS::one();
+                }
+                ConstraintInstruction::Lc0AddCoeff(const_index, index) => {
+                    lc0 = lc0 + (self.constants[const_index], variables[index]);
+                }
+                ConstraintInstruction::Lc1AddCoeff(const_index, index) => {
+                    lc1 = lc1 + (self.constants[const_index], variables[index]);
+                }
+                ConstraintInstruction::Lc2AddCoeff(const_index, index) => {
+                    lc2 = lc2 + (self.constants[const_index], variables[index]);
+                }
+                ConstraintInstruction::Lc0AddConstant(const_index) => {
+                    lc0 = lc0 + (self.constants[const_index], CS::one());
+                }
+                ConstraintInstruction::Lc1AddConstant(const_index) => {
+                    lc1 = lc1 + (self.constants[const_index], CS::one());
+                }
+                ConstraintInstruction::Lc2AddConstant(const_index) => {
+                    lc2 = lc2 + (self.constants[const_index], CS::one());
+                }
+                ConstraintInstruction::Enforce => {
+                    cs.enforce(
+                        || "constraint",
+                        |_| lc0.clone(),
+                        |_| lc1.clone(),
+                        |_| lc2.clone(),
+                    );
+                    coeff = bls12_381::Scalar::one();
+                    lc0 = bellman::LinearCombination::<Scalar>::zero();
+                    lc1 = bellman::LinearCombination::<Scalar>::zero();
+                    lc2 = bellman::LinearCombination::<Scalar>::zero();
+                }
+                ConstraintInstruction::LcCoeffReset => {
+                    coeff = bls12_381::Scalar::one();
+                }
+                ConstraintInstruction::LcCoeffDouble => {
+                    coeff = coeff.double();
+                }
+            }
+        }
+
+        Ok(())
+    }
+}

+ 245 - 0
src/vm_serial.rs

@@ -0,0 +1,245 @@
+use crate::error::{Error, Result};
+use crate::serial::{Decodable, Encodable, ReadExt, VarInt};
+use crate::vm::{
+    AllocType, ConstraintInstruction, CryptoOperation, VariableIndex, VariableRef, ZkVirtualMachine,
+};
+use crate::{impl_vec, ZkContract, ZkProof};
+use bellman::groth16;
+use bls12_381 as bls;
+use std::collections::HashMap;
+use std::io;
+
+impl_vec!((String, VariableIndex));
+impl_vec!((String, bls::Scalar));
+
+impl Encodable for ZkContract {
+    fn encode<S: io::Write>(&self, _s: S) -> Result<usize> {
+        unimplemented!();
+        //Ok(0)
+    }
+}
+
+impl Decodable for ZkContract {
+    fn decode<D: io::Read>(mut d: D) -> Result<Self> {
+        Ok(Self {
+            name: Decodable::decode(&mut d)?,
+            vm: ZkVirtualMachine {
+                constants: Decodable::decode(&mut d)?,
+                alloc: Decodable::decode(&mut d)?,
+                ops: Decodable::decode(&mut d)?,
+                constraints: Decodable::decode(&mut d)?,
+
+                aux: Vec::new(),
+                params: None,
+                verifying_key: None,
+            },
+            params_map: Vec::<(String, VariableIndex)>::decode(&mut d)?
+                .into_iter()
+                .collect(),
+            public_map: Vec::<(String, VariableIndex)>::decode(&mut d)?
+                .into_iter()
+                .collect(),
+
+            params: HashMap::new(),
+        })
+    }
+}
+
+impl Encodable for ZkProof {
+    fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
+        let mut len = self
+            .public
+            .iter()
+            .map(|(k, v)| (k.clone(), v.clone()))
+            .collect::<Vec<_>>()
+            .encode(&mut s)?;
+        len += self.proof.encode(&mut s)?;
+        Ok(len)
+    }
+}
+
+impl Decodable for ZkProof {
+    fn decode<D: io::Read>(mut d: D) -> Result<Self> {
+        Ok(Self {
+            public: Vec::<(String, bls::Scalar)>::decode(&mut d)?
+                .into_iter()
+                .collect(),
+            proof: Decodable::decode(&mut d)?,
+        })
+    }
+}
+
+impl Encodable for groth16::Proof<bls::Bls12> {
+    fn encode<S: io::Write>(&self, s: S) -> Result<usize> {
+        self.write(s)?;
+        // Depends on groth16 impl
+        Ok(48 + 96 + 48)
+    }
+}
+
+impl Decodable for groth16::Proof<bls::Bls12> {
+    fn decode<D: io::Read>(d: D) -> Result<Self> {
+        Ok(groth16::Proof::read(d)?)
+    }
+}
+
+impl Encodable for (AllocType, VariableIndex) {
+    fn encode<S: io::Write>(&self, _s: S) -> Result<usize> {
+        //let len = self.x.encode(&mut s)?;
+        //Ok(len + self.y.encode(s)?)
+        unimplemented!();
+        //Ok(0)
+    }
+}
+
+impl Decodable for (AllocType, VariableIndex) {
+    fn decode<D: io::Read>(mut d: D) -> Result<Self> {
+        let type_val = ReadExt::read_u8(&mut d)?;
+        assert!(type_val == 0 || type_val == 1);
+        let alloc_type = if type_val == 0 {
+            AllocType::Private
+        } else {
+            AllocType::Public
+        };
+        Ok((alloc_type, ReadExt::read_u32(&mut d)? as usize))
+    }
+}
+
+impl_vec!((AllocType, VariableIndex));
+
+impl Encodable for VariableIndex {
+    fn encode<S: io::Write>(&self, s: S) -> Result<usize> {
+        let len = Encodable::encode(&((*self) as u64), s)?;
+        Ok(len)
+    }
+}
+
+impl Decodable for VariableIndex {
+    fn decode<D: io::Read>(mut d: D) -> Result<Self> {
+        let val: u64 = Decodable::decode(&mut d)?;
+        Ok(val as Self)
+    }
+}
+
+impl Encodable for VariableRef {
+    fn encode<S: io::Write>(&self, _s: S) -> Result<usize> {
+        unimplemented!();
+        //Ok(0)
+    }
+}
+
+impl Decodable for VariableRef {
+    fn decode<D: io::Read>(mut d: D) -> Result<Self> {
+        let arg_type = ReadExt::read_u8(&mut d)?;
+        match arg_type {
+            0 => Ok(Self::Aux(Decodable::decode(&mut d)?)),
+            1 => Ok(Self::Local(Decodable::decode(&mut d)?)),
+            _ => Err(Error::BadVariableRefType),
+        }
+    }
+}
+
+impl Encodable for CryptoOperation {
+    fn encode<S: io::Write>(&self, _s: S) -> Result<usize> {
+        unimplemented!();
+        //Ok(0)
+    }
+}
+
+impl Decodable for CryptoOperation {
+    fn decode<D: io::Read>(mut d: D) -> Result<Self> {
+        let op_type = ReadExt::read_u8(&mut d)?;
+        match op_type {
+            0 => Ok(Self::Set(
+                Decodable::decode(&mut d)?,
+                Decodable::decode(&mut d)?,
+            )),
+            1 => Ok(Self::Mul(
+                Decodable::decode(&mut d)?,
+                Decodable::decode(&mut d)?,
+            )),
+            2 => Ok(Self::Add(
+                Decodable::decode(&mut d)?,
+                Decodable::decode(&mut d)?,
+            )),
+            3 => Ok(Self::Sub(
+                Decodable::decode(&mut d)?,
+                Decodable::decode(&mut d)?,
+            )),
+            4 => Ok(Self::Divide(
+                Decodable::decode(&mut d)?,
+                Decodable::decode(&mut d)?,
+            )),
+            5 => Ok(Self::Double(Decodable::decode(&mut d)?)),
+            6 => Ok(Self::Square(Decodable::decode(&mut d)?)),
+            7 => Ok(Self::Invert(Decodable::decode(&mut d)?)),
+            8 => Ok(Self::UnpackBits(
+                Decodable::decode(&mut d)?,
+                Decodable::decode(&mut d)?,
+                Decodable::decode(&mut d)?,
+            )),
+            9 => Ok(Self::Local),
+            10 => Ok(Self::Load(
+                Decodable::decode(&mut d)?,
+                Decodable::decode(&mut d)?,
+            )),
+            11 => Ok(Self::Debug(
+                Decodable::decode(&mut d)?,
+                Decodable::decode(&mut d)?,
+            )),
+            12 => Ok(Self::DumpAlloc),
+            13 => Ok(Self::DumpLocal),
+            _i => Err(Error::BadOperationType),
+        }
+    }
+}
+
+impl_vec!(CryptoOperation);
+
+impl Encodable for ConstraintInstruction {
+    fn encode<S: io::Write>(&self, _s: S) -> Result<usize> {
+        unimplemented!();
+        //Ok(0)
+    }
+}
+
+impl Decodable for ConstraintInstruction {
+    fn decode<D: io::Read>(mut d: D) -> Result<Self> {
+        let constraint_type = ReadExt::read_u8(&mut d)?;
+        match constraint_type {
+            0 => Ok(Self::Lc0Add(Decodable::decode(&mut d)?)),
+            1 => Ok(Self::Lc1Add(Decodable::decode(&mut d)?)),
+            2 => Ok(Self::Lc2Add(Decodable::decode(&mut d)?)),
+            3 => Ok(Self::Lc0Sub(Decodable::decode(&mut d)?)),
+            4 => Ok(Self::Lc1Sub(Decodable::decode(&mut d)?)),
+            5 => Ok(Self::Lc2Sub(Decodable::decode(&mut d)?)),
+            6 => Ok(Self::Lc0AddOne),
+            7 => Ok(Self::Lc1AddOne),
+            8 => Ok(Self::Lc2AddOne),
+            9 => Ok(Self::Lc0SubOne),
+            10 => Ok(Self::Lc1SubOne),
+            11 => Ok(Self::Lc2SubOne),
+            12 => Ok(Self::Lc0AddCoeff(
+                Decodable::decode(&mut d)?,
+                Decodable::decode(&mut d)?,
+            )),
+            13 => Ok(Self::Lc1AddCoeff(
+                Decodable::decode(&mut d)?,
+                Decodable::decode(&mut d)?,
+            )),
+            14 => Ok(Self::Lc2AddCoeff(
+                Decodable::decode(&mut d)?,
+                Decodable::decode(&mut d)?,
+            )),
+            15 => Ok(Self::Lc0AddConstant(Decodable::decode(&mut d)?)),
+            16 => Ok(Self::Lc1AddConstant(Decodable::decode(&mut d)?)),
+            17 => Ok(Self::Lc2AddConstant(Decodable::decode(&mut d)?)),
+            18 => Ok(Self::Enforce),
+            19 => Ok(Self::LcCoeffReset),
+            20 => Ok(Self::LcCoeffDouble),
+            _ => Err(Error::BadConstraintType),
+        }
+    }
+}
+
+impl_vec!(ConstraintInstruction);