├── .github └── workflows │ └── quality.yaml ├── .gitignore ├── Cargo.toml ├── README.md └── src ├── lib.rs └── verifier ├── mod.rs └── near └── mod.rs /.github/workflows/quality.yaml: -------------------------------------------------------------------------------- 1 | name: Electron-rs quality checks 2 | on: [pull_request, create] 3 | 4 | jobs: 5 | build: 6 | if: github.event_name == 'pull_request' 7 | name: Quality (clippy, rustfmt) 8 | runs-on: ubuntu-latest 9 | strategy: 10 | matrix: 11 | rust: 12 | - nightly 13 | - stable 14 | target: 15 | - x86_64-unknown-linux-gnu 16 | steps: 17 | - name: Code checkout 18 | uses: actions/checkout@v2 19 | - name: Install Rust toolchain (${{ matrix.rust }}) 20 | uses: actions-rs/toolchain@v1 21 | with: 22 | toolchain: ${{ matrix.rust }} 23 | target: ${{ matrix.target }} 24 | override: true 25 | components: rustfmt, clippy 26 | 27 | - name: Formatting (rustfmt) 28 | run: cargo fmt -- --check 29 | 30 | - name: Clippy (all features) 31 | run: cargo clippy --all-targets --all-features -- -D warnings 32 | 33 | - name: Run cargo unit tests 34 | run: cargo test 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | /Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | 12 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "electron-rs" 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 | borsh = { version = "0.9.3", features = ["const-generics"] } 10 | ark-bn254 = { version = "0.3.0", default-features = false, features = ["curve"] } 11 | ark-groth16 = { git = "https://github.com/arkworks-rs/groth16", rev = "765817f", default-features = false } 12 | ark-ff = "0.3.0" 13 | ark-ec = "0.3.0" 14 | near-sdk = "4.0.0" 15 | serde-json-wasm = { version = "0.4.0" } 16 | anyhow = "1.0" 17 | thiserror = "1.0" 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # electron.rs 2 | SDK for Zero Knowledge Proof Verification on Rust based chains 3 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2022, Electron Labs 2 | 3 | pub mod verifier; 4 | -------------------------------------------------------------------------------- /src/verifier/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2022, Electron Labs 2 | 3 | pub mod near; 4 | -------------------------------------------------------------------------------- /src/verifier/near/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2022, Electron Labs 2 | 3 | use anyhow::Result; 4 | use borsh::{BorshDeserialize, BorshSerialize}; 5 | use near_sdk::serde::Deserialize; 6 | use serde_json_wasm; 7 | use std::str::FromStr; 8 | use thiserror::Error; 9 | 10 | #[derive(Error, Debug)] 11 | pub enum VerifierError { 12 | #[error("Failed to parse circom {0} json")] 13 | ParseError(String), 14 | } 15 | 16 | #[derive(BorshSerialize, BorshDeserialize, Debug, PartialEq, Clone)] 17 | struct BigInteger256 { 18 | val: [u64; 4], 19 | } 20 | 21 | impl BigInteger256 { 22 | pub fn new(src: [u64; 4]) -> Self { 23 | BigInteger256 { val: src } 24 | } 25 | } 26 | 27 | impl From for ark_ff::BigInteger256 { 28 | fn from(src: BigInteger256) -> ark_ff::BigInteger256 { 29 | ark_ff::BigInteger256::new(src.val) 30 | } 31 | } 32 | 33 | impl From for BigInteger256 { 34 | fn from(src: ark_ff::BigInteger256) -> BigInteger256 { 35 | BigInteger256::new(src.0) 36 | } 37 | } 38 | 39 | #[derive(BorshSerialize, BorshDeserialize, Debug, Clone)] 40 | struct Fr { 41 | c0: BigInteger256, 42 | } 43 | 44 | impl Fr { 45 | pub fn new(src: BigInteger256) -> Self { 46 | Fr { c0: src } 47 | } 48 | } 49 | 50 | impl From for ark_bn254::Fr { 51 | fn from(src: Fr) -> ark_bn254::Fr { 52 | ark_bn254::Fr::new(src.c0.into()) 53 | } 54 | } 55 | 56 | impl From for Fr { 57 | fn from(src: ark_bn254::Fr) -> Fr { 58 | Fr::new(src.0.into()) 59 | } 60 | } 61 | 62 | #[derive(BorshSerialize, BorshDeserialize, Debug, PartialEq, Clone)] 63 | struct Fq { 64 | c0: BigInteger256, 65 | } 66 | 67 | impl Fq { 68 | pub fn new(src: BigInteger256) -> Self { 69 | Fq { c0: src } 70 | } 71 | } 72 | 73 | impl From for ark_bn254::Fq { 74 | fn from(src: Fq) -> ark_bn254::Fq { 75 | ark_bn254::Fq::new(src.c0.into()) 76 | } 77 | } 78 | 79 | impl From for Fq { 80 | fn from(src: ark_bn254::Fq) -> Fq { 81 | Fq::new(src.0.into()) 82 | } 83 | } 84 | 85 | #[derive(BorshSerialize, BorshDeserialize, Debug, PartialEq, Clone)] 86 | struct Fq2 { 87 | c0: BigInteger256, 88 | c1: BigInteger256, 89 | } 90 | 91 | impl Fq2 { 92 | pub fn new(c0_: BigInteger256, c1_: BigInteger256) -> Self { 93 | Fq2 { c0: c0_, c1: c1_ } 94 | } 95 | } 96 | 97 | impl From for ark_bn254::Fq2 { 98 | fn from(src: Fq2) -> ark_bn254::Fq2 { 99 | let c0: ark_ff::BigInteger256 = src.c0.into(); 100 | let c1: ark_ff::BigInteger256 = src.c1.into(); 101 | ark_bn254::Fq2::new(ark_ff::Fp256::new(c0), ark_ff::Fp256::new(c1)) 102 | } 103 | } 104 | 105 | impl From for Fq2 { 106 | fn from(src: ark_bn254::Fq2) -> Fq2 { 107 | Fq2::new(src.c0.0.into(), src.c1.0.into()) 108 | } 109 | } 110 | 111 | #[derive(BorshSerialize, BorshDeserialize, Debug, PartialEq, Clone)] 112 | struct Fq6 { 113 | c0: Fq2, 114 | c1: Fq2, 115 | c2: Fq2, 116 | } 117 | 118 | impl Fq6 { 119 | pub fn new(c0_: Fq2, c1_: Fq2, c2_: Fq2) -> Self { 120 | Fq6 { 121 | c0: c0_, 122 | c1: c1_, 123 | c2: c2_, 124 | } 125 | } 126 | } 127 | 128 | impl From for ark_bn254::Fq6 { 129 | fn from(src: Fq6) -> ark_bn254::Fq6 { 130 | let c0: ark_bn254::Fq2 = src.c0.into(); 131 | let c1: ark_bn254::Fq2 = src.c1.into(); 132 | let c2: ark_bn254::Fq2 = src.c2.into(); 133 | ark_bn254::Fq6::new(c0, c1, c2) 134 | } 135 | } 136 | 137 | impl From for Fq6 { 138 | fn from(src: ark_bn254::Fq6) -> Fq6 { 139 | let c0: ark_bn254::Fq2 = src.c0; 140 | let c1: ark_bn254::Fq2 = src.c1; 141 | let c2: ark_bn254::Fq2 = src.c2; 142 | Fq6::new(c0.into(), c1.into(), c2.into()) 143 | } 144 | } 145 | 146 | #[derive(BorshSerialize, BorshDeserialize, Debug, PartialEq, Clone)] 147 | struct Fq12 { 148 | c0: Fq6, 149 | c1: Fq6, 150 | } 151 | 152 | impl Fq12 { 153 | pub fn new(c0_: Fq6, c1_: Fq6) -> Self { 154 | Fq12 { c0: c0_, c1: c1_ } 155 | } 156 | } 157 | 158 | impl From for ark_bn254::Fq12 { 159 | fn from(src: Fq12) -> ark_bn254::Fq12 { 160 | let c0: ark_bn254::Fq6 = src.c0.into(); 161 | let c1: ark_bn254::Fq6 = src.c1.into(); 162 | ark_bn254::Fq12::new(c0, c1) 163 | } 164 | } 165 | 166 | impl From for Fq12 { 167 | fn from(src: ark_bn254::Fq12) -> Fq12 { 168 | let c0: ark_bn254::Fq6 = src.c0; 169 | let c1: ark_bn254::Fq6 = src.c1; 170 | Fq12::new(c0.into(), c1.into()) 171 | } 172 | } 173 | 174 | #[derive(BorshSerialize, BorshDeserialize, Debug, PartialEq, Clone)] 175 | struct G1Affine { 176 | x: BigInteger256, 177 | y: BigInteger256, 178 | infinity: bool, 179 | } 180 | 181 | impl G1Affine { 182 | pub fn new(x_: BigInteger256, y_: BigInteger256, infinity_: bool) -> Self { 183 | G1Affine { 184 | x: x_, 185 | y: y_, 186 | infinity: infinity_, 187 | } 188 | } 189 | } 190 | 191 | impl From for ark_bn254::G1Affine { 192 | fn from(src: G1Affine) -> ark_bn254::G1Affine { 193 | let x: ark_ff::BigInteger256 = src.x.into(); 194 | let y: ark_ff::BigInteger256 = src.y.into(); 195 | ark_bn254::G1Affine::new(ark_ff::Fp256::new(x), ark_ff::Fp256::new(y), src.infinity) 196 | } 197 | } 198 | 199 | impl From for G1Affine { 200 | fn from(src: ark_bn254::G1Affine) -> G1Affine { 201 | let x: ark_ff::BigInteger256 = src.x.0; 202 | let y: ark_ff::BigInteger256 = src.y.0; 203 | G1Affine::new(x.into(), y.into(), src.infinity) 204 | } 205 | } 206 | 207 | #[derive(BorshSerialize, BorshDeserialize, Debug, PartialEq, Clone)] 208 | struct G2Affine { 209 | x: Fq2, 210 | y: Fq2, 211 | infinity: bool, 212 | } 213 | 214 | impl G2Affine { 215 | pub fn new(x_: Fq2, y_: Fq2, infinity_: bool) -> Self { 216 | G2Affine { 217 | x: x_, 218 | y: y_, 219 | infinity: infinity_, 220 | } 221 | } 222 | } 223 | 224 | impl From for G2Affine { 225 | fn from(src: ark_bn254::G2Affine) -> G2Affine { 226 | let x: ark_bn254::Fq2 = src.x; 227 | let y: ark_bn254::Fq2 = src.y; 228 | G2Affine::new(x.into(), y.into(), src.infinity) 229 | } 230 | } 231 | 232 | impl From for ark_bn254::G2Affine { 233 | fn from(src: G2Affine) -> ark_bn254::G2Affine { 234 | let x: ark_bn254::Fq2 = src.x.into(); 235 | let y: ark_bn254::Fq2 = src.y.into(); 236 | ark_bn254::G2Affine::new(x, y, src.infinity) 237 | } 238 | } 239 | 240 | #[derive(BorshSerialize, BorshDeserialize, Debug, PartialEq, Clone)] 241 | struct G2Prepared { 242 | ell_coeffs: Vec<(Fq2, Fq2, Fq2)>, 243 | infinity: bool, 244 | } 245 | 246 | impl G2Prepared { 247 | pub fn new(ell_coeffs_: Vec<(Fq2, Fq2, Fq2)>, inf: bool) -> Self { 248 | G2Prepared { 249 | ell_coeffs: ell_coeffs_, 250 | infinity: inf, 251 | } 252 | } 253 | } 254 | 255 | impl From> for G2Prepared { 256 | fn from(src: ark_ec::bn::G2Prepared) -> G2Prepared { 257 | let ark_ell_coeffs = src 258 | .ell_coeffs 259 | .into_iter() 260 | .map(|elem| (elem.0, elem.1, elem.2)); 261 | let ell_coeffs: Vec<(Fq2, Fq2, Fq2)> = ark_ell_coeffs 262 | .map(|elem| (elem.0.into(), elem.1.into(), elem.2.into())) 263 | .collect(); 264 | G2Prepared::new(ell_coeffs, src.infinity) 265 | } 266 | } 267 | 268 | impl From for ark_ec::bn::G2Prepared { 269 | fn from(src: G2Prepared) -> ark_ec::bn::G2Prepared { 270 | let ark_ell_coeffs = src 271 | .ell_coeffs 272 | .into_iter() 273 | .map(|elem| (elem.0.into(), elem.1.into(), elem.2.into())); 274 | ark_ec::bn::G2Prepared { 275 | ell_coeffs: ark_ell_coeffs 276 | .map(|elem| (elem.0, elem.1, elem.2)) 277 | .collect(), 278 | infinity: src.infinity, 279 | } 280 | } 281 | } 282 | 283 | #[derive(BorshSerialize, BorshDeserialize, Debug, PartialEq, Clone)] 284 | struct VerifyingKey { 285 | alpha_g1: G1Affine, 286 | beta_g2: G2Affine, 287 | gamma_g2: G2Affine, 288 | delta_g2: G2Affine, 289 | gamma_abc_g1: Vec, 290 | } 291 | 292 | impl From for ark_groth16::VerifyingKey { 293 | fn from(src: VerifyingKey) -> ark_groth16::VerifyingKey { 294 | ark_groth16::VerifyingKey { 295 | alpha_g1: src.alpha_g1.into(), 296 | beta_g2: src.beta_g2.into(), 297 | gamma_g2: src.gamma_g2.into(), 298 | delta_g2: src.delta_g2.into(), 299 | gamma_abc_g1: src 300 | .gamma_abc_g1 301 | .into_iter() 302 | .map(|elem| elem.into()) 303 | .collect(), 304 | } 305 | } 306 | } 307 | 308 | impl From> for VerifyingKey { 309 | fn from(src: ark_groth16::VerifyingKey) -> VerifyingKey { 310 | VerifyingKey { 311 | alpha_g1: src.alpha_g1.into(), 312 | beta_g2: src.beta_g2.into(), 313 | gamma_g2: src.gamma_g2.into(), 314 | delta_g2: src.delta_g2.into(), 315 | gamma_abc_g1: src 316 | .gamma_abc_g1 317 | .into_iter() 318 | .map(|elem| elem.into()) 319 | .collect(), 320 | } 321 | } 322 | } 323 | 324 | #[derive(BorshSerialize, BorshDeserialize, Debug, PartialEq, Clone)] 325 | pub struct PreparedVerifyingKey { 326 | vk: VerifyingKey, 327 | alpha_g1_beta_g2: Fq12, 328 | gamma_g2_neg_pc: G2Prepared, 329 | delta_g2_neg_pc: G2Prepared, 330 | } 331 | 332 | impl From for ark_groth16::PreparedVerifyingKey { 333 | fn from(src: PreparedVerifyingKey) -> ark_groth16::PreparedVerifyingKey { 334 | ark_groth16::PreparedVerifyingKey { 335 | vk: src.vk.into(), 336 | alpha_g1_beta_g2: src.alpha_g1_beta_g2.into(), 337 | gamma_g2_neg_pc: src.gamma_g2_neg_pc.into(), 338 | delta_g2_neg_pc: src.delta_g2_neg_pc.into(), 339 | } 340 | } 341 | } 342 | 343 | impl From> for PreparedVerifyingKey { 344 | fn from(src: ark_groth16::PreparedVerifyingKey) -> PreparedVerifyingKey { 345 | PreparedVerifyingKey { 346 | vk: src.vk.into(), 347 | alpha_g1_beta_g2: src.alpha_g1_beta_g2.into(), 348 | gamma_g2_neg_pc: src.gamma_g2_neg_pc.into(), 349 | delta_g2_neg_pc: src.delta_g2_neg_pc.into(), 350 | } 351 | } 352 | } 353 | 354 | #[allow(dead_code)] 355 | #[derive(Deserialize, Clone)] 356 | #[serde(crate = "near_sdk::serde")] 357 | pub struct VerificationKeyJson { 358 | protocol: String, 359 | curve: String, 360 | #[serde(rename = "nPublic")] 361 | num_public: u64, 362 | vk_alpha_1: Vec, 363 | vk_beta_2: Vec>, 364 | vk_gamma_2: Vec>, 365 | vk_delta_2: Vec>, 366 | vk_alphabeta_12: Vec>>, 367 | #[serde(rename = "IC")] 368 | ic: Vec>, 369 | } 370 | 371 | #[allow(dead_code)] 372 | #[derive(Debug, Deserialize)] 373 | #[serde(crate = "near_sdk::serde")] 374 | pub struct CircomProofJson { 375 | pi_a: Vec, 376 | pi_b: Vec>, 377 | pi_c: Vec, 378 | protocol: String, 379 | #[serde(default = "String::new")] 380 | curve: String, 381 | } 382 | 383 | impl From for ark_groth16::Proof { 384 | fn from(src: CircomProofJson) -> Self { 385 | ark_groth16::Proof { 386 | a: g1_from_str(&src.pi_a), 387 | b: g2_from_str(&src.pi_b), 388 | c: g1_from_str(&src.pi_c), 389 | } 390 | } 391 | } 392 | 393 | fn parse_circom_proof(proof: String) -> Result { 394 | let proof = serde_json_wasm::from_str(&proof) 395 | .map_err(|_| VerifierError::ParseError("proof".to_string()))?; 396 | Ok(proof) 397 | } 398 | 399 | fn parse_public_inputs(inputs: String) -> Result> { 400 | let pub_inputs: Vec = serde_json_wasm::from_str(&inputs) 401 | .map_err(|_| VerifierError::ParseError("public inputs".to_string()))?; 402 | Ok(pub_inputs) 403 | } 404 | 405 | /// A helper function to parse raw verification key json returned by circom. 406 | /// 407 | /// # Errors 408 | /// VerifierError::VkeyParseError 409 | /// 410 | /// This function will return an error if it fails to parse the verification 411 | /// key json file returned by circom. 412 | pub fn parse_verification_key(vkey_str: String) -> Result { 413 | let vkey = serde_json_wasm::from_str(&vkey_str) 414 | .map_err(|_| VerifierError::ParseError("verification key".to_string()))?; 415 | Ok(vkey) 416 | } 417 | 418 | /// A helper function to parse verification key json into a prepared 419 | /// verifying key. 420 | pub fn get_prepared_verifying_key(vkey: VerificationKeyJson) -> PreparedVerifyingKey { 421 | let parse_vkey: ark_groth16::VerifyingKey = vkey.into(); 422 | ark_groth16::prepare_verifying_key(&parse_vkey).into() 423 | } 424 | 425 | /// A helper function to verify proof 426 | pub fn verify_proof( 427 | pvk: PreparedVerifyingKey, 428 | proof_str: String, 429 | pub_inputs_str: String, 430 | ) -> Result { 431 | let proof = parse_circom_proof(proof_str)?; 432 | let pub_inputs = parse_public_inputs(pub_inputs_str)?; 433 | let ark_pub_inputs: Vec = pub_inputs.into_iter().map(fr_from_str).collect(); 434 | 435 | // TODO: Convert this to a proper error type of Bolt-rs 436 | let res = ark_groth16::verify_proof(&pvk.into(), &proof.into(), &ark_pub_inputs[..]).unwrap(); 437 | 438 | Ok(res) 439 | } 440 | 441 | fn fq_from_str(s: String) -> ark_bn254::Fq { 442 | ark_bn254::Fq::from_str(&s).unwrap() 443 | } 444 | 445 | pub fn fr_from_str(s: String) -> ark_bn254::Fr { 446 | ark_bn254::Fr::from_str(&s).unwrap() 447 | } 448 | 449 | fn g1_from_str(g1: &[String]) -> ark_bn254::G1Affine { 450 | let x = fq_from_str(g1[0].clone()); 451 | let y = fq_from_str(g1[1].clone()); 452 | let z = fq_from_str(g1[2].clone()); 453 | ark_bn254::G1Affine::from(ark_bn254::G1Projective::new(x, y, z)) 454 | } 455 | 456 | fn g2_from_str(g2: &[Vec]) -> ark_bn254::G2Affine { 457 | let c0 = fq_from_str(g2[0][0].clone()); 458 | let c1 = fq_from_str(g2[0][1].clone()); 459 | let x = ark_bn254::Fq2::new(c0, c1); 460 | 461 | let c0 = fq_from_str(g2[1][0].clone()); 462 | let c1 = fq_from_str(g2[1][1].clone()); 463 | let y = ark_bn254::Fq2::new(c0, c1); 464 | 465 | let c0 = fq_from_str(g2[2][0].clone()); 466 | let c1 = fq_from_str(g2[2][1].clone()); 467 | let z = ark_bn254::Fq2::new(c0, c1); 468 | 469 | ark_bn254::G2Affine::from(ark_bn254::G2Projective::new(x, y, z)) 470 | } 471 | 472 | impl From for ark_groth16::VerifyingKey { 473 | fn from(src: VerificationKeyJson) -> Self { 474 | let alpha_g1_ = g1_from_str(&src.vk_alpha_1); 475 | let beta_g2_ = g2_from_str(&src.vk_beta_2); 476 | let gamma_g2_ = g2_from_str(&src.vk_gamma_2); 477 | let delta_g2_ = g2_from_str(&src.vk_delta_2); 478 | 479 | let gamma_abc_g1_: Vec = 480 | src.ic.iter().map(|x| g1_from_str(x)).collect(); 481 | 482 | ark_groth16::VerifyingKey { 483 | alpha_g1: alpha_g1_, 484 | beta_g2: beta_g2_, 485 | gamma_g2: gamma_g2_, 486 | delta_g2: delta_g2_, 487 | gamma_abc_g1: gamma_abc_g1_, 488 | } 489 | } 490 | } 491 | 492 | #[cfg(test)] 493 | mod tests { 494 | use super::*; 495 | 496 | fn get_vkey() -> &'static str { 497 | r#" 498 | { 499 | "protocol": "groth16", 500 | "curve": "bn128", 501 | "nPublic": 21, 502 | "vk_alpha_1": [ 503 | "20491192805390485299153009773594534940189261866228447918068658471970481763042", 504 | "9383485363053290200918347156157836566562967994039712273449902621266178545958", 505 | "1" 506 | ], 507 | "vk_beta_2": [ 508 | [ 509 | "6375614351688725206403948262868962793625744043794305715222011528459656738731", 510 | "4252822878758300859123897981450591353533073413197771768651442665752259397132" 511 | ], 512 | [ 513 | "10505242626370262277552901082094356697409835680220590971873171140371331206856", 514 | "21847035105528745403288232691147584728191162732299865338377159692350059136679" 515 | ], 516 | [ 517 | "1", 518 | "0" 519 | ] 520 | ], 521 | "vk_gamma_2": [ 522 | [ 523 | "10857046999023057135944570762232829481370756359578518086990519993285655852781", 524 | "11559732032986387107991004021392285783925812861821192530917403151452391805634" 525 | ], 526 | [ 527 | "8495653923123431417604973247489272438418190587263600148770280649306958101930", 528 | "4082367875863433681332203403145435568316851327593401208105741076214120093531" 529 | ], 530 | [ 531 | "1", 532 | "0" 533 | ] 534 | ], 535 | "vk_delta_2": [ 536 | [ 537 | "166438788818422684353143109466712365495487529761282054253940311767202847529", 538 | "14821889692288092546390398853883577003395705920427691037003877337111307008319" 539 | ], 540 | [ 541 | "5211044291848451570308359449705497730711843248959818951644537468318735026319", 542 | "3349759874590271776701023934351541831283252450166481144436728710799565826635" 543 | ], 544 | [ 545 | "1", 546 | "0" 547 | ] 548 | ], 549 | "vk_alphabeta_12": [ 550 | [ 551 | [ 552 | "2029413683389138792403550203267699914886160938906632433982220835551125967885", 553 | "21072700047562757817161031222997517981543347628379360635925549008442030252106" 554 | ], 555 | [ 556 | "5940354580057074848093997050200682056184807770593307860589430076672439820312", 557 | "12156638873931618554171829126792193045421052652279363021382169897324752428276" 558 | ], 559 | [ 560 | "7898200236362823042373859371574133993780991612861777490112507062703164551277", 561 | "7074218545237549455313236346927434013100842096812539264420499035217050630853" 562 | ] 563 | ], 564 | [ 565 | [ 566 | "7077479683546002997211712695946002074877511277312570035766170199895071832130", 567 | "10093483419865920389913245021038182291233451549023025229112148274109565435465" 568 | ], 569 | [ 570 | "4595479056700221319381530156280926371456704509942304414423590385166031118820", 571 | "19831328484489333784475432780421641293929726139240675179672856274388269393268" 572 | ], 573 | [ 574 | "11934129596455521040620786944827826205713621633706285934057045369193958244500", 575 | "8037395052364110730298837004334506829870972346962140206007064471173334027475" 576 | ] 577 | ] 578 | ], 579 | "IC": [ 580 | [ 581 | "19975645442203377055504350944199411205645925605842881710313661501103970826593", 582 | "17515161622283010384423259590087060433422690594791060414171309961412819784969", 583 | "1" 584 | ], 585 | [ 586 | "8314529012362679498714409542216060373647165806213078732764739247682086265767", 587 | "121366207716244222195924313927761544312158108247873731042786280646943184074", 588 | "1" 589 | ], 590 | [ 591 | "16709720837782968526180617884167855231344603866174025119200385206304701258678", 592 | "3147822512060247213265367088074297137791420360497197470911250310113275037763", 593 | "1" 594 | ], 595 | [ 596 | "14216723210244410575876418879665374598747581482663712212010511617392597830954", 597 | "15811996758528967218865995673654714048570588460636125402018277656651434631576", 598 | "1" 599 | ], 600 | [ 601 | "7348238908009886871059992732128931157271697524606274111411455960455037416413", 602 | "14001472805890407823397893627240743988837305207489952388063413323698861707624", 603 | "1" 604 | ], 605 | [ 606 | "2138882192497635891459717929673559440104769163700828386965661447497938982721", 607 | "5186793583243682306353927402481196491547812815293709454908025411581465445004", 608 | "1" 609 | ], 610 | [ 611 | "2116764452247307873087707246637130330345204236852642632713114592476993977670", 612 | "14896161713831569254989869822450928542555444355351318861266435690413316845347", 613 | "1" 614 | ], 615 | [ 616 | "16392430006950202355682918247811738427580100868571691215288876389925500647279", 617 | "19437084047439114680241004405825353549565621104782399561893962443338240135858", 618 | "1" 619 | ], 620 | [ 621 | "16963065381115919041780779888616737843143206987161162977928288398707149790618", 622 | "9087066945988971374305861013885116715721320414719802148300649773920118102481", 623 | "1" 624 | ], 625 | [ 626 | "13714673228950478504452201663230221577251226934030004828193127473877480610295", 627 | "9332072320101623120415187992550525752876274301602491265535702933221101004380", 628 | "1" 629 | ], 630 | [ 631 | "1064045990922553586834518447367936820175319540784875187573912133883165188670", 632 | "18287981330912970040426745735838860702735392209815444404076135459948276202848", 633 | "1" 634 | ], 635 | [ 636 | "9210826867500141415001909980706988517816622370128886786816673451224513701503", 637 | "3651094788905360180553273507287364045940819368096000322156684552199804097143", 638 | "1" 639 | ], 640 | [ 641 | "17720362295505313322759315353391656693108343058592864160681048989141882794083", 642 | "10097671657793855671159749436121468469201270375403582850205385628210921488731", 643 | "1" 644 | ], 645 | [ 646 | "9801543874486422221954003660705098546171144064277720948049325854942931758306", 647 | "20479944074043794678092216875190551894013835948904068657881623722226189539016", 648 | "1" 649 | ], 650 | [ 651 | "5374663040433250412848838440386505484894911153493652424898166227177046711199", 652 | "13679665179607144765496503536099360866217236185602567461732884358192393872279", 653 | "1" 654 | ], 655 | [ 656 | "1064329530975255434535409396597644022861254752006703233721201637345800440139", 657 | "5140009461438788926486789050955593582109349287858692508879168080077367120629", 658 | "1" 659 | ], 660 | [ 661 | "15366436033551689602012357199098419434258945123964889817106842055644617190504", 662 | "898268788386333715715903230667785887632210104432209295828625929694299885006", 663 | "1" 664 | ], 665 | [ 666 | "5625417729666095139456177838606211212046421091440422619829111829213675828978", 667 | "18455517249670178543137281808225159109856379895586238312217422816116366743603", 668 | "1" 669 | ], 670 | [ 671 | "17537235019815029148949517328224734386526017513684721827218738801833451783210", 672 | "2342105886191919519714066767578407697780765722350456533494274069027087830216", 673 | "1" 674 | ], 675 | [ 676 | "8512191115799353035296472708809096858085180357544392842547774011355858433041", 677 | "2541245043439530389724749443817975569327264943016202232800605721736943199048", 678 | "1" 679 | ], 680 | [ 681 | "19224585989189727449965872368330162278522031170641583311558474979239173678715", 682 | "18166021891232232834725962994255689261693690030629187665379835418854223722023", 683 | "1" 684 | ], 685 | [ 686 | "14017181509831449693830612331037537298674425286306310710534048602053149127774", 687 | "330831566870832606085453648362982294226755734586757078631724647552023101374", 688 | "1" 689 | ] 690 | ] 691 | } 692 | "# 693 | } 694 | 695 | #[test] 696 | fn test_parse_valid_verification_key() { 697 | let vkey_str = get_vkey(); 698 | let vkey = parse_verification_key(vkey_str.to_string()).unwrap(); 699 | assert_eq!(vkey.protocol, "groth16"); 700 | assert_eq!(vkey.curve, "bn128"); 701 | assert_eq!(vkey.num_public, 21); 702 | } 703 | 704 | #[test] 705 | fn test_parse_invalid_verification_key() { 706 | let vkey_str = r#" 707 | { 708 | "protocol": "groth16", 709 | "curve": "bn128", 710 | "nPublic": 1, 711 | "vk_beta_2": [ 712 | [ 713 | "3043345541449451671254450988991753002656660035846876061355339859941832004318", 714 | "9366036361352379018594831897170702393774275718261521192392224789664885279048" 715 | ], 716 | [ 717 | "13013276479422120091160662049955987435710012286605495842546532018893262680987", 718 | "14570689804927635484337933117252889899638838990887585775285700495326742500608" 719 | ], 720 | [ 721 | "1", 722 | "0" 723 | ] 724 | ], 725 | "vk_gamma_2": [ 726 | [ 727 | "10857046999023057135944570762232829481370756359578518086990519993285655852781", 728 | "11559732032986387107991004021392285783925812861821192530917403151452391805634" 729 | ], 730 | [ 731 | "8495653923123431417604973247489272438418190587263600148770280649306958101930", 732 | "4082367875863433681332203403145435568316851327593401208105741076214120093531" 733 | ], 734 | [ 735 | "1", 736 | "0" 737 | ] 738 | ], 739 | "vk_delta_2": [ 740 | [ 741 | "2734577848493477101784673168916689189152190109550989513773621988766628013896", 742 | "20992053824921110769159163698868426355728207712097181822869885973257549986665" 743 | ], 744 | [ 745 | "18858728426139214530397886298764629051579512035453478146479294850808428228226", 746 | "16650869185745772661582147225220884707446064820553793560683789497559329846949" 747 | ], 748 | [ 749 | "1", 750 | "0" 751 | ] 752 | ], 753 | "vk_alphabeta_12": [ 754 | [ 755 | [ 756 | "16403249578719490126072533602691465129046148109548339172692159293394071643386", 757 | "404083172884130787011880125990917651653105025179849649507378532814812033743" 758 | ], 759 | [ 760 | "9304686624381716522435760802435389234743930919257995833040856535135604271150", 761 | "7297682513079878497741793281328503938637410885893249606756478534362180551835" 762 | ], 763 | [ 764 | "17354121827975724085057788554351619925552460622743302973070914719205720740971", 765 | "17029060856042991949050729552637497721303925875794209439369222736105594947627" 766 | ] 767 | ], 768 | [ 769 | [ 770 | "7351439472145663460303190808494715160984862908266037163980906171905322144196", 771 | "4899830427462111655211072420148616010374627247339367569243756669854362971692" 772 | ], 773 | [ 774 | "11493816073724792379849577567766940080449553642999473348500952038852103043242", 775 | "20229043536413592615655482855555253411102261009946710916737819944352224248089" 776 | ], 777 | [ 778 | "20445551610334345159229738787294472467932316248073152880543490797842284204290", 779 | "4991801408713450062187668790956752622553932388084176879623832267439560781668" 780 | ] 781 | ] 782 | ], 783 | "IC": [ 784 | [ 785 | "20510024326636861894856056279186972251820656064299818504132684390781123564002", 786 | "3794043495370927585051135397901732182692326739063049522454286904701134003013", 787 | "1" 788 | ], 789 | [ 790 | "7791962724153994122113202116325467726962116651195725568779661762583649623632", 791 | "21733435539045095673745804075891544265305400637072500486664710068860705765791", 792 | "1" 793 | ] 794 | ] 795 | } 796 | "#; 797 | let vkey = parse_verification_key(vkey_str.to_string()); 798 | assert!(vkey.is_err()); 799 | assert_eq!( 800 | vkey.err().expect("Invalid Vkey").to_string(), 801 | "Failed to parse circom verification key json" 802 | ); 803 | } 804 | 805 | #[test] 806 | fn test_prepared_verification_key() { 807 | let vkey_str = get_vkey(); 808 | let vkey = parse_verification_key(vkey_str.to_string()).unwrap(); 809 | let prepared_vkey = get_prepared_verifying_key(vkey); 810 | let x: BigInteger256 = BigInteger256::new([ 811 | 129941079445278231, 812 | 14986904513597369283, 813 | 4385962745611939561, 814 | 498495035870568143, 815 | ]); 816 | let y: BigInteger256 = BigInteger256::new([ 817 | 3551982070992374558, 818 | 4387704605030068278, 819 | 1260785428361773688, 820 | 452138810654549394, 821 | ]); 822 | let g1 = G1Affine::new(x, y, false); 823 | 824 | assert_eq!(g1, prepared_vkey.vk.alpha_g1); 825 | } 826 | 827 | #[test] 828 | fn test_parse_public_input() { 829 | let pub_input_str = r#"[ 830 | "1", 831 | "277989581668086710587965336712738880284", 832 | "314891321346369595428838678892844352460" 833 | ]"#; 834 | let inputs = parse_public_inputs(pub_input_str.to_string()).unwrap(); 835 | assert_eq!("1", inputs[0]); 836 | assert_eq!("277989581668086710587965336712738880284", inputs[1]); 837 | assert_eq!("314891321346369595428838678892844352460", inputs[2]); 838 | } 839 | 840 | #[test] 841 | fn test_valid_proof_snarkjs() { 842 | let proof_str = r#" 843 | { 844 | "pi_a": [ 845 | "20198676790799425245595459194274498752473994950719073183074649501711660535595", 846 | "12758475309915023533579531485441554907458299575042834087971469653289637732346", 847 | "1" 848 | ], 849 | "pi_b": [ 850 | [ 851 | "13742117572560123711123425096963974481037753438772131102525214062174465939468", 852 | "9217768357543713672348398426848893195759877300475465964741673960918197283129" 853 | ], 854 | [ 855 | "13388985823083338129254299703944286332336674476925977438789020739020226493083", 856 | "13389941977815367065802562753053209214146349395284722106316234427940539426898" 857 | ], 858 | [ 859 | "1", 860 | "0" 861 | ] 862 | ], 863 | "pi_c": [ 864 | "5988936190268741469108357726405145464702633179533876088993318355641592876129", 865 | "15053058905266236652562457399329328685910831643948235107886315836157181001907", 866 | "1" 867 | ], 868 | "protocol": "groth16", 869 | "curve": "bn128" 870 | } 871 | "#; 872 | let pub_input_str = r#" 873 | [ 874 | "1", 875 | "139034790179591340742761703217010858871", 876 | "178747724383637324525799708680472596098", 877 | "249730154399878769526315894913495941533", 878 | "339453732354324016397146782775657558721", 879 | "208326850591216812292393721318634961999", 880 | "28902942442541169865286267622270965052", 881 | "208326850591216812292393721318634961999", 882 | "28902942442541169865286267622270965052", 883 | "208326850591216812292393721318634961999", 884 | "28902942442541169865286267622270965052", 885 | "208326850591216812292393721318634961999", 886 | "28902942442541169865286267622270965052", 887 | "208326850591216812292393721318634961999", 888 | "28902942442541169865286267622270965052", 889 | "208326850591216812292393721318634961999", 890 | "28902942442541169865286267622270965052", 891 | "208326850591216812292393721318634961999", 892 | "28902942442541169865286267622270965052", 893 | "208326850591216812292393721318634961999", 894 | "28902942442541169865286267622270965052" 895 | ] 896 | "#; 897 | let vkey_str = get_vkey(); 898 | let vkey = parse_verification_key(vkey_str.to_string()).unwrap(); 899 | let prepared_vkey = get_prepared_verifying_key(vkey); 900 | 901 | let res = verify_proof( 902 | prepared_vkey, 903 | proof_str.to_string(), 904 | pub_input_str.to_string(), 905 | ); 906 | assert!(res.unwrap()); 907 | } 908 | 909 | #[test] 910 | fn test_valid_proof_rapidsnark() { 911 | let proof_str = r#" 912 | { 913 | "pi_a": [ 914 | "20198676790799425245595459194274498752473994950719073183074649501711660535595", 915 | "12758475309915023533579531485441554907458299575042834087971469653289637732346", 916 | "1" 917 | ], 918 | "pi_b": [ 919 | [ 920 | "13742117572560123711123425096963974481037753438772131102525214062174465939468", 921 | "9217768357543713672348398426848893195759877300475465964741673960918197283129" 922 | ], 923 | [ 924 | "13388985823083338129254299703944286332336674476925977438789020739020226493083", 925 | "13389941977815367065802562753053209214146349395284722106316234427940539426898" 926 | ], 927 | [ 928 | "1", 929 | "0" 930 | ] 931 | ], 932 | "pi_c": [ 933 | "5988936190268741469108357726405145464702633179533876088993318355641592876129", 934 | "15053058905266236652562457399329328685910831643948235107886315836157181001907", 935 | "1" 936 | ], 937 | "protocol": "groth16" 938 | } 939 | "#; 940 | let pub_input_str = r#" 941 | [ 942 | "1", 943 | "139034790179591340742761703217010858871", 944 | "178747724383637324525799708680472596098", 945 | "249730154399878769526315894913495941533", 946 | "339453732354324016397146782775657558721", 947 | "208326850591216812292393721318634961999", 948 | "28902942442541169865286267622270965052", 949 | "208326850591216812292393721318634961999", 950 | "28902942442541169865286267622270965052", 951 | "208326850591216812292393721318634961999", 952 | "28902942442541169865286267622270965052", 953 | "208326850591216812292393721318634961999", 954 | "28902942442541169865286267622270965052", 955 | "208326850591216812292393721318634961999", 956 | "28902942442541169865286267622270965052", 957 | "208326850591216812292393721318634961999", 958 | "28902942442541169865286267622270965052", 959 | "208326850591216812292393721318634961999", 960 | "28902942442541169865286267622270965052", 961 | "208326850591216812292393721318634961999", 962 | "28902942442541169865286267622270965052" 963 | ] 964 | "#; 965 | let vkey_str = get_vkey(); 966 | let vkey = parse_verification_key(vkey_str.to_string()).unwrap(); 967 | let prepared_vkey = get_prepared_verifying_key(vkey); 968 | 969 | let res = verify_proof( 970 | prepared_vkey, 971 | proof_str.to_string(), 972 | pub_input_str.to_string(), 973 | ); 974 | assert!(res.unwrap()); 975 | } 976 | } 977 | --------------------------------------------------------------------------------