├── src └── main.rs ├── genpic.py ├── README.md ├── Cargo.toml ├── examples ├── crop.rs ├── gray.rs ├── generate-a-coms.rs ├── blur.rs ├── resize.rs ├── veritas.rs └── opt-veritas.rs └── Cargo.lock /src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("hello world!"); 3 | } 4 | -------------------------------------------------------------------------------- /genpic.py: -------------------------------------------------------------------------------- 1 | import random 2 | import sys 3 | 4 | prefix = sys.argv[1] 5 | imageSize = int(sys.argv[2]) 6 | pixelLength = int(sys.argv[3]) 7 | 8 | pixels = [] 9 | f = open(prefix + "_image_" + str(imageSize) + "_" + str(pixelLength) + ".txt", "w") 10 | for i in range(imageSize): 11 | #f.write(str(i)) 12 | pixel = str(random.randint(0, 2**pixelLength - 1)) 13 | pixels.append(pixel) 14 | f.write(pixel) 15 | f.write("\n") 16 | 17 | 18 | r = 52435875175126190479447740508185965837690552500527637822603658699938581184513 19 | 20 | f = open(prefix + "_hash_" + str(imageSize) + "_" + str(pixelLength) + ".txt", "w") 21 | for i in range(imageSize): 22 | #f.write(str(i)) 23 | f.write(str(random.randint(0, r - 1))) 24 | f.write("\n") -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | To create an example hash proof for D pixels of max value 2^E using VerITAS, run: 2 | 3 | `python3 genpic.py orig D E` 4 | 5 | `python3 genpic.py edited D E` 6 | 7 | Then, in `veritas.rs`, edit line 45 to say `static D : usize = D;`, and edit line 46 to say, static 8 | `EXPONENT : u32 = E;` 9 | 10 | Then, run: 11 | 12 | `cargo run --release --example veritas` 13 | 14 | To create an example hash proof for D pixels of max value 2^E using opt-VerITAS, in `generate-a-row-coms.rs`, 15 | edit line ?? to say `static D : usize = D;`, and edit line 49 to say, static `EXPONENT : u32 = E;` 16 | 17 | Then, run: 18 | 19 | `cargo run --release --example generate-a-row-coms` 20 | 21 | This should create 8 files of the form `A_D_E_i.txt`. 22 | 23 | Lastly, run: 24 | 25 | `cargo run --release --example opt-veritas` 26 | 27 | To create the editing proofs, you can run (and change the parameters within the corresponding files): 28 | 29 | `cargo run --release --example blur` 30 | 31 | `cargo run --release --example resize` 32 | 33 | `cargo run --release --example crop` 34 | 35 | `cargo run --release --example gray` 36 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "zk-veritas" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [features] 9 | #default = ["gate_testing", "parallel", "rand_chacha", "std", "timing"] 10 | #gate_testing = [] 11 | #parallel = ["hashbrown/rayon", "plonky2_maybe_rayon/parallel"] 12 | #std = ["anyhow/std", "rand/std", "itertools/use_std"] 13 | #timing = ["std", "dep:web-time"] 14 | 15 | [dependencies] 16 | ahash = { version = "0.8.7", default-features = false, features = ["compile-time-rng"] } # NOTE: Be sure to keep this version the same as the dependency in `hashbrown`. 17 | anyhow = { version = "1.0.40", default-features = false } 18 | hashbrown = { version = "0.14.3", default-features = false, features = ["ahash", "serde"] } # NOTE: When upgrading, see `ahash` dependency. 19 | itertools = { version = "0.11.0", default-features = false } 20 | log = { version = "0.4.14", default-features = false } 21 | num = { version = "0.4", default-features = false, features = ["rand"] } 22 | rand = { version = "0.8.4", default-features = false } 23 | serde = { version = "1.0", default-features = false, features = ["derive"] } 24 | static_assertions = { version = "1.1.0", default-features = false } 25 | unroll = { version = "0.1.5", default-features = false } 26 | sha256 = "1.1.2" 27 | plonky2 = "0.2.2" 28 | rayon = "1.10.0" 29 | 30 | 31 | # Local dependencies 32 | # plonky2_maybe_rayon = { version = "0.2.0", path = "../maybe_rayon", default-features = false } -------------------------------------------------------------------------------- /examples/crop.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Result; 2 | use plonky2::field::types::Field; 3 | use plonky2::iop::witness::{PartialWitness, WitnessWrite}; 4 | use plonky2::plonk::circuit_builder::CircuitBuilder; 5 | use plonky2::plonk::circuit_data::CircuitConfig; 6 | use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; 7 | use std::time::{SystemTime, UNIX_EPOCH}; 8 | 9 | use rand::rngs::OsRng; 10 | use rand::Rng; 11 | 12 | static OLD_SIZE : usize = 10; 13 | static NEW_SIZE : usize = 3; 14 | 15 | fn print_time_since(last: u128, tag: &str) -> u128 { 16 | let now = SystemTime::now(); 17 | let now_epoc = now 18 | .duration_since(UNIX_EPOCH) 19 | .expect("Time went backwards"); 20 | let now = now_epoc.as_millis(); 21 | println!("{:?} - time since last check: {:?}", tag, (now - last) as f32 / 60000.0); 22 | return now; 23 | } 24 | 25 | fn main() -> Result<()> { 26 | const D: usize = 2; 27 | type C = PoseidonGoldilocksConfig; 28 | type F = >::F; 29 | 30 | let mut rng = OsRng; 31 | 32 | // Timing setup 33 | let start = SystemTime::now(); 34 | let start_epoch = start 35 | .duration_since(UNIX_EPOCH) 36 | .expect("Time went backwards"); 37 | let start = start_epoch.as_millis(); 38 | let mut last = start; 39 | 40 | let mut w_r_vals = Vec::new(); 41 | let mut x_r_vals = Vec::new(); 42 | 43 | for _ in 0..OLD_SIZE { 44 | w_r_vals.push(rng.gen_range(0..256) as u32); 45 | } 46 | 47 | for i in 0..NEW_SIZE { 48 | x_r_vals.push(w_r_vals[i]); 49 | } 50 | 51 | last = print_time_since(last, "values generated"); 52 | 53 | let mut config = CircuitConfig::standard_recursion_config(); 54 | config.zero_knowledge = true; 55 | let mut builder = CircuitBuilder::::new(config); 56 | 57 | let mut pw = PartialWitness::new(); 58 | 59 | let mut w_r_targets = Vec::new(); 60 | 61 | for _ in 0..NEW_SIZE { 62 | let r = builder.add_virtual_target(); 63 | w_r_targets.push(r); 64 | builder.register_public_input(r); 65 | } 66 | 67 | 68 | let data = builder.build::(); 69 | last = print_time_since(last, "setup done"); 70 | 71 | for i in 0..NEW_SIZE { 72 | pw.set_target(w_r_targets[i], F::from_canonical_u32(w_r_vals[i])); 73 | } 74 | 75 | let proof = data.prove(pw)?; 76 | let compressed_proof = data.compress(proof)?; 77 | 78 | last = print_time_since(last, "proof done"); 79 | 80 | // println!("proof.public_inputs: {:?}", proof.public_inputs); 81 | 82 | let decompressed_compressed_proof = data.decompress(compressed_proof)?; 83 | 84 | 85 | for i in 0..decompressed_compressed_proof.public_inputs.len() { 86 | assert!((decompressed_compressed_proof.public_inputs[i].0) as u32 == x_r_vals[i]); 87 | } 88 | 89 | let res = data.verify(decompressed_compressed_proof); 90 | let _ = res.unwrap(); 91 | 92 | 93 | 94 | _ = print_time_since(last, "verify done"); 95 | 96 | Ok(()) 97 | } 98 | -------------------------------------------------------------------------------- /examples/gray.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Result; 2 | use plonky2::field::types::Field; 3 | use plonky2::iop::witness::{PartialWitness, WitnessWrite}; 4 | use plonky2::plonk::circuit_builder::CircuitBuilder; 5 | use plonky2::plonk::circuit_data::CircuitConfig; 6 | use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; 7 | use std::time::{SystemTime, UNIX_EPOCH}; 8 | 9 | use rand::rngs::OsRng; 10 | use rand::Rng; 11 | 12 | static PIXELS : usize = 10; 13 | 14 | fn print_time_since(last: u128, tag: &str) -> u128 { 15 | let now = SystemTime::now(); 16 | let now_epoc = now 17 | .duration_since(UNIX_EPOCH) 18 | .expect("Time went backwards"); 19 | let now = now_epoc.as_millis(); 20 | println!("{:?} - time since last check: {:?}", tag, (now - last) as f32 / 60000.0); 21 | return now; 22 | } 23 | 24 | fn main() -> Result<()> { 25 | const D: usize = 2; 26 | type C = PoseidonGoldilocksConfig; 27 | type F = >::F; 28 | 29 | let mut rng = OsRng; 30 | 31 | let mut r_vals = Vec::new(); 32 | let mut g_vals = Vec::new(); 33 | let mut b_vals = Vec::new(); 34 | let mut x_vals = Vec::new(); 35 | let mut rem_vals = Vec::new(); 36 | 37 | for i in 0..PIXELS { 38 | r_vals.push(rng.gen_range(0..256) as u32); 39 | g_vals.push(rng.gen_range(0..256) as u32); 40 | b_vals.push(rng.gen_range(0..256) as u32); 41 | 42 | let r_f = r_vals[i] as f64; 43 | let g_f = g_vals[i] as f64; 44 | let b_f = b_vals[i] as f64; 45 | 46 | let x_f = 0.3 * r_f + 0.59 * g_f + 0.11 * b_f; 47 | x_vals.push(x_f.round() as i32); 48 | 49 | rem_vals.push((r_vals[i] * 30 + g_vals[i] * 59 + b_vals[i] * 11) as i32 - 100 * x_vals[i]); 50 | } 51 | 52 | // Timing setup 53 | let start = SystemTime::now(); 54 | let start_epoch = start 55 | .duration_since(UNIX_EPOCH) 56 | .expect("Time went backwards"); 57 | let start = start_epoch.as_millis(); 58 | let mut last = start; 59 | 60 | let mut config = CircuitConfig::standard_recursion_config(); 61 | config.zero_knowledge = true; 62 | let mut builder = CircuitBuilder::::new(config); 63 | 64 | let mut pw = PartialWitness::new(); 65 | 66 | let mut r_targets = Vec::new(); 67 | let mut g_targets = Vec::new(); 68 | let mut b_targets = Vec::new(); 69 | 70 | for _ in 0..PIXELS { 71 | let r = builder.add_virtual_target(); 72 | r_targets.push(r); 73 | 74 | let g = builder.add_virtual_target(); 75 | g_targets.push(g); 76 | 77 | let b = builder.add_virtual_target(); 78 | b_targets.push(b); 79 | 80 | let mut all = Vec::new(); 81 | 82 | all.push(builder.mul_const(F::from_canonical_u32(30), r)); 83 | all.push(builder.mul_const(F::from_canonical_u32(59), g)); 84 | all.push(builder.mul_const(F::from_canonical_u32(11), b)); 85 | 86 | let s = builder.add_many(all); 87 | builder.register_public_input(s); 88 | } 89 | 90 | let data = builder.build::(); 91 | last = print_time_since(last, "setup done"); 92 | 93 | for i in 0..PIXELS { 94 | pw.set_target(r_targets[i], F::from_canonical_u32(r_vals[i])); 95 | pw.set_target(g_targets[i], F::from_canonical_u32(g_vals[i])); 96 | pw.set_target(b_targets[i], F::from_canonical_u32(b_vals[i])); 97 | } 98 | 99 | let proof = data.prove(pw)?; 100 | last = print_time_since(last, "proof done"); 101 | 102 | for i in 0..PIXELS { 103 | assert!((proof.public_inputs[i].0) as i32 == 100 * x_vals[i] + rem_vals[i]) 104 | } 105 | 106 | let res = data.verify(proof); 107 | let _ = res.unwrap(); 108 | 109 | _ = print_time_since(last, "verify done"); 110 | 111 | Ok(()) 112 | } 113 | -------------------------------------------------------------------------------- /examples/generate-a-coms.rs: -------------------------------------------------------------------------------- 1 | use plonky2::field::polynomial::{PolynomialValues}; 2 | use plonky2::fri::oracle::PolynomialBatch; 3 | use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; 4 | use plonky2::field::types::Field; 5 | use plonky2::util::timing::TimingTree; 6 | use plonky2::field::fft::fft_root_table; 7 | use plonky2::util::{log2_ceil, log2_strict}; 8 | use core::cmp::max; 9 | use std::time::{SystemTime, UNIX_EPOCH}; 10 | use std::fs::File; 11 | use plonky2::field::types::Field64; 12 | use std::io::BufWriter; 13 | use std::io::Write; 14 | 15 | static PIXELS : usize = 14; 16 | static EXPONENT : u32 = 3; 17 | static HASH_LENGTH : usize = 128; 18 | const BATCH_SIZE : usize = 32; 19 | const DEGREE : usize = 1 << 5; 20 | 21 | // lattice hash generation constants 22 | const A_CONSTANT : u128 = 3935559000370003845; 23 | const C_CONSTANT : u128 = 2691343689449507681; 24 | 25 | 26 | const D: usize = 2; 27 | type C = PoseidonGoldilocksConfig; 28 | type F = >::F; 29 | 30 | 31 | fn print_time_since(start: u128, last: u128, tag: &str) -> u128 { 32 | let now = SystemTime::now(); 33 | let now_epoc = now 34 | .duration_since(UNIX_EPOCH) 35 | .expect("Time went backwards"); 36 | let now = now_epoc.as_millis(); 37 | println!("{:?}; time since start {:?}; time since last check: {:?}", tag, (now - start) as f32 / 60000.0, (now - last) as f32 / 60000.0); 38 | return now; 39 | } 40 | 41 | 42 | fn main() { 43 | // FRI commitment constants 44 | let rate_bits = 2; 45 | let max_quotient_degree_factor = 4; 46 | let degree_bits = log2_strict(DEGREE); 47 | 48 | let max_fft_points = 1 << (degree_bits + max(rate_bits, log2_ceil(max_quotient_degree_factor))); 49 | 50 | let fft_root_table = fft_root_table(max_fft_points); 51 | 52 | 53 | let start = SystemTime::now(); 54 | let start_epoch = start 55 | .duration_since(UNIX_EPOCH) 56 | .expect("Time went backwards"); 57 | let start = start_epoch.as_millis(); 58 | let mut last = start; 59 | 60 | for batch in 0..HASH_LENGTH / BATCH_SIZE { 61 | let mut a_vals_vec = Vec::new(); 62 | 63 | for _ in 0..BATCH_SIZE { 64 | a_vals_vec.push(Vec::new()); 65 | } 66 | 67 | let mut x = 3091352403337663489; 68 | for _ in 0..PIXELS { 69 | for j in 0..HASH_LENGTH { 70 | x = (A_CONSTANT * x + C_CONSTANT) & 0xffffffffffffffff; 71 | let x1 = x >> 32; 72 | x = (A_CONSTANT * x + C_CONSTANT) & 0xffffffffffffffff; 73 | let x2 = ((x & 0xffffffff00000000) + x1) & 0xffffffffffffffff; 74 | let rand = F::from_canonical_u64(u64::try_from(x2).unwrap() % F::ORDER); 75 | 76 | if j / BATCH_SIZE == batch { 77 | a_vals_vec[j % BATCH_SIZE].push(rand); 78 | } 79 | } 80 | } 81 | 82 | let a_vals_length = a_vals_vec[0].len(); 83 | for _ in 0..DEGREE - a_vals_length { 84 | for i in 0..a_vals_vec.len() { 85 | a_vals_vec[i].push(F::ZERO); 86 | } 87 | } 88 | 89 | let mut polynomials_vec = Vec::new(); 90 | for i in 0..BATCH_SIZE { 91 | let a = PolynomialValues::new(a_vals_vec[i].clone()).ifft(); 92 | polynomials_vec.push(a); 93 | } 94 | 95 | last = print_time_since(start, last, "finished interpolating"); 96 | 97 | let commit0 = PolynomialBatch::::from_coeffs( 98 | polynomials_vec, 99 | rate_bits, 100 | false, 101 | 4, 102 | &mut TimingTree::default(), 103 | Some(&fft_root_table), 104 | ); 105 | 106 | let mut filename = "A_256_".to_owned(); 107 | filename.push_str(&PIXELS.to_string()); 108 | filename.push_str("_"); 109 | filename.push_str(&EXPONENT.to_string()); 110 | filename.push_str("_"); 111 | filename.push_str(&batch.to_string()); 112 | filename.push_str(".txt"); 113 | 114 | last = print_time_since(start, last, "finished committing"); 115 | 116 | let f = File::create(filename.clone()).expect("Unable to create file"); 117 | let mut f = BufWriter::new(f); 118 | 119 | println!("commit0.merkle_tree.cap.len() {:?}", commit0.merkle_tree.cap.len()); 120 | println!("commit0.merkle_tree.cap.0.len() {:?}", commit0.merkle_tree.cap.0[0].elements.len()); 121 | for hash in &commit0.merkle_tree.cap.0 { 122 | writeln!(f, "{:?}", hash.elements); 123 | } 124 | drop(f); 125 | 126 | last = print_time_since(start, last, "finished writing commits"); 127 | 128 | } 129 | 130 | } -------------------------------------------------------------------------------- /examples/blur.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Result; 2 | use plonky2::field::types::Field; 3 | use plonky2::iop::witness::{PartialWitness, WitnessWrite}; 4 | use plonky2::plonk::circuit_builder::CircuitBuilder; 5 | use plonky2::plonk::circuit_data::CircuitConfig; 6 | use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; 7 | use std::time::{SystemTime, UNIX_EPOCH}; 8 | 9 | use rand::rngs::OsRng; 10 | use rand::Rng; 11 | 12 | static H : usize = 14; 13 | static W : usize = 14; 14 | static BLUR_H : usize = 6; 15 | static BLUR_W : usize = 6; 16 | 17 | fn print_time_since(last: u128, tag: &str) -> u128 { 18 | let now = SystemTime::now(); 19 | let now_epoc = now 20 | .duration_since(UNIX_EPOCH) 21 | .expect("Time went backwards"); 22 | let now = now_epoc.as_millis(); 23 | println!("{:?} - time since last check: {:?}", tag, (now - last) as f32 / 60000.0); 24 | return now; 25 | } 26 | 27 | fn main() -> Result<()> { 28 | const D: usize = 2; 29 | type C = PoseidonGoldilocksConfig; 30 | type F = >::F; 31 | 32 | let mut rng = OsRng; 33 | 34 | let mut w_r_vals = Vec::new(); 35 | let mut x_r_vals = Vec::new(); 36 | 37 | for _ in 0..H { 38 | let mut r_row = Vec::new(); 39 | for _ in 0..W { 40 | r_row.push(rng.gen_range(0..256) as usize); 41 | } 42 | w_r_vals.push(r_row); 43 | } 44 | 45 | for i in 0..H { 46 | let mut r_row = Vec::new(); 47 | for j in 0..W { 48 | 49 | if i > 0 && i < 1 + BLUR_H && j > 0 && j < 1 + BLUR_W { 50 | // in blur region 51 | let sum_r = w_r_vals[i-1][j-1] + w_r_vals[i-1][j] + w_r_vals[i-1][j+1] 52 | + w_r_vals[i][j-1] + w_r_vals[i][j] + w_r_vals[i][j+1] 53 | + w_r_vals[i+1][j-1] + w_r_vals[i+1][j] + w_r_vals[i+1][j+1]; 54 | 55 | let blur_r = (sum_r as f64 / 9.0).round() as usize; 56 | r_row.push(blur_r); 57 | } 58 | else { 59 | r_row.push(w_r_vals[i][j]); 60 | } 61 | } 62 | x_r_vals.push(r_row); 63 | } 64 | 65 | // Timing setup 66 | let start = SystemTime::now(); 67 | let start_epoch = start 68 | .duration_since(UNIX_EPOCH) 69 | .expect("Time went backwards"); 70 | let start = start_epoch.as_millis(); 71 | let mut last = start; 72 | 73 | let config = CircuitConfig::standard_recursion_config(); 74 | let mut builder = CircuitBuilder::::new(config); 75 | 76 | let mut w_r_targets = Vec::new(); 77 | for _ in 0..H { 78 | let mut w_r_target_row = Vec::new(); 79 | for _ in 0..W { 80 | let w_r = builder.add_virtual_target(); 81 | w_r_target_row.push(w_r); 82 | } 83 | w_r_targets.push(w_r_target_row); 84 | } 85 | 86 | let mut x_r_targets = Vec::new(); 87 | for i in 0..H { 88 | let mut x_r_target_row = Vec::new(); 89 | for j in 0..W { 90 | if i > 0 && i < 1 + BLUR_H && j > 0 && j < 1 + BLUR_W { 91 | // in blur region 92 | let mut all_r = Vec::new(); 93 | 94 | all_r.push(w_r_targets[i-1][j-1]); 95 | all_r.push(w_r_targets[i-1][j]); 96 | all_r.push(w_r_targets[i-1][j+1]); 97 | all_r.push(w_r_targets[i][j-1]); 98 | all_r.push(w_r_targets[i][j]); 99 | all_r.push(w_r_targets[i][j+1]); 100 | all_r.push(w_r_targets[i+1][j-1]); 101 | all_r.push(w_r_targets[i+1][j]); 102 | all_r.push(w_r_targets[i+1][j+1]); 103 | 104 | 105 | let s_r = builder.add_many(all_r); 106 | 107 | // add 4 this so that remainder moves from value in [-4,4] to value in [0,8] 108 | let s_r_shift = builder.add_const(s_r, F::from_canonical_u32(4)); 109 | 110 | let x_r = builder.add_virtual_target(); 111 | x_r_target_row.push(x_r); 112 | let x_r_times_9 = builder.mul_const(F::from_canonical_u32(9), x_r); 113 | 114 | let rem_r = builder.sub(s_r_shift, x_r_times_9); 115 | 116 | // To check that rem \in [0, 8], we must check that rem < 2^4 and that 117 | // rem + 7 < 2^4 118 | builder.range_check(rem_r, 4); 119 | let rem_r_plus_7 = builder.add_const(rem_r, F::from_canonical_u32(7)); 120 | builder.range_check(rem_r_plus_7, 4); 121 | 122 | } 123 | else { 124 | builder.register_public_input(w_r_targets[i][j]); 125 | } 126 | } 127 | if x_r_target_row.len() > 0 { 128 | x_r_targets.push(x_r_target_row); 129 | } 130 | } 131 | 132 | let data = builder.build::(); 133 | last = print_time_since(last, "setup done"); 134 | 135 | let mut pw = PartialWitness::new(); 136 | 137 | for i in 0..H { 138 | for j in 0..W { 139 | pw.set_target(w_r_targets[i][j], F::from_canonical_u32(w_r_vals[i][j] as u32)); 140 | } 141 | } 142 | 143 | for i in 0..BLUR_H { 144 | for j in 0..BLUR_W { 145 | pw.set_target(x_r_targets[i][j], F::from_canonical_u32(x_r_vals[i+1][j+1] as u32)); 146 | } 147 | } 148 | 149 | 150 | let proof = data.prove(pw)?; 151 | last = print_time_since(last, "proof done"); 152 | 153 | let mut ctr = 0; 154 | for i in 0..H { 155 | for j in 0..W { 156 | if !(i > 0 && i < 1 + BLUR_H && j > 0 && j < 1 + BLUR_W) { 157 | assert!(x_r_vals[i][j] as u64 == proof.public_inputs[ctr].0); 158 | ctr += 1; 159 | } 160 | 161 | } 162 | } 163 | 164 | let res = data.verify(proof); 165 | let _ = res.unwrap(); 166 | 167 | _ = print_time_since(last, "verify done"); 168 | 169 | Ok(()) 170 | } 171 | -------------------------------------------------------------------------------- /examples/resize.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Result; 2 | use plonky2::field::types::Field; 3 | use plonky2::iop::witness::{PartialWitness, WitnessWrite}; 4 | use plonky2::plonk::circuit_builder::CircuitBuilder; 5 | use plonky2::plonk::circuit_data::CircuitConfig; 6 | use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; 7 | use std::time::{SystemTime, UNIX_EPOCH}; 8 | 9 | use rand::rngs::OsRng; 10 | use rand::Rng; 11 | 12 | static H_ORIG : usize = 10; 13 | static W_ORIG : usize = 10; 14 | static H_NEW : usize = 6; 15 | static W_NEW : usize = 6; 16 | 17 | /*static H_ORIG : usize = 6632; 18 | static W_ORIG : usize = 4976; 19 | static H_NEW : usize = 2048; 20 | static W_NEW : usize = 1365;*/ 21 | 22 | 23 | fn print_time_since(last: u128, tag: &str) -> u128 { 24 | let now = SystemTime::now(); 25 | let now_epoc = now 26 | .duration_since(UNIX_EPOCH) 27 | .expect("Time went backwards"); 28 | let now = now_epoc.as_millis(); 29 | println!("{:?} - time since last check: {:?}", tag, (now - last) as f32 / 60000.0); 30 | return now; 31 | } 32 | 33 | fn get_positions(i: usize, j: usize) -> (usize, usize, usize, usize) { 34 | let x_l = (W_ORIG - 1) * j / (W_NEW - 1); 35 | let y_l = (H_ORIG - 1) * i / (H_NEW - 1); 36 | 37 | let x_h = if x_l * (W_NEW - 1) == (W_ORIG - 1) * j { x_l } else { x_l + 1 }; 38 | let y_h = if y_l * (H_NEW - 1) == (H_ORIG - 1) * i { y_l } else { y_l + 1 }; 39 | 40 | return (x_l, y_l, x_h, y_h); 41 | } 42 | 43 | fn get_ratios(i: usize, j: usize) -> (usize, usize) { 44 | let x_ratio_weighted = ((W_ORIG - 1) * j) - (W_NEW - 1) * ((W_ORIG - 1) * j / (W_NEW - 1)); 45 | let y_ratio_weighted = ((H_ORIG - 1) * i) - (H_NEW - 1) * ((H_ORIG - 1) * i / (H_NEW - 1)); 46 | return (x_ratio_weighted, y_ratio_weighted); 47 | } 48 | 49 | fn main() -> Result<()> { 50 | const D: usize = 2; 51 | type C = PoseidonGoldilocksConfig; 52 | type F = >::F; 53 | 54 | let mut rng = OsRng; 55 | 56 | let mut w_r_vals = Vec::new(); 57 | let mut w_g_vals = Vec::new(); 58 | let mut w_b_vals = Vec::new(); 59 | let mut x_r_vals = Vec::new(); 60 | let mut rem_r_vals = Vec::new(); 61 | 62 | for _ in 0..H_ORIG { 63 | let mut r_row = Vec::new(); 64 | let mut g_row = Vec::new(); 65 | let mut b_row = Vec::new(); 66 | for _ in 0..W_ORIG { 67 | r_row.push(rng.gen_range(0..256) as usize); 68 | g_row.push(rng.gen_range(0..256) as usize); 69 | b_row.push(rng.gen_range(0..256) as usize); 70 | } 71 | w_r_vals.push(r_row); 72 | w_g_vals.push(g_row); 73 | w_b_vals.push(b_row); 74 | } 75 | 76 | // ONLY FOR RED VALUES....then you'll try for G and B values 77 | for i in 0..H_NEW { 78 | let mut r_row = Vec::new(); 79 | let mut rem_r_row = Vec::new(); 80 | for j in 0..W_NEW { 81 | let (x_l, y_l, x_h, y_h) = get_positions(i, j); 82 | 83 | let (x_ratio_weighted, y_ratio_weighted) = get_ratios(i, j); 84 | 85 | let a = w_r_vals[y_l][x_l]; 86 | let b = w_r_vals[y_l][x_h]; 87 | let c = w_r_vals[y_h][x_l]; 88 | let d = w_r_vals[y_h][x_h]; 89 | 90 | let s = a * (W_NEW - 1 - x_ratio_weighted) * (H_NEW - 1 - y_ratio_weighted) 91 | + b * x_ratio_weighted * (H_NEW - 1 - y_ratio_weighted) 92 | + c * y_ratio_weighted * (W_NEW - 1 - x_ratio_weighted) 93 | + d * x_ratio_weighted * y_ratio_weighted; 94 | 95 | let new = ((s as f64) / (((W_NEW - 1) * (H_NEW - 1)) as f64)).round() as usize; 96 | 97 | let r = s as i64 - (new * (W_NEW - 1) * (H_NEW - 1)) as i64; 98 | 99 | r_row.push(new); 100 | rem_r_row.push(r); 101 | } 102 | x_r_vals.push(r_row); 103 | rem_r_vals.push(rem_r_row); 104 | } 105 | 106 | let mut config = CircuitConfig::standard_recursion_config(); 107 | config.zero_knowledge = true; 108 | let mut builder = CircuitBuilder::::new(config); 109 | 110 | let mut pw = PartialWitness::new(); 111 | 112 | let mut w_r_targets = Vec::new(); 113 | 114 | for i in 0..H_NEW { 115 | for j in 0..W_NEW { 116 | let a = builder.add_virtual_target(); 117 | let b = builder.add_virtual_target(); 118 | let c = builder.add_virtual_target(); 119 | let d = builder.add_virtual_target(); 120 | 121 | w_r_targets.push(a); 122 | w_r_targets.push(b); 123 | w_r_targets.push(c); 124 | w_r_targets.push(d); 125 | 126 | let (x_ratio_weighted, y_ratio_weighted) = get_ratios(i, j); 127 | 128 | let mut all = Vec::new(); 129 | 130 | let a_const = ((W_NEW - 1 - x_ratio_weighted) * (H_NEW - 1 - y_ratio_weighted)) as u32; 131 | let b_const = (x_ratio_weighted * (H_NEW - 1 - y_ratio_weighted)) as u32; 132 | let c_const = (y_ratio_weighted * (W_NEW - 1 - x_ratio_weighted)) as u32; 133 | let d_const = (x_ratio_weighted * y_ratio_weighted) as u32; 134 | all.push(builder.mul_const(F::from_canonical_u32(a_const), a)); 135 | all.push(builder.mul_const(F::from_canonical_u32(b_const), b)); 136 | all.push(builder.mul_const(F::from_canonical_u32(c_const), c)); 137 | all.push(builder.mul_const(F::from_canonical_u32(d_const), d)); 138 | 139 | let s = builder.add_many(all); 140 | builder.register_public_input(s); 141 | } 142 | } 143 | 144 | // Timing setup 145 | let start = SystemTime::now(); 146 | let start_epoch = start 147 | .duration_since(UNIX_EPOCH) 148 | .expect("Time went backwards"); 149 | let start = start_epoch.as_millis(); 150 | let mut last = start; 151 | 152 | let data = builder.build::(); 153 | last = print_time_since(last, "setup done"); 154 | 155 | for i in 0..H_NEW { 156 | for j in 0..W_NEW { 157 | 158 | let (x_l, y_l, x_h, y_h) = get_positions(i, j); 159 | 160 | pw.set_target(w_r_targets[4 * i * W_NEW + 4 * j], F::from_canonical_u32(w_r_vals[y_l][x_l] as u32)); 161 | pw.set_target(w_r_targets[4 * i * W_NEW + 4 * j + 1], F::from_canonical_u32(w_r_vals[y_l][x_h] as u32)); 162 | pw.set_target(w_r_targets[4 * i * W_NEW + 4 * j + 2], F::from_canonical_u32(w_r_vals[y_h][x_l] as u32)); 163 | pw.set_target(w_r_targets[4 * i * W_NEW + 4 * j + 3], F::from_canonical_u32(w_r_vals[y_h][x_h] as u32)); 164 | } 165 | } 166 | 167 | let proof = data.prove(pw)?; 168 | last = print_time_since(last, "proof done"); 169 | 170 | let denom = (W_NEW - 1) * (H_NEW - 1); 171 | 172 | for i in 0..H_NEW { 173 | for j in 0..W_NEW { 174 | let x = (x_r_vals[i][j] * denom) as i64 + rem_r_vals[i][j]; 175 | assert!(x as u64 == proof.public_inputs[W_NEW * i + j].0); 176 | } 177 | } 178 | 179 | let res = data.verify(proof); 180 | let _ = res.unwrap(); 181 | 182 | _ = print_time_since(last, "verify done"); 183 | 184 | Ok(()) 185 | } -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.24.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler2" 16 | version = "2.0.0" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" 19 | 20 | [[package]] 21 | name = "ahash" 22 | version = "0.8.11" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" 25 | dependencies = [ 26 | "cfg-if", 27 | "const-random", 28 | "once_cell", 29 | "version_check", 30 | "zerocopy", 31 | ] 32 | 33 | [[package]] 34 | name = "anyhow" 35 | version = "1.0.89" 36 | source = "registry+https://github.com/rust-lang/crates.io-index" 37 | checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" 38 | 39 | [[package]] 40 | name = "async-trait" 41 | version = "0.1.83" 42 | source = "registry+https://github.com/rust-lang/crates.io-index" 43 | checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" 44 | dependencies = [ 45 | "proc-macro2", 46 | "quote", 47 | "syn 2.0.79", 48 | ] 49 | 50 | [[package]] 51 | name = "autocfg" 52 | version = "1.4.0" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 55 | 56 | [[package]] 57 | name = "backtrace" 58 | version = "0.3.74" 59 | source = "registry+https://github.com/rust-lang/crates.io-index" 60 | checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" 61 | dependencies = [ 62 | "addr2line", 63 | "cfg-if", 64 | "libc", 65 | "miniz_oxide", 66 | "object", 67 | "rustc-demangle", 68 | "windows-targets", 69 | ] 70 | 71 | [[package]] 72 | name = "block-buffer" 73 | version = "0.10.4" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 76 | dependencies = [ 77 | "generic-array", 78 | ] 79 | 80 | [[package]] 81 | name = "bumpalo" 82 | version = "3.16.0" 83 | source = "registry+https://github.com/rust-lang/crates.io-index" 84 | checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" 85 | 86 | [[package]] 87 | name = "byteorder" 88 | version = "1.5.0" 89 | source = "registry+https://github.com/rust-lang/crates.io-index" 90 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 91 | 92 | [[package]] 93 | name = "bytes" 94 | version = "1.7.2" 95 | source = "registry+https://github.com/rust-lang/crates.io-index" 96 | checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" 97 | 98 | [[package]] 99 | name = "cfg-if" 100 | version = "1.0.0" 101 | source = "registry+https://github.com/rust-lang/crates.io-index" 102 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 103 | 104 | [[package]] 105 | name = "const-random" 106 | version = "0.1.18" 107 | source = "registry+https://github.com/rust-lang/crates.io-index" 108 | checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" 109 | dependencies = [ 110 | "const-random-macro", 111 | ] 112 | 113 | [[package]] 114 | name = "const-random-macro" 115 | version = "0.1.16" 116 | source = "registry+https://github.com/rust-lang/crates.io-index" 117 | checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" 118 | dependencies = [ 119 | "getrandom", 120 | "once_cell", 121 | "tiny-keccak", 122 | ] 123 | 124 | [[package]] 125 | name = "cpufeatures" 126 | version = "0.2.14" 127 | source = "registry+https://github.com/rust-lang/crates.io-index" 128 | checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" 129 | dependencies = [ 130 | "libc", 131 | ] 132 | 133 | [[package]] 134 | name = "crossbeam-deque" 135 | version = "0.8.5" 136 | source = "registry+https://github.com/rust-lang/crates.io-index" 137 | checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" 138 | dependencies = [ 139 | "crossbeam-epoch", 140 | "crossbeam-utils", 141 | ] 142 | 143 | [[package]] 144 | name = "crossbeam-epoch" 145 | version = "0.9.18" 146 | source = "registry+https://github.com/rust-lang/crates.io-index" 147 | checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" 148 | dependencies = [ 149 | "crossbeam-utils", 150 | ] 151 | 152 | [[package]] 153 | name = "crossbeam-utils" 154 | version = "0.8.20" 155 | source = "registry+https://github.com/rust-lang/crates.io-index" 156 | checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" 157 | 158 | [[package]] 159 | name = "crunchy" 160 | version = "0.2.2" 161 | source = "registry+https://github.com/rust-lang/crates.io-index" 162 | checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" 163 | 164 | [[package]] 165 | name = "crypto-common" 166 | version = "0.1.6" 167 | source = "registry+https://github.com/rust-lang/crates.io-index" 168 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 169 | dependencies = [ 170 | "generic-array", 171 | "typenum", 172 | ] 173 | 174 | [[package]] 175 | name = "digest" 176 | version = "0.10.7" 177 | source = "registry+https://github.com/rust-lang/crates.io-index" 178 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 179 | dependencies = [ 180 | "block-buffer", 181 | "crypto-common", 182 | ] 183 | 184 | [[package]] 185 | name = "either" 186 | version = "1.13.0" 187 | source = "registry+https://github.com/rust-lang/crates.io-index" 188 | checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" 189 | 190 | [[package]] 191 | name = "fixed-hash" 192 | version = "0.7.0" 193 | source = "registry+https://github.com/rust-lang/crates.io-index" 194 | checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c" 195 | dependencies = [ 196 | "static_assertions", 197 | ] 198 | 199 | [[package]] 200 | name = "generic-array" 201 | version = "0.14.7" 202 | source = "registry+https://github.com/rust-lang/crates.io-index" 203 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 204 | dependencies = [ 205 | "typenum", 206 | "version_check", 207 | ] 208 | 209 | [[package]] 210 | name = "getrandom" 211 | version = "0.2.15" 212 | source = "registry+https://github.com/rust-lang/crates.io-index" 213 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 214 | dependencies = [ 215 | "cfg-if", 216 | "js-sys", 217 | "libc", 218 | "wasi", 219 | "wasm-bindgen", 220 | ] 221 | 222 | [[package]] 223 | name = "gimli" 224 | version = "0.31.1" 225 | source = "registry+https://github.com/rust-lang/crates.io-index" 226 | checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" 227 | 228 | [[package]] 229 | name = "hashbrown" 230 | version = "0.14.5" 231 | source = "registry+https://github.com/rust-lang/crates.io-index" 232 | checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" 233 | dependencies = [ 234 | "ahash", 235 | "rayon", 236 | "serde", 237 | ] 238 | 239 | [[package]] 240 | name = "hex" 241 | version = "0.4.3" 242 | source = "registry+https://github.com/rust-lang/crates.io-index" 243 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 244 | 245 | [[package]] 246 | name = "itertools" 247 | version = "0.11.0" 248 | source = "registry+https://github.com/rust-lang/crates.io-index" 249 | checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" 250 | dependencies = [ 251 | "either", 252 | ] 253 | 254 | [[package]] 255 | name = "js-sys" 256 | version = "0.3.71" 257 | source = "registry+https://github.com/rust-lang/crates.io-index" 258 | checksum = "0cb94a0ffd3f3ee755c20f7d8752f45cac88605a4dcf808abcff72873296ec7b" 259 | dependencies = [ 260 | "wasm-bindgen", 261 | ] 262 | 263 | [[package]] 264 | name = "keccak-hash" 265 | version = "0.8.0" 266 | source = "registry+https://github.com/rust-lang/crates.io-index" 267 | checksum = "ce2bd4c29270e724d3eaadf7bdc8700af4221fc0ed771b855eadcd1b98d52851" 268 | dependencies = [ 269 | "primitive-types", 270 | "tiny-keccak", 271 | ] 272 | 273 | [[package]] 274 | name = "libc" 275 | version = "0.2.159" 276 | source = "registry+https://github.com/rust-lang/crates.io-index" 277 | checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" 278 | 279 | [[package]] 280 | name = "log" 281 | version = "0.4.22" 282 | source = "registry+https://github.com/rust-lang/crates.io-index" 283 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 284 | 285 | [[package]] 286 | name = "memchr" 287 | version = "2.7.4" 288 | source = "registry+https://github.com/rust-lang/crates.io-index" 289 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 290 | 291 | [[package]] 292 | name = "miniz_oxide" 293 | version = "0.8.0" 294 | source = "registry+https://github.com/rust-lang/crates.io-index" 295 | checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" 296 | dependencies = [ 297 | "adler2", 298 | ] 299 | 300 | [[package]] 301 | name = "num" 302 | version = "0.4.3" 303 | source = "registry+https://github.com/rust-lang/crates.io-index" 304 | checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" 305 | dependencies = [ 306 | "num-bigint", 307 | "num-complex", 308 | "num-integer", 309 | "num-iter", 310 | "num-rational", 311 | "num-traits", 312 | ] 313 | 314 | [[package]] 315 | name = "num-bigint" 316 | version = "0.4.6" 317 | source = "registry+https://github.com/rust-lang/crates.io-index" 318 | checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" 319 | dependencies = [ 320 | "num-integer", 321 | "num-traits", 322 | "rand", 323 | ] 324 | 325 | [[package]] 326 | name = "num-complex" 327 | version = "0.4.6" 328 | source = "registry+https://github.com/rust-lang/crates.io-index" 329 | checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" 330 | dependencies = [ 331 | "num-traits", 332 | "rand", 333 | ] 334 | 335 | [[package]] 336 | name = "num-integer" 337 | version = "0.1.46" 338 | source = "registry+https://github.com/rust-lang/crates.io-index" 339 | checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" 340 | dependencies = [ 341 | "num-traits", 342 | ] 343 | 344 | [[package]] 345 | name = "num-iter" 346 | version = "0.1.45" 347 | source = "registry+https://github.com/rust-lang/crates.io-index" 348 | checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" 349 | dependencies = [ 350 | "autocfg", 351 | "num-integer", 352 | "num-traits", 353 | ] 354 | 355 | [[package]] 356 | name = "num-rational" 357 | version = "0.4.2" 358 | source = "registry+https://github.com/rust-lang/crates.io-index" 359 | checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" 360 | dependencies = [ 361 | "num-bigint", 362 | "num-integer", 363 | "num-traits", 364 | ] 365 | 366 | [[package]] 367 | name = "num-traits" 368 | version = "0.2.19" 369 | source = "registry+https://github.com/rust-lang/crates.io-index" 370 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 371 | dependencies = [ 372 | "autocfg", 373 | ] 374 | 375 | [[package]] 376 | name = "object" 377 | version = "0.36.5" 378 | source = "registry+https://github.com/rust-lang/crates.io-index" 379 | checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" 380 | dependencies = [ 381 | "memchr", 382 | ] 383 | 384 | [[package]] 385 | name = "once_cell" 386 | version = "1.20.2" 387 | source = "registry+https://github.com/rust-lang/crates.io-index" 388 | checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" 389 | 390 | [[package]] 391 | name = "pin-project-lite" 392 | version = "0.2.14" 393 | source = "registry+https://github.com/rust-lang/crates.io-index" 394 | checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" 395 | 396 | [[package]] 397 | name = "plonky2" 398 | version = "0.2.2" 399 | source = "registry+https://github.com/rust-lang/crates.io-index" 400 | checksum = "85f26b090b989aebdeaf6a4eed748c1fbcabf67e7273a22e4e0c877b63846d0f" 401 | dependencies = [ 402 | "ahash", 403 | "anyhow", 404 | "getrandom", 405 | "hashbrown", 406 | "itertools", 407 | "keccak-hash", 408 | "log", 409 | "num", 410 | "plonky2_field", 411 | "plonky2_maybe_rayon", 412 | "plonky2_util", 413 | "rand", 414 | "rand_chacha", 415 | "serde", 416 | "static_assertions", 417 | "unroll", 418 | "web-time", 419 | ] 420 | 421 | [[package]] 422 | name = "plonky2_field" 423 | version = "0.2.2" 424 | source = "registry+https://github.com/rust-lang/crates.io-index" 425 | checksum = "3a1dca60ad900d81b1fe2df3d0b88d43345988e2935e6709176e96573f4bcf5d" 426 | dependencies = [ 427 | "anyhow", 428 | "itertools", 429 | "num", 430 | "plonky2_util", 431 | "rand", 432 | "serde", 433 | "static_assertions", 434 | "unroll", 435 | ] 436 | 437 | [[package]] 438 | name = "plonky2_maybe_rayon" 439 | version = "0.2.0" 440 | source = "registry+https://github.com/rust-lang/crates.io-index" 441 | checksum = "92ff44a90aaca13e10e7ddf8fab815ba1b404c3f7c3ca82aaf11c46beabaa923" 442 | dependencies = [ 443 | "rayon", 444 | ] 445 | 446 | [[package]] 447 | name = "plonky2_util" 448 | version = "0.2.0" 449 | source = "registry+https://github.com/rust-lang/crates.io-index" 450 | checksum = "b16136f5f3019c1e83035af76cccddd56d789a5e2933306270185c3f99f12259" 451 | 452 | [[package]] 453 | name = "ppv-lite86" 454 | version = "0.2.20" 455 | source = "registry+https://github.com/rust-lang/crates.io-index" 456 | checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" 457 | dependencies = [ 458 | "zerocopy", 459 | ] 460 | 461 | [[package]] 462 | name = "primitive-types" 463 | version = "0.10.1" 464 | source = "registry+https://github.com/rust-lang/crates.io-index" 465 | checksum = "05e4722c697a58a99d5d06a08c30821d7c082a4632198de1eaa5a6c22ef42373" 466 | dependencies = [ 467 | "fixed-hash", 468 | "uint", 469 | ] 470 | 471 | [[package]] 472 | name = "proc-macro2" 473 | version = "1.0.87" 474 | source = "registry+https://github.com/rust-lang/crates.io-index" 475 | checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" 476 | dependencies = [ 477 | "unicode-ident", 478 | ] 479 | 480 | [[package]] 481 | name = "quote" 482 | version = "1.0.37" 483 | source = "registry+https://github.com/rust-lang/crates.io-index" 484 | checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" 485 | dependencies = [ 486 | "proc-macro2", 487 | ] 488 | 489 | [[package]] 490 | name = "rand" 491 | version = "0.8.5" 492 | source = "registry+https://github.com/rust-lang/crates.io-index" 493 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 494 | dependencies = [ 495 | "libc", 496 | "rand_chacha", 497 | "rand_core", 498 | ] 499 | 500 | [[package]] 501 | name = "rand_chacha" 502 | version = "0.3.1" 503 | source = "registry+https://github.com/rust-lang/crates.io-index" 504 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 505 | dependencies = [ 506 | "ppv-lite86", 507 | "rand_core", 508 | ] 509 | 510 | [[package]] 511 | name = "rand_core" 512 | version = "0.6.4" 513 | source = "registry+https://github.com/rust-lang/crates.io-index" 514 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 515 | dependencies = [ 516 | "getrandom", 517 | ] 518 | 519 | [[package]] 520 | name = "rayon" 521 | version = "1.10.0" 522 | source = "registry+https://github.com/rust-lang/crates.io-index" 523 | checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" 524 | dependencies = [ 525 | "either", 526 | "rayon-core", 527 | ] 528 | 529 | [[package]] 530 | name = "rayon-core" 531 | version = "1.12.1" 532 | source = "registry+https://github.com/rust-lang/crates.io-index" 533 | checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" 534 | dependencies = [ 535 | "crossbeam-deque", 536 | "crossbeam-utils", 537 | ] 538 | 539 | [[package]] 540 | name = "rustc-demangle" 541 | version = "0.1.24" 542 | source = "registry+https://github.com/rust-lang/crates.io-index" 543 | checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 544 | 545 | [[package]] 546 | name = "serde" 547 | version = "1.0.210" 548 | source = "registry+https://github.com/rust-lang/crates.io-index" 549 | checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" 550 | dependencies = [ 551 | "serde_derive", 552 | ] 553 | 554 | [[package]] 555 | name = "serde_derive" 556 | version = "1.0.210" 557 | source = "registry+https://github.com/rust-lang/crates.io-index" 558 | checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" 559 | dependencies = [ 560 | "proc-macro2", 561 | "quote", 562 | "syn 2.0.79", 563 | ] 564 | 565 | [[package]] 566 | name = "sha2" 567 | version = "0.10.8" 568 | source = "registry+https://github.com/rust-lang/crates.io-index" 569 | checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" 570 | dependencies = [ 571 | "cfg-if", 572 | "cpufeatures", 573 | "digest", 574 | ] 575 | 576 | [[package]] 577 | name = "sha256" 578 | version = "1.5.0" 579 | source = "registry+https://github.com/rust-lang/crates.io-index" 580 | checksum = "18278f6a914fa3070aa316493f7d2ddfb9ac86ebc06fa3b83bffda487e9065b0" 581 | dependencies = [ 582 | "async-trait", 583 | "bytes", 584 | "hex", 585 | "sha2", 586 | "tokio", 587 | ] 588 | 589 | [[package]] 590 | name = "static_assertions" 591 | version = "1.1.0" 592 | source = "registry+https://github.com/rust-lang/crates.io-index" 593 | checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" 594 | 595 | [[package]] 596 | name = "syn" 597 | version = "1.0.109" 598 | source = "registry+https://github.com/rust-lang/crates.io-index" 599 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 600 | dependencies = [ 601 | "proc-macro2", 602 | "quote", 603 | "unicode-ident", 604 | ] 605 | 606 | [[package]] 607 | name = "syn" 608 | version = "2.0.79" 609 | source = "registry+https://github.com/rust-lang/crates.io-index" 610 | checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" 611 | dependencies = [ 612 | "proc-macro2", 613 | "quote", 614 | "unicode-ident", 615 | ] 616 | 617 | [[package]] 618 | name = "tiny-keccak" 619 | version = "2.0.2" 620 | source = "registry+https://github.com/rust-lang/crates.io-index" 621 | checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" 622 | dependencies = [ 623 | "crunchy", 624 | ] 625 | 626 | [[package]] 627 | name = "tokio" 628 | version = "1.40.0" 629 | source = "registry+https://github.com/rust-lang/crates.io-index" 630 | checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" 631 | dependencies = [ 632 | "backtrace", 633 | "bytes", 634 | "pin-project-lite", 635 | ] 636 | 637 | [[package]] 638 | name = "typenum" 639 | version = "1.17.0" 640 | source = "registry+https://github.com/rust-lang/crates.io-index" 641 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 642 | 643 | [[package]] 644 | name = "uint" 645 | version = "0.9.5" 646 | source = "registry+https://github.com/rust-lang/crates.io-index" 647 | checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" 648 | dependencies = [ 649 | "byteorder", 650 | "crunchy", 651 | "hex", 652 | "static_assertions", 653 | ] 654 | 655 | [[package]] 656 | name = "unicode-ident" 657 | version = "1.0.13" 658 | source = "registry+https://github.com/rust-lang/crates.io-index" 659 | checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" 660 | 661 | [[package]] 662 | name = "unroll" 663 | version = "0.1.5" 664 | source = "registry+https://github.com/rust-lang/crates.io-index" 665 | checksum = "5ad948c1cb799b1a70f836077721a92a35ac177d4daddf4c20a633786d4cf618" 666 | dependencies = [ 667 | "quote", 668 | "syn 1.0.109", 669 | ] 670 | 671 | [[package]] 672 | name = "version_check" 673 | version = "0.9.5" 674 | source = "registry+https://github.com/rust-lang/crates.io-index" 675 | checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 676 | 677 | [[package]] 678 | name = "wasi" 679 | version = "0.11.0+wasi-snapshot-preview1" 680 | source = "registry+https://github.com/rust-lang/crates.io-index" 681 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 682 | 683 | [[package]] 684 | name = "wasm-bindgen" 685 | version = "0.2.94" 686 | source = "registry+https://github.com/rust-lang/crates.io-index" 687 | checksum = "ef073ced962d62984fb38a36e5fdc1a2b23c9e0e1fa0689bb97afa4202ef6887" 688 | dependencies = [ 689 | "cfg-if", 690 | "once_cell", 691 | "wasm-bindgen-macro", 692 | ] 693 | 694 | [[package]] 695 | name = "wasm-bindgen-backend" 696 | version = "0.2.94" 697 | source = "registry+https://github.com/rust-lang/crates.io-index" 698 | checksum = "c4bfab14ef75323f4eb75fa52ee0a3fb59611977fd3240da19b2cf36ff85030e" 699 | dependencies = [ 700 | "bumpalo", 701 | "log", 702 | "once_cell", 703 | "proc-macro2", 704 | "quote", 705 | "syn 2.0.79", 706 | "wasm-bindgen-shared", 707 | ] 708 | 709 | [[package]] 710 | name = "wasm-bindgen-macro" 711 | version = "0.2.94" 712 | source = "registry+https://github.com/rust-lang/crates.io-index" 713 | checksum = "a7bec9830f60924d9ceb3ef99d55c155be8afa76954edffbb5936ff4509474e7" 714 | dependencies = [ 715 | "quote", 716 | "wasm-bindgen-macro-support", 717 | ] 718 | 719 | [[package]] 720 | name = "wasm-bindgen-macro-support" 721 | version = "0.2.94" 722 | source = "registry+https://github.com/rust-lang/crates.io-index" 723 | checksum = "4c74f6e152a76a2ad448e223b0fc0b6b5747649c3d769cc6bf45737bf97d0ed6" 724 | dependencies = [ 725 | "proc-macro2", 726 | "quote", 727 | "syn 2.0.79", 728 | "wasm-bindgen-backend", 729 | "wasm-bindgen-shared", 730 | ] 731 | 732 | [[package]] 733 | name = "wasm-bindgen-shared" 734 | version = "0.2.94" 735 | source = "registry+https://github.com/rust-lang/crates.io-index" 736 | checksum = "a42f6c679374623f295a8623adfe63d9284091245c3504bde47c17a3ce2777d9" 737 | 738 | [[package]] 739 | name = "web-time" 740 | version = "1.1.0" 741 | source = "registry+https://github.com/rust-lang/crates.io-index" 742 | checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" 743 | dependencies = [ 744 | "js-sys", 745 | "wasm-bindgen", 746 | ] 747 | 748 | [[package]] 749 | name = "windows-targets" 750 | version = "0.52.6" 751 | source = "registry+https://github.com/rust-lang/crates.io-index" 752 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 753 | dependencies = [ 754 | "windows_aarch64_gnullvm", 755 | "windows_aarch64_msvc", 756 | "windows_i686_gnu", 757 | "windows_i686_gnullvm", 758 | "windows_i686_msvc", 759 | "windows_x86_64_gnu", 760 | "windows_x86_64_gnullvm", 761 | "windows_x86_64_msvc", 762 | ] 763 | 764 | [[package]] 765 | name = "windows_aarch64_gnullvm" 766 | version = "0.52.6" 767 | source = "registry+https://github.com/rust-lang/crates.io-index" 768 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 769 | 770 | [[package]] 771 | name = "windows_aarch64_msvc" 772 | version = "0.52.6" 773 | source = "registry+https://github.com/rust-lang/crates.io-index" 774 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 775 | 776 | [[package]] 777 | name = "windows_i686_gnu" 778 | version = "0.52.6" 779 | source = "registry+https://github.com/rust-lang/crates.io-index" 780 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 781 | 782 | [[package]] 783 | name = "windows_i686_gnullvm" 784 | version = "0.52.6" 785 | source = "registry+https://github.com/rust-lang/crates.io-index" 786 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 787 | 788 | [[package]] 789 | name = "windows_i686_msvc" 790 | version = "0.52.6" 791 | source = "registry+https://github.com/rust-lang/crates.io-index" 792 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 793 | 794 | [[package]] 795 | name = "windows_x86_64_gnu" 796 | version = "0.52.6" 797 | source = "registry+https://github.com/rust-lang/crates.io-index" 798 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 799 | 800 | [[package]] 801 | name = "windows_x86_64_gnullvm" 802 | version = "0.52.6" 803 | source = "registry+https://github.com/rust-lang/crates.io-index" 804 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 805 | 806 | [[package]] 807 | name = "windows_x86_64_msvc" 808 | version = "0.52.6" 809 | source = "registry+https://github.com/rust-lang/crates.io-index" 810 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 811 | 812 | [[package]] 813 | name = "zerocopy" 814 | version = "0.7.35" 815 | source = "registry+https://github.com/rust-lang/crates.io-index" 816 | checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" 817 | dependencies = [ 818 | "byteorder", 819 | "zerocopy-derive", 820 | ] 821 | 822 | [[package]] 823 | name = "zerocopy-derive" 824 | version = "0.7.35" 825 | source = "registry+https://github.com/rust-lang/crates.io-index" 826 | checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" 827 | dependencies = [ 828 | "proc-macro2", 829 | "quote", 830 | "syn 2.0.79", 831 | ] 832 | 833 | [[package]] 834 | name = "zk-veritas" 835 | version = "0.1.0" 836 | dependencies = [ 837 | "ahash", 838 | "anyhow", 839 | "hashbrown", 840 | "itertools", 841 | "log", 842 | "num", 843 | "plonky2", 844 | "rand", 845 | "rayon", 846 | "serde", 847 | "sha256", 848 | "static_assertions", 849 | "unroll", 850 | ] 851 | -------------------------------------------------------------------------------- /examples/veritas.rs: -------------------------------------------------------------------------------- 1 | use plonky2::field::polynomial::{PolynomialCoeffs, PolynomialValues}; 2 | use plonky2::fri::oracle::PolynomialBatch; 3 | use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; 4 | use plonky2::field::types::Field; 5 | use plonky2::field::extension::Extendable; 6 | use plonky2::util::timing::TimingTree; 7 | use plonky2::field::fft::fft_root_table; 8 | use plonky2::util::{log2_ceil, log2_strict}; 9 | use core::cmp::max; 10 | use std::time::{SystemTime, UNIX_EPOCH}; 11 | use std::io::{BufRead, BufReader}; 12 | use std::fs::File; 13 | use rayon::prelude::*; 14 | use plonky2::plonk::config::GenericHashOut; 15 | use sha256::digest; 16 | use plonky2::field::goldilocks_field::GoldilocksField; 17 | use plonky2::fri::structure::FriPolynomialInfo; 18 | use plonky2::fri::structure::FriInstanceInfo; 19 | use plonky2::fri::structure::FriBatchInfo; 20 | use plonky2::iop::challenger::Challenger; 21 | use plonky2::fri::structure::FriOracleInfo; 22 | use plonky2::fri::reduction_strategies::FriReductionStrategy; 23 | use plonky2::fri::FriConfig; 24 | use plonky2::fri::structure::FriOpeningBatch; 25 | use plonky2::fri::structure::FriOpenings; 26 | use plonky2::fri::verifier::verify_fri_proof; 27 | use plonky2::field::extension::quadratic::QuadraticExtension; 28 | use plonky2::field::types::PrimeField64; 29 | use plonky2::field::types::Field64; 30 | use plonky2::fri::proof::FriProof; 31 | use plonky2::hash::poseidon::PoseidonHash; 32 | use plonky2::hash::merkle_tree::MerkleCap; 33 | use plonky2::field::fft::FftRootTable; 34 | 35 | static PIXELS : usize = 14; 36 | static EXPONENT : u32 = 3; 37 | const DEGREE : usize = 1 << 5; 38 | static PIXEL_RANGE : i32 = 2_i32.pow(EXPONENT); 39 | static HASH_LENGTH : usize = 128; 40 | const X : u128 = 3091352403337663489; 41 | const A_CONSTANT : u128 = 3935559000370003845; 42 | const C_CONSTANT : u128 = 2691343689449507681; 43 | 44 | const D: usize = 2; 45 | type C = PoseidonGoldilocksConfig; 46 | type F = >::F; 47 | const USE_ZK : bool = true; 48 | 49 | fn print_time_since(start: u128, last: u128, tag: &str) -> u128 { 50 | let now = SystemTime::now(); 51 | let now_epoc = now 52 | .duration_since(UNIX_EPOCH) 53 | .expect("Time went backwards"); 54 | let now = now_epoc.as_millis(); 55 | println!("{:?}; time since start {:?}; time since last check: {:?}", tag, (now - start) as f32 / 60000.0, (now - last) as f32 / 60000.0); 56 | return now; 57 | } 58 | 59 | 60 | fn get_filename(prefix: &str) -> String { 61 | let mut filename = prefix.to_owned(); 62 | filename.push_str("image_"); 63 | filename.push_str(&PIXELS.to_string()); 64 | filename.push_str("_"); 65 | filename.push_str(&EXPONENT.to_string()); 66 | filename.push_str(".txt"); 67 | return filename 68 | } 69 | 70 | fn read_photo(prefix: &str) -> BufReader { 71 | let file = File::open(get_filename(prefix)).expect("Unable to open file"); 72 | return BufReader::new(file); 73 | } 74 | 75 | // gets sha256 of commitments for random challenges 76 | fn get_sha256_of_commitments(merkle_cap: &MerkleCap, instance_hash: &str, num_elements: usize) -> Vec { 77 | let mut byte_vec = Vec::new(); 78 | 79 | for hash in &merkle_cap.0 { 80 | let h = hash.to_vec(); 81 | for elem in h { 82 | byte_vec.append(&mut elem.to_canonical_u64().to_le_bytes().to_vec()); 83 | } 84 | } 85 | 86 | let s = format!("{:?}{:?}", &byte_vec, instance_hash); 87 | let mut val = digest(s); 88 | 89 | let mut ret = Vec::new(); 90 | 91 | for _ in 0..num_elements/4 { 92 | let sha2561 = u64::from_str_radix(&val[0..16], 16).unwrap() % F::ORDER; 93 | ret.push(F::from_canonical_u64(sha2561)); 94 | let sha2562 = u64::from_str_radix(&val[16..32], 16).unwrap(); 95 | ret.push(F::from_canonical_u64(sha2562)); 96 | let sha2563 = u64::from_str_radix(&val[32..48], 16).unwrap(); 97 | ret.push(F::from_canonical_u64(sha2563)); 98 | let sha2564 = u64::from_str_radix(&val[48..64], 16).unwrap(); 99 | ret.push(F::from_canonical_u64(sha2564)); 100 | val = digest(val); 101 | } 102 | 103 | return ret; 104 | } 105 | 106 | fn get_fri_config(rate_bits: usize, cap_height: usize) -> FriConfig { 107 | return FriConfig { 108 | rate_bits: rate_bits, 109 | cap_height: cap_height, 110 | proof_of_work_bits: 16, 111 | reduction_strategy: FriReductionStrategy::ConstantArityBits(4, 5), 112 | num_query_rounds: 28, 113 | }; 114 | } 115 | 116 | fn get_instance(length_0 : usize, length_1 : usize, length_2 : usize, degree_bits : usize, zeta : QuadraticExtension) -> FriInstanceInfo { 117 | let g = <>::F as Extendable>::Extension::primitive_root_of_unity(degree_bits); 118 | let commit0_polys = FriPolynomialInfo::from_range( 119 | 0, 120 | 0..length_0, 121 | ); 122 | 123 | let commit1_polys = FriPolynomialInfo::from_range( 124 | 1, 125 | 0..length_1, 126 | ); 127 | 128 | let commit2_polys = FriPolynomialInfo::from_range( 129 | 2, 130 | 0..length_2, 131 | ); 132 | 133 | let all_polys = [commit0_polys, commit1_polys, commit2_polys].concat(); 134 | 135 | 136 | let zeta_batch = FriBatchInfo { 137 | point: zeta, 138 | polynomials: all_polys.clone(), 139 | }; 140 | 141 | // The Z polynomials are also opened at g * zeta. 142 | let zeta_next = g * zeta; 143 | let zeta_next_batch = FriBatchInfo { 144 | point: zeta_next, 145 | polynomials: all_polys.clone(), 146 | }; 147 | 148 | let pixels = g.exp_u64((PIXELS) as u64); 149 | let pixels_batch = FriBatchInfo { 150 | point: pixels, 151 | polynomials: all_polys.clone(), 152 | }; 153 | 154 | let pixel_range = g.exp_u64((PIXEL_RANGE) as u64); 155 | let pixel_range_batch = FriBatchInfo { 156 | point: pixel_range, 157 | polynomials: all_polys.clone(), 158 | }; 159 | 160 | let pixels_plus_pixel_range = g.exp_u64((PIXELS + PIXEL_RANGE as usize) as u64); 161 | let pixels_plus_pixel_range_batch = FriBatchInfo { 162 | point: pixels_plus_pixel_range, 163 | polynomials: all_polys, 164 | }; 165 | 166 | let openings = vec![zeta_batch, zeta_next_batch, pixels_batch, pixel_range_batch, pixels_plus_pixel_range_batch]; 167 | 168 | let fri_oracles = vec![ 169 | FriOracleInfo { 170 | num_polys: length_0, 171 | blinding: USE_ZK, 172 | }, 173 | FriOracleInfo { 174 | num_polys: length_1, 175 | blinding: USE_ZK, 176 | }, 177 | FriOracleInfo { 178 | num_polys: length_2, 179 | blinding: USE_ZK, 180 | } 181 | ]; 182 | 183 | return FriInstanceInfo { 184 | oracles: fri_oracles, 185 | batches: openings, 186 | }; 187 | } 188 | 189 | fn prove(start: u128, old_last: u128, rate_bits: usize, cap_height: usize, omega: F, fft_root_table: &FftRootTable) 190 | -> (FriOpenings, [MerkleCap; 3], FriProof>::Hasher, D>, u128) { 191 | let mut last = old_last; 192 | let mut x = X; 193 | 194 | 195 | // w_vals = [0, 1,...,PIXEL_RANGE - 1] 196 | let mut w_vals = Vec::new(); 197 | for i in 0..PIXEL_RANGE { 198 | let i_in_fr = GoldilocksField(i as u64); 199 | w_vals.push(i_in_fr); 200 | } 201 | 202 | let mut w_vals = Vec::new(); 203 | for i in 0..PIXEL_RANGE { 204 | let i_in_fr = GoldilocksField(i as u64); 205 | w_vals.push(i_in_fr); 206 | } 207 | 208 | for _ in 0..DEGREE - (PIXEL_RANGE as usize) { 209 | w_vals.push(F::ZERO); 210 | } 211 | 212 | // w[X] = poly(w_vals) 213 | let w = PolynomialValues::new(w_vals).ifft(); 214 | 215 | last = print_time_since(start, last, "w interpolation done"); 216 | 217 | // v_vals = [pixel_0,...,pixel_{D-1}] 218 | let mut v_vals = Vec::new(); 219 | // z_vals = [sort(v || w)] 220 | let mut z_vals = Vec::new(); 221 | 222 | // reading in photo pixels... 223 | let file = read_photo("orig_"); 224 | for line in file.lines() { 225 | let line = line.expect("Unable to read line"); 226 | let i = line.parse::().unwrap(); 227 | 228 | let v_point = GoldilocksField(i as u64); 229 | v_vals.push(v_point); 230 | z_vals.push(i); 231 | } 232 | 233 | for _ in 0..DEGREE - PIXELS { 234 | v_vals.push(F::ZERO); 235 | } 236 | 237 | for i in 0..PIXEL_RANGE { 238 | z_vals.push(i); 239 | } 240 | 241 | // pad z_vals so that [z[omega*x] - z[x][1 - (z[omega*x] - z[x])] = 0 still holds true 242 | let z_vals_length = z_vals.len(); 243 | for _ in 0..DEGREE - z_vals_length { 244 | z_vals.push(PIXEL_RANGE - 1); 245 | } 246 | z_vals.sort(); 247 | 248 | let mut z_f_vals = Vec::new(); 249 | for i in 0..z_vals.len() { 250 | z_f_vals.push(GoldilocksField(z_vals[i] as u64)); 251 | } 252 | 253 | 254 | // v[X] = poly(v_vals) 255 | let v = PolynomialValues::new(v_vals).ifft(); 256 | // z[X] = poly(z_vals) 257 | let z = PolynomialValues::new(z_f_vals.clone()).ifft(); 258 | last = print_time_since(start, last, "z and v interpolation done"); 259 | 260 | 261 | 262 | let mut values_vec_0 = Vec::new(); 263 | values_vec_0.push(w.clone()); 264 | values_vec_0.push(v.clone()); 265 | values_vec_0.push(z.clone()); 266 | 267 | last = print_time_since(start, last, "polynomial push done"); 268 | 269 | let commit0 = PolynomialBatch::::from_coeffs( 270 | values_vec_0, 271 | rate_bits, 272 | USE_ZK, 273 | cap_height, 274 | &mut TimingTree::default(), 275 | Some(&fft_root_table), 276 | ); 277 | 278 | last = print_time_since(start, last, "commit0 done"); 279 | let gamma = get_sha256_of_commitments(&commit0.merkle_tree.cap, "", 4)[0]; 280 | 281 | last = print_time_since(start, last, "gamma done"); 282 | 283 | // Permutation argument 284 | // We want to prove: 285 | // product_{i=0}^{D-1}(v_i + gamma) * product_{i=0}^{PIXEL_RANGE-1}(w_i + gamma) = product_{i=0}^{D + PIXEL_RANGE - 1}(z_i + gamma) 286 | // where v holds the image pixels, w is the range that the pixel values must lie in [0, PIXEL_RANGE-1], 287 | // and z is the sorted concatentation of v and w 288 | 289 | let mut values_vec_1 = Vec::new(); 290 | 291 | // w_prod_vals = [1, (gamma), [(gamma)(1 + gamma)],...,[(gamma)...(PIXEL_RANGE - 1 + gamma)]] 292 | let mut w_prod_vals = Vec::new(); 293 | let mut product = F::ONE; 294 | w_prod_vals.push(product); 295 | 296 | for i in 0..PIXEL_RANGE { 297 | let i_in_fr = GoldilocksField(i as u64); 298 | product *= i_in_fr + gamma; 299 | w_prod_vals.push(product); 300 | } 301 | 302 | let w_prod_vals_len = w_prod_vals.len(); 303 | for _ in 0..DEGREE - w_prod_vals_len { 304 | product *= gamma; 305 | w_prod_vals.push(product); 306 | } 307 | 308 | // w_prod_omega_vals = [(gamma), [(gamma)(1 + gamma)],...,[(gamma)...(PIXEL_RANGE + gamma)], 1] 309 | let mut w_prod_omega_vals = Vec::new(); 310 | for i in 1..w_prod_vals.len() { 311 | w_prod_omega_vals.push(w_prod_vals[i]); 312 | } 313 | w_prod_omega_vals.push(w_prod_vals[0]); 314 | 315 | let w_prod = PolynomialValues::new(w_prod_vals).ifft(); 316 | 317 | let w_prod_omega = PolynomialValues::new(w_prod_omega_vals).ifft(); 318 | 319 | last = print_time_since(start, last, "w_prod and w_prod_omega interpolation done"); 320 | 321 | let mut n_1_coeffs = Vec::new(); 322 | n_1_coeffs.push(omega.exp_u64((DEGREE - 1) as u64)); 323 | n_1_coeffs.push(F::ZERO - F::ONE); 324 | 325 | let n_1 = PolynomialCoeffs::from(n_1_coeffs); 326 | println!("n_1 eval {:?}", n_1.eval(omega.exp_u64((DEGREE - 1) as u64))); 327 | last = print_time_since(start, last, "n_1 interpolation done"); 328 | 329 | let mut gamma_coeffs = Vec::new(); 330 | gamma_coeffs.push(gamma); 331 | let gamma_poly = PolynomialCoeffs::from(gamma_coeffs); 332 | 333 | // let (q_w, r_w) = (&(&w_prod_omega - &(&w_prod * &(&gamma_poly + &w))) * &n_1).div_rem(&vanishing_poly); 334 | let sum = &(&w_prod_omega - &(&w_prod * &(&gamma_poly + &w))) * &n_1; 335 | let q_w = PolynomialCoeffs::new(sum.coeffs[0..DEGREE].to_vec()); 336 | last = print_time_since(start, last, "q_w division done"); 337 | 338 | // Will commit to w_prod[X], q_w[X] 339 | values_vec_1.push(w_prod); 340 | values_vec_1.push(q_w); 341 | 342 | // v_prod_vals = [1, (pixel_0 + gamma), [(pixel_0 + gamma)(pixel_1 + gamma)],...,[(pixel_0 + gamma)...(pixel_{D-1} + gamma)]] 343 | let mut v_prod_vals = Vec::new(); 344 | let mut product = F::ONE; 345 | v_prod_vals.push(product); 346 | 347 | // reading in photo pixels... 348 | let file = read_photo("orig_"); 349 | for line in file.lines() { 350 | let line = line.expect("Unable to read line"); 351 | let i = line.parse::().unwrap(); 352 | 353 | let v_point = GoldilocksField(i as u64); 354 | 355 | product *= v_point + gamma; 356 | v_prod_vals.push(product); 357 | } 358 | 359 | for _ in 0..DEGREE - PIXELS - 1 { 360 | product *= gamma; 361 | v_prod_vals.push(product); 362 | } 363 | 364 | // v_prod_omega_vals = [(pixel_0 + gamma), [(pixel_0 + gamma)(pixel_1 + gamma)],...,[(pixel_0 + gamma)...(pixel_{D-1} + gamma)], 1] 365 | let mut v_prod_omega_vals = Vec::new(); 366 | for i in 1..v_prod_vals.len() { 367 | v_prod_omega_vals.push(v_prod_vals[i]); 368 | } 369 | v_prod_omega_vals.push(v_prod_vals[0]); 370 | 371 | // for all i \in [1, D + 1], v_prod[omega^i] = \prod_{j=0}^{i-1}(v_j + gamma) 372 | let v_prod = PolynomialValues::from(v_prod_vals).ifft(); 373 | 374 | // v_prod_omega[X] = v_prod[omega*X] 375 | let v_prod_omega = PolynomialValues::from(v_prod_omega_vals).ifft(); 376 | 377 | last = print_time_since(start, last, "v_prod and v_prod_omega interpolation done"); 378 | 379 | // q_v[X] = (v_prod[omega * X] - (v_prod[X] * (gamma + v[X]))) * n_1[X] / Z_H[X] 380 | // let (q_v, r_v) = (&(&v_prod_omega - &(&v_prod * &(&gamma_poly + &v))) * &n_1).div_rem(&vanishing_poly); 381 | let sum = &(&v_prod_omega - &(&v_prod * &(&gamma_poly + &v))) * &n_1; 382 | let q_v = PolynomialCoeffs::new(sum.coeffs[0..DEGREE].to_vec()); 383 | 384 | last = print_time_since(start, last, "q_v division done"); 385 | 386 | // Will commit to v_prod[X], q_v[X] 387 | values_vec_1.push(v_prod); 388 | values_vec_1.push(q_v); 389 | 390 | // z_prod_vals = [1, z_vals_0 + gamma, [(z_0 + gamma)(z_vals_1 + gamma)],...,[(z_vals_0 + gamma)...(z_vals_{PIXEL_RANGE + D - 1} + gamma)]] 391 | let mut z_prod_vals = Vec::new(); 392 | let mut product = F::ONE; 393 | z_prod_vals.push(product); 394 | for i in 0..z_f_vals.len() - 1 { 395 | product *= z_f_vals[i] + gamma; 396 | z_prod_vals.push(product); 397 | } 398 | 399 | // Range argument 400 | // We want to prove for the z constructed above that: 401 | // (z[X] - z[omega*X])(1 - (z[X] - z[omega*X]) = 0 mod Z_H[X] 402 | 403 | // z_omega_vals = [z_vals_0 + gamma,...,[(z_vals_0 + gamma)...(z_vals_{PIXEL_RANGE + D - 1} + gamma)], 1] 404 | let mut z_omega_vals = Vec::new(); 405 | for i in 1..z_vals.len() { 406 | z_omega_vals.push(z_f_vals[i]); 407 | } 408 | z_omega_vals.push(z_f_vals[0]); 409 | 410 | // z_prod_omega_vals = [z_vals_0 + gamma, [(z_vals_0 + gamma)(z_vals_1 + gamma)],...,[(z_vals_0 + gamma)...(z_vals_{PIXEL_RANGE + D - 1} + gamma)], 1] 411 | let mut z_prod_omega_vals = Vec::new(); 412 | for i in 1..z_prod_vals.len() { 413 | z_prod_omega_vals.push(z_prod_vals[i]); 414 | } 415 | z_prod_omega_vals.push(z_prod_vals[0]); 416 | 417 | // for all i \in [1, PIXEL_RANGE + D], z_prod[omega^i] = \prod_{j=0}^{i-1}(z_j + gamma) 418 | let z_prod = PolynomialValues::from(z_prod_vals).ifft(); 419 | 420 | // z_prod_omega[X] = z_prod[omega*X] 421 | let z_prod_omega = PolynomialValues::from(z_prod_omega_vals).ifft(); 422 | last = print_time_since(start, last, "z_prod and z_prod_omega interpolation done"); 423 | 424 | // q_z[X] = (z_prod[omega * X] - (z_prod[X] * (gamma + z[X]))) * n_1[X] / Z_H[X] 425 | // let (q_z, r_z) = (&(&z_prod_omega - &(&z_prod * &(&gamma_poly + &z))) * &n_1).div_rem(&vanishing_poly); 426 | let sum = &(&z_prod_omega - &(&z_prod * &(&gamma_poly + &z))) * &n_1; 427 | let q_z = PolynomialCoeffs::new(sum.coeffs[0..DEGREE].to_vec()); 428 | last = print_time_since(start, last, "q_z division done"); 429 | 430 | let z_omega = PolynomialValues::from(z_omega_vals).ifft(); 431 | 432 | let mut one_coeffs = Vec::new(); 433 | one_coeffs.push(F::ONE); 434 | 435 | let one = PolynomialCoeffs::from(one_coeffs); 436 | last = print_time_since(start, last, "one interpolation done"); 437 | 438 | let sum = &(&(&z_omega - &z) * &(&one - &(&z_omega - &z))) * &n_1; 439 | let q_range = PolynomialCoeffs::new(sum.coeffs[0..DEGREE].to_vec()); 440 | 441 | last = print_time_since(start, last, "q_range division done"); 442 | 443 | // Will commit to z_prod[X], q_z[X], q_range[X] 444 | values_vec_1.push(z_prod); 445 | values_vec_1.push(q_z); 446 | values_vec_1.push(q_range); 447 | 448 | let commit1 = PolynomialBatch::::from_coeffs( 449 | values_vec_1, 450 | rate_bits, 451 | USE_ZK, 452 | cap_height, 453 | &mut TimingTree::default(), 454 | Some(&fft_root_table), 455 | ); 456 | 457 | last = print_time_since(start, last, "commit1 done"); 458 | 459 | // Now we prove knowledge of actual hash value 460 | // Want to generate a[X] and prove that Equation 11 in Section 5.5 holds for 461 | // this a[X] and the v[X] generated above 462 | 463 | // Use commitments to generate random coefficients [r_0,...,r_{HASH_LENGTH-1}] 464 | // for random linear combination of sum checks 465 | let hash_coeffs = get_sha256_of_commitments(&commit1.merkle_tree.cap, "", HASH_LENGTH); 466 | 467 | // Let A be the public hashing matrix (we will generate it with a PRG) 468 | // a_vals = [\sum_{i=0}{HASH_LENGTH-1}r_i * A_{i, 0},...,\sum_{i=0}{HASH_LENGTH-1}r_i * A_{i, D - 1}] 469 | let mut a_vals = Vec::new(); 470 | 471 | // h_sum_vals = [0, v_vals_0 * a_vals_0 ,..., \sum_{i=0}^{D - 1} v_vals_0 * a_vals_0] 472 | let mut h_sum_vals = Vec::new(); 473 | 474 | // h_sum_omega_vals = [\sum_{i=0}^{1} v_vals_0 * a_vals_0,...,\sum_{i=0}^{D - 1} v_vals_0 * a_vals_0, v_vals_0 * a_vals_0] 475 | let mut h_sum_omega_vals = Vec::new(); 476 | h_sum_vals.push(F::ZERO); 477 | let mut sum = F::ZERO; 478 | 479 | // Re-read in pixels 480 | let file = read_photo("orig_"); 481 | for line in file.lines() { 482 | let line = line.expect("Unable to read line"); 483 | let i = line.parse::().unwrap(); 484 | 485 | let v_point = GoldilocksField(i as u64); 486 | 487 | let mut a_point = F::ZERO; 488 | for j in 0..hash_coeffs.len() { 489 | x = (A_CONSTANT * x + C_CONSTANT) & 0xffffffffffffffff; 490 | let x1 = x >> 32; 491 | x = (A_CONSTANT * x + C_CONSTANT) & 0xffffffffffffffff; 492 | let x2 = ((x & 0xffffffff00000000) + x1) & 0xffffffffffffffff; 493 | 494 | a_point += F::from_canonical_u64(u64::try_from(x2).unwrap() % F::ORDER) * hash_coeffs[j]; 495 | } 496 | a_vals.push(a_point); 497 | 498 | sum += v_point * a_point; 499 | h_sum_vals.push(sum); 500 | h_sum_omega_vals.push(sum); 501 | } 502 | 503 | let a_vals_length = a_vals.len(); 504 | for _ in 0..DEGREE - a_vals_length { 505 | a_vals.push(F::ZERO); 506 | } 507 | 508 | for _ in 0..DEGREE - PIXELS - 1 { 509 | h_sum_vals.push(sum); 510 | h_sum_omega_vals.push(sum); 511 | } 512 | h_sum_omega_vals.push(F::ZERO); 513 | 514 | 515 | // for all i \in [0, D - 1], a[omega^i] = \sum_{j=0}{HASH_LENGTH-1}r_j * A_{j, i} 516 | let a = PolynomialValues::from(a_vals).ifft(); 517 | 518 | // for all i \in [0, D], h_sum[omega^i] = \sum_{j=0}^{i} v_vals_j * a_vals_j 519 | let h_sum = PolynomialValues::from(h_sum_vals).ifft(); 520 | 521 | // h_sum_omega[X] = h_sum[omega*X] 522 | let h_sum_omega = PolynomialValues::from(h_sum_omega_vals).ifft(); 523 | 524 | last = print_time_since(start, last, "a, h_sum, h_sum_omega interpolation done"); 525 | 526 | // q_h_sum[X] = (h_sum[omega*X] - h_sum[X] - (v[X] * a[X]))* n_1[X] / Z_H[X] 527 | let sum = &(&(&h_sum_omega - &h_sum) - &(&v * &a))* &n_1; 528 | let q_h_sum = PolynomialCoeffs::new(sum.coeffs[0..DEGREE].to_vec()); 529 | last = print_time_since(start, last, "q_h_sum interpolation done"); 530 | 531 | // Second set of polynomials we commit to 532 | let mut values_vec_2 = Vec::new(); 533 | 534 | // Will commit to a[X], h_sum[X], q_h_sum[X] 535 | values_vec_2.push(a); 536 | values_vec_2.push(h_sum); 537 | values_vec_2.push(q_h_sum); 538 | 539 | let commit2 = PolynomialBatch::::from_coeffs( 540 | values_vec_2, 541 | rate_bits, 542 | USE_ZK, 543 | cap_height, 544 | &mut TimingTree::default(), 545 | Some(&fft_root_table), 546 | ); 547 | 548 | 549 | last = print_time_since(start, last, "commit2 done"); 550 | 551 | let mut challenger = Challenger::>::Hasher>::new(); 552 | 553 | challenger.observe_cap::<>::Hasher>(&commit0.merkle_tree.cap); 554 | challenger.observe_cap::<>::Hasher>(&commit1.merkle_tree.cap); 555 | challenger.observe_cap::<>::Hasher>(&commit2.merkle_tree.cap); 556 | 557 | let zeta = challenger.get_extension_challenge::(); 558 | 559 | let degree_bits = log2_strict(DEGREE); 560 | 561 | let g = <>::F as Extendable>::Extension::primitive_root_of_unity(degree_bits); 562 | 563 | let commit0_polys = FriPolynomialInfo::from_range( 564 | 0, 565 | 0..commit0.polynomials.len(), 566 | ); 567 | 568 | let commit1_polys = FriPolynomialInfo::from_range( 569 | 1, 570 | 0..commit1.polynomials.len(), 571 | ); 572 | 573 | let commit2_polys = FriPolynomialInfo::from_range( 574 | 2, 575 | 0..commit2.polynomials.len(), 576 | ); 577 | 578 | let all_polys = [commit0_polys, commit1_polys, commit2_polys].concat(); 579 | 580 | 581 | let zeta_batch = FriBatchInfo { 582 | point: zeta, 583 | polynomials: all_polys.clone(), 584 | }; 585 | 586 | // The Z polynomials are also opened at g * zeta. 587 | let zeta_next = g * zeta; 588 | let zeta_next_batch = FriBatchInfo { 589 | point: zeta_next, 590 | polynomials: all_polys.clone(), 591 | }; 592 | 593 | let pixels = g.exp_u64((PIXELS) as u64); 594 | let pixels_batch = FriBatchInfo { 595 | point: pixels, 596 | polynomials: all_polys.clone(), 597 | }; 598 | 599 | let pixel_range = g.exp_u64((PIXEL_RANGE) as u64); 600 | let pixel_range_batch = FriBatchInfo { 601 | point: pixel_range, 602 | polynomials: all_polys.clone(), 603 | }; 604 | 605 | let pixels_plus_pixel_range = g.exp_u64((PIXELS + PIXEL_RANGE as usize) as u64); 606 | let pixels_plus_pixel_range_batch = FriBatchInfo { 607 | point: pixels_plus_pixel_range, 608 | polynomials: all_polys, 609 | }; 610 | 611 | let openings = vec![zeta_batch, zeta_next_batch, pixels_batch, pixel_range_batch, pixels_plus_pixel_range_batch]; 612 | 613 | let fri_oracles = vec![ 614 | FriOracleInfo { 615 | num_polys: commit0.polynomials.len(), 616 | blinding: USE_ZK, 617 | }, 618 | FriOracleInfo { 619 | num_polys: commit1.polynomials.len(), 620 | blinding: USE_ZK, 621 | }, 622 | FriOracleInfo { 623 | num_polys: commit2.polynomials.len(), 624 | blinding: USE_ZK, 625 | } 626 | ]; 627 | 628 | let instance = FriInstanceInfo { 629 | oracles: fri_oracles, 630 | batches: openings, 631 | }; 632 | 633 | let fri_config = get_fri_config(rate_bits, cap_height); 634 | 635 | let mut challenger = Challenger::>::Hasher>::new(); 636 | 637 | let opening_proof = PolynomialBatch::::prove_openings( 638 | &instance, 639 | &[ 640 | &commit0, 641 | &commit1, 642 | &commit2 643 | ], 644 | &mut challenger, 645 | &fri_config.fri_params(degree_bits, true), 646 | &mut TimingTree::default(), 647 | ); 648 | 649 | last = print_time_since(start, last, "openings commitment done"); 650 | 651 | let merkle_caps = &[ 652 | commit0.merkle_tree.cap.clone(), 653 | commit1.merkle_tree.cap.clone(), 654 | commit2.merkle_tree.cap.clone() 655 | ]; 656 | 657 | let eval_commitment = |z: <>::F as Extendable>::Extension, c: &PolynomialBatch| { 658 | c.polynomials 659 | .par_iter() 660 | .map(|p| p.to_extension::().eval(z)) 661 | .collect::>() 662 | }; 663 | 664 | let commit0_zeta_eval = eval_commitment(zeta, &commit0); 665 | let commit0_zeta_next_eval = eval_commitment(zeta_next, &commit0); 666 | let commit0_pixels_eval = eval_commitment(pixels, &commit0); 667 | let commit0_pixel_range_eval = eval_commitment(pixel_range, &commit0); 668 | let commit0_pixels_and_pixel_eval = eval_commitment(pixels_plus_pixel_range, &commit0); 669 | 670 | let commit1_zeta_eval = eval_commitment(zeta, &commit1); 671 | let commit1_zeta_next_eval = eval_commitment(zeta_next, &commit1); 672 | let commit1_pixels_eval = eval_commitment(pixels, &commit1); 673 | let commit1_pixel_range_eval = eval_commitment(pixel_range, &commit1); 674 | let commit1_pixels_and_pixel_eval = eval_commitment(pixels_plus_pixel_range, &commit1); 675 | 676 | let commit2_zeta_eval = eval_commitment(zeta, &commit2); 677 | let commit2_zeta_next_eval = eval_commitment(zeta_next, &commit2); 678 | let commit2_pixels_eval = eval_commitment(pixels, &commit2); 679 | let commit2_pixel_range_eval = eval_commitment(pixel_range, &commit2); 680 | let commit2_pixels_and_pixel_eval = eval_commitment(pixels_plus_pixel_range, &commit2); 681 | 682 | 683 | let zeta_batch = FriOpeningBatch { 684 | values: [ 685 | commit0_zeta_eval.as_slice(), 686 | commit1_zeta_eval.as_slice(), 687 | commit2_zeta_eval.as_slice(), 688 | ].concat(), 689 | }; 690 | 691 | let zeta_next_batch = FriOpeningBatch { 692 | values: [ 693 | commit0_zeta_next_eval.as_slice(), 694 | commit1_zeta_next_eval.as_slice(), 695 | commit2_zeta_next_eval.as_slice(), 696 | ].concat() 697 | }; 698 | 699 | let pixels_batch = FriOpeningBatch { 700 | values: [ 701 | commit0_pixels_eval.as_slice(), 702 | commit1_pixels_eval.as_slice(), 703 | commit2_pixels_eval.as_slice(), 704 | ].concat(), 705 | }; 706 | 707 | let pixel_range_batch = FriOpeningBatch { 708 | values: [ 709 | commit0_pixel_range_eval.as_slice(), 710 | commit1_pixel_range_eval.as_slice(), 711 | commit2_pixel_range_eval.as_slice(), 712 | ].concat(), 713 | }; 714 | 715 | let pixels_plus_pixel_range_batch = FriOpeningBatch { 716 | values: [ 717 | commit0_pixels_and_pixel_eval.as_slice(), 718 | commit1_pixels_and_pixel_eval.as_slice(), 719 | commit2_pixels_and_pixel_eval.as_slice(), 720 | ].concat(), 721 | }; 722 | 723 | let fri_openings = FriOpenings { 724 | batches: vec![zeta_batch, zeta_next_batch, pixels_batch, pixel_range_batch, pixels_plus_pixel_range_batch], 725 | }; 726 | 727 | last = print_time_since(start, last, "eval commitments done"); 728 | 729 | return (fri_openings, merkle_caps.clone(), opening_proof, last); 730 | } 731 | 732 | 733 | fn main() { 734 | // FRI commitment constants 735 | let rate_bits = 2; 736 | let cap_height = 4; 737 | let max_quotient_degree_factor = 4; 738 | let degree_bits = log2_strict(DEGREE); 739 | let omega = F::primitive_root_of_unity(degree_bits); 740 | 741 | let max_fft_points = 1 << (degree_bits + max(rate_bits, log2_ceil(max_quotient_degree_factor))); 742 | 743 | let fft_root_table = fft_root_table(max_fft_points); 744 | 745 | let start = SystemTime::now(); 746 | let start_epoch = start 747 | .duration_since(UNIX_EPOCH) 748 | .expect("Time went backwards"); 749 | let start = start_epoch.as_millis(); 750 | 751 | // Prover 752 | let (fri_openings, merkle_caps, opening_proof, mut last) = prove(start, start, rate_bits, cap_height, omega, &fft_root_table); 753 | last = print_time_since(start, last, "proving done"); 754 | 755 | // Verifier 756 | let mut challenger = Challenger::>::Hasher>::new(); 757 | 758 | challenger.observe_cap::<>::Hasher>(&merkle_caps[0]); 759 | challenger.observe_cap::<>::Hasher>(&merkle_caps[1]); 760 | challenger.observe_cap::<>::Hasher>(&merkle_caps[2]); 761 | 762 | let zeta = challenger.get_extension_challenge::(); 763 | 764 | // Verify opening proof 765 | let fri_config = get_fri_config(rate_bits, cap_height); 766 | let mut challenger = Challenger::>::Hasher>::new(); 767 | let fri_challenges = challenger.fri_challenges::( 768 | &opening_proof.commit_phase_merkle_caps, 769 | &opening_proof.final_poly, 770 | opening_proof.pow_witness, 771 | degree_bits, 772 | &fri_config, 773 | ); 774 | 775 | let instance = get_instance(3, 7, 3, degree_bits, zeta); 776 | 777 | let res = verify_fri_proof::( 778 | &instance, 779 | &fri_openings, 780 | &fri_challenges, 781 | &merkle_caps, 782 | &opening_proof, 783 | &fri_config.fri_params(degree_bits, true), 784 | ); 785 | 786 | let _res = res.unwrap(); 787 | 788 | // Check polynomial equalities 789 | let mut vals = Vec::new(); 790 | vals.push(F::ONE); 791 | for _ in 0..DEGREE - 1 { 792 | vals.push(F::ZERO); 793 | } 794 | vals.push(F::ZERO - F::ONE); 795 | let vanishing_poly = PolynomialCoeffs::new(vals); 796 | 797 | let mut n_1_coeffs = Vec::new(); 798 | n_1_coeffs.push(omega.exp_u64((DEGREE - 1) as u64)); 799 | n_1_coeffs.push(F::ZERO - F::ONE); 800 | let n_1 = PolynomialCoeffs::from(n_1_coeffs); 801 | 802 | let vanishing_poly_zeta_eval = vanishing_poly.to_extension::().eval(zeta); 803 | let n_1_zeta_eval = n_1.to_extension::().eval(zeta); 804 | 805 | let hash_coeffs = get_sha256_of_commitments(&merkle_caps[1], "", HASH_LENGTH); 806 | 807 | let mut a_vals = Vec::new(); 808 | let mut x = X; 809 | for _ in 0..PIXELS { 810 | let mut a_point = F::ZERO; 811 | for j in 0..hash_coeffs.len() { 812 | x = (A_CONSTANT * x + C_CONSTANT) & 0xffffffffffffffff; 813 | let x1 = x >> 32; 814 | x = (A_CONSTANT * x + C_CONSTANT) & 0xffffffffffffffff; 815 | let x2 = ((x & 0xffffffff00000000) + x1) & 0xffffffffffffffff; 816 | 817 | a_point += F::from_canonical_u64(u64::try_from(x2).unwrap() % F::ORDER) * hash_coeffs[j]; 818 | } 819 | a_vals.push(a_point); 820 | } 821 | let a_vals_length = a_vals.len(); 822 | for _ in 0..DEGREE - a_vals_length { 823 | a_vals.push(F::ZERO); 824 | } 825 | let a = PolynomialValues::from(a_vals).ifft(); 826 | let a_zeta_eval = a.to_extension::().eval(zeta); 827 | 828 | let gamma = get_sha256_of_commitments(&merkle_caps[0], "", 4)[0]; 829 | let gamma_ext = QuadraticExtension::from(gamma); 830 | 831 | // Check (w_prod[omega*zeta] - w_prod[zeta](gamma + w[zeta])) * n_1[zeta] = q_w[zeta] * Z_H[zeta] 832 | assert!((fri_openings.batches[1].values[3] - fri_openings.batches[0].values[3] * (gamma_ext + fri_openings.batches[0].values[0])) * n_1_zeta_eval == fri_openings.batches[0].values[4] * vanishing_poly_zeta_eval); 833 | // Check (v_prod[omega*zeta] - v_prod[zeta](gamma + v[zeta])) * n_1[zeta] = q_v[zeta] * Z_H[zeta] 834 | assert!((fri_openings.batches[1].values[5] - fri_openings.batches[0].values[5] * (gamma_ext + fri_openings.batches[0].values[1])) * n_1_zeta_eval == fri_openings.batches[0].values[6] * vanishing_poly_zeta_eval); 835 | // Check (z_prod[omega*alpha] - z_prod[alpha](gamma + z[alpha])) * n_1[alpha] = q_z[alpha] * Z_H[alpha] 836 | assert!((fri_openings.batches[1].values[7] - fri_openings.batches[0].values[7] * (gamma_ext + fri_openings.batches[0].values[2])) * n_1_zeta_eval == fri_openings.batches[0].values[8] * vanishing_poly_zeta_eval); 837 | // Check v_prod[omega^D] * w_prod[omega^PIXEL_RANGE] = z_prod[omega^{D + PIXEL_RANGE}] 838 | assert!(fri_openings.batches[2].values[5] * fri_openings.batches[3].values[3] == fri_openings.batches[4].values[7]); 839 | 840 | // Range Checks 841 | // Check n_1[zeta] * (z[omega*zeta] - z[zeta]) (1 - z[omega*zeta] - z[zeta]) = q_range[zeta] * Z_H[zeta] 842 | let dif = fri_openings.batches[1].values[2] - fri_openings.batches[0].values[2]; 843 | assert!(n_1_zeta_eval * dif * (QuadraticExtension::from(F::ONE) - dif) == fri_openings.batches[0].values[9] * vanishing_poly_zeta_eval); 844 | 845 | // Hash Value Checks 846 | // Check (h_sum[omega*zeta] - h_sum[zeta] - v[zeta] * a[zeta]) * n_1[zeta] = q_h_sum[zeta] * Z_H[zeta] 847 | assert!((fri_openings.batches[1].values[11] - fri_openings.batches[0].values[11] - fri_openings.batches[0].values[1] * a_zeta_eval) * n_1_zeta_eval == fri_openings.batches[0].values[12] * vanishing_poly_zeta_eval); 848 | 849 | //let mem = proc_status::mem_usage().unwrap(); 850 | //println!("Mem usage in bytes: current={}, peak={}", mem.current, mem.peak); 851 | _ = print_time_since(start, last, "verification done"); 852 | 853 | } -------------------------------------------------------------------------------- /examples/opt-veritas.rs: -------------------------------------------------------------------------------- 1 | use plonky2::field::polynomial::{PolynomialCoeffs, PolynomialValues}; 2 | use plonky2::fri::oracle::PolynomialBatch; 3 | use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; 4 | use plonky2::field::types::Field; 5 | use plonky2::field::extension::Extendable; 6 | use plonky2::util::timing::TimingTree; 7 | use plonky2::field::fft::fft_root_table; 8 | use plonky2::util::{log2_ceil, log2_strict}; 9 | use core::cmp::max; 10 | use std::time::{SystemTime, UNIX_EPOCH}; 11 | use std::io::{BufRead, BufReader}; 12 | use rayon::prelude::*; 13 | use plonky2::plonk::config::GenericHashOut; 14 | use sha256::digest; 15 | use std::fs::File; 16 | use plonky2::field::goldilocks_field::GoldilocksField; 17 | use plonky2::fri::structure::FriPolynomialInfo; 18 | use plonky2::fri::structure::FriInstanceInfo; 19 | use plonky2::fri::structure::FriBatchInfo; 20 | use plonky2::iop::challenger::Challenger; 21 | use plonky2::fri::structure::FriOracleInfo; 22 | use plonky2::fri::reduction_strategies::FriReductionStrategy; 23 | use plonky2::fri::FriConfig; 24 | use plonky2::fri::structure::FriOpeningBatch; 25 | use plonky2::fri::structure::FriOpenings; 26 | use plonky2::fri::verifier::verify_fri_proof; 27 | use plonky2::field::extension::quadratic::QuadraticExtension; 28 | use plonky2::field::types::PrimeField64; 29 | use plonky2::field::types::Field64; 30 | use plonky2::hash::merkle_tree::MerkleCap; 31 | use plonky2::hash::hash_types::HashOut; 32 | use plonky2::hash::poseidon::PoseidonHash; 33 | use plonky2::field::fft::FftRootTable; 34 | use plonky2::fri::proof::FriProof; 35 | 36 | static PIXELS : usize = 14; 37 | static EXPONENT : u32 = 3; 38 | const DEGREE : usize = 1 << 5; 39 | static PIXEL_RANGE : i32 = 2_i32.pow(EXPONENT); 40 | const HASH_LENGTH : usize = 128; 41 | const BATCH_SIZE : usize = 32; 42 | const X : u128 = 3091352403337663489; 43 | const A_CONSTANT : u128 = 3935559000370003845; 44 | const C_CONSTANT : u128 = 2691343689449507681; 45 | const USE_ZK : bool = false; 46 | 47 | const D: usize = 2; 48 | type C = PoseidonGoldilocksConfig; 49 | type F = >::F; 50 | 51 | fn print_time_since(start: u128, last: u128, tag: &str) -> u128 { 52 | let now = SystemTime::now(); 53 | let now_epoc = now 54 | .duration_since(UNIX_EPOCH) 55 | .expect("Time went backwards"); 56 | let now = now_epoc.as_millis(); 57 | println!("{:?}; time since start {:?}; time since last check: {:?}", tag, (now - start) as f32 / 60000.0, (now - last) as f32 / 60000.0); 58 | return now; 59 | } 60 | 61 | 62 | fn get_filename(prefix: &str) -> String { 63 | let mut filename = prefix.to_owned(); 64 | filename.push_str("image_"); 65 | filename.push_str(&PIXELS.to_string()); 66 | filename.push_str("_"); 67 | filename.push_str(&EXPONENT.to_string()); 68 | filename.push_str(".txt"); 69 | return filename 70 | } 71 | 72 | fn read_photo(prefix: &str) -> BufReader { 73 | let file = File::open(get_filename(prefix)).expect("Unable to open file"); 74 | return BufReader::new(file); 75 | } 76 | 77 | // gets sha256 of commitments for random challenges 78 | fn get_sha256_of_commitments(merkle_cap: &MerkleCap, instance_hash: &str, num_elements: usize) -> Vec { 79 | let mut byte_vec = Vec::new(); 80 | 81 | for hash in &merkle_cap.0 { 82 | let h = hash.to_vec(); 83 | for elem in h { 84 | byte_vec.append(&mut elem.to_canonical_u64().to_le_bytes().to_vec()); 85 | } 86 | } 87 | 88 | let s = format!("{:?}{:?}", &byte_vec, instance_hash); 89 | let mut val = digest(s); 90 | 91 | let mut ret = Vec::new(); 92 | 93 | for _ in 0..num_elements/4 { 94 | let sha2561 = u64::from_str_radix(&val[0..16], 16).unwrap() % F::ORDER; 95 | ret.push(F::from_canonical_u64(sha2561)); 96 | let sha2562 = u64::from_str_radix(&val[16..32], 16).unwrap(); 97 | ret.push(F::from_canonical_u64(sha2562)); 98 | let sha2563 = u64::from_str_radix(&val[32..48], 16).unwrap(); 99 | ret.push(F::from_canonical_u64(sha2563)); 100 | let sha2564 = u64::from_str_radix(&val[48..64], 16).unwrap(); 101 | ret.push(F::from_canonical_u64(sha2564)); 102 | val = digest(val); 103 | } 104 | 105 | return ret; 106 | } 107 | 108 | fn read_a_merkle_caps(batch: usize) -> MerkleCap{ 109 | let mut filename = "A_256_".to_owned(); 110 | filename.push_str(&PIXELS.to_string()); 111 | filename.push_str("_"); 112 | filename.push_str(&EXPONENT.to_string()); 113 | filename.push_str("_"); 114 | filename.push_str(&batch.to_string()); 115 | filename.push_str(".txt"); 116 | 117 | let mut cap_hashes = Vec::new(); 118 | let f = File::open(filename).expect("Unable to open file"); 119 | let f = BufReader::new(f); 120 | for line in f.lines() { 121 | let line = line.expect("Unable to read line"); 122 | let first_last_off: &str = &line[1..line.len() - 1]; 123 | let parts = first_last_off.split(", "); 124 | let mut cap_hash = Vec::new(); 125 | for part in parts { 126 | cap_hash.push(F::from_canonical_u64(part.parse::().unwrap())); 127 | } 128 | let hash = HashOut::from_vec(cap_hash); 129 | cap_hashes.push(hash); 130 | } 131 | let mut cap = MerkleCap::default(); 132 | cap.0 = cap_hashes; 133 | return cap; 134 | } 135 | 136 | fn get_fri_config(rate_bits: usize, cap_height: usize) -> FriConfig { 137 | return FriConfig { 138 | rate_bits: rate_bits, 139 | cap_height: cap_height, 140 | proof_of_work_bits: 16, 141 | reduction_strategy: FriReductionStrategy::ConstantArityBits(4, 5), 142 | num_query_rounds: 28, 143 | }; 144 | } 145 | 146 | fn prove_one(start: u128, old_last: u128, rate_bits: usize, cap_height: usize, omega: F, fft_root_table: &FftRootTable) 147 | -> (FriOpenings, [MerkleCap; 3], FriProof>::Hasher, D>, QuadraticExtension, u128) { 148 | let mut last = old_last; 149 | // w_vals = [0, 1,...,PIXEL_RANGE - 1] 150 | let mut w_vals = Vec::new(); 151 | for i in 0..PIXEL_RANGE { 152 | let i_in_fr = GoldilocksField(i as u64); 153 | w_vals.push(i_in_fr); 154 | } 155 | 156 | let mut w_vals = Vec::new(); 157 | for i in 0..PIXEL_RANGE { 158 | let i_in_fr = GoldilocksField(i as u64); 159 | w_vals.push(i_in_fr); 160 | } 161 | 162 | for _ in 0..DEGREE - (PIXEL_RANGE as usize) { 163 | w_vals.push(F::ZERO); 164 | } 165 | 166 | // w[X] = poly(w_vals) 167 | let w = PolynomialValues::new(w_vals).ifft(); 168 | 169 | last = print_time_since(start, last, "w interpolation done"); 170 | 171 | // v_vals = [pixel_0,...,pixel_{D-1}] 172 | let mut v_vals = Vec::new(); 173 | // z_vals = [sort(v || w)] 174 | let mut z_vals = Vec::new(); 175 | 176 | // reading in photo pixels... 177 | let file = read_photo("orig_"); 178 | for line in file.lines() { 179 | let line = line.expect("Unable to read line"); 180 | let i = line.parse::().unwrap(); 181 | 182 | let v_point = GoldilocksField(i as u64); 183 | v_vals.push(v_point); 184 | z_vals.push(i); 185 | } 186 | 187 | for _ in 0..DEGREE - PIXELS { 188 | v_vals.push(F::ZERO); 189 | } 190 | 191 | for i in 0..PIXEL_RANGE { 192 | z_vals.push(i); 193 | } 194 | 195 | // pad z_vals so that [z[omega*x] - z[x][1 - (z[omega*x] - z[x])] = 0 still holds true 196 | let z_vals_length = z_vals.len(); 197 | for _ in 0..DEGREE - z_vals_length { 198 | z_vals.push(PIXEL_RANGE - 1); 199 | } 200 | z_vals.sort(); 201 | 202 | let mut z_f_vals = Vec::new(); 203 | for i in 0..z_vals.len() { 204 | z_f_vals.push(GoldilocksField(z_vals[i] as u64)); 205 | } 206 | 207 | 208 | // v[X] = poly(v_vals) 209 | let v = PolynomialValues::new(v_vals).ifft(); 210 | // z[X] = poly(z_vals) 211 | let z = PolynomialValues::new(z_f_vals.clone()).ifft(); 212 | last = print_time_since(start, last, "z and v interpolation done"); 213 | 214 | 215 | 216 | let mut values_vec_0 = Vec::new(); 217 | values_vec_0.push(w.clone()); 218 | values_vec_0.push(v.clone()); 219 | values_vec_0.push(z.clone()); 220 | 221 | last = print_time_since(start, last, "polynomial push done"); 222 | 223 | let commit0 = PolynomialBatch::::from_coeffs( 224 | values_vec_0, 225 | rate_bits, 226 | USE_ZK, 227 | cap_height, 228 | &mut TimingTree::default(), 229 | Some(&fft_root_table), 230 | ); 231 | 232 | last = print_time_since(start, last, "commit0 done"); 233 | let gamma = get_sha256_of_commitments(&commit0.merkle_tree.cap, "", 4)[0]; 234 | 235 | last = print_time_since(start, last, "gamma done"); 236 | 237 | // Permutation argument 238 | // We want to prove: 239 | // product_{i=0}^{D-1}(v_i + gamma) * product_{i=0}^{PIXEL_RANGE-1}(w_i + gamma) = product_{i=0}^{D + PIXEL_RANGE - 1}(z_i + gamma) 240 | // where v holds the image pixels, w is the range that the pixel values must lie in [0, PIXEL_RANGE-1], 241 | // and z is the sorted concatentation of v and w 242 | 243 | let mut values_vec_1 = Vec::new(); 244 | 245 | // w_prod_vals = [1, (gamma), [(gamma)(1 + gamma)],...,[(gamma)...(PIXEL_RANGE - 1 + gamma)]] 246 | let mut w_prod_vals = Vec::new(); 247 | let mut product = F::ONE; 248 | w_prod_vals.push(product); 249 | 250 | for i in 0..PIXEL_RANGE { 251 | let i_in_fr = GoldilocksField(i as u64); 252 | product *= i_in_fr + gamma; 253 | w_prod_vals.push(product); 254 | } 255 | 256 | let w_prod_vals_len = w_prod_vals.len(); 257 | for _ in 0..DEGREE - w_prod_vals_len { 258 | product *= gamma; 259 | w_prod_vals.push(product); 260 | } 261 | 262 | // w_prod_omega_vals = [(gamma), [(gamma)(1 + gamma)],...,[(gamma)...(PIXEL_RANGE + gamma)], 1] 263 | let mut w_prod_omega_vals = Vec::new(); 264 | for i in 1..w_prod_vals.len() { 265 | w_prod_omega_vals.push(w_prod_vals[i]); 266 | } 267 | w_prod_omega_vals.push(w_prod_vals[0]); 268 | 269 | let w_prod = PolynomialValues::new(w_prod_vals).ifft(); 270 | 271 | let w_prod_omega = PolynomialValues::new(w_prod_omega_vals).ifft(); 272 | 273 | last = print_time_since(start, last, "w_prod and w_prod_omega interpolation done"); 274 | 275 | let mut n_1_coeffs = Vec::new(); 276 | n_1_coeffs.push(omega.exp_u64((DEGREE - 1) as u64)); 277 | n_1_coeffs.push(F::ZERO - F::ONE); 278 | 279 | let n_1 = PolynomialCoeffs::from(n_1_coeffs); 280 | println!("n_1 eval {:?}", n_1.eval(omega.exp_u64((DEGREE - 1) as u64))); 281 | last = print_time_since(start, last, "n_1 interpolation done"); 282 | 283 | let mut gamma_coeffs = Vec::new(); 284 | gamma_coeffs.push(gamma); 285 | let gamma_poly = PolynomialCoeffs::from(gamma_coeffs); 286 | 287 | // let (q_w, r_w) = (&(&w_prod_omega - &(&w_prod * &(&gamma_poly + &w))) * &n_1).div_rem(&vanishing_poly); 288 | // assert!(r_w.is_zero()); 289 | let sum = &(&w_prod_omega - &(&w_prod * &(&gamma_poly + &w))) * &n_1; 290 | let q_w = PolynomialCoeffs::new(sum.coeffs[0..DEGREE].to_vec()); 291 | // assert!(q_fake == q_w); 292 | last = print_time_since(start, last, "q_w division done"); 293 | 294 | // Will commit to w_prod[X], q_w[X] 295 | values_vec_1.push(w_prod); 296 | values_vec_1.push(q_w); 297 | 298 | // v_prod_vals = [1, (pixel_0 + gamma), [(pixel_0 + gamma)(pixel_1 + gamma)],...,[(pixel_0 + gamma)...(pixel_{D-1} + gamma)]] 299 | let mut v_prod_vals = Vec::new(); 300 | let mut product = F::ONE; 301 | v_prod_vals.push(product); 302 | 303 | // reading in photo pixels... 304 | let file = read_photo("orig_"); 305 | for line in file.lines() { 306 | let line = line.expect("Unable to read line"); 307 | let i = line.parse::().unwrap(); 308 | 309 | let v_point = GoldilocksField(i as u64); 310 | 311 | product *= v_point + gamma; 312 | v_prod_vals.push(product); 313 | } 314 | 315 | for _ in 0..DEGREE - PIXELS - 1 { 316 | product *= gamma; 317 | v_prod_vals.push(product); 318 | } 319 | 320 | // v_prod_omega_vals = [(pixel_0 + gamma), [(pixel_0 + gamma)(pixel_1 + gamma)],...,[(pixel_0 + gamma)...(pixel_{D-1} + gamma)], 1] 321 | let mut v_prod_omega_vals = Vec::new(); 322 | for i in 1..v_prod_vals.len() { 323 | v_prod_omega_vals.push(v_prod_vals[i]); 324 | } 325 | v_prod_omega_vals.push(v_prod_vals[0]); 326 | 327 | // for all i \in [1, D + 1], v_prod[omega^i] = \prod_{j=0}^{i-1}(v_j + gamma) 328 | let v_prod = PolynomialValues::from(v_prod_vals).ifft(); 329 | 330 | // v_prod_omega[X] = v_prod[omega*X] 331 | let v_prod_omega = PolynomialValues::from(v_prod_omega_vals).ifft(); 332 | 333 | last = print_time_since(start, last, "v_prod and v_prod_omega interpolation done"); 334 | 335 | // q_v[X] = (v_prod[omega * X] - (v_prod[X] * (gamma + v[X]))) * n_1[X] / Z_H[X] 336 | // let (q_v, r_v) = (&(&v_prod_omega - &(&v_prod * &(&gamma_poly + &v))) * &n_1).div_rem(&vanishing_poly); 337 | let sum = &(&v_prod_omega - &(&v_prod * &(&gamma_poly + &v))) * &n_1; 338 | let q_v = PolynomialCoeffs::new(sum.coeffs[0..DEGREE].to_vec()); 339 | // assert!(q_fake == q_v); 340 | // assert!(r_v.is_zero()); 341 | 342 | last = print_time_since(start, last, "q_v division done"); 343 | 344 | // Will commit to v_prod[X], q_v[X] 345 | values_vec_1.push(v_prod); 346 | values_vec_1.push(q_v); 347 | 348 | // z_prod_vals = [1, z_vals_0 + gamma, [(z_0 + gamma)(z_vals_1 + gamma)],...,[(z_vals_0 + gamma)...(z_vals_{PIXEL_RANGE + D - 1} + gamma)]] 349 | let mut z_prod_vals = Vec::new(); 350 | let mut product = F::ONE; 351 | z_prod_vals.push(product); 352 | for i in 0..z_f_vals.len() - 1 { 353 | product *= z_f_vals[i] + gamma; 354 | z_prod_vals.push(product); 355 | } 356 | 357 | // Range argument 358 | // We want to prove for the z constructed above that: 359 | // (z[X] - z[omega*X])(1 - (z[X] - z[omega*X]) = 0 mod Z_H[X] 360 | 361 | // z_omega_vals = [z_vals_0 + gamma,...,[(z_vals_0 + gamma)...(z_vals_{PIXEL_RANGE + D - 1} + gamma)], 1] 362 | let mut z_omega_vals = Vec::new(); 363 | for i in 1..z_vals.len() { 364 | z_omega_vals.push(z_f_vals[i]); 365 | } 366 | z_omega_vals.push(z_f_vals[0]); 367 | 368 | // z_prod_omega_vals = [z_vals_0 + gamma, [(z_vals_0 + gamma)(z_vals_1 + gamma)],...,[(z_vals_0 + gamma)...(z_vals_{PIXEL_RANGE + D - 1} + gamma)], 1] 369 | let mut z_prod_omega_vals = Vec::new(); 370 | for i in 1..z_prod_vals.len() { 371 | z_prod_omega_vals.push(z_prod_vals[i]); 372 | } 373 | z_prod_omega_vals.push(z_prod_vals[0]); 374 | 375 | // for all i \in [1, PIXEL_RANGE + D], z_prod[omega^i] = \prod_{j=0}^{i-1}(z_j + gamma) 376 | let z_prod = PolynomialValues::from(z_prod_vals).ifft(); 377 | 378 | // z_prod_omega[X] = z_prod[omega*X] 379 | let z_prod_omega = PolynomialValues::from(z_prod_omega_vals).ifft(); 380 | last = print_time_since(start, last, "z_prod and z_prod_omega interpolation done"); 381 | 382 | // q_z[X] = (z_prod[omega * X] - (z_prod[X] * (gamma + z[X]))) * n_1[X] / Z_H[X] 383 | // let (q_z, r_z) = (&(&z_prod_omega - &(&z_prod * &(&gamma_poly + &z))) * &n_1).div_rem(&vanishing_poly); 384 | let sum = &(&z_prod_omega - &(&z_prod * &(&gamma_poly + &z))) * &n_1; 385 | let q_z = PolynomialCoeffs::new(sum.coeffs[0..DEGREE].to_vec()); 386 | // assert!(q_fake == q_z); 387 | // assert!(r_z.is_zero()); 388 | last = print_time_since(start, last, "q_z division done"); 389 | 390 | let z_omega = PolynomialValues::from(z_omega_vals).ifft(); 391 | 392 | let mut one_coeffs = Vec::new(); 393 | one_coeffs.push(F::ONE); 394 | 395 | let one = PolynomialCoeffs::from(one_coeffs); 396 | last = print_time_since(start, last, "one interpolation done"); 397 | 398 | 399 | let sum = &(&(&z_omega - &z) * &(&one - &(&z_omega - &z))) * &n_1; 400 | let q_range = PolynomialCoeffs::new(sum.coeffs[0..DEGREE].to_vec()); 401 | 402 | last = print_time_since(start, last, "q_range division done"); 403 | 404 | // Will commit to z_prod[X], q_z[X], q_range[X] 405 | values_vec_1.push(z_prod); 406 | values_vec_1.push(q_z); 407 | values_vec_1.push(q_range); 408 | 409 | let commit1 = PolynomialBatch::::from_coeffs( 410 | values_vec_1, 411 | rate_bits, 412 | USE_ZK, 413 | cap_height, 414 | &mut TimingTree::default(), 415 | Some(&fft_root_table), 416 | ); 417 | 418 | last = print_time_since(start, last, "commit1 done"); 419 | 420 | // Now we prove knowledge of actual hash value (Section 5.5) 421 | // Want to generate a[X] and prove that Equation 11 in Section 5.5 holds for 422 | // this a[X] and the v[X] generated above 423 | 424 | // Use commitments to generate random coefficients [r_0,...,r_{HASH_LENGTH-1}] 425 | // for random linear combination of sum checks 426 | let hash_coeffs = get_sha256_of_commitments(&commit1.merkle_tree.cap, "", HASH_LENGTH); 427 | 428 | // Let A be the public hashing matrix (we will generate it with a PRG) 429 | // a_vals = [\sum_{i=0}{HASH_LENGTH-1}r_i * A_{i, 0},...,\sum_{i=0}{HASH_LENGTH-1}r_i * A_{i, D - 1}] 430 | let mut a_vals = Vec::new(); 431 | 432 | // h_sum_vals = [0, v_vals_0 * a_vals_0 ,..., \sum_{i=0}^{D - 1} v_vals_0 * a_vals_0] 433 | let mut h_sum_vals = Vec::new(); 434 | 435 | // h_sum_omega_vals = [\sum_{i=0}^{1} v_vals_0 * a_vals_0,...,\sum_{i=0}^{D - 1} v_vals_0 * a_vals_0, v_vals_0 * a_vals_0] 436 | let mut h_sum_omega_vals = Vec::new(); 437 | h_sum_vals.push(F::ZERO); 438 | let mut sum = F::ZERO; 439 | 440 | let mut x = X; 441 | 442 | // Re-read in pixels 443 | let file = read_photo("orig_"); 444 | for line in file.lines() { 445 | let line = line.expect("Unable to read line"); 446 | let i = line.parse::().unwrap(); 447 | 448 | let v_point = GoldilocksField(i as u64); 449 | 450 | let mut a_point = F::ZERO; 451 | for j in 0..hash_coeffs.len() { 452 | x = (A_CONSTANT * x + C_CONSTANT) & 0xffffffffffffffff; 453 | let x1 = x >> 32; 454 | x = (A_CONSTANT * x + C_CONSTANT) & 0xffffffffffffffff; 455 | let x2 = ((x & 0xffffffff00000000) + x1) & 0xffffffffffffffff; 456 | 457 | a_point += F::from_canonical_u64(u64::try_from(x2).unwrap() % F::ORDER) * hash_coeffs[j]; 458 | } 459 | a_vals.push(a_point); 460 | 461 | sum += v_point * a_point; 462 | h_sum_vals.push(sum); 463 | h_sum_omega_vals.push(sum); 464 | } 465 | 466 | let a_vals_length = a_vals.len(); 467 | for _ in 0..DEGREE - a_vals_length { 468 | a_vals.push(F::ZERO); 469 | } 470 | 471 | for _ in 0..DEGREE - PIXELS - 1 { 472 | h_sum_vals.push(sum); 473 | h_sum_omega_vals.push(sum); 474 | } 475 | h_sum_omega_vals.push(F::ZERO); 476 | 477 | 478 | // for all i \in [0, D - 1], a[omega^i] = \sum_{j=0}{HASH_LENGTH-1}r_j * A_{j, i} 479 | let a = PolynomialValues::from(a_vals).ifft(); 480 | 481 | // for all i \in [0, D], h_sum[omega^i] = \sum_{j=0}^{i} v_vals_j * a_vals_j 482 | let h_sum = PolynomialValues::from(h_sum_vals).ifft(); 483 | 484 | // h_sum_omega[X] = h_sum[omega*X] 485 | let h_sum_omega = PolynomialValues::from(h_sum_omega_vals).ifft(); 486 | 487 | last = print_time_since(start, last, "a, h_sum, h_sum_omega interpolation done"); 488 | 489 | // q_h_sum[X] = (h_sum[omega*X] - h_sum[X] - (v[X] * a[X]))* n_1[X] / Z_H[X] 490 | // let (q_h_sum, r_h_sum) = (&(&(&h_sum_omega - &h_sum) - &(&v * &a))* &n_1).div_rem(&vanishing_poly); 491 | let sum = &(&(&h_sum_omega - &h_sum) - &(&v * &a))* &n_1; 492 | let q_h_sum = PolynomialCoeffs::new(sum.coeffs[0..DEGREE].to_vec()); 493 | // assert!(r_h_sum.is_zero()); 494 | last = print_time_since(start, last, "q_h_sum interpolation done"); 495 | 496 | // Second set of polynomials we commit to 497 | let mut values_vec_2 = Vec::new(); 498 | 499 | // Will commit to a[X], h_sum[X], q_h_sum[X] 500 | // values_vec_2.push(a); 501 | values_vec_2.push(h_sum); 502 | values_vec_2.push(q_h_sum); 503 | 504 | let commit2 = PolynomialBatch::::from_coeffs( 505 | values_vec_2, 506 | rate_bits, 507 | USE_ZK, 508 | cap_height, 509 | &mut TimingTree::default(), 510 | Some(&fft_root_table), 511 | ); 512 | 513 | 514 | last = print_time_since(start, last, "commit2 done"); 515 | 516 | let mut challenger = Challenger::>::Hasher>::new(); 517 | 518 | challenger.observe_cap::<>::Hasher>(&commit0.merkle_tree.cap); 519 | challenger.observe_cap::<>::Hasher>(&commit1.merkle_tree.cap); 520 | challenger.observe_cap::<>::Hasher>(&commit2.merkle_tree.cap); 521 | 522 | for i in 0..HASH_LENGTH / BATCH_SIZE { 523 | let cap = read_a_merkle_caps(i); 524 | challenger.observe_cap::<>::Hasher>(&cap); 525 | } 526 | 527 | 528 | 529 | let zeta = challenger.get_extension_challenge::(); 530 | 531 | let degree_bits = log2_strict(DEGREE); 532 | 533 | let g = <>::F as Extendable>::Extension::primitive_root_of_unity(degree_bits); 534 | 535 | assert!(zeta.exp_power_of_2(degree_bits) != <>::F as Extendable>::Extension::ONE); 536 | 537 | let commit0_polys = FriPolynomialInfo::from_range( 538 | 0, 539 | 0..commit0.polynomials.len(), 540 | ); 541 | 542 | let commit1_polys = FriPolynomialInfo::from_range( 543 | 1, 544 | 0..commit1.polynomials.len(), 545 | ); 546 | 547 | let commit2_polys = FriPolynomialInfo::from_range( 548 | 2, 549 | 0..commit2.polynomials.len(), 550 | ); 551 | 552 | let all_polys = [commit0_polys, commit1_polys, commit2_polys].concat(); 553 | 554 | 555 | let zeta_batch = FriBatchInfo { 556 | point: zeta, 557 | polynomials: all_polys.clone(), 558 | }; 559 | 560 | // The Z polynomials are also opened at g * zeta. 561 | let zeta_next = g * zeta; 562 | let zeta_next_batch = FriBatchInfo { 563 | point: zeta_next, 564 | polynomials: all_polys.clone(), 565 | }; 566 | 567 | let pixels = g.exp_u64((PIXELS) as u64); 568 | let pixels_batch = FriBatchInfo { 569 | point: pixels, 570 | polynomials: all_polys.clone(), 571 | }; 572 | 573 | let pixel_range = g.exp_u64((PIXEL_RANGE) as u64); 574 | let pixel_range_batch = FriBatchInfo { 575 | point: pixel_range, 576 | polynomials: all_polys.clone(), 577 | }; 578 | 579 | let pixels_plus_pixel_range = g.exp_u64((PIXELS + PIXEL_RANGE as usize) as u64); 580 | let pixels_plus_pixel_range_batch = FriBatchInfo { 581 | point: pixels_plus_pixel_range, 582 | polynomials: all_polys, 583 | }; 584 | 585 | let openings = vec![zeta_batch, zeta_next_batch, pixels_batch, pixel_range_batch, pixels_plus_pixel_range_batch]; 586 | 587 | 588 | let fri_oracles = vec![ 589 | FriOracleInfo { 590 | num_polys: commit0.polynomials.len(), 591 | blinding: USE_ZK, 592 | }, 593 | FriOracleInfo { 594 | num_polys: commit1.polynomials.len(), 595 | blinding: USE_ZK, 596 | }, 597 | FriOracleInfo { 598 | num_polys: commit2.polynomials.len(), 599 | blinding: USE_ZK, 600 | } 601 | ]; 602 | 603 | let instance = FriInstanceInfo { 604 | oracles: fri_oracles, 605 | batches: openings, 606 | }; 607 | 608 | let fri_config = get_fri_config(rate_bits, cap_height); 609 | 610 | let mut challenger = Challenger::>::Hasher>::new(); 611 | 612 | let opening_proof = PolynomialBatch::::prove_openings( 613 | &instance, 614 | &[ 615 | &commit0, 616 | &commit1, 617 | &commit2 618 | ], 619 | &mut challenger, 620 | &fri_config.fri_params(degree_bits, true), 621 | &mut TimingTree::default(), 622 | ); 623 | 624 | last = print_time_since(start, last, "openings commitment done"); 625 | 626 | 627 | let merkle_caps = &[ 628 | commit0.merkle_tree.cap.clone(), 629 | commit1.merkle_tree.cap.clone(), 630 | commit2.merkle_tree.cap.clone() 631 | ]; 632 | 633 | let eval_commitment = |z: <>::F as Extendable>::Extension, c: &PolynomialBatch| { 634 | c.polynomials 635 | .par_iter() 636 | .map(|p| p.to_extension::().eval(z)) 637 | .collect::>() 638 | }; 639 | 640 | let commit0_zeta_eval = eval_commitment(zeta, &commit0); 641 | let commit0_zeta_next_eval = eval_commitment(zeta_next, &commit0); 642 | let commit0_pixels_eval = eval_commitment(pixels, &commit0); 643 | let commit0_pixel_range_eval = eval_commitment(pixel_range, &commit0); 644 | let commit0_pixels_and_pixel_eval = eval_commitment(pixels_plus_pixel_range, &commit0); 645 | 646 | let commit1_zeta_eval = eval_commitment(zeta, &commit1); 647 | let commit1_zeta_next_eval = eval_commitment(zeta_next, &commit1); 648 | let commit1_pixels_eval = eval_commitment(pixels, &commit1); 649 | let commit1_pixel_range_eval = eval_commitment(pixel_range, &commit1); 650 | let commit1_pixels_and_pixel_eval = eval_commitment(pixels_plus_pixel_range, &commit1); 651 | 652 | let commit2_zeta_eval = eval_commitment(zeta, &commit2); 653 | let commit2_zeta_next_eval = eval_commitment(zeta_next, &commit2); 654 | let commit2_pixels_eval = eval_commitment(pixels, &commit2); 655 | let commit2_pixel_range_eval = eval_commitment(pixel_range, &commit2); 656 | let commit2_pixels_and_pixel_eval = eval_commitment(pixels_plus_pixel_range, &commit2); 657 | 658 | let zeta_batch = FriOpeningBatch { 659 | values: [ 660 | commit0_zeta_eval.as_slice(), 661 | commit1_zeta_eval.as_slice(), 662 | commit2_zeta_eval.as_slice(), 663 | ].concat(), 664 | }; 665 | 666 | let zeta_next_batch = FriOpeningBatch { 667 | values: [ 668 | commit0_zeta_next_eval.as_slice(), 669 | commit1_zeta_next_eval.as_slice(), 670 | commit2_zeta_next_eval.as_slice(), 671 | ].concat() 672 | }; 673 | 674 | let pixels_batch = FriOpeningBatch { 675 | values: [ 676 | commit0_pixels_eval.as_slice(), 677 | commit1_pixels_eval.as_slice(), 678 | commit2_pixels_eval.as_slice(), 679 | ].concat(), 680 | }; 681 | 682 | let pixel_range_batch = FriOpeningBatch { 683 | values: [ 684 | commit0_pixel_range_eval.as_slice(), 685 | commit1_pixel_range_eval.as_slice(), 686 | commit2_pixel_range_eval.as_slice(), 687 | ].concat(), 688 | }; 689 | 690 | let pixels_plus_pixel_range_batch = FriOpeningBatch { 691 | values: [ 692 | commit0_pixels_and_pixel_eval.as_slice(), 693 | commit1_pixels_and_pixel_eval.as_slice(), 694 | commit2_pixels_and_pixel_eval.as_slice(), 695 | ].concat(), 696 | }; 697 | 698 | let fri_openings = FriOpenings { 699 | batches: vec![zeta_batch, zeta_next_batch, pixels_batch, pixel_range_batch, pixels_plus_pixel_range_batch], 700 | }; 701 | 702 | 703 | last = print_time_since(start, last, "finished evaluating non-a stuff"); 704 | 705 | return (fri_openings, merkle_caps.clone(), opening_proof, zeta, last); 706 | } 707 | 708 | fn prove_two(start: u128, old_last: u128, rate_bits: usize, cap_height: usize, fft_root_table: &FftRootTable, zeta: QuadraticExtension) -> 709 | (Vec>, Vec>::Hasher, D>>, Vec>) { 710 | let mut last = old_last; 711 | let mut all_a_fri_openings = Vec::new(); 712 | let mut all_a_opening_proofs = Vec::new(); 713 | 714 | let fri_config = get_fri_config(rate_bits, cap_height); 715 | 716 | 717 | let eval_commitment = |z: <>::F as Extendable>::Extension, c: &PolynomialBatch| { 718 | c.polynomials 719 | .par_iter() 720 | .map(|p| p.to_extension::().eval(z)) 721 | .collect::>() 722 | }; 723 | 724 | 725 | let mut a_all_zeta_evals = Vec::new(); 726 | // do row commitments and openings 727 | for batch in 0..HASH_LENGTH / BATCH_SIZE { 728 | let mut a_vals_vec = Vec::new(); 729 | 730 | for _ in 0..BATCH_SIZE { 731 | a_vals_vec.push(Vec::new()); 732 | } 733 | 734 | let mut x = 3091352403337663489; 735 | for _ in 0..PIXELS { 736 | for j in 0..HASH_LENGTH { 737 | x = (A_CONSTANT * x + C_CONSTANT) & 0xffffffffffffffff; 738 | let x1 = x >> 32; 739 | x = (A_CONSTANT * x + C_CONSTANT) & 0xffffffffffffffff; 740 | let x2 = ((x & 0xffffffff00000000) + x1) & 0xffffffffffffffff; 741 | let rand = F::from_canonical_u64(u64::try_from(x2).unwrap() % F::ORDER); 742 | 743 | if j / BATCH_SIZE == batch { 744 | a_vals_vec[j % BATCH_SIZE].push(rand); 745 | } 746 | } 747 | } 748 | 749 | let a_vals_length = a_vals_vec[0].len(); 750 | for _ in 0..DEGREE - a_vals_length { 751 | for i in 0..a_vals_vec.len() { 752 | a_vals_vec[i].push(F::ZERO); 753 | } 754 | } 755 | 756 | let mut polynomials_vec = Vec::new(); 757 | for i in 0..BATCH_SIZE { 758 | let a = PolynomialValues::new(a_vals_vec[i].clone()).ifft(); 759 | polynomials_vec.push(a); 760 | } 761 | 762 | last = print_time_since(start, last, "a finished interpolating"); 763 | 764 | let commit = PolynomialBatch::::from_coeffs( 765 | polynomials_vec, 766 | rate_bits, 767 | false, 768 | 4, 769 | &mut TimingTree::default(), 770 | Some(&fft_root_table), 771 | ); 772 | 773 | last = print_time_since(start, last, "a finished committing"); 774 | 775 | // A ROW OPENINGS 776 | let a_instance = generate_a_instance(zeta); 777 | 778 | let mut a_challenger = Challenger::>::Hasher>::new(); 779 | 780 | let degree_bits = log2_strict(DEGREE); 781 | 782 | let a_opening_proof = PolynomialBatch::::prove_openings( 783 | &a_instance, 784 | &[ 785 | &commit 786 | ], 787 | &mut a_challenger, 788 | &fri_config.fri_params(degree_bits, true), 789 | &mut TimingTree::default(), 790 | ); 791 | all_a_opening_proofs.push(a_opening_proof.clone()); 792 | 793 | last = print_time_since(start, last, "a openings commitment done"); 794 | 795 | let commit_zeta_eval = eval_commitment(zeta, &commit); 796 | a_all_zeta_evals = [a_all_zeta_evals, commit_zeta_eval.clone()].concat(); 797 | 798 | let a_zeta_batch = FriOpeningBatch { 799 | values: [ 800 | commit_zeta_eval.as_slice() 801 | ].concat(), 802 | }; 803 | 804 | let a_fri_openings = FriOpenings { 805 | batches: vec![a_zeta_batch], 806 | }; 807 | all_a_fri_openings.push(a_fri_openings); 808 | 809 | last = print_time_since(start, last, "a eval commitment done"); 810 | 811 | last = print_time_since(start, last, "verification a eval proof done"); 812 | } 813 | 814 | return (all_a_fri_openings, all_a_opening_proofs, a_all_zeta_evals); 815 | } 816 | 817 | fn get_instance(length_0 : usize, length_1 : usize, length_2 : usize, degree_bits : usize, zeta : QuadraticExtension) -> FriInstanceInfo { 818 | let g = <>::F as Extendable>::Extension::primitive_root_of_unity(degree_bits); 819 | let commit0_polys = FriPolynomialInfo::from_range( 820 | 0, 821 | 0..length_0, 822 | ); 823 | 824 | let commit1_polys = FriPolynomialInfo::from_range( 825 | 1, 826 | 0..length_1, 827 | ); 828 | 829 | let commit2_polys = FriPolynomialInfo::from_range( 830 | 2, 831 | 0..length_2, 832 | ); 833 | 834 | let all_polys = [commit0_polys, commit1_polys, commit2_polys].concat(); 835 | 836 | 837 | let zeta_batch = FriBatchInfo { 838 | point: zeta, 839 | polynomials: all_polys.clone(), 840 | }; 841 | 842 | // The Z polynomials are also opened at g * zeta. 843 | let zeta_next = g * zeta; 844 | let zeta_next_batch = FriBatchInfo { 845 | point: zeta_next, 846 | polynomials: all_polys.clone(), 847 | }; 848 | 849 | let pixels = g.exp_u64((PIXELS) as u64); 850 | let pixels_batch = FriBatchInfo { 851 | point: pixels, 852 | polynomials: all_polys.clone(), 853 | }; 854 | 855 | let pixel_range = g.exp_u64((PIXEL_RANGE) as u64); 856 | let pixel_range_batch = FriBatchInfo { 857 | point: pixel_range, 858 | polynomials: all_polys.clone(), 859 | }; 860 | 861 | let pixels_plus_pixel_range = g.exp_u64((PIXELS + PIXEL_RANGE as usize) as u64); 862 | let pixels_plus_pixel_range_batch = FriBatchInfo { 863 | point: pixels_plus_pixel_range, 864 | polynomials: all_polys, 865 | }; 866 | 867 | let openings = vec![zeta_batch, zeta_next_batch, pixels_batch, pixel_range_batch, pixels_plus_pixel_range_batch]; 868 | 869 | let fri_oracles = vec![ 870 | FriOracleInfo { 871 | num_polys: length_0, 872 | blinding: USE_ZK, 873 | }, 874 | FriOracleInfo { 875 | num_polys: length_1, 876 | blinding: USE_ZK, 877 | }, 878 | FriOracleInfo { 879 | num_polys: length_2, 880 | blinding: USE_ZK, 881 | } 882 | ]; 883 | 884 | return FriInstanceInfo { 885 | oracles: fri_oracles, 886 | batches: openings, 887 | }; 888 | } 889 | 890 | fn generate_a_instance(zeta: QuadraticExtension) -> FriInstanceInfo { 891 | let commit_polys = FriPolynomialInfo::from_range( 892 | 0, 893 | 0..BATCH_SIZE, 894 | ); 895 | 896 | let a_all_polys = [commit_polys].concat(); 897 | 898 | let zeta_a_batch: FriBatchInfo = FriBatchInfo { 899 | point: zeta, 900 | polynomials: a_all_polys.clone(), 901 | }; 902 | let a_openings = vec![zeta_a_batch]; 903 | 904 | let a_fri_oracles = vec![ 905 | FriOracleInfo { 906 | num_polys: BATCH_SIZE, 907 | blinding: false, 908 | } 909 | ]; 910 | 911 | return FriInstanceInfo { 912 | oracles: a_fri_oracles, 913 | batches: a_openings, 914 | }; 915 | } 916 | 917 | fn main() { 918 | // FRI commitment constants 919 | let rate_bits = 2; 920 | let cap_height = 4; 921 | let max_quotient_degree_factor = 4; 922 | let degree_bits = log2_strict(DEGREE); 923 | let omega = F::primitive_root_of_unity(degree_bits); 924 | 925 | let max_fft_points = 1 << (degree_bits + max(rate_bits, log2_ceil(max_quotient_degree_factor))); 926 | let fft_root_table = fft_root_table(max_fft_points); 927 | 928 | let start = SystemTime::now(); 929 | let start_epoch = start 930 | .duration_since(UNIX_EPOCH) 931 | .expect("Time went backwards"); 932 | let start = start_epoch.as_millis(); 933 | 934 | // PROVER 935 | let (fri_openings, merkle_caps, opening_proof, zeta, mut last) = prove_one(start, start, rate_bits, cap_height, omega, &fft_root_table); 936 | let (all_a_openings, all_a_proofs, a_all_zeta_evals) = prove_two(start, last, rate_bits, cap_height, &fft_root_table, zeta); 937 | 938 | last = print_time_since(start, last, "all prover work done"); 939 | 940 | // VERIFIER 941 | let mut challenger = Challenger::>::Hasher>::new(); 942 | 943 | challenger.observe_cap::<>::Hasher>(&merkle_caps[0]); 944 | challenger.observe_cap::<>::Hasher>(&merkle_caps[1]); 945 | challenger.observe_cap::<>::Hasher>(&merkle_caps[2]); 946 | 947 | for i in 0..HASH_LENGTH / BATCH_SIZE { 948 | let cap = read_a_merkle_caps(i); 949 | challenger.observe_cap::<>::Hasher>(&cap); 950 | } 951 | let zeta = challenger.get_extension_challenge::(); 952 | 953 | // Verify all opening proofs 954 | let fri_config = get_fri_config(rate_bits, cap_height); 955 | let instance = get_instance(3, 7, 2, degree_bits, zeta); 956 | let mut challenger = Challenger::>::Hasher>::new(); 957 | let fri_challenges = challenger.fri_challenges::( 958 | &opening_proof.commit_phase_merkle_caps, 959 | &opening_proof.final_poly, 960 | opening_proof.pow_witness, 961 | degree_bits, 962 | &fri_config, 963 | ); 964 | let res = verify_fri_proof::( 965 | &instance, 966 | &fri_openings, 967 | &fri_challenges, 968 | &merkle_caps, 969 | &opening_proof, 970 | &fri_config.fri_params(degree_bits, true), 971 | ); 972 | _ = res.unwrap(); 973 | for i in 0..all_a_openings.len() { 974 | let mut a_challenger = Challenger::>::Hasher>::new(); 975 | let a_fri_challenges = a_challenger.fri_challenges::( 976 | &all_a_proofs[i].commit_phase_merkle_caps, 977 | &all_a_proofs[i].final_poly, 978 | all_a_proofs[i].pow_witness, 979 | degree_bits, 980 | &fri_config, 981 | ); 982 | let a_instance = generate_a_instance(zeta); 983 | let cap = read_a_merkle_caps(i); 984 | let a_res = verify_fri_proof::( 985 | &a_instance, 986 | &all_a_openings[i], 987 | &a_fri_challenges, 988 | &[cap], 989 | &all_a_proofs[i], 990 | &fri_config.fri_params(degree_bits, true), 991 | ); 992 | _ = a_res.unwrap(); 993 | } 994 | 995 | // Check polynomial equalities 996 | let mut vals = Vec::new(); 997 | vals.push(F::ONE); 998 | for _ in 0..DEGREE - 1 { 999 | vals.push(F::ZERO); 1000 | } 1001 | vals.push(F::ZERO - F::ONE); 1002 | let vanishing_poly = PolynomialCoeffs::new(vals); 1003 | 1004 | let mut n_1_coeffs = Vec::new(); 1005 | n_1_coeffs.push(omega.exp_u64((DEGREE - 1) as u64)); 1006 | n_1_coeffs.push(F::ZERO - F::ONE); 1007 | 1008 | let n_1 = PolynomialCoeffs::from(n_1_coeffs); 1009 | 1010 | let vanishing_poly_zeta_eval = vanishing_poly.to_extension::().eval(zeta); 1011 | let n_1_zeta_eval = n_1.to_extension::().eval(zeta); 1012 | 1013 | let hash_coeffs = get_sha256_of_commitments(&merkle_caps[1], "", HASH_LENGTH); 1014 | let mut a_zeta_eval = QuadraticExtension::from(F::ZERO); 1015 | for i in 0..hash_coeffs.len() { 1016 | a_zeta_eval += QuadraticExtension::from(hash_coeffs[i]) * a_all_zeta_evals[i]; 1017 | } 1018 | 1019 | let gamma = get_sha256_of_commitments(&merkle_caps[0], "", 4)[0]; 1020 | let gamma_ext = QuadraticExtension::from(gamma); 1021 | 1022 | // Check (w_prod[omega*zeta] - w_prod[zeta](gamma + w[zeta])) * n_1[zeta] = q_w[zeta] * Z_H[zeta] 1023 | assert!((fri_openings.batches[1].values[3] - fri_openings.batches[0].values[3] * (gamma_ext + fri_openings.batches[0].values[0])) * n_1_zeta_eval == fri_openings.batches[0].values[4] * vanishing_poly_zeta_eval); 1024 | // Check (v_prod[omega*zeta] - v_prod[zeta](gamma + v[zeta])) * n_1[zeta] = q_v[zeta] * Z_H[zeta] 1025 | assert!((fri_openings.batches[1].values[5] - fri_openings.batches[0].values[5] * (gamma_ext + fri_openings.batches[0].values[1])) * n_1_zeta_eval == fri_openings.batches[0].values[6] * vanishing_poly_zeta_eval); 1026 | // Check (z_prod[omega*alpha] - z_prod[alpha](gamma + z[alpha])) * n_1[alpha] = q_z[alpha] * Z_H[alpha] 1027 | assert!((fri_openings.batches[1].values[7] - fri_openings.batches[0].values[7] * (gamma_ext + fri_openings.batches[0].values[2])) * n_1_zeta_eval == fri_openings.batches[0].values[8] * vanishing_poly_zeta_eval); 1028 | // Check v_prod[omega^D] * w_prod[omega^PIXEL_RANGE] = z_prod[omega^{D + PIXEL_RANGE}] 1029 | assert!(fri_openings.batches[2].values[5] * fri_openings.batches[3].values[3] == fri_openings.batches[4].values[7]); 1030 | 1031 | // Range Checks 1032 | // Check n_1[zeta] * (z[omega*zeta] - z[zeta]) (1 - z[omega*zeta] - z[zeta]) = q_range[zeta] * Z_H[zeta] 1033 | let dif = fri_openings.batches[1].values[2] - fri_openings.batches[0].values[2]; 1034 | assert!(n_1_zeta_eval * dif * (QuadraticExtension::from(F::ONE) - dif) == fri_openings.batches[0].values[9] * vanishing_poly_zeta_eval); 1035 | 1036 | // Hash Value Checks 1037 | // Check (h_sum[omega*zeta] - h_sum[zeta] - v[zeta] * a[zeta]) * n_1[zeta] = q_h_sum[zeta] * Z_H[zeta] 1038 | assert!((fri_openings.batches[1].values[10] - fri_openings.batches[0].values[10] - fri_openings.batches[0].values[1] * a_zeta_eval) * n_1_zeta_eval == fri_openings.batches[0].values[11] * vanishing_poly_zeta_eval); 1039 | 1040 | //let mem = proc_status::mem_usage().unwrap(); 1041 | //println!("Mem usage in bytes: current={}, peak={}", mem.current, mem.peak); 1042 | _ = print_time_since(start, last, "all verification done"); 1043 | 1044 | } --------------------------------------------------------------------------------