├── .gitignore ├── Cargo.lock ├── Cargo.toml └── src ├── fold.rs ├── iop.rs ├── lib.rs └── minroot.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /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 = "ahash" 7 | version = "0.7.6" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" 10 | dependencies = [ 11 | "getrandom", 12 | "once_cell", 13 | "version_check", 14 | ] 15 | 16 | [[package]] 17 | name = "ark-bn254" 18 | version = "0.3.0" 19 | source = "registry+https://github.com/rust-lang/crates.io-index" 20 | checksum = "ea691771ebbb28aea556c044e2e5c5227398d840cee0c34d4d20fa8eb2689e8c" 21 | dependencies = [ 22 | "ark-ec", 23 | "ark-ff", 24 | "ark-std", 25 | ] 26 | 27 | [[package]] 28 | name = "ark-ec" 29 | version = "0.3.0" 30 | source = "registry+https://github.com/rust-lang/crates.io-index" 31 | checksum = "dea978406c4b1ca13c2db2373b05cc55429c3575b8b21f1b9ee859aa5b03dd42" 32 | dependencies = [ 33 | "ark-ff", 34 | "ark-serialize", 35 | "ark-std", 36 | "derivative", 37 | "num-traits", 38 | "zeroize", 39 | ] 40 | 41 | [[package]] 42 | name = "ark-ff" 43 | version = "0.3.0" 44 | source = "registry+https://github.com/rust-lang/crates.io-index" 45 | checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" 46 | dependencies = [ 47 | "ark-ff-asm", 48 | "ark-ff-macros", 49 | "ark-serialize", 50 | "ark-std", 51 | "derivative", 52 | "num-bigint", 53 | "num-traits", 54 | "paste", 55 | "rustc_version", 56 | "zeroize", 57 | ] 58 | 59 | [[package]] 60 | name = "ark-ff-asm" 61 | version = "0.3.0" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" 64 | dependencies = [ 65 | "quote", 66 | "syn", 67 | ] 68 | 69 | [[package]] 70 | name = "ark-ff-macros" 71 | version = "0.3.0" 72 | source = "registry+https://github.com/rust-lang/crates.io-index" 73 | checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" 74 | dependencies = [ 75 | "num-bigint", 76 | "num-traits", 77 | "quote", 78 | "syn", 79 | ] 80 | 81 | [[package]] 82 | name = "ark-poly" 83 | version = "0.3.0" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | checksum = "7b0f78f47537c2f15706db7e98fe64cc1711dbf9def81218194e17239e53e5aa" 86 | dependencies = [ 87 | "ark-ff", 88 | "ark-serialize", 89 | "ark-std", 90 | "derivative", 91 | "hashbrown", 92 | ] 93 | 94 | [[package]] 95 | name = "ark-serialize" 96 | version = "0.3.0" 97 | source = "registry+https://github.com/rust-lang/crates.io-index" 98 | checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671" 99 | dependencies = [ 100 | "ark-serialize-derive", 101 | "ark-std", 102 | "digest", 103 | ] 104 | 105 | [[package]] 106 | name = "ark-serialize-derive" 107 | version = "0.3.0" 108 | source = "registry+https://github.com/rust-lang/crates.io-index" 109 | checksum = "8dd4e5f0bf8285d5ed538d27fab7411f3e297908fd93c62195de8bee3f199e82" 110 | dependencies = [ 111 | "proc-macro2", 112 | "quote", 113 | "syn", 114 | ] 115 | 116 | [[package]] 117 | name = "ark-std" 118 | version = "0.3.0" 119 | source = "registry+https://github.com/rust-lang/crates.io-index" 120 | checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" 121 | dependencies = [ 122 | "num-traits", 123 | "rand", 124 | ] 125 | 126 | [[package]] 127 | name = "autocfg" 128 | version = "1.1.0" 129 | source = "registry+https://github.com/rust-lang/crates.io-index" 130 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 131 | 132 | [[package]] 133 | name = "cfg-if" 134 | version = "1.0.0" 135 | source = "registry+https://github.com/rust-lang/crates.io-index" 136 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 137 | 138 | [[package]] 139 | name = "derivative" 140 | version = "2.2.0" 141 | source = "registry+https://github.com/rust-lang/crates.io-index" 142 | checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" 143 | dependencies = [ 144 | "proc-macro2", 145 | "quote", 146 | "syn", 147 | ] 148 | 149 | [[package]] 150 | name = "digest" 151 | version = "0.9.0" 152 | source = "registry+https://github.com/rust-lang/crates.io-index" 153 | checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" 154 | dependencies = [ 155 | "generic-array", 156 | ] 157 | 158 | [[package]] 159 | name = "fapam" 160 | version = "0.1.0" 161 | dependencies = [ 162 | "ark-bn254", 163 | "ark-ec", 164 | "ark-ff", 165 | "ark-poly", 166 | "ark-std", 167 | ] 168 | 169 | [[package]] 170 | name = "generic-array" 171 | version = "0.14.6" 172 | source = "registry+https://github.com/rust-lang/crates.io-index" 173 | checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" 174 | dependencies = [ 175 | "typenum", 176 | "version_check", 177 | ] 178 | 179 | [[package]] 180 | name = "getrandom" 181 | version = "0.2.8" 182 | source = "registry+https://github.com/rust-lang/crates.io-index" 183 | checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" 184 | dependencies = [ 185 | "cfg-if", 186 | "libc", 187 | "wasi", 188 | ] 189 | 190 | [[package]] 191 | name = "hashbrown" 192 | version = "0.11.2" 193 | source = "registry+https://github.com/rust-lang/crates.io-index" 194 | checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" 195 | dependencies = [ 196 | "ahash", 197 | ] 198 | 199 | [[package]] 200 | name = "libc" 201 | version = "0.2.139" 202 | source = "registry+https://github.com/rust-lang/crates.io-index" 203 | checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" 204 | 205 | [[package]] 206 | name = "num-bigint" 207 | version = "0.4.3" 208 | source = "registry+https://github.com/rust-lang/crates.io-index" 209 | checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" 210 | dependencies = [ 211 | "autocfg", 212 | "num-integer", 213 | "num-traits", 214 | ] 215 | 216 | [[package]] 217 | name = "num-integer" 218 | version = "0.1.45" 219 | source = "registry+https://github.com/rust-lang/crates.io-index" 220 | checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" 221 | dependencies = [ 222 | "autocfg", 223 | "num-traits", 224 | ] 225 | 226 | [[package]] 227 | name = "num-traits" 228 | version = "0.2.15" 229 | source = "registry+https://github.com/rust-lang/crates.io-index" 230 | checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" 231 | dependencies = [ 232 | "autocfg", 233 | ] 234 | 235 | [[package]] 236 | name = "once_cell" 237 | version = "1.17.1" 238 | source = "registry+https://github.com/rust-lang/crates.io-index" 239 | checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" 240 | 241 | [[package]] 242 | name = "paste" 243 | version = "1.0.11" 244 | source = "registry+https://github.com/rust-lang/crates.io-index" 245 | checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba" 246 | 247 | [[package]] 248 | name = "pest" 249 | version = "2.5.5" 250 | source = "registry+https://github.com/rust-lang/crates.io-index" 251 | checksum = "028accff104c4e513bad663bbcd2ad7cfd5304144404c31ed0a77ac103d00660" 252 | dependencies = [ 253 | "thiserror", 254 | "ucd-trie", 255 | ] 256 | 257 | [[package]] 258 | name = "ppv-lite86" 259 | version = "0.2.17" 260 | source = "registry+https://github.com/rust-lang/crates.io-index" 261 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 262 | 263 | [[package]] 264 | name = "proc-macro2" 265 | version = "1.0.51" 266 | source = "registry+https://github.com/rust-lang/crates.io-index" 267 | checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" 268 | dependencies = [ 269 | "unicode-ident", 270 | ] 271 | 272 | [[package]] 273 | name = "quote" 274 | version = "1.0.23" 275 | source = "registry+https://github.com/rust-lang/crates.io-index" 276 | checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" 277 | dependencies = [ 278 | "proc-macro2", 279 | ] 280 | 281 | [[package]] 282 | name = "rand" 283 | version = "0.8.5" 284 | source = "registry+https://github.com/rust-lang/crates.io-index" 285 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 286 | dependencies = [ 287 | "rand_chacha", 288 | "rand_core", 289 | ] 290 | 291 | [[package]] 292 | name = "rand_chacha" 293 | version = "0.3.1" 294 | source = "registry+https://github.com/rust-lang/crates.io-index" 295 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 296 | dependencies = [ 297 | "ppv-lite86", 298 | "rand_core", 299 | ] 300 | 301 | [[package]] 302 | name = "rand_core" 303 | version = "0.6.4" 304 | source = "registry+https://github.com/rust-lang/crates.io-index" 305 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 306 | 307 | [[package]] 308 | name = "rustc_version" 309 | version = "0.3.3" 310 | source = "registry+https://github.com/rust-lang/crates.io-index" 311 | checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" 312 | dependencies = [ 313 | "semver", 314 | ] 315 | 316 | [[package]] 317 | name = "semver" 318 | version = "0.11.0" 319 | source = "registry+https://github.com/rust-lang/crates.io-index" 320 | checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" 321 | dependencies = [ 322 | "semver-parser", 323 | ] 324 | 325 | [[package]] 326 | name = "semver-parser" 327 | version = "0.10.2" 328 | source = "registry+https://github.com/rust-lang/crates.io-index" 329 | checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" 330 | dependencies = [ 331 | "pest", 332 | ] 333 | 334 | [[package]] 335 | name = "syn" 336 | version = "1.0.109" 337 | source = "registry+https://github.com/rust-lang/crates.io-index" 338 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 339 | dependencies = [ 340 | "proc-macro2", 341 | "quote", 342 | "unicode-ident", 343 | ] 344 | 345 | [[package]] 346 | name = "synstructure" 347 | version = "0.12.6" 348 | source = "registry+https://github.com/rust-lang/crates.io-index" 349 | checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" 350 | dependencies = [ 351 | "proc-macro2", 352 | "quote", 353 | "syn", 354 | "unicode-xid", 355 | ] 356 | 357 | [[package]] 358 | name = "thiserror" 359 | version = "1.0.38" 360 | source = "registry+https://github.com/rust-lang/crates.io-index" 361 | checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" 362 | dependencies = [ 363 | "thiserror-impl", 364 | ] 365 | 366 | [[package]] 367 | name = "thiserror-impl" 368 | version = "1.0.38" 369 | source = "registry+https://github.com/rust-lang/crates.io-index" 370 | checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" 371 | dependencies = [ 372 | "proc-macro2", 373 | "quote", 374 | "syn", 375 | ] 376 | 377 | [[package]] 378 | name = "typenum" 379 | version = "1.16.0" 380 | source = "registry+https://github.com/rust-lang/crates.io-index" 381 | checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" 382 | 383 | [[package]] 384 | name = "ucd-trie" 385 | version = "0.1.5" 386 | source = "registry+https://github.com/rust-lang/crates.io-index" 387 | checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" 388 | 389 | [[package]] 390 | name = "unicode-ident" 391 | version = "1.0.6" 392 | source = "registry+https://github.com/rust-lang/crates.io-index" 393 | checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" 394 | 395 | [[package]] 396 | name = "unicode-xid" 397 | version = "0.2.4" 398 | source = "registry+https://github.com/rust-lang/crates.io-index" 399 | checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" 400 | 401 | [[package]] 402 | name = "version_check" 403 | version = "0.9.4" 404 | source = "registry+https://github.com/rust-lang/crates.io-index" 405 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 406 | 407 | [[package]] 408 | name = "wasi" 409 | version = "0.11.0+wasi-snapshot-preview1" 410 | source = "registry+https://github.com/rust-lang/crates.io-index" 411 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 412 | 413 | [[package]] 414 | name = "zeroize" 415 | version = "1.5.7" 416 | source = "registry+https://github.com/rust-lang/crates.io-index" 417 | checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" 418 | dependencies = [ 419 | "zeroize_derive", 420 | ] 421 | 422 | [[package]] 423 | name = "zeroize_derive" 424 | version = "1.3.3" 425 | source = "registry+https://github.com/rust-lang/crates.io-index" 426 | checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c" 427 | dependencies = [ 428 | "proc-macro2", 429 | "quote", 430 | "syn", 431 | "synstructure", 432 | ] 433 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fapam" 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 | [dependencies] 9 | ark-std = "0.3" 10 | ark-ff = "0.3" 11 | ark-ec = "0.3" 12 | ark-poly = "0.3" 13 | ark-bn254 = "0.3" 14 | 15 | [features] 16 | default = [ ] 17 | -------------------------------------------------------------------------------- /src/fold.rs: -------------------------------------------------------------------------------- 1 | use ark_ff::{Field, PrimeField}; 2 | 3 | use crate::minroot::MinRootParam; 4 | 5 | fn fold( 6 | witness_1: &[F], 7 | error_1: &[F], 8 | witness_2: &[F], 9 | error_2: &[F], 10 | ) -> (Vec, Vec) { 11 | // sanity checks on all the inputs 12 | let num_constraints = witness_1.len(); 13 | assert_eq!(num_constraints, error_1.len()); 14 | assert_eq!(num_constraints, error_2.len()); 15 | assert_eq!(num_constraints, witness_2.len()); 16 | for i in 0..num_constraints - 2 { 17 | assert_eq!( 18 | witness_1[i] + witness_1[i + 1] - witness_1[i + 2].pow(&[5]) + error_1[i], 19 | F::zero() 20 | ); 21 | assert_eq!( 22 | witness_2[i] + witness_2[i + 1] - witness_2[i + 2].pow(&[5]) + error_2[i], 23 | F::zero() 24 | ); 25 | } 26 | 27 | // for now we use a fixed randomizer for random linear combination 28 | let randomizer = F::from(2u64); 29 | // w3 = r * w1 + w2 30 | let mut witness_res = vec![]; 31 | // e2 = delta + r * e1 + e2 + (r^5-r) w_13^5 32 | let mut error_res = vec![]; 33 | 34 | for i in 0..num_constraints { 35 | witness_res.push(randomizer * witness_1[i] + witness_2[i]); 36 | } 37 | for i in 0..num_constraints - 2 { 38 | // compute the actual data for the rest rows 39 | let delta = compute_delta_new(&witness_1[i + 2], &witness_2[i + 2], &randomizer); 40 | error_res.push( 41 | randomizer * error_1[i] 42 | + error_2[i] 43 | + delta 44 | + (randomizer.pow(&[5]) - randomizer) * witness_1[i + 2].pow(&[5u64]), 45 | ); 46 | } 47 | // pad the last two rows; the errors here are not used 48 | error_res.push(F::zero()); 49 | error_res.push(F::zero()); 50 | 51 | (witness_res, error_res) 52 | } 53 | 54 | // TODO: improve this code 55 | #[inline] 56 | fn compute_delta(w1: &F, w2: &F) -> F { 57 | let five = F::from(5u64); 58 | let ten = F::from(10u64); 59 | 60 | five * w1.pow(&[4]) * w2 61 | + ten * w1.pow(&[3]) * w2.pow(&[2]) 62 | + ten * w1.pow(&[2]) * w2.pow(&[3]) 63 | + five * w1 * w2.pow(&[4]) 64 | } 65 | 66 | // TODO: improve this code 67 | fn compute_delta_new(w1: &F, w2: &F, r: &F) -> F { 68 | let five = F::from(5u64); 69 | let ten = F::from(10u64); 70 | let w1 = *r * *w1; 71 | five * w1.pow(&[4]) * w2 72 | + ten * w1.pow(&[3]) * w2.pow(&[2]) 73 | + ten * w1.pow(&[2]) * w2.pow(&[3]) 74 | + five * w1 * w2.pow(&[4]) 75 | } 76 | 77 | #[cfg(test)] 78 | mod test { 79 | use crate::minroot::MinRootHasher; 80 | 81 | use super::*; 82 | use ark_bn254::Fr; 83 | use ark_ff::{UniformRand, Zero}; 84 | use ark_poly::{Polynomial, Radix2EvaluationDomain}; 85 | use ark_std::{rand::RngCore, test_rng}; 86 | #[test] 87 | fn test_fold() { 88 | let mut rng = test_rng(); 89 | for _ in 0..10 { 90 | let iter = rng.next_u32() as usize % 100 + 10; 91 | // let iter = 10; 92 | let x1 = Fr::rand(&mut rng); 93 | let y1 = Fr::rand(&mut rng); 94 | let x2 = Fr::rand(&mut rng); 95 | let y2 = Fr::rand(&mut rng); 96 | let x3 = Fr::rand(&mut rng); 97 | let y3 = Fr::rand(&mut rng); 98 | let x4 = Fr::rand(&mut rng); 99 | let y4 = Fr::rand(&mut rng); 100 | 101 | let mut hasher1 = MinRootHasher::::new(); 102 | let mut hasher2 = MinRootHasher::::new(); 103 | let mut hasher3 = MinRootHasher::::new(); 104 | let mut hasher4 = MinRootHasher::::new(); 105 | let _res = hasher1.hash(&x1, &y1, iter as usize); 106 | let _res = hasher2.hash(&x2, &y2, iter as usize); 107 | let _res = hasher3.hash(&x3, &y3, iter as usize); 108 | let _res = hasher4.hash(&x4, &y4, iter as usize); 109 | let (x12, e12) = fold( 110 | &hasher1.vec_x[..iter], 111 | &hasher1.vec_indexer[..iter], 112 | &hasher2.vec_x[..iter], 113 | &hasher2.vec_indexer[..iter], 114 | ); 115 | assert!(MinRootHasher::::check(&x12, &e12)); 116 | let (x34, e34) = fold( 117 | &hasher1.vec_x[..iter], 118 | &hasher1.vec_indexer[..iter], 119 | &hasher2.vec_x[..iter], 120 | &hasher2.vec_indexer[..iter], 121 | ); 122 | assert!(MinRootHasher::::check(&x34, &e34)); 123 | let (x1234, e1234) = fold(&x12, &e12, &x34, &e34); 124 | assert!(MinRootHasher::::check(&x1234, &e1234)); 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/iop.rs: -------------------------------------------------------------------------------- 1 | //! IOP component for MinRoot relation. 2 | //! Given a list of vectors $X := x0, \dots, x_N$, generate an IOP that 3 | //! X satisfies the MinRoot relation: 4 | //! x_i + x_{i+1} - x_{i+2}^\alpha + i + 1 = 0 5 | 6 | use ark_poly::{ 7 | univariate::DensePolynomial, EvaluationDomain, GeneralEvaluationDomain, Polynomial, 8 | Radix2EvaluationDomain, UVPolynomial, 9 | }; 10 | 11 | use crate::minroot::MinRootParam; 12 | 13 | /// Input a MinRoot sequence of length $l$; output a polynomial $h[x]$ where 14 | /// $h[omega^i] = 0$ for $0 <= i < l$ 15 | fn compute_polynomial_h(x_i: &[F]) -> DensePolynomial { 16 | let num_constraints = x_i.len(); 17 | assert!(num_constraints > 2); 18 | let domain_size = num_constraints + 2; 19 | let domain = Radix2EvaluationDomain::::new(domain_size).unwrap(); 20 | let coset_domain = GeneralEvaluationDomain::::new(domain.size() * 5).unwrap(); 21 | 22 | println!( 23 | "number of constraits: {}\n\ 24 | domain size: {}\n\ 25 | coset domain size: {}", 26 | num_constraints, 27 | domain.size(), 28 | coset_domain.size() 29 | ); 30 | 31 | let first = x_i[0]; 32 | let second = x_i[1]; 33 | 34 | let mut x_i = x_i.to_vec(); 35 | x_i.insert(0, F::zero()); 36 | x_i.insert(0, F::zero()); 37 | 38 | // w[X] 39 | let witness_poly = domain.ifft(&x_i[..num_constraints]); 40 | // w[omega X] 41 | let witness_rotated = domain.ifft(&x_i[1..num_constraints + 1]); 42 | // w[omega^2 X] 43 | let witness_rotated_twice = domain.ifft(&x_i[2..num_constraints + 2]); 44 | 45 | // q(x) 46 | // q(x) = ifft(1, 2, 3, 4...) 47 | let mut q_i = (1..num_constraints - 1) 48 | .map(|i| F::from(i as u64)) 49 | .collect::>(); 50 | // front-pad the first two elements of q(x) with 51 | // x[0]^5 and x[1]^5 - x[0] 52 | // to ensure the first two rows are also 0 53 | q_i.insert(0, second.pow(&[5]) - first); 54 | q_i.insert(0, first.pow(&[5])); 55 | let selector_poly = domain.ifft(&q_i); 56 | 57 | // h(x) = w(x) + w(omega x) - w(omega^2 x)^alpha + q(x) 58 | let (h, t) = { 59 | let mut h_evals = vec![]; 60 | let mut t_evals = vec![]; 61 | 62 | let witness_poly_coset = coset_domain.coset_fft(&witness_poly); 63 | let witness_poly_rotated_coset = coset_domain.coset_fft(&witness_rotated); 64 | let witness_poly_rotated_twice_coset = coset_domain.coset_fft(&witness_rotated_twice); 65 | let selector_poly_coset = coset_domain.coset_fft(&selector_poly); 66 | let vanish_poly: DensePolynomial = domain.vanishing_polynomial().into(); 67 | let vanish_poly_coset = coset_domain.coset_fft(&vanish_poly); 68 | 69 | for i in 0..coset_domain.size() { 70 | let h_i = witness_poly_coset[i] + witness_poly_rotated_coset[i] 71 | - witness_poly_rotated_twice_coset[i].pow(&[F::ALPHA]) 72 | + selector_poly_coset[i]; 73 | let t_i = h_i / vanish_poly_coset[i]; 74 | 75 | h_evals.push(h_i); 76 | t_evals.push(t_i); 77 | } 78 | ( 79 | coset_domain.coset_ifft(&h_evals), 80 | coset_domain.coset_ifft(&t_evals), 81 | ) 82 | }; 83 | 84 | // low degree testing for t: t's degree must be less than 4n 85 | let t = DensePolynomial::from_coefficients_vec(t); 86 | assert!(t.degree() < domain.size() * 4); 87 | // for (i,e) in t.iter().enumerate() { 88 | // println!("t_{} {}", i, e); 89 | // } 90 | // println!("{}", t.degree()); 91 | // println!(); 92 | // for (i,e) in h.iter().enumerate() { 93 | // println!("h_{} {}", i, e); 94 | // } 95 | 96 | DensePolynomial::from_coefficients_vec(h) 97 | } 98 | 99 | #[cfg(test)] 100 | mod test { 101 | use crate::minroot::MinRootHasher; 102 | 103 | use super::*; 104 | use ark_bn254::Fr; 105 | use ark_ff::{UniformRand, Zero}; 106 | use ark_poly::Polynomial; 107 | use ark_std::{rand::RngCore, test_rng}; 108 | #[test] 109 | fn test_polynomial_h() { 110 | let mut rng = test_rng(); 111 | for _ in 0..10 { 112 | let iter = rng.next_u32() % 100 + 10; 113 | // let iter = 10; 114 | let x = Fr::rand(&mut rng); 115 | let y = Fr::rand(&mut rng); 116 | 117 | let mut hasher = MinRootHasher::::new(); 118 | let _res = hasher.hash(&x, &y, iter as usize); 119 | 120 | let domain_size = iter + 2; 121 | let domain = Radix2EvaluationDomain::::new(domain_size as usize).unwrap(); 122 | 123 | let h = compute_polynomial_h(&hasher.vec_x); 124 | for i in 0..domain.size() { 125 | println!("h_{} {}", i, h.evaluate(&domain.element(i as usize))); 126 | assert_eq!(h.evaluate(&domain.element(i as usize)), Fr::zero()) 127 | } 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Reference implementation of FapAm: Fold a plonk for MinRoot 2 | #![allow(dead_code)] 3 | 4 | mod fold; 5 | mod iop; 6 | mod minroot; 7 | -------------------------------------------------------------------------------- /src/minroot.rs: -------------------------------------------------------------------------------- 1 | //! Implementation of MinRoot hash 2 | //! 3 | 4 | use std::marker::PhantomData; 5 | 6 | use ark_ff::{BigInteger256, PrimeField}; 7 | 8 | pub trait MinRootParam: PrimeField { 9 | const ALPHA: u64; 10 | // 1/alpha mod p-1 11 | const ALPHA_INV: ::BigInt; 12 | } 13 | 14 | #[derive(Clone, Debug)] 15 | pub struct MinRootHasher { 16 | pub(crate) vec_x: Vec, 17 | pub(crate) vec_y: Vec, 18 | pub(crate) vec_indexer: Vec, 19 | _phantom: PhantomData, 20 | } 21 | 22 | impl MinRootHasher { 23 | pub fn new() -> Self { 24 | Self { 25 | _phantom: PhantomData, 26 | vec_x: vec![], 27 | vec_y: vec![], 28 | vec_indexer: vec![], 29 | } 30 | } 31 | 32 | fn iterate_once(&mut self, cur_x: &F, cur_y: &F, indexer: usize) -> (F, F) { 33 | let indexer = F::from(indexer as u64); 34 | let next_x = (*cur_x + *cur_y).pow(F::ALPHA_INV); 35 | let next_y = *cur_x + indexer; 36 | 37 | self.vec_x.push(next_x); 38 | self.vec_y.push(next_y); 39 | self.vec_indexer.push(indexer); 40 | 41 | (next_x, next_y) 42 | } 43 | 44 | pub fn hash(&mut self, x0: &F, y0: &F, iteration: usize) -> (F, F) { 45 | let mut cur_x = *x0; 46 | let mut cur_y = *y0; 47 | 48 | self.vec_x.push(cur_x); 49 | self.vec_y.push(cur_y); 50 | 51 | for indexer in 1..=iteration { 52 | (cur_x, cur_y) = self.iterate_once(&cur_x, &cur_y, indexer) 53 | } 54 | self.vec_indexer.push(F::zero()); 55 | (cur_x, cur_y) 56 | } 57 | 58 | pub fn display(&self) { 59 | for (i, (indexer, (x, y))) in self 60 | .vec_indexer 61 | .iter() 62 | .zip(self.vec_x.iter().zip(self.vec_y.iter())) 63 | .enumerate() 64 | { 65 | println!("{}-th iter: indexer {}; x {}; y {}", i, indexer, x, y) 66 | } 67 | } 68 | 69 | pub(crate) fn check(witnesses: &[F], errors: &[F]) -> bool { 70 | let len = witnesses.len() - 2; 71 | if errors.len() - 2 != len { 72 | println!("lens do not match"); 73 | return false; 74 | } 75 | for i in 0..len { 76 | if witnesses[i] + witnesses[i + 1] - witnesses[i + 2].pow(&[5]) + errors[i] != F::zero() 77 | { 78 | println!("equation not satisfied"); 79 | return false; 80 | } 81 | } 82 | return true; 83 | } 84 | } 85 | 86 | impl MinRootParam for ark_bn254::Fr { 87 | const ALPHA: u64 = 5; 88 | // 1/alpha mod p-1 89 | const ALPHA_INV: ::BigInt = BigInteger256([ 90 | 0xcfe7f7a98ccccccd, 91 | 0x535cb9d394945a0d, 92 | 0x93736af8679aad17, 93 | 0x26b6a528b427b354, 94 | ]); 95 | } 96 | 97 | #[cfg(test)] 98 | mod test { 99 | use super::*; 100 | use ark_bn254::Fr; 101 | use ark_ff::{Field, UniformRand}; 102 | use ark_std::test_rng; 103 | 104 | #[test] 105 | fn test_alpha_inv() { 106 | let mut rng = test_rng(); 107 | for _ in 0..10 { 108 | let tmp = Fr::rand(&mut rng); 109 | assert_eq!(tmp.pow(&[Fr::ALPHA]).pow(Fr::ALPHA_INV), tmp); 110 | } 111 | } 112 | 113 | #[test] 114 | fn test_min_root_hash() { 115 | let x = Fr::from(1); 116 | let y = Fr::from(2); 117 | 118 | let mut hasher = MinRootHasher::::new(); 119 | let _res = hasher.hash(&x, &y, 10); 120 | assert!(MinRootHasher::::check( 121 | &hasher.vec_x, 122 | &hasher.vec_indexer 123 | )); 124 | hasher.display() 125 | } 126 | } 127 | --------------------------------------------------------------------------------