diff --git a/.github/ISSUE_TEMPLATE/bug_form_template.yml b/.github/ISSUE_TEMPLATE/bug_form_template.yml new file mode 100644 index 0000000..db41757 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_form_template.yml @@ -0,0 +1,23 @@ +name: Bug report +description: File a bug report +labels: ["bug"] +body: + - type: markdown + attributes: + value: | + Please ensure that the bug has not already been filed in the issue tracker. + - type: input + attributes: + label: What command(s) is the bug in? + description: Leave empty if not relevant + placeholder: "For example: make test" + - type: textarea + attributes: + label: Describe the bug + description: Please include relevant code snippets as well if relevant. + validations: + required: true + - type: textarea + attributes: + label: Concrete steps to reproduce the bug. If it's able reproduce via testool, please share `test_id` from jenkins report + description: Leave empty if not relevant \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature_form_template.yml b/.github/ISSUE_TEMPLATE/feature_form_template.yml new file mode 100644 index 0000000..cc3a378 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_form_template.yml @@ -0,0 +1,18 @@ +name: Feature request +description: Suggest a feature +labels: ["feature"] +body: + - type: markdown + attributes: + value: | + Please ensure that the feature has not already been requested in the issue tracker. + - type: textarea + attributes: + label: Describe the feature you would like + description: Please also describe what the feature is aiming to solve, if relevant. + validations: + required: true + - type: textarea + attributes: + label: Additional context + description: Add any other context to the feature (like screenshots, resources) \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/research_form_template.yml b/.github/ISSUE_TEMPLATE/research_form_template.yml new file mode 100644 index 0000000..c94a15a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/research_form_template.yml @@ -0,0 +1,25 @@ +name: Research +description: Share the Research +labels: ["research"] +body: + - type: textarea + attributes: + label: What's the purpose of this research? + description: explain what you want to make sure on this research (please itemize) + placeholder: ex) to make sure what is the difference between A and B + validations: + required: true + - type: textarea + attributes: + label: Concrete milestone by steps + description: explain what we need to do to achieve this research + placeholder: ex) 1. test the library + validations: + required: true + - type: textarea + attributes: + label: Describe references if exists + description: Please refer the related papers, articles or implementations if you know + - type: markdown + attributes: + value: Please share the progress/result on the comment below! \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..9d2bb75 --- /dev/null +++ b/README.md @@ -0,0 +1,61 @@ +# MynaWallet Halo2 Circuits + +This repository aims to create proofs which verifies the RSA signatures signed by Myna Card(Japan's ID Card). + +## Getting Started + +For a brief introduction to zero-knowledge proofs (ZK), see this [doc](https://docs.axiom.xyz/zero-knowledge-proofs/introduction-to-zk). + +Halo 2 is written in Rust, so you need to [install](https://www.rust-lang.org/tools/install) Rust to use this library: + +```bash +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh +``` + +Clone this repo and start off in the `halo2-circuits` directory. + +```bash +git clone git@github.com:MynaWallet/halo2-circuits.git +cd halo2-circuits +``` + +## Run test + +```bash +cargo test -- --nocapture +``` + +## Benchmarks + +```bash +cargo bench +``` + +Result Not Yet + +## Milestones + +- ✅ RSA Verification Circuit Base +- RSA Verification Circuit (SHA2 Hash as input) +- Test & Benchmarks +- Verifier Contracts +- Example Codes which call Prover +- (Phase2) RSA Verification Circuit (DER-encoded certificate as input) +- (Phase3) Selective Disclosure + +See more details on the [issues](https://github.com/MynaWallet/halo2-circuits/issues) + +## Workspace + +Please make sure to cut your own branch from `feature/base`. + +## Specs + +- [Signature Verification](./spec/SignatureVerification.md) + +## References + +You can refer to these repos of RSA verification circuits. + +- [halo2-rsa](https://github.com/zkemail/halo2-rsa/tree/feat/new_bigint) +- [zk-email-verify](https://github.com/zkemail/zk-email-verify) diff --git a/spec/SignatureVerification.md b/spec/SignatureVerification.md new file mode 100644 index 0000000..348aa03 --- /dev/null +++ b/spec/SignatureVerification.md @@ -0,0 +1,27 @@ +# RSA Signature Verification Circuit + +The Circuit which Verifies RSA signature. + +## Overview + +This is the circuit overview. +(The input will change in phase2.) + +```mermaid +flowchart LR + hashed-->verify_signature + signature-->verify_signature + modulus-->verify_signature + subgraph circuit + verify_signature + end + verify_signature-->ok +``` + +## Functions + +- `verify_signature()`: verify RSA signature and return assigned set values if signature is valid + +## How verify_signature() works + +(add it later) \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index d389464..983c2b7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -154,69 +154,151 @@ mod test { use rand::thread_rng; use rand::Rng; use rsa::{Hash, PaddingScheme, PublicKeyParts, RsaPrivateKey, RsaPublicKey}; + use sha2::digest::Output; use sha2::{Digest, Sha256}; - #[test] - fn test_signature_verification() { + fn test_gen_key() -> (RsaPublicKey, RsaPrivateKey) { let bits = 2048; - - // 1. Generate a key pair. let mut rng = thread_rng(); + + // let mut rng = thread_rng(); let private_key = RsaPrivateKey::new(&mut rng, bits).expect("failed to generate a key"); let public_key = RsaPublicKey::from(&private_key); - // 2. Uniformly sample a message. - let mut msg: [u8; 128] = [0; 128]; - for x in &mut msg[..] { - *x = rng.gen(); - } - - // 3. Compute the SHA256 hash of `msg`. - let hashed_msg = Sha256::digest(msg); + (public_key, private_key) + } - // 4. Generate a pkcs1v15 signature. + fn test_sign(private_key: RsaPrivateKey, hashed_msg: Output) -> Vec { let padding = PaddingScheme::PKCS1v15Sign { hash: Some(Hash::SHA2_256), }; - let sign = private_key + + private_key .sign(padding, &hashed_msg) - .expect("fail to sign a hashed message."); + .expect("fail to sign a hashed message.") + } - let public_key_n = BigUint::from_bytes_be(&public_key.n().clone().to_bytes_be()); + fn test_hash_rng() -> Output { + let mut rng = thread_rng(); + let mut msg: [u8; 128] = [0; 128]; + for x in &mut msg[..] { + *x = rng.gen(); + } + Sha256::digest(msg) + } + + fn test_hash_msg(msg: Vec) -> Output { + Sha256::digest(msg) + } - // 公開鍵をVecに変換 - let pub_key_vec = public_key - .n() - .clone() - .to_bytes_be() + fn str2field(a: Vec) -> Vec { + let res = a + .to_vec() .iter() .map(|v| Fr::from(*v as u64)) .collect::>(); - // 署名をVecに変換 - let sign_vec = sign + res + } + + fn hash2field(a: Output) -> Vec { + let res = a .to_vec() .iter() .map(|v| Fr::from(*v as u64)) .collect::>(); - // ハッシュされたメッセージをVecに変換 - let hashed_vec = hashed_msg + res + } + + #[test] + fn test_signature_verification() { + let (public_key, private_key) = test_gen_key(); + let hashed_msg = test_hash_rng(); + let sign = test_sign(private_key, hashed_msg); + let public_key_n = BigUint::from_bytes_be(&public_key.n().clone().to_bytes_be()); + + // Frに変換 + let pub_key_vec = str2field(public_key.n().clone().to_bytes_be()); + let sign_vec = str2field(sign.clone()); + let hashed_msg_vec = hash2field(hashed_msg.clone()); + + // 公開鍵、署名、ハッシュされたメッセージを結合 + let public_inputs = pub_key_vec .iter() - .map(|v| Fr::from(*v as u64)) + .chain(sign_vec.iter()) + .chain(hashed_msg_vec.iter()) + .cloned() .collect::>(); + let circuit = + DefaultMynaCircuit::::new( + hashed_msg.to_vec(), + sign.to_vec(), + public_key_n + ); + let prover = MockProver::run(19, &circuit, vec![public_inputs]).unwrap(); + assert_eq!(prover.verify(), Ok(())); + } + + #[test] + fn test_invalid_signature_verification() { + let (public_key, private_key) = test_gen_key(); + let hashed_msg = test_hash_rng(); + let hashed_msg_2 = test_hash_msg("hellohellohello".into()); + let sign = test_sign(private_key, hashed_msg); + let public_key_n = BigUint::from_bytes_be(&public_key.n().clone().to_bytes_be()); + + // Frに変換 + let pub_key_vec = str2field(public_key.n().clone().to_bytes_be()); + let sign_vec = str2field(sign.clone()); + let hashed_msg_vec = hash2field(hashed_msg_2.clone()); // set different message from sign + // 公開鍵、署名、ハッシュされたメッセージを結合 let public_inputs = pub_key_vec .iter() .chain(sign_vec.iter()) - .chain(hashed_vec.iter()) + .chain(hashed_msg_vec.iter()) .cloned() .collect::>(); let circuit = - DefaultMynaCircuit::::new(hashed_msg.to_vec(), sign.to_vec(), public_key_n); + DefaultMynaCircuit::::new( + hashed_msg_2.to_vec(), // different message from signature + sign.to_vec(), + public_key_n + ); let prover = MockProver::run(19, &circuit, vec![public_inputs]).unwrap(); - assert_eq!(prover.verify(), Ok(())); + assert!(prover.verify().is_err()); + } + + #[test] + fn test_invalid_instance() { + let (public_key, private_key) = test_gen_key(); + let hashed_msg = test_hash_rng(); + let sign = test_sign(private_key, hashed_msg); + let public_key_n = BigUint::from_bytes_be(&public_key.n().clone().to_bytes_be()); + + // Frに変換 + let pub_key_vec = vec![Fr::from(3274), Fr::from(32344)]; + let sign_vec = vec![Fr::from(3274), Fr::from(32344)]; + let hashed_msg_vec = vec![Fr::from(3274), Fr::from(32344)]; + + // 公開鍵、署名、ハッシュされたメッセージを結合 + let public_inputs = pub_key_vec + .iter() + .chain(sign_vec.iter()) + .chain(hashed_msg_vec.iter()) + .cloned() + .collect::>(); + + let circuit = + DefaultMynaCircuit::::new( + hashed_msg.to_vec(), + sign.to_vec(), + public_key_n + ); + let prover = MockProver::run(19, &circuit, vec![public_inputs]).unwrap(); + assert!(prover.verify().is_err()); } }