├── .config └── nextest.toml ├── .github ├── PULL_REQUEST_TEMPLATE.md ├── banner.png ├── dependabot.yml └── workflows │ └── ci.yml ├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── accumulators ├── Cargo.toml ├── src │ ├── errors.rs │ ├── lib.rs │ └── merkle_tree.rs └── tests │ └── merkle_tree.rs ├── algebra ├── Cargo.toml ├── benches │ └── msm.rs └── src │ ├── baby_jubjub │ ├── fq.rs │ ├── fr.rs │ ├── g1.rs │ └── mod.rs │ ├── bls12_381 │ ├── fastmsm.wasm │ ├── fq.rs │ ├── fr.rs │ ├── g1.rs │ ├── g2.rs │ ├── gt.rs │ ├── mod.rs │ └── pairing.rs │ ├── bn254 │ ├── fq.rs │ ├── fr.rs │ ├── g1.rs │ ├── g2.rs │ ├── gt.rs │ ├── mod.rs │ └── pairing.rs │ ├── ed25519 │ ├── fq.rs │ ├── fr.rs │ ├── g1.rs │ └── mod.rs │ ├── errors.rs │ ├── jubjub │ ├── fq.rs │ ├── fr.rs │ ├── g1.rs │ └── mod.rs │ ├── lib.rs │ ├── prelude.rs │ ├── rand_helper.rs │ ├── ristretto │ └── mod.rs │ ├── secp256k1 │ ├── fq.rs │ ├── fr.rs │ ├── g1.rs │ └── mod.rs │ ├── secq256k1 │ ├── fq.rs │ ├── fr.rs │ ├── g1.rs │ └── mod.rs │ ├── serialization.rs │ ├── traits.rs │ ├── utils.rs │ └── zorro │ ├── fq.rs │ ├── fr.rs │ ├── g1.rs │ └── mod.rs ├── api ├── Cargo.toml ├── benches │ ├── anemoi.rs │ ├── anon_xfr.rs │ ├── bulletproofs.rs │ ├── merkle_tree.rs │ └── xfr.rs ├── parameters │ ├── abar-to-ar-vk-ed25519.bin │ ├── abar-to-ar-vk-secp256k1.bin │ ├── abar-to-bar-vk-ed25519.bin │ ├── abar-to-bar-vk-secp256k1.bin │ ├── ar-to-abar-vk.bin │ ├── bar-to-abar-vk.bin │ ├── bulletproof-curve25519-urs.bin │ ├── bulletproof-secq256k1-urs.bin │ ├── bulletproof-zorro-urs.bin │ ├── lagrange-srs-4096.bin │ ├── lagrange-srs-8192.bin │ ├── srs-padding.bin │ ├── transfer-vk-common.bin │ ├── transfer-vk-ed25519-specific.bin │ └── transfer-vk-secp256k1-specific.bin └── src │ ├── anon_creds.rs │ ├── anon_xfr │ ├── abar_to_abar.rs │ ├── abar_to_ar.rs │ ├── abar_to_bar.rs │ ├── address_folding_ed25519.rs │ ├── address_folding_secp256k1.rs │ ├── ar_to_abar.rs │ ├── bar_to_abar.rs │ ├── mod.rs │ └── structs.rs │ ├── errors.rs │ ├── keys.rs │ ├── lib.rs │ ├── nextgen │ ├── ar_to_nabar.rs │ ├── bar_to_nabar.rs │ ├── mod.rs │ ├── nabar_or_abar_xfr.rs │ ├── nabar_to_ar.rs │ ├── nabar_to_bar.rs │ ├── nullifiers │ │ └── mod.rs │ └── structs │ │ ├── memo.rs │ │ └── mod.rs │ ├── parameters │ ├── bulletproofs.rs │ ├── mod.rs │ ├── params.rs │ └── setup.rs │ ├── serialization.rs │ └── xfr │ ├── asset_mixer.rs │ ├── asset_record.rs │ ├── asset_tracer.rs │ ├── mod.rs │ ├── proofs.rs │ ├── structs.rs │ └── tests.rs ├── crypto ├── Cargo.toml ├── benches │ └── hashing.rs └── src │ ├── anemoi_jive │ ├── bls12_381.rs │ ├── bls12_381_deprecated.rs │ ├── bn254.rs │ ├── mds.rs │ ├── mod.rs │ ├── salts │ │ ├── bls12_381.rs │ │ ├── bn254.rs │ │ └── mod.rs │ ├── tests │ │ ├── bls12_381.rs │ │ ├── bls12_381_deprecated.rs │ │ ├── bn254.rs │ │ └── mod.rs │ └── traces.rs │ ├── anon_creds.rs │ ├── bulletproofs │ ├── hashing_to_the_curve │ │ ├── ed25519_elligator.rs │ │ ├── mod.rs │ │ └── secp256k1_sswu.rs │ ├── mix.rs │ ├── mod.rs │ ├── plume │ │ ├── ed25519.rs │ │ ├── mod.rs │ │ └── secp256k1.rs │ ├── range.rs │ └── scalar_mul │ │ ├── ed25519.rs │ │ ├── mod.rs │ │ └── secp256k1.rs │ ├── chaum_pedersen.rs │ ├── confidential_anon_creds.rs │ ├── delegated_schnorr.rs │ ├── doubly_snark_friendly │ ├── ecies_encryption.rs │ ├── mod.rs │ └── schnorr_signature.rs │ ├── elgamal.rs │ ├── errors.rs │ ├── field_simulation │ ├── bls12_381.rs │ ├── bn254.rs │ └── mod.rs │ ├── gapdh │ ├── hoisting.rs │ ├── mod.rs │ └── standard.rs │ ├── hashing_to_the_curve │ ├── ed25519 │ │ ├── elligator.rs │ │ ├── mod.rs │ │ ├── sswu.rs │ │ └── sw.rs │ ├── mod.rs │ ├── models │ │ ├── elligator.rs │ │ ├── mod.rs │ │ ├── sswu.rs │ │ └── sw.rs │ ├── secp256k1 │ │ ├── mod.rs │ │ ├── sswu.rs │ │ └── sw.rs │ └── traits.rs │ ├── hybrid_encryption.rs │ ├── lib.rs │ ├── matrix_sigma.rs │ ├── pedersen_elgamal.rs │ └── schnorr_gadgets │ ├── gadget1_square.rs │ ├── gadget2_crossed_mul.rs │ ├── gadget3_move.rs │ ├── gadget4_merged.rs │ └── mod.rs ├── plonk ├── Cargo.toml ├── benches │ ├── fft.rs │ └── verifier.rs └── src │ ├── errors.rs │ ├── lib.rs │ ├── plonk │ ├── constraint_system │ │ ├── anemoi_jive.rs │ │ ├── ecc │ │ │ ├── const_base_ecc.rs │ │ │ ├── mod.rs │ │ │ └── nonconst_base_ecc.rs │ │ ├── field_simulation │ │ │ ├── fr_mul_var.rs │ │ │ ├── fr_var.rs │ │ │ └── mod.rs │ │ ├── mod.rs │ │ └── turbo.rs │ ├── helpers.rs │ ├── indexer.rs │ ├── mod.rs │ ├── prover.rs │ ├── transcript.rs │ └── verifier.rs │ └── poly_commit │ ├── field_polynomial.rs │ ├── kzg_poly_com.rs │ ├── mod.rs │ ├── pcs.rs │ └── transcript.rs └── smoke-tests ├── Cargo.toml └── src ├── lib.rs └── tests ├── abar_merkle_tree.rs ├── mod.rs ├── smoke_axfr.rs ├── smoke_axfr_compatibility.rs ├── smoke_axfr_secp256k1_address.rs ├── smoke_axfr_wasm.rs ├── smoke_xfr.rs ├── smoke_xfr_compatibility.rs ├── smoke_xfr_identity.rs ├── smoke_xfr_secp256k1_address.rs ├── smoke_xfr_tracing.rs └── xfr_note_complex.rs /.config/nextest.toml: -------------------------------------------------------------------------------- 1 | [profile.default] 2 | slow-timeout = "1m" -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | * **The major changes of this PR** 2 | 3 | 4 | * **The major impacts of this PR** 5 | - [ ] Impact WASM? 6 | - [ ] Impact mainnet data compatibility? 7 | 8 | * **Extra documentations** 9 | 10 | -------------------------------------------------------------------------------- /.github/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FindoraNetwork/noah/f13d3595dcac5b7e63afdf1f4a0b0c89b16688ba/.github/banner.png -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "cargo" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | target-branch: "develop" 11 | schedule: 12 | interval: "daily" 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # IDE files 2 | .idea 3 | **/.DS_Store 4 | 5 | 6 | # Build files 7 | /release 8 | /target 9 | **/target 10 | **/release 11 | **/*.rs.bk 12 | .*.sw* 13 | Cargo.lock -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "accumulators", 4 | "algebra", 5 | "crypto", 6 | "plonk", 7 | "api", 8 | "smoke-tests" 9 | ] 10 | resolver = "2" 11 | 12 | [profile.release] 13 | opt-level = 3 14 | lto = "thin" 15 | incremental = true 16 | panic = 'abort' 17 | 18 | [profile.bench] 19 | opt-level = 3 20 | debug = false 21 | rpath = false 22 | lto = "thin" 23 | incremental = true 24 | debug-assertions = false 25 | 26 | [profile.dev] 27 | opt-level = 3 28 | lto = "thin" 29 | incremental = true 30 | debug-assertions = true 31 | debug = true 32 | panic = 'abort' 33 | 34 | [profile.test] 35 | opt-level = 2 36 | lto = "off" 37 | incremental = true 38 | debug-assertions = true 39 | debug = true -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Business Source License 1.1 2 | 3 | License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved. 4 | "Business Source License" is a trademark of MariaDB Corporation Ab. 5 | 6 | ----------------------------------------------------------------------------- 7 | 8 | Parameters 9 | 10 | Licensor: Findora Foundation 11 | 12 | Licensed Work: Noah 13 | The Licensed Work is (c) 2022 Findora Foundation 14 | 15 | Additional Use Grant: None 16 | 17 | Change Date: 2025-10-02 18 | 19 | Change License: GNU General Public License v2.0 or later 20 | 21 | ----------------------------------------------------------------------------- 22 | 23 | Terms 24 | 25 | The Licensor hereby grants you the right to copy, modify, create derivative 26 | works, redistribute, and make non-production use of the Licensed Work. The 27 | Licensor may make an Additional Use Grant, above, permitting limited 28 | production use. 29 | 30 | Effective on the Change Date, or the fourth anniversary of the first publicly 31 | available distribution of a specific version of the Licensed Work under this 32 | License, whichever comes first, the Licensor hereby grants you rights under 33 | the terms of the Change License, and the rights granted in the paragraph 34 | above terminate. 35 | 36 | If your use of the Licensed Work does not comply with the requirements 37 | currently in effect as described in this License, you must purchase a 38 | commercial license from the Licensor, its affiliated entities, or authorized 39 | resellers, or you must refrain from using the Licensed Work. 40 | 41 | All copies of the original and modified Licensed Work, and derivative works 42 | of the Licensed Work, are subject to this License. This License applies 43 | separately for each version of the Licensed Work and the Change Date may vary 44 | for each version of the Licensed Work released by Licensor. 45 | 46 | You must conspicuously display this License on each original or modified copy 47 | of the Licensed Work. If you receive the Licensed Work in original or 48 | modified form from a third party, the terms and conditions set forth in this 49 | License apply to your use of that work. 50 | 51 | Any use of the Licensed Work in violation of this License will automatically 52 | terminate your rights under this License for the current and all other 53 | versions of the Licensed Work. 54 | 55 | This License does not grant you any right in any trademark or logo of 56 | Licensor or its affiliates (provided that you may use a trademark or logo of 57 | Licensor as expressly required by this License). 58 | 59 | TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON 60 | AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, 61 | EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF 62 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND 63 | TITLE. 64 | 65 | MariaDB hereby grants you permission to use this License’s text to license 66 | your works, and to refer to it using the trademark "Business Source License", 67 | as long as you comply with the Covenants of Licensor below. 68 | 69 | ----------------------------------------------------------------------------- 70 | 71 | Covenants of Licensor 72 | 73 | In consideration of the right to use this License’s text and the "Business 74 | Source License" name and trademark, Licensor covenants to MariaDB, and to all 75 | other recipients of the licensed work to be provided by Licensor: 76 | 77 | 1. To specify as the Change License the GPL Version 2.0 or any later version, 78 | or a license that is compatible with GPL Version 2.0 or a later version, 79 | where "compatible" means that software provided under the Change License can 80 | be included in a program with software provided under GPL Version 2.0 or a 81 | later version. Licensor may specify additional Change Licenses without 82 | limitation. 83 | 84 | 2. To either: (a) specify an additional grant of rights to use that does not 85 | impose any additional restriction on the right granted in this License, as 86 | the Additional Use Grant; or (b) insert the text "None". 87 | 88 | 3. To specify a Change Date. 89 | 90 | 4. Not to modify this License in any other way. 91 | 92 | ----------------------------------------------------------------------------- 93 | 94 | Notice 95 | 96 | The Business Source License (this document, or the "License") is not an Open 97 | Source license. However, the Licensed Work will eventually be made available 98 | under an Open Source License, as stated in this License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](https://tokei.rs/b1/github/FindoraNetwork/noah) 2 | ![GitHub top language](https://img.shields.io/github/languages/top/FindoraNetwork/noah) 3 | ![GitHub tag (latest SemVer)](https://img.shields.io/github/v/tag/FindoraNetwork/noah) 4 | ![GitHub issues](https://img.shields.io/github/issues-raw/FindoraNetwork/noah) 5 | ![GitHub pull requests](https://img.shields.io/github/issues-pr-raw/FindoraNetwork/noah) 6 | ![License](https://img.shields.io/badge/license-BUSL--1.1-lightgreen) 7 | 8 | ## Noah: A Cryptographic Library for Privacy Assets 9 | 10 | 11 | 12 | Noah is a Rust library that implements various cryptographic primitives for privacy assets. It implements two 13 | constructions: 14 | 15 | - **Maxwell construction.** In 2015, a renowned blockchain developer Gregory Maxwell presented a construction of 16 | confidential transactions (CT) for a UTXO chain. We implemented it with: 17 | - Secp256k1 or Ed25519 for digital signatures 18 | - The Ristretto group over Curve25519 for Pedersen commitments 19 | - Bulletproofs over Curve25519 20 | 21 | - **Zerocash construction.** Improved over a prior protocol Zerocoin, the Zerocash construction, firstly proposed by 22 | Ben-Sasson, Chiesa, Garman, Green, Miers, Tromer, and Virza and improved subsequently by the Zcash 23 | Foundation and Electric Coin Company (ECC), is another privacy-preserving transfer protocol over a UTXO chain. We implemented it with: 24 | - Secp256k1 or Ed25519 (incoming) for digital signatures 25 | - An inhouse variant of TurboPlonk with various optimization tricks 26 | - The European technique for efficient memory in zk-SNARK, using the Anemoi-Jive hashes 27 | 28 | Thanks to all the people who already contributed! 29 | 30 | 31 | 32 | 33 | 34 | ## Licensing 35 | 36 | The primary license for Noah is the Business Source License 1.1 (`BUSL-1.1`), see [`LICENSE`](./LICENSE). 37 | -------------------------------------------------------------------------------- /accumulators/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = 'noah-accumulators' 3 | version = '0.5.0' 4 | authors = ['Findora '] 5 | edition = '2021' 6 | description = 'Noah accumulators commons' 7 | 8 | [lib] 9 | name = 'noah_accumulators' 10 | crate-type = ['rlib'] 11 | 12 | [dependencies] 13 | itertools = '0.12.0' 14 | ruc = '1.0' 15 | parking_lot = '0.12' 16 | 17 | [dependencies.noah-algebra] 18 | path = '../algebra' 19 | 20 | [dependencies.noah-crypto] 21 | path = '../crypto' 22 | 23 | [dependencies.storage] 24 | git = 'https://github.com/FindoraNetwork/storage.git' 25 | tag = 'v1.1.6' 26 | 27 | [dev-dependencies.mem_db] 28 | git = 'https://github.com/FindoraNetwork/storage.git' 29 | tag = 'v1.1.6' 30 | -------------------------------------------------------------------------------- /accumulators/src/errors.rs: -------------------------------------------------------------------------------- 1 | use noah_algebra::error; 2 | use noah_algebra::prelude::AlgebraError; 3 | 4 | pub(crate) type Result = core::result::Result; 5 | 6 | #[derive(Debug, Clone, Eq, PartialEq)] 7 | #[allow(missing_docs)] 8 | pub enum AccumulatorError { 9 | Message(String), 10 | Ruc(String), 11 | Algebra(AlgebraError), 12 | } 13 | 14 | impl core::fmt::Display for AccumulatorError { 15 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 16 | use AccumulatorError::*; 17 | f.write_str(match self { 18 | Message(e) => Box::leak(format!("Message: {}", e).into_boxed_str()), 19 | Ruc(e) => Box::leak(format!("Ruc: {}", e).into_boxed_str()), 20 | Algebra(e) => Box::leak(format!("Algebra: {}", e).into_boxed_str()), 21 | }) 22 | } 23 | } 24 | 25 | impl From for AccumulatorError { 26 | fn from(e: AlgebraError) -> AccumulatorError { 27 | AccumulatorError::Algebra(e) 28 | } 29 | } 30 | 31 | impl From> for AccumulatorError { 32 | fn from(e: Box) -> AccumulatorError { 33 | AccumulatorError::Ruc(format!("{}", e)) 34 | } 35 | } 36 | 37 | impl error::Error for AccumulatorError { 38 | #[cfg(feature = "std")] 39 | fn description(&self) -> &str { 40 | Box::leak(format!("{}", self).into_boxed_str()) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /accumulators/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! The crate for the Merkle tree that stores the records used in the anonymous payment 2 | #![deny(unused_import_braces, unused_qualifications, trivial_casts)] 3 | #![deny(trivial_numeric_casts)] 4 | #![deny(stable_features, unreachable_pub, non_shorthand_field_patterns)] 5 | #![deny(unused_attributes, unused_imports, unused_mut, missing_docs)] 6 | #![deny(renamed_and_removed_lints, stable_features, unused_allocation)] 7 | #![deny(unused_comparisons, bare_trait_objects, unused_must_use)] 8 | #![doc(html_logo_url = "https://avatars.githubusercontent.com/u/74745723?s=200&v=4")] 9 | #![doc(html_playground_url = "https://play.rust-lang.org")] 10 | #![forbid(unsafe_code)] 11 | #![warn( 12 | unused, 13 | future_incompatible, 14 | nonstandard_style, 15 | rust_2018_idioms, 16 | rust_2021_compatibility 17 | )] 18 | 19 | /// The module for the Merkle tree implementation 20 | pub mod merkle_tree; 21 | 22 | /// The module for error handling 23 | pub mod errors; 24 | -------------------------------------------------------------------------------- /accumulators/tests/merkle_tree.rs: -------------------------------------------------------------------------------- 1 | use mem_db::MemoryDB; 2 | use noah_accumulators::merkle_tree::{verify, PersistentMerkleTree, TREE_DEPTH}; 3 | use noah_algebra::{bn254::BN254Scalar, prelude::*}; 4 | use parking_lot::RwLock; 5 | use std::sync::Arc; 6 | use std::time::Instant; 7 | use storage::state::{ChainState, State}; 8 | use storage::store::PrefixedStore; 9 | 10 | #[test] 11 | fn test_merkle_tree() { 12 | let fdb = MemoryDB::new(); 13 | let ver_window = 100; 14 | let cs = Arc::new(RwLock::new(ChainState::new( 15 | fdb, 16 | "test_db".to_string(), 17 | ver_window, 18 | ))); 19 | let mut state = State::new(cs, false); 20 | let store = PrefixedStore::new("my_store", &mut state); 21 | let mut mt = PersistentMerkleTree::new(store).unwrap(); 22 | assert_eq!(0, mt.version()); 23 | 24 | let start = Instant::now(); 25 | for _ in 0..10 { 26 | let sid_0 = mt.add_commitment_hash(BN254Scalar::one()).unwrap(); 27 | let proof0 = mt.generate_proof(sid_0).unwrap(); 28 | assert_eq!(proof0.uid, sid_0); 29 | assert!(verify(BN254Scalar::one(), &proof0)); 30 | } 31 | let end = start.elapsed(); 32 | println!("Time: {:?} microseconds", end.as_micros()); 33 | let v1 = mt.commit().unwrap(); 34 | let root1 = mt.get_root().unwrap(); 35 | assert_eq!(v1, mt.version()); 36 | assert_eq!(1, v1); 37 | 38 | let sid_x = mt.add_commitment_hash(BN254Scalar::one()).unwrap(); 39 | let proofx = mt.generate_proof_with_depth(sid_x, TREE_DEPTH).unwrap(); 40 | 41 | assert!(verify(BN254Scalar::one(), &proofx)); 42 | assert!(mt.generate_proof_with_depth(sid_x, 31).is_err()); 43 | assert!(mt.generate_proof_with_depth(sid_x, 2).is_err()); 44 | assert_eq!( 45 | mt.get_root_with_depth_and_version(TREE_DEPTH, v1).unwrap(), 46 | root1 47 | ); 48 | } 49 | -------------------------------------------------------------------------------- /algebra/Cargo.toml: -------------------------------------------------------------------------------- 1 | [[bench]] 2 | name = 'msm' 3 | path = 'benches/msm.rs' 4 | harness = false 5 | 6 | [package] 7 | name = 'noah-algebra' 8 | description = 'Noah algebra library' 9 | version = '0.5.0' 10 | authors = ['Findora '] 11 | edition = '2021' 12 | 13 | [lib] 14 | name = 'noah_algebra' 15 | crate-type = ['rlib'] 16 | 17 | [dependencies] 18 | base64 = "0.21" 19 | digest = '0.10' 20 | itertools = '0.12.0' 21 | serde = '1.0' 22 | serde_derive = '1.0' 23 | rayon = { version = "1", optional = true } 24 | 25 | [target.'cfg(target_arch = "wasm32")'.dependencies] 26 | js-sys = "0.3.27" 27 | web-sys = { version = "0.3.61", features = [ "console" ] } 28 | wasm-bindgen-futures = "0.4.23" 29 | wasm-rs-async-executor = "0.9.0" 30 | wasm-bindgen-test = { version = "^0.3" } 31 | 32 | [dependencies.curve25519-dalek] 33 | package = "noah-curve25519-dalek" 34 | version = "4.0.0" 35 | default-features = false 36 | features = ['serde'] 37 | 38 | [dependencies.x25519-dalek] 39 | package = "noah-x25519-dalek" 40 | version = "4.0.0" 41 | default-features = false 42 | 43 | [dependencies.bulletproofs] 44 | package = "noah-bulletproofs" 45 | version = "4.1.0" 46 | 47 | [dependencies.ark-ec] 48 | version = '0.4.0' 49 | default-features = false 50 | 51 | [dependencies.ark-ff] 52 | version = '0.4.0' 53 | default-features = false 54 | features = ['asm'] 55 | 56 | [dependencies.ark-std] 57 | version = '0.4.0' 58 | default-features = false 59 | 60 | [dependencies.ark-serialize] 61 | version = '0.4.0' 62 | default-features = false 63 | 64 | [dependencies.ark-ed-on-bls12-381] 65 | version = '0.4.0' 66 | default-features = false 67 | 68 | [dependencies.ark-bls12-381] 69 | version = '0.4.0' 70 | default-features = false 71 | features = ['curve'] 72 | 73 | [dependencies.ark-ed-on-bn254] 74 | package = "ark-ed-on-bn254-mixed-radix" 75 | git = "https://github.com/FindoraNetwork/ark-ed-on-bn254-mixed-radix" 76 | tag = "v0.4.1" 77 | default-features = false 78 | 79 | [dependencies.ark-bn254] 80 | package = "ark-bn254-mixed-radix" 81 | git = "https://github.com/FindoraNetwork/ark-bn254-mixed-radix" 82 | tag = "v0.4.1" 83 | default-features = false 84 | features = ['curve'] 85 | 86 | [dependencies.ark-secp256k1] 87 | version = '0.4.0' 88 | default-features = false 89 | 90 | [dependencies.ark-secq256k1] 91 | version = '0.4.0' 92 | default-features = false 93 | 94 | [dependencies.ark-ed25519] 95 | version = '0.4.0' 96 | default-features = false 97 | 98 | [dependencies.ark-bulletproofs] 99 | version = '4.1.0' 100 | default-features = false 101 | features = ['yoloproofs'] 102 | 103 | [dependencies.byteorder] 104 | version = '^1.2.3' 105 | default-features = false 106 | features = ['i128'] 107 | 108 | [dependencies.rand_chacha] 109 | version = '0.3' 110 | default-features = false 111 | 112 | [dependencies.wasm-bindgen] 113 | version = '0.2.50' 114 | features = ['serde-serialize'] 115 | 116 | [dependencies.num-bigint] 117 | version = '0.4' 118 | 119 | [dependencies.num-traits] 120 | version = "0.2" 121 | 122 | [dependencies.num-integer] 123 | version = "0.1" 124 | 125 | [features] 126 | default = [ 127 | 'std', 128 | 'u64_backend', 129 | ] 130 | std = [ 131 | 'curve25519-dalek/std', 132 | 'bulletproofs/std', 133 | 'ark-bulletproofs/std', 134 | 'ark-ed-on-bls12-381/std', 135 | 'ark-bls12-381/std', 136 | 'ark-secp256k1/std', 137 | 'ark-secq256k1/std', 138 | 'ark-ed25519/std', 139 | 'ark-ec/std', 140 | 'ark-std/std', 141 | 'ark-ff/std', 142 | 'ark-serialize/std' 143 | ] 144 | alloc = ['curve25519-dalek/alloc'] 145 | nightly = ['curve25519-dalek/nightly'] 146 | u64_backend = ['curve25519-dalek/u64_backend'] 147 | u32_backend = ['curve25519-dalek/u32_backend'] 148 | avx2_backend = ['curve25519-dalek/avx2_backend'] 149 | parallel = [ 150 | 'rayon', 151 | 'ark-std/parallel', 152 | 'ark-ec/parallel', 153 | 'ark-ff/parallel', 154 | 'ark-bulletproofs/parallel' 155 | ] 156 | asm = ['ark-ff/asm'] 157 | print-trace = ['ark-std/print-trace'] 158 | -------------------------------------------------------------------------------- /algebra/benches/msm.rs: -------------------------------------------------------------------------------- 1 | use ark_std::time::Instant; 2 | use noah_algebra::bn254::BN254G1; 3 | use noah_algebra::{bn254::BN254Scalar, prelude::*}; 4 | 5 | fn main() { 6 | let mut prng = test_rng(); 7 | 8 | let count = 65536; 9 | 10 | // Sample random points 11 | let mut points = Vec::new(); 12 | for _ in 0..count { 13 | points.push(BN254G1::random(&mut prng)); 14 | } 15 | 16 | // Sample random scalars 17 | let mut scalars = Vec::new(); 18 | for _ in 0..count { 19 | scalars.push(BN254Scalar::random(&mut prng)); 20 | } 21 | 22 | let points_ptr = points.iter().collect::>(); 23 | let scalars_ptr = scalars.iter().collect::>(); 24 | 25 | let start = Instant::now(); 26 | for _ in 0..10 { 27 | let _ = BN254G1::multi_exp(&scalars_ptr, &points_ptr); 28 | } 29 | println!("average time: {} s", start.elapsed().as_secs_f32() / 10f32); 30 | } 31 | -------------------------------------------------------------------------------- /algebra/src/baby_jubjub/fq.rs: -------------------------------------------------------------------------------- 1 | /// The wrapped struct for `ark_ed_on_bn254::Fq` 2 | pub type BabyJubjubFq = crate::bn254::BN254Scalar; 3 | -------------------------------------------------------------------------------- /algebra/src/baby_jubjub/mod.rs: -------------------------------------------------------------------------------- 1 | /// The number of bytes for a scalar value over Jubjub 2 | pub const BABY_JUBJUB_SCALAR_LEN: usize = 32; 3 | 4 | mod fr; 5 | pub use fr::*; 6 | 7 | mod fq; 8 | pub use fq::*; 9 | 10 | mod g1; 11 | pub use g1::*; 12 | 13 | #[cfg(test)] 14 | mod baby_jubjub_groups_test { 15 | use crate::{ 16 | baby_jubjub::{BabyJubjubPoint, BabyJubjubScalar}, 17 | prelude::*, 18 | traits::group_tests::{test_scalar_operations, test_scalar_serialization}, 19 | }; 20 | use rand_chacha::ChaCha20Rng; 21 | 22 | #[test] 23 | fn test_scalar_ops() { 24 | test_scalar_operations::(); 25 | } 26 | 27 | #[test] 28 | fn scalar_deser() { 29 | test_scalar_serialization::(); 30 | } 31 | 32 | #[test] 33 | fn scalar_from_to_bytes() { 34 | let small_value = BabyJubjubScalar::from(165747u32); 35 | let small_value_bytes = small_value.to_bytes(); 36 | let expected_small_value_bytes: [u8; 32] = [ 37 | 115, 135, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38 | 0, 0, 0, 0, 39 | ]; 40 | assert_eq!(small_value_bytes, expected_small_value_bytes); 41 | 42 | let small_value_from_bytes = BabyJubjubScalar::from_bytes(&small_value_bytes).unwrap(); 43 | assert_eq!(small_value_from_bytes, small_value); 44 | } 45 | 46 | #[test] 47 | fn schnorr_identification_protocol() { 48 | let mut rng = ChaCha20Rng::from_entropy(); 49 | 50 | // Private key 51 | let alpha = BabyJubjubScalar::random(&mut rng); 52 | 53 | // Public key 54 | let base = BabyJubjubPoint::get_base(); 55 | let u = base.mul(&alpha); 56 | 57 | // Verifier challenge 58 | let c = BabyJubjubScalar::random(&mut rng); 59 | 60 | // Prover commitment 61 | let alpha_t = BabyJubjubScalar::random(&mut rng); 62 | let u_t = base.mul(&alpha_t); 63 | 64 | // Prover response 65 | let alpha_z = alpha_t.add(&c.mul(&alpha)); 66 | 67 | // Proof verification 68 | let left = base.mul(&alpha_z); 69 | let right = u_t.add(&u.mul(&c)); 70 | 71 | assert_eq!(left, right); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /algebra/src/bls12_381/fastmsm.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FindoraNetwork/noah/f13d3595dcac5b7e63afdf1f4a0b0c89b16688ba/algebra/src/bls12_381/fastmsm.wasm -------------------------------------------------------------------------------- /algebra/src/bls12_381/g2.rs: -------------------------------------------------------------------------------- 1 | use crate::bls12_381::BLSScalar; 2 | use crate::prelude::*; 3 | use ark_bls12_381::{G2Affine, G2Projective}; 4 | use ark_ec::{AffineRepr, CurveGroup as ArkCurveGroup, Group as ArkGroup}; 5 | use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Compress, Validate}; 6 | use ark_std::{ 7 | fmt::{Debug, Display, Formatter}, 8 | vec::Vec, 9 | }; 10 | use digest::{consts::U64, Digest}; 11 | use wasm_bindgen::prelude::*; 12 | 13 | /// The wrapped struct for `ark_bls12_381::G2Projective` 14 | #[wasm_bindgen] 15 | #[derive(Copy, Default, Clone, PartialEq, Eq)] 16 | pub struct BLSG2(pub(crate) G2Projective); 17 | 18 | impl Debug for BLSG2 { 19 | fn fmt(&self, f: &mut Formatter<'_>) -> ark_std::fmt::Result { 20 | ::fmt(&self.0.into_affine(), f) 21 | } 22 | } 23 | 24 | impl Group for BLSG2 { 25 | type ScalarType = BLSScalar; 26 | const COMPRESSED_LEN: usize = 96; 27 | const UNCOMPRESSED_LEN: usize = 192; 28 | 29 | #[inline] 30 | fn double(&self) -> Self { 31 | Self(self.0.double()) 32 | } 33 | 34 | #[inline] 35 | fn get_identity() -> Self { 36 | Self(G2Projective::zero()) 37 | } 38 | 39 | #[inline] 40 | fn get_base() -> Self { 41 | Self(G2Projective::generator()) 42 | } 43 | 44 | #[inline] 45 | fn random(prng: &mut R) -> Self { 46 | Self(G2Projective::rand(prng)) 47 | } 48 | 49 | #[inline] 50 | fn to_compressed_bytes(&self) -> Vec { 51 | let mut buf = Vec::new(); 52 | self.0.serialize_with_mode(&mut buf, Compress::Yes).unwrap(); 53 | 54 | buf 55 | } 56 | 57 | #[inline] 58 | fn to_unchecked_bytes(&self) -> Vec { 59 | let affine = G2Affine::from(self.0); 60 | let mut buf = Vec::new(); 61 | affine.serialize_with_mode(&mut buf, Compress::No).unwrap(); 62 | 63 | buf 64 | } 65 | 66 | #[inline] 67 | fn from_compressed_bytes(bytes: &[u8]) -> Result { 68 | let affine = G2Affine::deserialize_with_mode(bytes, Compress::Yes, Validate::Yes) 69 | .map_err(|_| AlgebraError::DeserializationError)?; 70 | 71 | Ok(Self(affine.into_group())) 72 | } 73 | 74 | #[inline] 75 | fn from_unchecked_bytes(bytes: &[u8]) -> Result { 76 | let affine = G2Affine::deserialize_with_mode(bytes, Compress::No, Validate::No) 77 | .map_err(|_| AlgebraError::DeserializationError)?; 78 | 79 | Ok(Self(affine.into_group())) 80 | } 81 | 82 | #[inline] 83 | fn unchecked_size() -> usize { 84 | G2Affine::default().serialized_size(Compress::No) 85 | } 86 | 87 | #[inline] 88 | fn from_hash(hash: D) -> Self 89 | where 90 | D: Digest + Default, 91 | { 92 | let mut prng = derive_prng_from_hash::(hash); 93 | Self(G2Projective::rand(&mut prng)) 94 | } 95 | } 96 | 97 | impl Neg for BLSG2 { 98 | type Output = Self; 99 | 100 | fn neg(self) -> Self::Output { 101 | Self(self.0.neg()) 102 | } 103 | } 104 | 105 | impl<'a> Add<&'a BLSG2> for BLSG2 { 106 | type Output = BLSG2; 107 | 108 | #[inline] 109 | fn add(self, rhs: &'a Self) -> Self::Output { 110 | Self(self.0.add(&rhs.0)) 111 | } 112 | } 113 | 114 | impl<'a> Sub<&'a BLSG2> for BLSG2 { 115 | type Output = BLSG2; 116 | 117 | #[inline] 118 | fn sub(self, rhs: &'a Self) -> Self::Output { 119 | Self(self.0.sub(&rhs.0)) 120 | } 121 | } 122 | 123 | impl<'a> Mul<&'a BLSScalar> for BLSG2 { 124 | type Output = BLSG2; 125 | 126 | #[inline] 127 | fn mul(self, rhs: &'a BLSScalar) -> Self::Output { 128 | Self(self.0.mul(&rhs.0)) 129 | } 130 | } 131 | 132 | impl<'a> AddAssign<&'a BLSG2> for BLSG2 { 133 | #[inline] 134 | fn add_assign(&mut self, rhs: &BLSG2) { 135 | self.0.add_assign(&rhs.0) 136 | } 137 | } 138 | 139 | impl<'a> SubAssign<&'a BLSG2> for BLSG2 { 140 | #[inline] 141 | fn sub_assign(&mut self, rhs: &BLSG2) { 142 | self.0.sub_assign(&rhs.0) 143 | } 144 | } 145 | 146 | impl<'a> MulAssign<&'a BLSScalar> for BLSG2 { 147 | #[inline] 148 | fn mul_assign(&mut self, rhs: &'a BLSScalar) { 149 | self.0.mul_assign(rhs.0) 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /algebra/src/bls12_381/gt.rs: -------------------------------------------------------------------------------- 1 | use crate::bls12_381::{BLSPairingEngine, BLSScalar, BLSG1, BLSG2}; 2 | use crate::prelude::*; 3 | use crate::traits::Pairing; 4 | use ark_bls12_381::{Bls12_381, Fq12Config}; 5 | use ark_ec::pairing::PairingOutput; 6 | use ark_ff::{BigInteger, Fp12, PrimeField}; 7 | use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Compress, Validate}; 8 | use ark_std::{vec::Vec, UniformRand}; 9 | use digest::{consts::U64, Digest}; 10 | use wasm_bindgen::prelude::*; 11 | 12 | /// The wrapped struct for [`Fp12`](https://docs.rs/ark-bls12-381/0.3.0/ark_bls12_381/fq12/struct.Fq12Parameters.html), 13 | /// which is the pairing result 14 | #[wasm_bindgen] 15 | #[derive(Copy, Default, Clone, PartialEq, Eq, Debug)] 16 | pub struct BLSGt(pub(crate) Fp12); 17 | 18 | impl Neg for BLSGt { 19 | type Output = Self; 20 | 21 | fn neg(self) -> Self::Output { 22 | let mut v = self.0; 23 | v.conjugate_in_place(); 24 | Self(v) 25 | } 26 | } 27 | 28 | impl<'a> Add<&'a BLSGt> for BLSGt { 29 | type Output = BLSGt; 30 | 31 | #[inline] 32 | fn add(self, rhs: &'a BLSGt) -> Self::Output { 33 | Self(self.0.mul(&rhs.0)) 34 | } 35 | } 36 | 37 | impl<'a> Sub<&'a BLSGt> for BLSGt { 38 | type Output = BLSGt; 39 | 40 | #[inline] 41 | fn sub(self, rhs: &'a BLSGt) -> Self::Output { 42 | let mut rhs_inverse = rhs.0; 43 | rhs_inverse.conjugate_in_place(); 44 | 45 | Self(self.0.mul(&rhs_inverse)) 46 | } 47 | } 48 | 49 | impl<'a> Mul<&'a BLSScalar> for BLSGt { 50 | type Output = BLSGt; 51 | 52 | fn mul(self, rhs: &'a BLSScalar) -> Self::Output { 53 | let mut acc = Self::get_identity(); 54 | 55 | // This is a simple double-and-add implementation of group element 56 | // multiplication, moving from most significant to least 57 | // significant bit of the scalar. 58 | // 59 | // We skip the leading bit because it's always unset for Fq 60 | // elements. 61 | for bit in rhs 62 | .0 63 | .into_bigint() 64 | .to_bytes_le() 65 | .iter() 66 | .rev() 67 | .flat_map(|byte| (0..8).rev().map(move |i| ((byte >> i) & 1u8) == 1u8)) 68 | .skip(1) 69 | { 70 | acc = acc.double(); 71 | if bit { 72 | acc = acc.add(&self) 73 | } 74 | } 75 | 76 | acc 77 | } 78 | } 79 | 80 | impl<'a> AddAssign<&'a BLSGt> for BLSGt { 81 | #[inline] 82 | fn add_assign(&mut self, rhs: &'a BLSGt) { 83 | self.0.mul_assign(&rhs.0) 84 | } 85 | } 86 | 87 | impl<'a> SubAssign<&'a BLSGt> for BLSGt { 88 | #[inline] 89 | fn sub_assign(&mut self, rhs: &'a BLSGt) { 90 | let mut rhs_inverse = rhs.0; 91 | rhs_inverse.conjugate_in_place(); 92 | 93 | self.0.mul_assign(&rhs_inverse) 94 | } 95 | } 96 | 97 | impl<'a> MulAssign<&'a BLSScalar> for BLSGt { 98 | #[inline] 99 | fn mul_assign(&mut self, rhs: &'a BLSScalar) { 100 | *self = self.mul(rhs); 101 | } 102 | } 103 | 104 | impl Group for BLSGt { 105 | type ScalarType = BLSScalar; 106 | 107 | const COMPRESSED_LEN: usize = 576; 108 | const UNCOMPRESSED_LEN: usize = 576; 109 | 110 | #[inline] 111 | fn double(&self) -> Self { 112 | Self(self.0.mul(&self.0)) 113 | } 114 | 115 | #[inline] 116 | fn get_identity() -> Self { 117 | Self(Fp12::::one()) 118 | } 119 | 120 | #[inline] 121 | fn get_base() -> Self { 122 | BLSPairingEngine::pairing(&BLSG1::get_base(), &BLSG2::get_base()) 123 | } 124 | 125 | #[inline] 126 | fn random(prng: &mut R) -> Self { 127 | let g: PairingOutput = prng.gen(); 128 | Self(g.0) 129 | } 130 | 131 | #[inline] 132 | fn to_compressed_bytes(&self) -> Vec { 133 | let mut buf = Vec::new(); 134 | self.0.serialize_with_mode(&mut buf, Compress::Yes).unwrap(); 135 | 136 | buf 137 | } 138 | 139 | #[inline] 140 | fn to_unchecked_bytes(&self) -> Vec { 141 | let mut buf = Vec::new(); 142 | self.0.serialize_with_mode(&mut buf, Compress::No).unwrap(); 143 | 144 | buf 145 | } 146 | 147 | #[inline] 148 | fn from_compressed_bytes(bytes: &[u8]) -> Result { 149 | let res = Fp12::::deserialize_with_mode(bytes, Compress::Yes, Validate::Yes) 150 | .map_err(|_| AlgebraError::DeserializationError)?; 151 | 152 | Ok(Self(res)) 153 | } 154 | 155 | #[inline] 156 | fn from_unchecked_bytes(bytes: &[u8]) -> Result { 157 | let res = Fp12::::deserialize_with_mode(bytes, Compress::No, Validate::No) 158 | .map_err(|_| AlgebraError::DeserializationError)?; 159 | 160 | Ok(Self(res)) 161 | } 162 | 163 | #[inline] 164 | fn unchecked_size() -> usize { 165 | let g = Self::get_base().0; 166 | g.serialized_size(Compress::No) 167 | } 168 | 169 | #[inline] 170 | fn from_hash(hash: D) -> Self 171 | where 172 | D: Digest + Default, 173 | { 174 | let mut prng = derive_prng_from_hash::(hash); 175 | Self(Fp12::::rand(&mut prng)) 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /algebra/src/bls12_381/pairing.rs: -------------------------------------------------------------------------------- 1 | use crate::bls12_381::g2::BLSG2; 2 | use crate::bls12_381::gt::BLSGt; 3 | use crate::bls12_381::{BLSScalar, BLSG1}; 4 | use crate::traits::Pairing; 5 | use ark_bls12_381::Bls12_381 as Bls12381pairing; 6 | use ark_ec::{ 7 | bls12::{G1Prepared, G2Prepared}, 8 | pairing::Pairing as ArkPairing, 9 | CurveGroup, 10 | }; 11 | use ark_std::vec::Vec; 12 | 13 | /// The pairing engine for BLS12-381 14 | pub struct BLSPairingEngine; 15 | 16 | impl Pairing for BLSPairingEngine { 17 | type ScalarField = BLSScalar; 18 | type G1 = BLSG1; 19 | type G2 = BLSG2; 20 | type Gt = BLSGt; 21 | 22 | #[inline] 23 | fn pairing(a: &Self::G1, b: &Self::G2) -> Self::Gt { 24 | BLSGt(Bls12381pairing::pairing(a.0, b.0).0) 25 | } 26 | 27 | #[inline] 28 | fn product_of_pairings(a: &[Self::G1], b: &[Self::G2]) -> Self::Gt { 29 | let c1: Vec> = a.iter().map(|x| x.0.into_affine().into()).collect(); 30 | let c2: Vec> = b.iter().map(|x| x.0.into_affine().into()).collect(); 31 | BLSGt(Bls12381pairing::multi_pairing(c1, c2).0) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /algebra/src/bn254/g1.rs: -------------------------------------------------------------------------------- 1 | use crate::bn254::{BN254Fq, BN254Scalar}; 2 | use crate::prelude::*; 3 | use ark_bn254::{Fq, G1Affine, G1Projective}; 4 | use ark_ec::{CurveGroup, Group as ArkGroup}; 5 | use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Compress, Validate}; 6 | use ark_std::{ 7 | fmt::{Debug, Display, Formatter}, 8 | vec::Vec, 9 | }; 10 | use digest::{consts::U64, Digest}; 11 | use wasm_bindgen::prelude::*; 12 | 13 | /// The wrapped struct for ark_bn254::G1Projective 14 | #[wasm_bindgen] 15 | #[derive(Copy, Default, Clone, PartialEq, Eq)] 16 | pub struct BN254G1(pub(crate) G1Projective); 17 | 18 | impl Debug for BN254G1 { 19 | fn fmt(&self, f: &mut Formatter<'_>) -> ark_std::fmt::Result { 20 | ::fmt(&self.0.into_affine(), f) 21 | } 22 | } 23 | 24 | impl Group for BN254G1 { 25 | type ScalarType = BN254Scalar; 26 | const COMPRESSED_LEN: usize = 32; 27 | const UNCOMPRESSED_LEN: usize = 64; 28 | 29 | #[inline] 30 | fn double(&self) -> Self { 31 | Self(self.0.double()) 32 | } 33 | 34 | #[inline] 35 | fn get_identity() -> Self { 36 | Self(G1Projective::zero()) 37 | } 38 | 39 | #[inline] 40 | fn get_base() -> Self { 41 | Self(G1Projective::generator()) 42 | } 43 | 44 | #[inline] 45 | fn random(prng: &mut R) -> Self { 46 | Self(G1Projective::rand(prng)) 47 | } 48 | 49 | #[inline] 50 | fn to_compressed_bytes(&self) -> Vec { 51 | let affine = G1Affine::from(self.0); 52 | let mut buf = Vec::new(); 53 | affine.serialize_with_mode(&mut buf, Compress::Yes).unwrap(); 54 | 55 | buf 56 | } 57 | 58 | #[inline] 59 | fn to_unchecked_bytes(&self) -> Vec { 60 | let affine = G1Affine::from(self.0); 61 | let mut buf = Vec::new(); 62 | affine.serialize_with_mode(&mut buf, Compress::No).unwrap(); 63 | 64 | buf 65 | } 66 | 67 | #[inline] 68 | fn from_compressed_bytes(bytes: &[u8]) -> Result { 69 | let affine = G1Affine::deserialize_with_mode(bytes, Compress::Yes, Validate::Yes) 70 | .map_err(|_| AlgebraError::DeserializationError)?; 71 | 72 | Ok(Self(G1Projective::from(affine))) 73 | } 74 | 75 | #[inline] 76 | fn from_unchecked_bytes(bytes: &[u8]) -> Result { 77 | let affine = G1Affine::deserialize_with_mode(bytes, Compress::No, Validate::No) 78 | .map_err(|_| AlgebraError::DeserializationError)?; 79 | 80 | Ok(Self(G1Projective::from(affine))) 81 | } 82 | 83 | #[inline] 84 | fn unchecked_size() -> usize { 85 | G1Affine::default().serialized_size(Compress::No) 86 | } 87 | 88 | #[inline] 89 | fn from_hash(hash: D) -> Self 90 | where 91 | D: Digest + Default, 92 | { 93 | let mut prng = derive_prng_from_hash::(hash); 94 | Self(G1Projective::rand(&mut prng)) 95 | } 96 | 97 | #[inline] 98 | fn multi_exp(scalars: &[&Self::ScalarType], points: &[&Self]) -> Self { 99 | Self::common_multi_exp(scalars, points) 100 | } 101 | } 102 | 103 | impl<'a> Add<&'a BN254G1> for BN254G1 { 104 | type Output = BN254G1; 105 | 106 | #[inline] 107 | fn add(self, rhs: &Self) -> Self::Output { 108 | Self(self.0.add(&rhs.0)) 109 | } 110 | } 111 | 112 | impl<'a> Sub<&'a BN254G1> for BN254G1 { 113 | type Output = BN254G1; 114 | 115 | #[inline] 116 | fn sub(self, rhs: &Self) -> Self::Output { 117 | Self(self.0.sub(&rhs.0)) 118 | } 119 | } 120 | 121 | impl<'a> Mul<&'a BN254Scalar> for BN254G1 { 122 | type Output = BN254G1; 123 | 124 | #[inline] 125 | fn mul(self, rhs: &BN254Scalar) -> Self::Output { 126 | Self(self.0.mul(&rhs.0)) 127 | } 128 | } 129 | 130 | impl<'a> AddAssign<&'a BN254G1> for BN254G1 { 131 | #[inline] 132 | fn add_assign(&mut self, rhs: &'a BN254G1) { 133 | self.0.add_assign(&rhs.0) 134 | } 135 | } 136 | 137 | impl<'a> SubAssign<&'a BN254G1> for BN254G1 { 138 | #[inline] 139 | fn sub_assign(&mut self, rhs: &'a BN254G1) { 140 | self.0.sub_assign(&rhs.0) 141 | } 142 | } 143 | 144 | impl<'a> MulAssign<&'a BN254Scalar> for BN254G1 { 145 | #[inline] 146 | fn mul_assign(&mut self, rhs: &'a BN254Scalar) { 147 | self.0.mul_assign(rhs.0) 148 | } 149 | } 150 | 151 | impl Neg for BN254G1 { 152 | type Output = Self; 153 | 154 | fn neg(self) -> Self::Output { 155 | Self(self.0.neg()) 156 | } 157 | } 158 | 159 | impl BN254G1 { 160 | /// Get the x-coordinate of the BN254 affine point. 161 | #[inline] 162 | pub fn get_x(&self) -> BN254Fq { 163 | BN254Fq(self.0.x) 164 | } 165 | /// Get the y-coordinate of the BN254 affine point. 166 | #[inline] 167 | pub fn get_y(&self) -> BN254Fq { 168 | BN254Fq(self.0.y) 169 | } 170 | /// Construct from the x-coordinate and y-coordinate 171 | pub fn from_xy(x: BN254Fq, y: BN254Fq) -> Self { 172 | if x.is_zero() && y.is_zero() { 173 | Self(G1Projective::zero()) 174 | } else { 175 | Self(G1Projective::new(x.0, y.0, Fq::one())) 176 | } 177 | } 178 | 179 | #[inline] 180 | fn common_multi_exp(scalars: &[&::ScalarType], points: &[&Self]) -> Self { 181 | use ark_ec::VariableBaseMSM; 182 | 183 | let scalars_raw: Vec<_> = scalars.iter().map(|r| r.0).collect(); 184 | let points_raw = G1Projective::normalize_batch( 185 | &points.iter().map(|r| r.0).collect::>(), 186 | ); 187 | 188 | Self(G1Projective::msm(&points_raw, scalars_raw.as_ref()).unwrap()) 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /algebra/src/bn254/g2.rs: -------------------------------------------------------------------------------- 1 | use crate::bn254::BN254Scalar; 2 | use crate::prelude::*; 3 | use ark_bn254::{G2Affine, G2Projective}; 4 | use ark_ec::{AffineRepr, CurveGroup as ArkCurveGroup, Group as ArkGroup}; 5 | use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Compress, Validate}; 6 | use ark_std::{ 7 | fmt::{Debug, Display, Formatter}, 8 | vec::Vec, 9 | }; 10 | use digest::{consts::U64, Digest}; 11 | use wasm_bindgen::prelude::*; 12 | 13 | /// The wrapped struct for `ark_bn254::G2Projective` 14 | #[wasm_bindgen] 15 | #[derive(Copy, Default, Clone, PartialEq, Eq)] 16 | pub struct BN254G2(pub(crate) G2Projective); 17 | 18 | impl Debug for BN254G2 { 19 | fn fmt(&self, f: &mut Formatter<'_>) -> ark_std::fmt::Result { 20 | ::fmt(&self.0.into_affine(), f) 21 | } 22 | } 23 | 24 | impl Group for BN254G2 { 25 | type ScalarType = BN254Scalar; 26 | const COMPRESSED_LEN: usize = 64; 27 | const UNCOMPRESSED_LEN: usize = 128; 28 | 29 | #[inline] 30 | fn double(&self) -> Self { 31 | Self(self.0.double()) 32 | } 33 | 34 | #[inline] 35 | fn get_identity() -> Self { 36 | Self(G2Projective::zero()) 37 | } 38 | 39 | #[inline] 40 | fn get_base() -> Self { 41 | Self(G2Projective::generator()) 42 | } 43 | 44 | #[inline] 45 | fn random(prng: &mut R) -> Self { 46 | Self(G2Projective::rand(prng)) 47 | } 48 | 49 | #[inline] 50 | fn to_compressed_bytes(&self) -> Vec { 51 | let mut buf = Vec::new(); 52 | self.0.serialize_with_mode(&mut buf, Compress::Yes).unwrap(); 53 | 54 | buf 55 | } 56 | 57 | #[inline] 58 | fn to_unchecked_bytes(&self) -> Vec { 59 | let affine = G2Affine::from(self.0); 60 | let mut buf = Vec::new(); 61 | affine.serialize_with_mode(&mut buf, Compress::No).unwrap(); 62 | 63 | buf 64 | } 65 | 66 | #[inline] 67 | fn from_compressed_bytes(bytes: &[u8]) -> Result { 68 | let affine = G2Affine::deserialize_with_mode(bytes, Compress::Yes, Validate::Yes) 69 | .map_err(|_| AlgebraError::DeserializationError)?; 70 | 71 | Ok(Self(affine.into_group())) 72 | } 73 | 74 | #[inline] 75 | fn from_unchecked_bytes(bytes: &[u8]) -> Result { 76 | let affine = G2Affine::deserialize_with_mode(bytes, Compress::No, Validate::No) 77 | .map_err(|_| AlgebraError::DeserializationError)?; 78 | 79 | Ok(Self(affine.into_group())) 80 | } 81 | 82 | #[inline] 83 | fn unchecked_size() -> usize { 84 | G2Affine::default().serialized_size(Compress::No) 85 | } 86 | 87 | #[inline] 88 | fn from_hash(hash: D) -> Self 89 | where 90 | D: Digest + Default, 91 | { 92 | let mut prng = derive_prng_from_hash::(hash); 93 | Self(G2Projective::rand(&mut prng)) 94 | } 95 | } 96 | 97 | impl Neg for BN254G2 { 98 | type Output = Self; 99 | 100 | fn neg(self) -> Self::Output { 101 | Self(self.0.neg()) 102 | } 103 | } 104 | 105 | impl<'a> Add<&'a BN254G2> for BN254G2 { 106 | type Output = BN254G2; 107 | 108 | #[inline] 109 | fn add(self, rhs: &'a Self) -> Self::Output { 110 | Self(self.0.add(&rhs.0)) 111 | } 112 | } 113 | 114 | impl<'a> Sub<&'a BN254G2> for BN254G2 { 115 | type Output = BN254G2; 116 | 117 | #[inline] 118 | fn sub(self, rhs: &'a Self) -> Self::Output { 119 | Self(self.0.sub(&rhs.0)) 120 | } 121 | } 122 | 123 | impl<'a> Mul<&'a BN254Scalar> for BN254G2 { 124 | type Output = BN254G2; 125 | 126 | #[inline] 127 | fn mul(self, rhs: &'a BN254Scalar) -> Self::Output { 128 | Self(self.0.mul(&rhs.0)) 129 | } 130 | } 131 | 132 | impl<'a> AddAssign<&'a BN254G2> for BN254G2 { 133 | #[inline] 134 | fn add_assign(&mut self, rhs: &BN254G2) { 135 | self.0.add_assign(&rhs.0) 136 | } 137 | } 138 | 139 | impl<'a> SubAssign<&'a BN254G2> for BN254G2 { 140 | #[inline] 141 | fn sub_assign(&mut self, rhs: &BN254G2) { 142 | self.0.sub_assign(&rhs.0) 143 | } 144 | } 145 | 146 | impl<'a> MulAssign<&'a BN254Scalar> for BN254G2 { 147 | #[inline] 148 | fn mul_assign(&mut self, rhs: &'a BN254Scalar) { 149 | self.0.mul_assign(rhs.0) 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /algebra/src/bn254/gt.rs: -------------------------------------------------------------------------------- 1 | use crate::bn254::{BN254PairingEngine, BN254Scalar, BN254G1, BN254G2}; 2 | use crate::prelude::*; 3 | use crate::traits::Pairing; 4 | use ark_bn254::{Bn254, Fq12Config}; 5 | use ark_ec::pairing::PairingOutput; 6 | use ark_ff::{BigInteger, Fp12, PrimeField}; 7 | use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Compress, Validate}; 8 | use ark_std::{vec::Vec, UniformRand}; 9 | use digest::{consts::U64, Digest}; 10 | use wasm_bindgen::prelude::*; 11 | 12 | /// The wrapped struct for [`Fp12`](https://docs.rs/ark-bn254/0.3.0/ark_bn254/fq12/struct.Fq12Parameters.html), 13 | /// which is the pairing result 14 | #[wasm_bindgen] 15 | #[derive(Copy, Default, Clone, PartialEq, Eq, Debug)] 16 | pub struct BN254Gt(pub(crate) Fp12); 17 | 18 | impl Neg for BN254Gt { 19 | type Output = Self; 20 | 21 | fn neg(self) -> Self::Output { 22 | let mut v = self.0; 23 | v.conjugate_in_place(); 24 | Self(v) 25 | } 26 | } 27 | 28 | impl<'a> Add<&'a BN254Gt> for BN254Gt { 29 | type Output = BN254Gt; 30 | 31 | #[inline] 32 | fn add(self, rhs: &'a BN254Gt) -> Self::Output { 33 | Self(self.0.mul(&rhs.0)) 34 | } 35 | } 36 | 37 | impl<'a> Sub<&'a BN254Gt> for BN254Gt { 38 | type Output = BN254Gt; 39 | 40 | #[inline] 41 | fn sub(self, rhs: &'a BN254Gt) -> Self::Output { 42 | let mut rhs_inverse = rhs.0; 43 | rhs_inverse.conjugate_in_place(); 44 | 45 | Self(self.0.mul(&rhs_inverse)) 46 | } 47 | } 48 | 49 | impl<'a> MulAssign<&'a BN254Scalar> for BN254Gt { 50 | #[inline] 51 | fn mul_assign(&mut self, rhs: &'a BN254Scalar) { 52 | *self = self.mul(rhs) 53 | } 54 | } 55 | 56 | impl<'a> Mul<&'a BN254Scalar> for BN254Gt { 57 | type Output = BN254Gt; 58 | 59 | fn mul(self, rhs: &'a BN254Scalar) -> Self::Output { 60 | let mut acc = Self::get_identity(); 61 | 62 | // This is a simple double-and-add implementation of group element 63 | // multiplication, moving from most significant to least 64 | // significant bit of the scalar. 65 | // 66 | // We skip the leading bit because it's always unset for Fq 67 | // elements. 68 | for bit in rhs 69 | .0 70 | .into_bigint() 71 | .to_bytes_le() 72 | .iter() 73 | .rev() 74 | .flat_map(|byte| (0..8).rev().map(move |i| ((byte >> i) & 1u8) == 1u8)) 75 | .skip(1) 76 | { 77 | acc = acc.double(); 78 | if bit { 79 | acc = acc.add(&self) 80 | } 81 | } 82 | 83 | acc 84 | } 85 | } 86 | 87 | impl<'a> AddAssign<&'a BN254Gt> for BN254Gt { 88 | #[inline] 89 | fn add_assign(&mut self, rhs: &'a BN254Gt) { 90 | self.0.mul_assign(&rhs.0) 91 | } 92 | } 93 | 94 | impl<'a> SubAssign<&'a BN254Gt> for BN254Gt { 95 | #[inline] 96 | fn sub_assign(&mut self, rhs: &'a BN254Gt) { 97 | let mut rhs_inverse = rhs.0; 98 | rhs_inverse.conjugate_in_place(); 99 | 100 | self.0.mul_assign(&rhs_inverse) 101 | } 102 | } 103 | 104 | impl Group for BN254Gt { 105 | type ScalarType = BN254Scalar; 106 | 107 | const COMPRESSED_LEN: usize = 384; 108 | const UNCOMPRESSED_LEN: usize = 384; 109 | 110 | #[inline] 111 | fn double(&self) -> Self { 112 | Self(self.0.mul(&self.0)) 113 | } 114 | 115 | #[inline] 116 | fn get_identity() -> Self { 117 | Self(Fp12::::one()) 118 | } 119 | 120 | #[inline] 121 | fn get_base() -> Self { 122 | BN254PairingEngine::pairing(&BN254G1::get_base(), &BN254G2::get_base()) 123 | } 124 | 125 | #[inline] 126 | fn random(prng: &mut R) -> Self { 127 | let g: PairingOutput = prng.gen(); 128 | Self(g.0) 129 | } 130 | 131 | #[inline] 132 | fn to_compressed_bytes(&self) -> Vec { 133 | let mut buf = Vec::new(); 134 | self.0.serialize_with_mode(&mut buf, Compress::Yes).unwrap(); 135 | 136 | buf 137 | } 138 | 139 | #[inline] 140 | fn to_unchecked_bytes(&self) -> Vec { 141 | let mut buf = Vec::new(); 142 | self.0.serialize_with_mode(&mut buf, Compress::No).unwrap(); 143 | 144 | buf 145 | } 146 | 147 | #[inline] 148 | fn from_compressed_bytes(bytes: &[u8]) -> Result { 149 | let res = Fp12::::deserialize_with_mode(bytes, Compress::Yes, Validate::Yes) 150 | .map_err(|_| AlgebraError::DeserializationError)?; 151 | 152 | Ok(Self(res)) 153 | } 154 | 155 | #[inline] 156 | fn from_unchecked_bytes(bytes: &[u8]) -> Result { 157 | let res = Fp12::::deserialize_with_mode(bytes, Compress::No, Validate::No) 158 | .map_err(|_| AlgebraError::DeserializationError)?; 159 | 160 | Ok(Self(res)) 161 | } 162 | 163 | #[inline] 164 | fn unchecked_size() -> usize { 165 | let g = Self::get_base().0; 166 | g.serialized_size(Compress::No) 167 | } 168 | 169 | #[inline] 170 | fn from_hash(hash: D) -> Self 171 | where 172 | D: Digest + Default, 173 | { 174 | let mut prng = derive_prng_from_hash::(hash); 175 | Self(Fp12::::rand(&mut prng)) 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /algebra/src/bn254/pairing.rs: -------------------------------------------------------------------------------- 1 | use crate::bn254::{BN254Gt, BN254Scalar, BN254G1, BN254G2}; 2 | use crate::traits::Pairing; 3 | use ark_bn254::Bn254 as BN254Pairing; 4 | use ark_ec::{ 5 | bn::{G1Prepared, G2Prepared}, 6 | pairing::Pairing as ArkPairing, 7 | CurveGroup, 8 | }; 9 | use ark_std::vec::Vec; 10 | 11 | /// The pairing engine for BN254 12 | pub struct BN254PairingEngine; 13 | 14 | impl Pairing for BN254PairingEngine { 15 | type ScalarField = BN254Scalar; 16 | type G1 = BN254G1; 17 | type G2 = BN254G2; 18 | type Gt = BN254Gt; 19 | 20 | #[inline] 21 | fn pairing(a: &Self::G1, b: &Self::G2) -> Self::Gt { 22 | BN254Gt(BN254Pairing::pairing(a.0, b.0).0) 23 | } 24 | 25 | #[inline] 26 | fn product_of_pairings(a: &[Self::G1], b: &[Self::G2]) -> Self::Gt { 27 | let c1: Vec> = a.iter().map(|x| x.0.into_affine().into()).collect(); 28 | let c2: Vec> = b.iter().map(|x| x.0.into_affine().into()).collect(); 29 | BN254Gt(BN254Pairing::multi_pairing(c1, c2).0) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /algebra/src/ed25519/fq.rs: -------------------------------------------------------------------------------- 1 | /// The wrapped struct for `ark_ed25519::Fq` 2 | pub type Ed25519Fq = crate::zorro::ZorroScalar; 3 | -------------------------------------------------------------------------------- /algebra/src/ed25519/mod.rs: -------------------------------------------------------------------------------- 1 | use ark_ed25519::Fq; 2 | 3 | /// The number of bytes for a scalar value over the ed25519 curve 4 | pub const ED25519_SCALAR_LEN: usize = 32; 5 | 6 | mod fr; 7 | pub use fr::*; 8 | 9 | mod fq; 10 | pub use fq::*; 11 | 12 | mod g1; 13 | pub use g1::*; 14 | 15 | /// A convenient macro to initialize a field element over the ED25519 curve. 16 | #[macro_export] 17 | macro_rules! new_ed25519_fq { 18 | ($c0:expr) => {{ 19 | let (is_positive, limbs) = ark_ff::ark_ff_macros::to_sign_and_limbs!($c0); 20 | Ed25519Fq::new(is_positive, &limbs) 21 | }}; 22 | } 23 | 24 | /// Obtain the d parameter of the ed25519 curve 25 | pub const ED25519_D: Fq = new_ed25519_fq!( 26 | "37095705934669439343138083508754565189542113879843219016388785533085940283555" 27 | ) 28 | .0; 29 | 30 | #[cfg(test)] 31 | mod ed25519_groups_test { 32 | use crate::{ 33 | ed25519::{Ed25519Point, Ed25519Scalar}, 34 | prelude::*, 35 | traits::group_tests::{test_scalar_operations, test_scalar_serialization}, 36 | }; 37 | use ark_ec::CurveGroup; 38 | use ark_ed25519::EdwardsAffine; 39 | 40 | #[test] 41 | fn test_scalar_ops() { 42 | test_scalar_operations::(); 43 | } 44 | 45 | #[test] 46 | fn scalar_deser() { 47 | test_scalar_serialization::(); 48 | } 49 | 50 | #[test] 51 | fn scalar_from_to_bytes() { 52 | let small_value = Ed25519Scalar::from(165747u32); 53 | let small_value_bytes = small_value.to_bytes(); 54 | let expected_small_value_bytes: [u8; 32] = [ 55 | 115, 135, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56 | 0, 0, 0, 0, 57 | ]; 58 | assert_eq!(small_value_bytes, expected_small_value_bytes); 59 | 60 | let small_value_from_bytes = Ed25519Scalar::from_bytes(&small_value_bytes).unwrap(); 61 | assert_eq!(small_value_from_bytes, small_value); 62 | } 63 | 64 | #[test] 65 | fn curve_points_respresentation_of_g1() { 66 | let mut prng = test_rng(); 67 | 68 | let g1 = Ed25519Point::get_base(); 69 | let s1 = Ed25519Scalar::from(50 + prng.next_u32() % 50); 70 | 71 | let g1 = g1.mul(&s1); 72 | 73 | let g1_prime = Ed25519Point::random(&mut prng); 74 | 75 | // This is the projective representation of g1 76 | let g1_projective = g1.0; 77 | let g1_prime_projective = g1_prime.0; 78 | 79 | // This is the affine representation of g1_prime 80 | let g1_prime_affine = EdwardsAffine::from(g1_prime_projective); 81 | 82 | let g1_pr_plus_g1_prime_pr = g1_projective.add(&g1_prime_projective); 83 | 84 | // These two operations correspond to summation of points, 85 | // one in projective form and the other in affine form 86 | let g1_pr_plus_g1_prime_af = g1_projective.add(&g1_prime_affine); 87 | assert_eq!(g1_pr_plus_g1_prime_pr, g1_pr_plus_g1_prime_af); 88 | 89 | let g1_pr_plus_g1_prime_af = g1_projective.add(&g1_prime_projective.into_affine()); 90 | assert_eq!(g1_pr_plus_g1_prime_pr, g1_pr_plus_g1_prime_af); 91 | } 92 | 93 | #[test] 94 | fn test_serialization_of_points() { 95 | let mut prng = test_rng(); 96 | 97 | let g1 = Ed25519Point::random(&mut prng); 98 | let g1_bytes = g1.to_compressed_bytes(); 99 | let g1_recovered = Ed25519Point::from_compressed_bytes(&g1_bytes).unwrap(); 100 | assert_eq!(g1, g1_recovered); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /algebra/src/errors.rs: -------------------------------------------------------------------------------- 1 | use ark_std::{error, fmt}; 2 | 3 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] 4 | #[allow(missing_docs)] 5 | pub enum AlgebraError { 6 | ArgumentVerificationError, 7 | BitConversionError, 8 | CommitmentInputError, 9 | CommitmentVerificationError, 10 | DecompressElementError, 11 | DeserializationError, 12 | SerializationError, 13 | IndexError, 14 | ParameterError, 15 | InconsistentStructureError, 16 | SignatureError, 17 | GroupInversionError, 18 | } 19 | 20 | impl fmt::Display for AlgebraError { 21 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 22 | use AlgebraError::*; 23 | f.write_str(match self { 24 | ArgumentVerificationError => "Proof(argument) not valid for statement", 25 | BitConversionError => "Bit conversion is not valid", 26 | CommitmentInputError => "The number of messages to be committed is invalid", 27 | CommitmentVerificationError => "Commitment verification failed", 28 | DecompressElementError => "Could not decompress group Element", 29 | DeserializationError => "Could not deserialize object", 30 | SerializationError => "Could not serialize object", 31 | IndexError => "Index out of bounds", 32 | ParameterError => "Unexpected parameter for method or function", 33 | SignatureError => "Signature verification failed", 34 | InconsistentStructureError => "Noah Structure is inconsistent", 35 | GroupInversionError => "Group Element not invertible", 36 | }) 37 | } 38 | } 39 | 40 | impl error::Error for AlgebraError { 41 | #[cfg(feature = "std")] 42 | fn description(&self) -> &str { 43 | Box::leak(format!("{}", self).into_boxed_str()) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /algebra/src/jubjub/fq.rs: -------------------------------------------------------------------------------- 1 | /// The wrapped struct for `ark_ed_on_bls12_381::Fq` 2 | pub type JubjubFq = crate::bls12_381::BLSScalar; 3 | -------------------------------------------------------------------------------- /algebra/src/jubjub/mod.rs: -------------------------------------------------------------------------------- 1 | /// The number of bytes for a scalar value over Jubjub 2 | pub const JUBJUB_SCALAR_LEN: usize = 32; 3 | 4 | mod fr; 5 | pub use fr::*; 6 | 7 | mod fq; 8 | pub use fq::*; 9 | 10 | mod g1; 11 | pub use g1::*; 12 | 13 | #[cfg(test)] 14 | mod jubjub_groups_test { 15 | use crate::{ 16 | jubjub::{JubjubPoint, JubjubScalar}, 17 | prelude::*, 18 | traits::group_tests::{test_scalar_operations, test_scalar_serialization}, 19 | }; 20 | use rand_chacha::ChaCha20Rng; 21 | 22 | #[test] 23 | fn test_scalar_ops() { 24 | test_scalar_operations::(); 25 | } 26 | 27 | #[test] 28 | fn scalar_deser() { 29 | test_scalar_serialization::(); 30 | } 31 | 32 | #[test] 33 | fn scalar_from_to_bytes() { 34 | let small_value = JubjubScalar::from(165747u32); 35 | let small_value_bytes = small_value.to_bytes(); 36 | let expected_small_value_bytes: [u8; 32] = [ 37 | 115, 135, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38 | 0, 0, 0, 0, 39 | ]; 40 | assert_eq!(small_value_bytes, expected_small_value_bytes); 41 | 42 | let small_value_from_bytes = JubjubScalar::from_bytes(&small_value_bytes).unwrap(); 43 | assert_eq!(small_value_from_bytes, small_value); 44 | } 45 | 46 | #[test] 47 | fn schnorr_identification_protocol() { 48 | let mut rng = ChaCha20Rng::from_entropy(); 49 | 50 | // Private key 51 | let alpha = JubjubScalar::random(&mut rng); 52 | 53 | // Public key 54 | let base = JubjubPoint::get_base(); 55 | let u = base.mul(&alpha); 56 | 57 | // Verifier challenge 58 | let c = JubjubScalar::random(&mut rng); 59 | 60 | // Prover commitment 61 | let alpha_t = JubjubScalar::random(&mut rng); 62 | let u_t = base.mul(&alpha_t); 63 | 64 | // Prover response 65 | let alpha_z = alpha_t.add(&c.mul(&alpha)); 66 | 67 | // Proof verification 68 | let left = base.mul(&alpha_z); 69 | let right = u_t.add(&u.mul(&c)); 70 | 71 | assert_eq!(left, right); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /algebra/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! The crate for algebra for the Noah library, which unifies the interfaces of different curves 2 | #![cfg_attr(not(feature = "std"), no_std)] 3 | #![deny(unused_import_braces, unused_qualifications, trivial_casts)] 4 | #![deny(trivial_numeric_casts)] 5 | #![deny(stable_features, unreachable_pub, non_shorthand_field_patterns)] 6 | #![deny(unused_attributes, unused_imports, unused_mut, missing_docs)] 7 | #![deny(renamed_and_removed_lints, stable_features, unused_allocation)] 8 | #![deny(unused_comparisons, bare_trait_objects, unused_must_use)] 9 | #![doc(html_logo_url = "https://avatars.githubusercontent.com/u/74745723?s=200&v=4")] 10 | #![doc(html_playground_url = "https://play.rust-lang.org")] 11 | #![warn( 12 | unused, 13 | future_incompatible, 14 | nonstandard_style, 15 | rust_2018_idioms, 16 | rust_2021_compatibility 17 | )] 18 | #![allow( 19 | clippy::op_ref, 20 | clippy::suspicious_op_assign_impl, 21 | clippy::upper_case_acronyms 22 | )] 23 | 24 | #[macro_use] 25 | extern crate serde_derive; 26 | 27 | /// Module for the BLS12-381 curve. 28 | pub mod bls12_381; 29 | 30 | /// Module for the BN254 curve. 31 | pub mod bn254; 32 | 33 | /// Module for the secq256k1 curve. 34 | pub mod secq256k1; 35 | 36 | /// Module for the secp256k1 curve. 37 | pub mod secp256k1; 38 | 39 | /// Module for the Jubjub curve. 40 | pub mod jubjub; 41 | 42 | /// Module for the BabyJubjub curve. 43 | pub mod baby_jubjub; 44 | 45 | /// Module for the Zorro curve. 46 | pub mod zorro; 47 | 48 | /// Module for the ed25519 curve used to work with the Zorro curve in address folding. 49 | pub mod ed25519; 50 | 51 | /// Module for the Ristretto group. 52 | pub mod ristretto; 53 | 54 | /// Module for error handling. 55 | pub mod errors; 56 | 57 | /// Module for traits. 58 | pub mod traits; 59 | 60 | /// Module for serialization of scalars and group elements. 61 | pub mod serialization; 62 | 63 | /// Module for utils. 64 | pub mod utils; 65 | 66 | /// Module for prelude. 67 | #[doc(hidden)] 68 | pub mod prelude; 69 | 70 | /// Module for test rng. 71 | pub mod rand_helper; 72 | 73 | #[doc(hidden)] 74 | pub use ark_std::{ 75 | borrow, cfg_into_iter, cmp, collections, end_timer, error, fmt, hash, io, iter, marker, ops, 76 | rand, result, start_timer, str, One, UniformRand, Zero, 77 | }; 78 | 79 | /// Implement serialization and deserialization 80 | #[macro_export] 81 | macro_rules! serialize_deserialize { 82 | ($t:ident) => { 83 | impl serde::Serialize for $t { 84 | fn serialize(&self, serializer: S) -> core::result::Result 85 | where 86 | S: Serializer, 87 | { 88 | if serializer.is_human_readable() { 89 | serializer.serialize_str(&b64enc(&self.noah_to_bytes())) 90 | } else { 91 | serializer.serialize_bytes(&self.noah_to_bytes()) 92 | } 93 | } 94 | } 95 | 96 | impl<'de> serde::Deserialize<'de> for $t { 97 | fn deserialize(deserializer: D) -> core::result::Result 98 | where 99 | D: serde::Deserializer<'de>, 100 | { 101 | let bytes = if deserializer.is_human_readable() { 102 | deserializer.deserialize_str(noah_obj_serde::BytesVisitor)? 103 | } else { 104 | deserializer.deserialize_bytes(noah_obj_serde::BytesVisitor)? 105 | }; 106 | $t::noah_from_bytes(bytes.as_slice()).map_err(serde::de::Error::custom) 107 | } 108 | } 109 | }; 110 | } 111 | -------------------------------------------------------------------------------- /algebra/src/prelude.rs: -------------------------------------------------------------------------------- 1 | pub use crate::borrow::Borrow; 2 | pub use crate::errors::AlgebraError; 3 | pub use crate::fmt::Formatter; 4 | pub use crate::iter::Sum; 5 | pub use crate::marker::PhantomData; 6 | pub use crate::ops::*; 7 | pub use crate::rand::{CryptoRng, Rng, RngCore, SeedableRng}; 8 | pub use crate::rand_helper::test_rng; 9 | pub use crate::serialization::*; 10 | pub use crate::traits::{CurveGroup, Group, LegendreSymbol, Scalar}; 11 | pub use crate::utils::*; 12 | pub use crate::{not_matches, serialize_deserialize, One, UniformRand, Zero}; 13 | pub use ark_std::{string::String, vec, vec::Vec}; 14 | pub use itertools::Itertools; 15 | 16 | pub(crate) type Result = core::result::Result; 17 | 18 | #[derive(Clone, Debug, Default, PartialEq, Eq)] 19 | /// The ciphertext from the symmetric encryption. 20 | pub struct CompactByteArray(pub Vec); 21 | -------------------------------------------------------------------------------- /algebra/src/rand_helper.rs: -------------------------------------------------------------------------------- 1 | use rand_chacha::{ 2 | rand_core::{CryptoRng, RngCore, SeedableRng}, 3 | ChaChaRng, 4 | }; 5 | 6 | fn test_rng_helper() -> ChaChaRng { 7 | // arbitrary seed 8 | let seed = [ 9 | 1, 0, 0, 0, 23, 0, 0, 0, 200, 1, 0, 0, 210, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10 | 0, 0, 0, 0, 11 | ]; 12 | ChaChaRng::from_seed(seed) 13 | } 14 | 15 | /// Should be used only for tests, not for any real world usage. 16 | #[cfg(not(feature = "std"))] 17 | pub fn test_rng() -> impl RngCore + CryptoRng { 18 | test_rng_helper() 19 | } 20 | 21 | /// Should be used only for tests, not for any real world usage. 22 | #[cfg(feature = "std")] 23 | pub fn test_rng() -> impl RngCore + CryptoRng { 24 | let is_deterministic = 25 | std::env::vars().any(|(key, val)| key == "DETERMINISTIC_TEST_RNG" && val == "1"); 26 | if is_deterministic { 27 | test_rng_helper() 28 | } else { 29 | ChaChaRng::from_entropy() 30 | } 31 | } 32 | 33 | #[cfg(all(test, feature = "std"))] 34 | mod test { 35 | use ark_std::UniformRand; 36 | 37 | #[test] 38 | fn test_deterministic_rng() { 39 | let mut rng = super::test_rng(); 40 | let a = u128::rand(&mut rng); 41 | 42 | // Reset the rng by sampling a new one. 43 | let mut rng = super::test_rng(); 44 | let b = u128::rand(&mut rng); 45 | assert_ne!(a, b); // should be unequal with high probability. 46 | 47 | // Let's make the rng deterministic. 48 | std::env::set_var("DETERMINISTIC_TEST_RNG", "1"); 49 | let mut rng = super::test_rng(); 50 | let a = u128::rand(&mut rng); 51 | 52 | // Reset the rng by sampling a new one. 53 | let mut rng = super::test_rng(); 54 | let b = u128::rand(&mut rng); 55 | assert_eq!(a, b); // should be equal with high probability. 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /algebra/src/secp256k1/fq.rs: -------------------------------------------------------------------------------- 1 | use crate::secq256k1::SECQ256K1Scalar; 2 | 3 | /// The wrapped struct for `ark_secp256k1::Fq` 4 | pub type SECP256K1Fq = SECQ256K1Scalar; 5 | -------------------------------------------------------------------------------- /algebra/src/secp256k1/mod.rs: -------------------------------------------------------------------------------- 1 | /// The number of bytes for a scalar value over secp256k1 2 | pub const SECP256K1_SCALAR_LEN: usize = 32; 3 | 4 | mod fr; 5 | pub use fr::*; 6 | 7 | mod fq; 8 | pub use fq::*; 9 | 10 | mod g1; 11 | pub use g1::*; 12 | 13 | /// A convenient macro to initialize a field element over the SECP256K1 curve. 14 | #[macro_export] 15 | macro_rules! new_secp256k1_fq { 16 | ($c0:expr) => {{ 17 | let (is_positive, limbs) = ark_ff::ark_ff_macros::to_sign_and_limbs!($c0); 18 | SECP256K1Fq::new(is_positive, &limbs) 19 | }}; 20 | } 21 | 22 | #[cfg(test)] 23 | mod secp256k1_groups_test { 24 | use crate::{ 25 | prelude::*, 26 | secp256k1::{SECP256K1Scalar, SECP256K1G1}, 27 | traits::group_tests::{test_scalar_operations, test_scalar_serialization}, 28 | }; 29 | use ark_ec::CurveGroup; 30 | use ark_secp256k1::Affine; 31 | 32 | #[test] 33 | fn test_scalar_ops() { 34 | test_scalar_operations::(); 35 | } 36 | 37 | #[test] 38 | fn scalar_deser() { 39 | test_scalar_serialization::(); 40 | } 41 | 42 | #[test] 43 | fn scalar_from_to_bytes() { 44 | let small_value = SECP256K1Scalar::from(165747u32); 45 | let small_value_bytes = small_value.to_bytes(); 46 | let expected_small_value_bytes: [u8; 32] = [ 47 | 115, 135, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48 | 0, 0, 0, 0, 49 | ]; 50 | assert_eq!(small_value_bytes, expected_small_value_bytes); 51 | 52 | let small_value_from_bytes = SECP256K1Scalar::from_bytes(&small_value_bytes).unwrap(); 53 | assert_eq!(small_value_from_bytes, small_value); 54 | } 55 | 56 | #[test] 57 | fn curve_points_respresentation_of_g1() { 58 | let mut prng = test_rng(); 59 | 60 | let g1 = SECP256K1G1::get_base(); 61 | let s1 = SECP256K1Scalar::from(50 + prng.next_u32() % 50); 62 | 63 | let g1 = g1.mul(&s1); 64 | 65 | let g1_prime = SECP256K1G1::random(&mut prng); 66 | 67 | // This is the projective representation of g1 68 | let g1_projective = g1.0; 69 | let g1_prime_projective = g1_prime.0; 70 | 71 | // This is the affine representation of g1_prime 72 | let g1_prime_affine = Affine::from(g1_prime_projective); 73 | 74 | let g1_pr_plus_g1_prime_pr = g1_projective.add(&g1_prime_projective); 75 | 76 | // These two operations correspond to summation of points, 77 | // one in projective form and the other in affine form 78 | let g1_pr_plus_g1_prime_af = g1_projective.add(&g1_prime_affine); 79 | assert_eq!(g1_pr_plus_g1_prime_pr, g1_pr_plus_g1_prime_af); 80 | 81 | let g1_pr_plus_g1_prime_af = g1_projective.add(&g1_prime_projective.into_affine()); 82 | assert_eq!(g1_pr_plus_g1_prime_pr, g1_pr_plus_g1_prime_af); 83 | } 84 | 85 | #[test] 86 | fn test_serialization_of_points() { 87 | let mut prng = test_rng(); 88 | 89 | let g1 = SECP256K1G1::random(&mut prng); 90 | let g1_bytes = g1.to_compressed_bytes(); 91 | let g1_recovered = SECP256K1G1::from_compressed_bytes(&g1_bytes).unwrap(); 92 | assert_eq!(g1, g1_recovered); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /algebra/src/secq256k1/fq.rs: -------------------------------------------------------------------------------- 1 | use crate::secp256k1::SECP256K1Scalar; 2 | 3 | /// The wrapped struct for `ark_bulletproofs::curve::secq256k1::Fq` 4 | pub type SECQ256K1Fq = SECP256K1Scalar; 5 | -------------------------------------------------------------------------------- /algebra/src/secq256k1/g1.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | use crate::secq256k1::SECQ256K1Scalar; 3 | use ark_ec::{AffineRepr, CurveGroup, Group as ArkGroup, VariableBaseMSM}; 4 | use ark_secq256k1::{Affine, Projective}; 5 | use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Compress, Validate}; 6 | use ark_std::{ 7 | fmt::{Debug, Formatter}, 8 | vec::Vec, 9 | }; 10 | use digest::consts::U64; 11 | use digest::Digest; 12 | use wasm_bindgen::prelude::*; 13 | 14 | /// The wrapped struct for `ark_secq256k1::Projective` 15 | #[wasm_bindgen] 16 | #[derive(Copy, Default, Clone, PartialEq, Eq)] 17 | pub struct SECQ256K1G1(pub(crate) Projective); 18 | 19 | impl Neg for SECQ256K1G1 { 20 | type Output = Self; 21 | 22 | fn neg(self) -> Self::Output { 23 | Self(self.0.neg()) 24 | } 25 | } 26 | 27 | impl Debug for SECQ256K1G1 { 28 | fn fmt(&self, f: &mut Formatter<'_>) -> ark_std::fmt::Result { 29 | Debug::fmt(&self.0.into_affine(), f) 30 | } 31 | } 32 | 33 | impl Group for SECQ256K1G1 { 34 | type ScalarType = SECQ256K1Scalar; 35 | const COMPRESSED_LEN: usize = 33; 36 | const UNCOMPRESSED_LEN: usize = 65; 37 | 38 | #[inline] 39 | fn double(&self) -> Self { 40 | Self(Projective::double(&self.0)) 41 | } 42 | 43 | #[inline] 44 | fn get_identity() -> Self { 45 | Self(Projective::zero()) 46 | } 47 | 48 | #[inline] 49 | fn get_base() -> Self { 50 | Self(Projective::generator()) 51 | } 52 | 53 | #[inline] 54 | fn random(prng: &mut R) -> Self { 55 | Self(Projective::rand(prng)) 56 | } 57 | 58 | #[inline] 59 | fn to_compressed_bytes(&self) -> Vec { 60 | let affine = Affine::from(self.0); 61 | let mut buf = Vec::new(); 62 | affine.serialize_with_mode(&mut buf, Compress::Yes).unwrap(); 63 | 64 | buf 65 | } 66 | 67 | #[inline] 68 | fn to_unchecked_bytes(&self) -> Vec { 69 | let affine = Affine::from(self.0); 70 | let mut buf = Vec::new(); 71 | affine.serialize_with_mode(&mut buf, Compress::No).unwrap(); 72 | 73 | buf 74 | } 75 | 76 | #[inline] 77 | fn from_compressed_bytes(bytes: &[u8]) -> Result { 78 | let affine = Affine::deserialize_with_mode(bytes, Compress::Yes, Validate::Yes) 79 | .map_err(|_| AlgebraError::DeserializationError)?; 80 | 81 | Ok(Self(Projective::from(affine))) 82 | } 83 | 84 | #[inline] 85 | fn from_unchecked_bytes(bytes: &[u8]) -> Result { 86 | let affine = Affine::deserialize_with_mode(bytes, Compress::No, Validate::No) 87 | .map_err(|_| AlgebraError::DeserializationError)?; 88 | 89 | Ok(Self(Projective::from(affine))) 90 | } 91 | 92 | #[inline] 93 | fn unchecked_size() -> usize { 94 | Affine::default().serialized_size(Compress::No) 95 | } 96 | 97 | #[inline] 98 | fn from_hash(hash: D) -> Self 99 | where 100 | D: Digest + Default, 101 | { 102 | let mut prng = derive_prng_from_hash::(hash); 103 | Self(Projective::rand(&mut prng)) 104 | } 105 | 106 | #[inline] 107 | fn multi_exp(scalars: &[&Self::ScalarType], points: &[&Self]) -> Self { 108 | let scalars_raw: Vec<_> = scalars.iter().map(|r| r.0).collect(); 109 | let points_raw = 110 | Projective::normalize_batch(&points.iter().map(|r| r.0).collect::>()); 111 | 112 | Self(Projective::msm(&points_raw, &scalars_raw).unwrap()) 113 | } 114 | } 115 | 116 | impl SECQ256K1G1 { 117 | /// Get the raw data. 118 | pub fn get_raw(&self) -> Affine { 119 | self.0.into_affine() 120 | } 121 | 122 | /// From the raw data. 123 | pub fn from_raw(raw: Affine) -> Self { 124 | Self(raw.into_group()) 125 | } 126 | } 127 | 128 | impl<'a> Add<&'a SECQ256K1G1> for SECQ256K1G1 { 129 | type Output = SECQ256K1G1; 130 | 131 | #[inline] 132 | fn add(self, rhs: &Self) -> Self::Output { 133 | Self(self.0.add(&rhs.0)) 134 | } 135 | } 136 | 137 | impl<'a> Sub<&'a SECQ256K1G1> for SECQ256K1G1 { 138 | type Output = SECQ256K1G1; 139 | 140 | #[inline] 141 | fn sub(self, rhs: &Self) -> Self::Output { 142 | Self(self.0.sub(&rhs.0)) 143 | } 144 | } 145 | 146 | impl<'a> Mul<&'a SECQ256K1Scalar> for SECQ256K1G1 { 147 | type Output = SECQ256K1G1; 148 | 149 | #[inline] 150 | fn mul(self, rhs: &SECQ256K1Scalar) -> Self::Output { 151 | Self(self.0.mul(&rhs.0)) 152 | } 153 | } 154 | 155 | impl<'a> AddAssign<&'a SECQ256K1G1> for SECQ256K1G1 { 156 | #[inline] 157 | fn add_assign(&mut self, rhs: &'a SECQ256K1G1) { 158 | self.0.add_assign(&rhs.0) 159 | } 160 | } 161 | 162 | impl<'a> SubAssign<&'a SECQ256K1G1> for SECQ256K1G1 { 163 | #[inline] 164 | fn sub_assign(&mut self, rhs: &'a SECQ256K1G1) { 165 | self.0.sub_assign(&rhs.0) 166 | } 167 | } 168 | 169 | impl<'a> MulAssign<&'a SECQ256K1Scalar> for SECQ256K1G1 { 170 | #[inline] 171 | fn mul_assign(&mut self, rhs: &'a SECQ256K1Scalar) { 172 | self.0.mul_assign(rhs.0) 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /algebra/src/secq256k1/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | use crate::traits::PedersenCommitment; 3 | use ark_secq256k1::Affine; 4 | 5 | mod fr; 6 | pub use fr::*; 7 | 8 | mod fq; 9 | pub use fq::*; 10 | 11 | mod g1; 12 | pub use g1::*; 13 | 14 | /// The wrapped struct for 15 | /// `ark_bulletproofs::r1cs::R1CSProof` 16 | pub type SECQ256K1Proof = ark_bulletproofs::r1cs::R1CSProof; 17 | 18 | #[allow(non_snake_case)] 19 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] 20 | /// The Pedersen commitment implementation for the secq256k1 group. 21 | pub struct PedersenCommitmentSecq256k1 { 22 | /// The generator for the value part. 23 | pub B: SECQ256K1G1, 24 | /// The generator for the blinding part. 25 | pub B_blinding: SECQ256K1G1, 26 | } 27 | 28 | impl Default for PedersenCommitmentSecq256k1 { 29 | fn default() -> Self { 30 | let pc_gens = ark_bulletproofs::PedersenGens::default(); 31 | Self { 32 | B: SECQ256K1G1::from_raw(pc_gens.B), 33 | B_blinding: SECQ256K1G1::from_raw(pc_gens.B_blinding), 34 | } 35 | } 36 | } 37 | 38 | impl PedersenCommitment for PedersenCommitmentSecq256k1 { 39 | fn generator(&self) -> SECQ256K1G1 { 40 | self.B 41 | } 42 | 43 | fn blinding_generator(&self) -> SECQ256K1G1 { 44 | self.B_blinding 45 | } 46 | 47 | fn commit(&self, value: SECQ256K1Scalar, blinding: SECQ256K1Scalar) -> SECQ256K1G1 { 48 | self.B.mul(&value).add(&self.B_blinding.mul(&blinding)) 49 | } 50 | } 51 | 52 | impl From<&PedersenCommitmentSecq256k1> for ark_bulletproofs::PedersenGens { 53 | fn from(rp: &PedersenCommitmentSecq256k1) -> Self { 54 | ark_bulletproofs::PedersenGens { 55 | B: rp.B.get_raw(), 56 | B_blinding: rp.B_blinding.get_raw(), 57 | } 58 | } 59 | } 60 | 61 | /// The wrapper struct for the Bulletproof generators. 62 | pub type Secq256k1BulletproofGens = ark_bulletproofs::BulletproofGens; 63 | 64 | /// The number of bytes for a scalar value over the secq256k1 curve 65 | pub const SECQ256K1_SCALAR_LEN: usize = 32; 66 | 67 | #[cfg(test)] 68 | mod secq256k1_groups_test { 69 | use crate::{ 70 | prelude::*, 71 | secq256k1::{SECQ256K1Scalar, SECQ256K1G1}, 72 | traits::group_tests::{test_scalar_operations, test_scalar_serialization}, 73 | }; 74 | use ark_ec::CurveGroup; 75 | use ark_secq256k1::Affine; 76 | 77 | #[test] 78 | fn test_scalar_ops() { 79 | test_scalar_operations::(); 80 | } 81 | 82 | #[test] 83 | fn scalar_deser() { 84 | test_scalar_serialization::(); 85 | } 86 | 87 | #[test] 88 | fn scalar_from_to_bytes() { 89 | let small_value = SECQ256K1Scalar::from(165747u32); 90 | let small_value_bytes = small_value.to_bytes(); 91 | let expected_small_value_bytes: [u8; 32] = [ 92 | 115, 135, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 93 | 0, 0, 0, 0, 94 | ]; 95 | assert_eq!(small_value_bytes, expected_small_value_bytes); 96 | 97 | let small_value_from_bytes = SECQ256K1Scalar::from_bytes(&small_value_bytes).unwrap(); 98 | assert_eq!(small_value_from_bytes, small_value); 99 | } 100 | 101 | #[test] 102 | fn curve_points_respresentation_of_g1() { 103 | let mut prng = test_rng(); 104 | 105 | let g1 = SECQ256K1G1::get_base(); 106 | let s1 = SECQ256K1Scalar::from(50 + prng.next_u32() % 50); 107 | 108 | let g1 = g1.mul(&s1); 109 | 110 | let g1_prime = SECQ256K1G1::random(&mut prng); 111 | 112 | // This is the projective representation of g1 113 | let g1_projective = g1.0; 114 | let g1_prime_projective = g1_prime.0; 115 | 116 | // This is the affine representation of g1_prime 117 | let g1_prime_affine = Affine::from(g1_prime_projective); 118 | 119 | let g1_pr_plus_g1_prime_pr = g1_projective.add(&g1_prime_projective); 120 | 121 | // These two operations correspond to summation of points, 122 | // one in projective form and the other in affine form 123 | let g1_pr_plus_g1_prime_af = g1_projective.add(&g1_prime_affine); 124 | assert_eq!(g1_pr_plus_g1_prime_pr, g1_pr_plus_g1_prime_af); 125 | 126 | let g1_pr_plus_g1_prime_af = g1_projective.add(&g1_prime_projective.into_affine()); 127 | assert_eq!(g1_pr_plus_g1_prime_pr, g1_pr_plus_g1_prime_af); 128 | } 129 | 130 | #[test] 131 | fn test_serialization_of_points() { 132 | let mut prng = test_rng(); 133 | 134 | let g1 = SECQ256K1G1::random(&mut prng); 135 | let g1_bytes = g1.to_compressed_bytes(); 136 | let g1_recovered = SECQ256K1G1::from_compressed_bytes(&g1_bytes).unwrap(); 137 | assert_eq!(g1, g1_recovered); 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /algebra/src/zorro/g1.rs: -------------------------------------------------------------------------------- 1 | use crate::fmt::{Debug, Formatter}; 2 | use crate::prelude::*; 3 | use crate::zorro::ZorroScalar; 4 | use ark_bulletproofs::curve::zorro::{G1Affine, G1Projective}; 5 | use ark_ec::{AffineRepr, CurveGroup as ArkCurveGroup, Group as ArkGroup, VariableBaseMSM}; 6 | use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Compress, Validate}; 7 | use ark_std::vec::Vec; 8 | use digest::consts::U64; 9 | use digest::Digest; 10 | use wasm_bindgen::prelude::wasm_bindgen; 11 | 12 | /// The wrapped struct for `ark_bulletproofs::curve::zorro::G1Projective` 13 | #[wasm_bindgen] 14 | #[derive(Copy, Default, Clone, PartialEq, Eq)] 15 | pub struct ZorroG1(pub(crate) G1Projective); 16 | 17 | impl Neg for ZorroG1 { 18 | type Output = Self; 19 | 20 | fn neg(self) -> Self::Output { 21 | Self(self.0.neg()) 22 | } 23 | } 24 | 25 | impl Debug for ZorroG1 { 26 | fn fmt(&self, f: &mut Formatter<'_>) -> ark_std::fmt::Result { 27 | Debug::fmt(&self.0.into_affine(), f) 28 | } 29 | } 30 | 31 | impl ZorroG1 { 32 | /// Get the raw data. 33 | pub fn get_raw(&self) -> G1Affine { 34 | self.0.into_affine() 35 | } 36 | 37 | /// From the raw data. 38 | pub fn from_raw(raw: G1Affine) -> Self { 39 | Self(raw.into_group()) 40 | } 41 | 42 | /// From the projective data. 43 | pub fn from_projective(p: G1Projective) -> Self { 44 | Self(p) 45 | } 46 | } 47 | 48 | impl<'a> Add<&'a ZorroG1> for ZorroG1 { 49 | type Output = ZorroG1; 50 | 51 | #[inline] 52 | fn add(self, rhs: &Self) -> Self::Output { 53 | Self(self.0.add(&rhs.0)) 54 | } 55 | } 56 | 57 | impl<'a> Sub<&'a ZorroG1> for ZorroG1 { 58 | type Output = ZorroG1; 59 | 60 | #[inline] 61 | fn sub(self, rhs: &Self) -> Self::Output { 62 | Self(self.0.sub(&rhs.0)) 63 | } 64 | } 65 | 66 | impl<'a> Mul<&'a ZorroScalar> for ZorroG1 { 67 | type Output = ZorroG1; 68 | 69 | #[inline] 70 | fn mul(self, rhs: &ZorroScalar) -> Self::Output { 71 | Self(self.0.mul(&rhs.0)) 72 | } 73 | } 74 | 75 | impl<'a> AddAssign<&'a ZorroG1> for ZorroG1 { 76 | #[inline] 77 | fn add_assign(&mut self, rhs: &'a ZorroG1) { 78 | self.0.add_assign(&rhs.0) 79 | } 80 | } 81 | 82 | impl<'a> SubAssign<&'a ZorroG1> for ZorroG1 { 83 | #[inline] 84 | fn sub_assign(&mut self, rhs: &'a ZorroG1) { 85 | self.0.sub_assign(&rhs.0) 86 | } 87 | } 88 | 89 | impl<'a> MulAssign<&'a ZorroScalar> for ZorroG1 { 90 | #[inline] 91 | fn mul_assign(&mut self, rhs: &'a ZorroScalar) { 92 | self.0.mul_assign(rhs.0) 93 | } 94 | } 95 | 96 | impl Group for ZorroG1 { 97 | type ScalarType = ZorroScalar; 98 | const COMPRESSED_LEN: usize = 33; 99 | const UNCOMPRESSED_LEN: usize = 65; 100 | 101 | #[inline] 102 | fn double(&self) -> Self { 103 | Self(G1Projective::double(&self.0)) 104 | } 105 | 106 | #[inline] 107 | fn get_identity() -> Self { 108 | Self(G1Projective::zero()) 109 | } 110 | 111 | #[inline] 112 | fn get_base() -> Self { 113 | Self(G1Projective::generator()) 114 | } 115 | 116 | #[inline] 117 | fn random(prng: &mut R) -> Self { 118 | Self(G1Projective::rand(prng)) 119 | } 120 | 121 | #[inline] 122 | fn to_compressed_bytes(&self) -> Vec { 123 | let affine = G1Affine::from(self.0); 124 | let mut buf = Vec::new(); 125 | affine.serialize_with_mode(&mut buf, Compress::Yes).unwrap(); 126 | 127 | buf 128 | } 129 | 130 | #[inline] 131 | fn to_unchecked_bytes(&self) -> Vec { 132 | let affine = G1Affine::from(self.0); 133 | let mut buf = Vec::new(); 134 | affine.serialize_with_mode(&mut buf, Compress::No).unwrap(); 135 | 136 | buf 137 | } 138 | 139 | #[inline] 140 | fn from_compressed_bytes(bytes: &[u8]) -> Result { 141 | let affine = G1Affine::deserialize_with_mode(bytes, Compress::Yes, Validate::Yes) 142 | .map_err(|_| AlgebraError::DeserializationError)?; 143 | 144 | Ok(Self(G1Projective::from(affine))) 145 | } 146 | 147 | #[inline] 148 | fn from_unchecked_bytes(bytes: &[u8]) -> Result { 149 | let affine = G1Affine::deserialize_with_mode(bytes, Compress::No, Validate::No) 150 | .map_err(|_| AlgebraError::DeserializationError)?; 151 | 152 | Ok(Self(G1Projective::from(affine))) 153 | } 154 | 155 | #[inline] 156 | fn unchecked_size() -> usize { 157 | G1Affine::default().serialized_size(Compress::No) 158 | } 159 | 160 | #[inline] 161 | fn from_hash(hash: D) -> Self 162 | where 163 | D: Digest + Default, 164 | { 165 | let mut prng = derive_prng_from_hash::(hash); 166 | Self(G1Projective::rand(&mut prng)) 167 | } 168 | 169 | #[inline] 170 | fn multi_exp(scalars: &[&Self::ScalarType], points: &[&Self]) -> Self { 171 | let scalars_raw: Vec<_> = scalars.iter().map(|r| r.0).collect(); 172 | let points_raw = G1Projective::normalize_batch( 173 | &points.iter().map(|r| r.0).collect::>(), 174 | ); 175 | 176 | Self(G1Projective::msm(&points_raw, scalars_raw.as_ref()).unwrap()) 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /algebra/src/zorro/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::prelude::*; 2 | use crate::traits::PedersenCommitment; 3 | use ark_bulletproofs::curve::zorro::G1Affine; 4 | 5 | /// The number of bytes for a scalar value over Zorro 6 | pub const ZORRO_SCALAR_LEN: usize = 32; 7 | 8 | mod fr; 9 | pub use fr::*; 10 | 11 | mod fq; 12 | pub use fq::*; 13 | 14 | mod g1; 15 | pub use g1::*; 16 | 17 | /// The wrapped struct for 18 | /// `ark_bulletproofs::r1cs::R1CSProof` 19 | pub type ZorroProof = ark_bulletproofs::r1cs::R1CSProof; 20 | 21 | #[allow(non_snake_case)] 22 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] 23 | /// The Pedersen commitment implementation for the secq256k1 group. 24 | pub struct PedersenCommitmentZorro { 25 | /// The generator for the value part. 26 | pub B: ZorroG1, 27 | /// The generator for the blinding part. 28 | pub B_blinding: ZorroG1, 29 | } 30 | 31 | impl Default for PedersenCommitmentZorro { 32 | fn default() -> Self { 33 | let pc_gens = ark_bulletproofs::PedersenGens::default(); 34 | Self { 35 | B: ZorroG1::from_raw(pc_gens.B), 36 | B_blinding: ZorroG1::from_raw(pc_gens.B_blinding), 37 | } 38 | } 39 | } 40 | 41 | impl PedersenCommitment for PedersenCommitmentZorro { 42 | fn generator(&self) -> ZorroG1 { 43 | self.B 44 | } 45 | 46 | fn blinding_generator(&self) -> ZorroG1 { 47 | self.B_blinding 48 | } 49 | 50 | fn commit(&self, value: ZorroScalar, blinding: ZorroScalar) -> ZorroG1 { 51 | self.B.mul(&value).add(&self.B_blinding.mul(&blinding)) 52 | } 53 | } 54 | 55 | impl From<&PedersenCommitmentZorro> for ark_bulletproofs::PedersenGens { 56 | fn from(rp: &PedersenCommitmentZorro) -> Self { 57 | ark_bulletproofs::PedersenGens { 58 | B: rp.B.get_raw(), 59 | B_blinding: rp.B_blinding.get_raw(), 60 | } 61 | } 62 | } 63 | 64 | /// The wrapper struct for the Bulletproof generators. 65 | pub type ZorroBulletproofGens = ark_bulletproofs::BulletproofGens; 66 | 67 | #[cfg(test)] 68 | mod zorro_groups_test { 69 | use crate::{ 70 | prelude::*, 71 | traits::group_tests::{test_scalar_operations, test_scalar_serialization}, 72 | zorro::{ZorroFq, ZorroG1, ZorroScalar}, 73 | }; 74 | use ark_bulletproofs::curve::zorro::G1Affine; 75 | use ark_ec::CurveGroup; 76 | 77 | #[test] 78 | fn test_scalar_ops() { 79 | test_scalar_operations::(); 80 | test_scalar_operations::(); 81 | } 82 | 83 | #[test] 84 | fn scalar_deser() { 85 | test_scalar_serialization::(); 86 | test_scalar_serialization::(); 87 | } 88 | 89 | #[test] 90 | fn scalar_from_to_bytes() { 91 | let small_value = ZorroScalar::from(165747u32); 92 | let small_value_bytes = small_value.to_bytes(); 93 | let expected_small_value_bytes: [u8; 32] = [ 94 | 115, 135, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95 | 0, 0, 0, 0, 96 | ]; 97 | assert_eq!(small_value_bytes, expected_small_value_bytes); 98 | 99 | let small_value_from_bytes = ZorroScalar::from_bytes(&small_value_bytes).unwrap(); 100 | assert_eq!(small_value_from_bytes, small_value); 101 | } 102 | 103 | #[test] 104 | fn curve_points_respresentation_of_g1() { 105 | let mut prng = test_rng(); 106 | 107 | let g1 = ZorroG1::get_base(); 108 | let s1 = ZorroScalar::from(50 + prng.next_u32() % 50); 109 | 110 | let g1 = g1.mul(&s1); 111 | 112 | let g1_prime = ZorroG1::random(&mut prng); 113 | 114 | // This is the projective representation of g1 115 | let g1_projective = g1.0; 116 | let g1_prime_projective = g1_prime.0; 117 | 118 | // This is the affine representation of g1_prime 119 | let g1_prime_affine = G1Affine::from(g1_prime_projective); 120 | 121 | let g1_pr_plus_g1_prime_pr = g1_projective.add(&g1_prime_projective); 122 | 123 | // These two operations correspond to summation of points, 124 | // one in projective form and the other in affine form 125 | let g1_pr_plus_g1_prime_af = g1_projective.add(&g1_prime_affine); 126 | assert_eq!(g1_pr_plus_g1_prime_pr, g1_pr_plus_g1_prime_af); 127 | 128 | let g1_pr_plus_g1_prime_af = g1_projective.add(&g1_prime_projective.into_affine()); 129 | assert_eq!(g1_pr_plus_g1_prime_pr, g1_pr_plus_g1_prime_af); 130 | } 131 | 132 | #[test] 133 | fn test_serialization_of_points() { 134 | let mut prng = test_rng(); 135 | 136 | let g1 = ZorroG1::random(&mut prng); 137 | let g1_bytes = g1.to_compressed_bytes(); 138 | let g1_recovered = ZorroG1::from_compressed_bytes(&g1_bytes).unwrap(); 139 | assert_eq!(g1, g1_recovered); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /api/Cargo.toml: -------------------------------------------------------------------------------- 1 | [[bin]] 2 | name = 'gen-params' 3 | path = 'src/parameters/setup.rs' 4 | required-features = ['gen'] 5 | 6 | [[bench]] 7 | name = 'bulletproofs' 8 | path = 'benches/bulletproofs.rs' 9 | harness = false 10 | 11 | [[bench]] 12 | name = 'xfr' 13 | path = 'benches/xfr.rs' 14 | harness = false 15 | 16 | [[bench]] 17 | name = 'anon_xfr' 18 | path = 'benches/anon_xfr.rs' 19 | harness = false 20 | 21 | [[bench]] 22 | name = 'merkle_tree' 23 | path = 'benches/merkle_tree.rs' 24 | harness = false 25 | 26 | [[bench]] 27 | name = 'anemoi' 28 | path = 'benches/anemoi.rs' 29 | harness = false 30 | 31 | [package] 32 | name = 'noah' 33 | version = '0.5.0' 34 | authors = ['Findora '] 35 | edition = '2021' 36 | description = 'Noah Platform Interface' 37 | 38 | [lib] 39 | name = 'noah' 40 | crate-type = ['rlib'] 41 | 42 | [dependencies] 43 | aes = '0.8.1' 44 | aes-gcm = '0.10.1' 45 | bincode = '1.3.1' 46 | digest = '0.10' 47 | lazy_static = "1.4.0" 48 | libsecp256k1 = '0.7' 49 | linear-map = '1.2.0' 50 | merlin = '3.0' 51 | rand_chacha = '0.3' 52 | rmp-serde = '1.0.0' 53 | serde = '1.0' 54 | serde_derive = '1.0' 55 | serde_str = '0.1.0' 56 | sha2 = '0.10' 57 | sha3 = '0.10' 58 | wasm-bindgen-test = "^0.3" 59 | 60 | 61 | [dependencies.noah-algebra] 62 | path = '../algebra' 63 | 64 | [dependencies.noah-crypto] 65 | path = '../crypto' 66 | 67 | [dependencies.noah-plonk] 68 | path = '../plonk' 69 | 70 | [dependencies.curve25519-dalek] 71 | package = "noah-curve25519-dalek" 72 | version = "4.0.0" 73 | default-features = false 74 | features = ['serde'] 75 | 76 | [dependencies.ed25519-dalek] 77 | package = "noah-ed25519-dalek" 78 | version = "4.0.0" 79 | 80 | [dependencies.bulletproofs] 81 | package = "noah-bulletproofs" 82 | version = "4.1.0" 83 | 84 | [dependencies.ark-ff] 85 | version = '0.4.0' 86 | default-features = false 87 | 88 | [dependencies.ark-serialize] 89 | version = '0.4.0' 90 | default-features = false 91 | 92 | [dependencies.ark-std] 93 | version = '0.4.0' 94 | default-features = false 95 | 96 | [dependencies.ark-ec] 97 | version = '0.4.0' 98 | default-features = false 99 | 100 | [dependencies.ark-bulletproofs] 101 | version = '4.0.0' 102 | default-features = false 103 | features = ['yoloproofs'] 104 | 105 | [dependencies.rand_core] 106 | version = '0.6' 107 | default-features = false 108 | features = ['alloc'] 109 | 110 | [dependencies.wasm-bindgen] 111 | version = '0.2.50' 112 | features = ['serde-serialize'] 113 | 114 | [dependencies.num-integer] 115 | version = '0.1.43' 116 | 117 | [dependencies.num-traits] 118 | version = '0.2.12' 119 | 120 | [dependencies.num-bigint] 121 | version = '0.4.0' 122 | features = ['rand'] 123 | 124 | [dependencies.rayon] 125 | version = '1.5' 126 | optional = true 127 | 128 | [dependencies.structopt] 129 | version = '0.3.26' 130 | optional = true 131 | 132 | [dev-dependencies] 133 | bit-array = '0.4.3' 134 | criterion = { version = '0.5.0', default-features = false } 135 | hex = '0.4' 136 | lazy_static = '1.4.0' 137 | serde_json = '1.0' 138 | typenum = '1.11.2' 139 | parking_lot = '0.12' 140 | 141 | [dev-dependencies.noah-accumulators] 142 | path = '../accumulators' 143 | 144 | [dev-dependencies.rand] 145 | version = '0.8' 146 | default-features = false 147 | 148 | [dev-dependencies.storage] 149 | git = 'https://github.com/FindoraNetwork/storage.git' 150 | tag = 'v1.1.6' 151 | 152 | [dev-dependencies.mem_db] 153 | git = 'https://github.com/FindoraNetwork/storage.git' 154 | tag = 'v1.1.6' 155 | 156 | [features] 157 | default = ['std', 'u64_backend'] 158 | debug = ['noah-plonk/debug'] 159 | std = [ 160 | 'noah-algebra/std', 161 | 'noah-crypto/std', 162 | 'noah-plonk/std', 163 | 'curve25519-dalek/std', 164 | 'bulletproofs/std', 165 | 'ark-bulletproofs/std', 166 | 'ark-std/std', 167 | 'ark-ec/std', 168 | ] 169 | alloc = ['curve25519-dalek/alloc'] 170 | nightly = ['curve25519-dalek/nightly', 'rand/nightly'] 171 | u64_backend = ['curve25519-dalek/u64_backend'] 172 | u32_backend = ['curve25519-dalek/u32_backend'] 173 | avx2_backend = ['curve25519-dalek/avx2_backend'] 174 | asm = ['noah-algebra/asm'] 175 | no_urs = [] 176 | no_srs = [] 177 | no_vk = [] 178 | parallel = ['default', 'rayon', 'noah-algebra/parallel', 'noah-plonk/parallel'] 179 | gen = ["parallel", "structopt"] 180 | lightweight = [] # Minimize size for only AR2ABAR and ABAR2AR. 181 | print-trace = ['noah-algebra/print-trace'] 182 | xfr-tracing = [] 183 | -------------------------------------------------------------------------------- /api/benches/anemoi.rs: -------------------------------------------------------------------------------- 1 | use criterion::{criterion_group, criterion_main, Criterion}; 2 | use merlin::Transcript; 3 | use noah_algebra::bn254::{BN254PairingEngine, BN254Scalar}; 4 | use noah_algebra::prelude::*; 5 | use noah_crypto::anemoi_jive::{AnemoiJive, AnemoiJive254, ANEMOI_JIVE_BN254_SALTS}; 6 | use noah_plonk::plonk::constraint_system::{ConstraintSystem, TurboCS}; 7 | use noah_plonk::plonk::indexer::{indexer, indexer_with_lagrange, PlonkVK}; 8 | use noah_plonk::plonk::prover::prover; 9 | use noah_plonk::plonk::verifier::verifier; 10 | use noah_plonk::poly_commit::kzg_poly_com::KZGCommitmentScheme; 11 | use noah_plonk::poly_commit::pcs::PolyComScheme; 12 | 13 | fn anemoi(c: &mut Criterion) { 14 | let mut cs = TurboCS::new(); 15 | cs.load_anemoi_jive_parameters::(); 16 | 17 | let va = cs.new_variable(BN254Scalar::from(1u64)); 18 | let vb = cs.new_variable(BN254Scalar::from(2u64)); 19 | let vc = cs.new_variable(BN254Scalar::from(3u64)); 20 | 21 | let trace = AnemoiJive254::eval_jive_with_trace( 22 | &[BN254Scalar::from(1u64), BN254Scalar::from(2u64)], 23 | &[BN254Scalar::from(3u64), ANEMOI_JIVE_BN254_SALTS[0]], 24 | ); 25 | 26 | for _ in 0..500 { 27 | let _ = cs.jive_crh::(&trace, &[va, vb, vc], ANEMOI_JIVE_BN254_SALTS[0]); 28 | } 29 | println!("number of constraints: {}", cs.size); 30 | cs.pad(); 31 | let witness = cs.get_and_clear_witness(); 32 | 33 | let mut prng = test_rng(); 34 | let pcs = KZGCommitmentScheme::::new(8195, &mut prng); 35 | 36 | let prover_params = indexer(&cs, &pcs).unwrap(); 37 | let verifier_params = prover_params.get_verifier_params_ref(); 38 | 39 | let mut single_group = c.benchmark_group("prover"); 40 | single_group.sample_size(10); 41 | single_group.bench_function("batch of 500".to_string(), |b| { 42 | b.iter(|| { 43 | let mut transcript = Transcript::new(b"TestTurboPlonk"); 44 | prover( 45 | &mut prng, 46 | &mut transcript, 47 | &pcs, 48 | &cs, 49 | &prover_params, 50 | &witness, 51 | ) 52 | .unwrap() 53 | }); 54 | }); 55 | single_group.finish(); 56 | 57 | let mut transcript = Transcript::new(b"TestTurboPlonk"); 58 | let proof = prover( 59 | &mut prng, 60 | &mut transcript, 61 | &pcs, 62 | &cs, 63 | &prover_params, 64 | &witness, 65 | ) 66 | .unwrap(); 67 | 68 | let mut single_group = c.benchmark_group("verifier"); 69 | single_group.sample_size(10); 70 | single_group.bench_function("batch of 500".to_string(), |b| { 71 | b.iter(|| { 72 | let mut transcript = Transcript::new(b"TestTurboPlonk"); 73 | verifier( 74 | &mut transcript, 75 | &pcs.shrink_to_verifier_only(), 76 | &cs.shrink_to_verifier_only(), 77 | verifier_params, 78 | &[], 79 | &proof, 80 | ) 81 | .unwrap() 82 | }); 83 | }); 84 | single_group.finish(); 85 | 86 | let mut single_group = c.benchmark_group("indexer"); 87 | single_group.sample_size(10); 88 | single_group.bench_function("batch of 500".to_string(), |b| { 89 | b.iter(|| { 90 | let _ = indexer_with_lagrange(&cs, &pcs, Some(&pcs), None).unwrap(); 91 | }); 92 | }); 93 | single_group.finish(); 94 | 95 | let vk = PlonkVK::>::from(verifier_params.clone()); 96 | let mut single_group = c.benchmark_group("re-indexer"); 97 | single_group.sample_size(10); 98 | single_group.bench_function("batch of 500".to_string(), |b| { 99 | b.iter(|| { 100 | let _ = indexer_with_lagrange(&cs, &pcs, Some(&pcs), Some(vk.clone())).unwrap(); 101 | }); 102 | }); 103 | single_group.finish(); 104 | } 105 | 106 | criterion_group!(benches, anemoi); 107 | criterion_main!(benches); 108 | -------------------------------------------------------------------------------- /api/parameters/abar-to-ar-vk-ed25519.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FindoraNetwork/noah/f13d3595dcac5b7e63afdf1f4a0b0c89b16688ba/api/parameters/abar-to-ar-vk-ed25519.bin -------------------------------------------------------------------------------- /api/parameters/abar-to-ar-vk-secp256k1.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FindoraNetwork/noah/f13d3595dcac5b7e63afdf1f4a0b0c89b16688ba/api/parameters/abar-to-ar-vk-secp256k1.bin -------------------------------------------------------------------------------- /api/parameters/abar-to-bar-vk-ed25519.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FindoraNetwork/noah/f13d3595dcac5b7e63afdf1f4a0b0c89b16688ba/api/parameters/abar-to-bar-vk-ed25519.bin -------------------------------------------------------------------------------- /api/parameters/abar-to-bar-vk-secp256k1.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FindoraNetwork/noah/f13d3595dcac5b7e63afdf1f4a0b0c89b16688ba/api/parameters/abar-to-bar-vk-secp256k1.bin -------------------------------------------------------------------------------- /api/parameters/ar-to-abar-vk.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FindoraNetwork/noah/f13d3595dcac5b7e63afdf1f4a0b0c89b16688ba/api/parameters/ar-to-abar-vk.bin -------------------------------------------------------------------------------- /api/parameters/bar-to-abar-vk.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FindoraNetwork/noah/f13d3595dcac5b7e63afdf1f4a0b0c89b16688ba/api/parameters/bar-to-abar-vk.bin -------------------------------------------------------------------------------- /api/parameters/bulletproof-curve25519-urs.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FindoraNetwork/noah/f13d3595dcac5b7e63afdf1f4a0b0c89b16688ba/api/parameters/bulletproof-curve25519-urs.bin -------------------------------------------------------------------------------- /api/parameters/bulletproof-secq256k1-urs.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FindoraNetwork/noah/f13d3595dcac5b7e63afdf1f4a0b0c89b16688ba/api/parameters/bulletproof-secq256k1-urs.bin -------------------------------------------------------------------------------- /api/parameters/bulletproof-zorro-urs.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FindoraNetwork/noah/f13d3595dcac5b7e63afdf1f4a0b0c89b16688ba/api/parameters/bulletproof-zorro-urs.bin -------------------------------------------------------------------------------- /api/parameters/lagrange-srs-4096.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FindoraNetwork/noah/f13d3595dcac5b7e63afdf1f4a0b0c89b16688ba/api/parameters/lagrange-srs-4096.bin -------------------------------------------------------------------------------- /api/parameters/lagrange-srs-8192.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FindoraNetwork/noah/f13d3595dcac5b7e63afdf1f4a0b0c89b16688ba/api/parameters/lagrange-srs-8192.bin -------------------------------------------------------------------------------- /api/parameters/srs-padding.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FindoraNetwork/noah/f13d3595dcac5b7e63afdf1f4a0b0c89b16688ba/api/parameters/srs-padding.bin -------------------------------------------------------------------------------- /api/parameters/transfer-vk-common.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FindoraNetwork/noah/f13d3595dcac5b7e63afdf1f4a0b0c89b16688ba/api/parameters/transfer-vk-common.bin -------------------------------------------------------------------------------- /api/parameters/transfer-vk-ed25519-specific.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FindoraNetwork/noah/f13d3595dcac5b7e63afdf1f4a0b0c89b16688ba/api/parameters/transfer-vk-ed25519-specific.bin -------------------------------------------------------------------------------- /api/parameters/transfer-vk-secp256k1-specific.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FindoraNetwork/noah/f13d3595dcac5b7e63afdf1f4a0b0c89b16688ba/api/parameters/transfer-vk-secp256k1-specific.bin -------------------------------------------------------------------------------- /api/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! The API interfaces of the Noah library 2 | #![cfg_attr(not(feature = "std"), no_std)] 3 | #![deny(unused, unused_import_braces, unused_qualifications, trivial_casts)] 4 | #![deny(trivial_numeric_casts)] 5 | #![deny(stable_features, unreachable_pub, non_shorthand_field_patterns)] 6 | #![deny(unused_attributes, unused_imports, unused_mut)] 7 | #![deny(missing_docs)] 8 | #![deny(renamed_and_removed_lints, stable_features, unused_allocation)] 9 | #![deny(unused_comparisons, bare_trait_objects, unused_must_use)] 10 | #![doc(html_logo_url = "https://avatars.githubusercontent.com/u/74745723?s=200&v=4")] 11 | #![doc(html_playground_url = "https://play.rust-lang.org")] 12 | #![forbid(unsafe_code)] 13 | #![warn( 14 | unused, 15 | future_incompatible, 16 | nonstandard_style, 17 | rust_2018_idioms, 18 | rust_2021_compatibility 19 | )] 20 | #![allow(clippy::too_many_arguments)] 21 | 22 | #[macro_use] 23 | extern crate serde_derive; 24 | 25 | #[macro_use] 26 | extern crate lazy_static; 27 | 28 | /// The wrapper for anonymous credentials. 29 | pub mod anon_creds; 30 | /// Module for anonymous transfer. 31 | pub mod anon_xfr; 32 | /// Module for error handling 33 | pub mod errors; 34 | /// Module for anonymous and confidential keys 35 | pub mod keys; 36 | /// Module for next-generation anonymous transfer. 37 | pub mod nextgen; 38 | /// The wrapper of the parameters. 39 | pub mod parameters; 40 | /// Module for serialization. 41 | pub mod serialization; 42 | /// Module for confidential transfer. 43 | pub mod xfr; 44 | 45 | pub use errors::NoahError; 46 | pub use noah_algebra::ristretto; 47 | -------------------------------------------------------------------------------- /api/src/nextgen/ar_to_nabar.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /api/src/nextgen/bar_to_nabar.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /api/src/nextgen/mod.rs: -------------------------------------------------------------------------------- 1 | /// Module for converting transparent assets to Nextgen assets. 2 | pub mod ar_to_nabar; 3 | /// Module for converting Maxwell assets to Nextgen assets. 4 | pub mod bar_to_nabar; 5 | /// Module for transferring Zerocash or Nextgen assets where outcomes are Zerocash or Nextgen assets. 6 | pub mod nabar_or_abar_xfr; 7 | /// Module for converting Nextgen assets to transparent assets. 8 | pub mod nabar_to_ar; 9 | /// Module for converting Nextgen assets to confidential assets. 10 | pub mod nabar_to_bar; 11 | 12 | /// Module for shared structures. 13 | pub mod structs; 14 | 15 | /// Module for nullifiers 16 | pub mod nullifiers; 17 | -------------------------------------------------------------------------------- /api/src/nextgen/nabar_or_abar_xfr.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /api/src/nextgen/nabar_to_ar.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /api/src/nextgen/nabar_to_bar.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /api/src/nextgen/nullifiers/mod.rs: -------------------------------------------------------------------------------- 1 | /// The scheme for GDH signature. 2 | pub struct GDHSignatureScheme; 3 | -------------------------------------------------------------------------------- /api/src/nextgen/structs/memo.rs: -------------------------------------------------------------------------------- 1 | use noah_algebra::baby_jubjub::BabyJubjubPoint; 2 | use noah_algebra::bn254::{BN254Scalar, BN254_SCALAR_LEN}; 3 | use noah_algebra::prelude::*; 4 | use serde::de::Error as SerdeError; 5 | use serde::{Deserialize, Deserializer, Serialize, Serializer}; 6 | 7 | /// Compute the expected number of BLS scalar elements in the memo ciphertext. 8 | /// 9 | /// Note that the memo ciphertext consists of other information, such as: 10 | /// - The Diffie-Hellman key exchange group element, r * G 11 | /// - A fast-detection element 12 | /// 13 | /// So it would consist of more elements than what we show here. 14 | /// 15 | pub fn get_auditor_memo_length(num_inputs: usize, num_outputs: usize) -> usize { 16 | // Every transaction has at most one audited asset, which means that there 17 | // is also at most one auditor. 18 | // 19 | // The auditor will be presented all the input and output information. 20 | // 21 | // The memo first includes the sender address (3 BLS scalar elements). 22 | // 23 | // Note that, similar to anon_xfr, we prefer to consolidate assets into 24 | // a few addresses, and therefore, we also restrict all the inputs to 25 | // have the same owner (same public key). 26 | // 27 | // For each input, the memo includes: 28 | // - the coin commitment, which enables back-tracing. 29 | // - the amount 30 | // - the asset type (all not assets have to be the audited one) 31 | // 32 | // For each output, the memo includes: 33 | // - the amount 34 | // - the asset type 35 | // - the receiving address (it takes 3 BLS scalar elements) 36 | // - the randomizer 37 | // 38 | // Finally, there is one element for zk-ID 39 | 40 | 3 + num_inputs * (1 + 1 + 1) + num_outputs * (1 + 1 + 3 + 1) + 1 41 | } 42 | 43 | /// A struct for the auditor's memo. 44 | #[derive(Clone, Default, Debug, Eq, PartialEq)] 45 | pub struct NabarAuditorMemo { 46 | /// The Diffie-Hellman key exchange group element. 47 | /// 48 | /// Note: we explicitly stress that this point is often uncompressed and unchecked, 49 | /// and the application should take the responsibility to make application-specific checks. 50 | pub dh_point_unchecked: BabyJubjubPoint, 51 | /// The fast-detection element. 52 | pub fast_detection: BN254Scalar, 53 | /// The body of the memo. 54 | pub body: Vec, 55 | } 56 | 57 | impl Serialize for NabarAuditorMemo { 58 | fn serialize(&self, serializer: S) -> Result 59 | where 60 | S: Serializer, 61 | { 62 | let mut bytes = Vec::::new(); 63 | 64 | // We overwrite the serialization algorithm to avoid the need of recovering the point. 65 | bytes.extend_from_slice(&self.dh_point_unchecked.to_unchecked_bytes()); 66 | bytes.extend_from_slice(&self.fast_detection.noah_to_bytes()); 67 | 68 | for elem in self.body.iter() { 69 | bytes.extend_from_slice(&elem.noah_to_bytes()); 70 | } 71 | 72 | if serializer.is_human_readable() { 73 | serializer.serialize_str(&b64enc(&bytes)) 74 | } else { 75 | serializer.serialize_bytes(&bytes) 76 | } 77 | } 78 | } 79 | 80 | impl<'de> Deserialize<'de> for NabarAuditorMemo { 81 | fn deserialize(deserializer: D) -> Result 82 | where 83 | D: Deserializer<'de>, 84 | { 85 | let bytes = if deserializer.is_human_readable() { 86 | deserializer.deserialize_str(noah_obj_serde::BytesVisitor)? 87 | } else { 88 | deserializer.deserialize_bytes(noah_obj_serde::BytesVisitor)? 89 | }; 90 | 91 | let dh_point_unchecked = 92 | BabyJubjubPoint::from_unchecked_bytes(&bytes[0..64]).map_err(SerdeError::custom)?; 93 | 94 | let fast_detection = 95 | BN254Scalar::noah_from_bytes(&bytes[64..96]).map_err(SerdeError::custom)?; 96 | 97 | let remaining_bytes = bytes.len() - 96; 98 | if remaining_bytes % BN254_SCALAR_LEN != 0 { 99 | return Err(SerdeError::custom( 100 | "The auditor memo does not have the correct length.", 101 | )); 102 | } 103 | 104 | let mut body = Vec::with_capacity(remaining_bytes / BN254_SCALAR_LEN); 105 | for elem_bytes in bytes[96..].chunks_exact(96) { 106 | let res = BN254Scalar::noah_from_bytes(elem_bytes).map_err(SerdeError::custom)?; 107 | 108 | body.push(res); 109 | } 110 | 111 | Ok(Self { 112 | dh_point_unchecked, 113 | fast_detection, 114 | body, 115 | }) 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /api/src/nextgen/structs/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::xfr::structs::AssetType; 2 | use noah_algebra::jubjub::JubjubPoint; 3 | 4 | /// The data structure for the memo. 5 | pub mod memo; 6 | pub use memo::*; 7 | 8 | /// On-chain disclosure for a new asset that has the auditability. 9 | /// 10 | /// Note: this asset is not limited to Nextgen assets. To enforce the auditability, 11 | /// the enforcement must propagate all the ways to transparent, Maxwell, and Zerocash assets. 12 | /// - Maxwell assets and Zerocash assets are completely suspended for auditable assets. 13 | /// Transactions that include auditable assets in ops that involve Maxwell or Zerocash will fail. 14 | /// - This is done by having the consensus to remember a list of all auditable assets. 15 | /// 16 | /// The disclosure performs three things: 17 | /// - declare that an asset code represents an auditable asset 18 | /// (which would be verified for consistency on the platform side). 19 | /// - provide the randomness and the signature verifying key for the auditor. 20 | /// - provide a number of signed encryption key. 21 | /// 22 | /// A transaction fee shall be charged for on-chain disclosure. 23 | /// 24 | /// This is planned to be submitted from the EVM side. 25 | /// 26 | pub struct NabarAuditableAssetIssuance { 27 | /// The asset type code after remapping. 28 | /// We expect all auditable assets be issued on the EVM side. 29 | pub remapped_asset_type: AssetType, 30 | /// The signature verifying key, which is a point on the Jubjub curve. 31 | /// 32 | /// However, note that the Jubjub curve has cofactor 8. 33 | /// Checking if the point is in the correct subgroup is cumbersome. 34 | /// 35 | /// Therefore, we choose a separate way of implementation. 36 | /// The issuance request should use sign_vk divided by 8. 37 | /// This allows the other party to get the actual point by simply 38 | /// multiplying by 8 (i.e., doubling three times). 39 | pub sign_vk_div_by_cofactor: JubjubPoint, 40 | // A list of encryption keys to be authorized. 41 | // pub enc_ek: Vec, 42 | // A list of signatures for such authorization. 43 | // pub enc_sign: Vec, 44 | } 45 | -------------------------------------------------------------------------------- /api/src/parameters/bulletproofs.rs: -------------------------------------------------------------------------------- 1 | use crate::errors::{NoahError, Result}; 2 | use crate::parameters::params::{ 3 | BULLET_PROOF_RANGE, DEFAULT_BP_NUM_GENS, MAX_CONFIDENTIAL_RECORD_NUMBER, 4 | }; 5 | use crate::parameters::{ 6 | BULLETPROOF_CURVE25519_URS, BULLETPROOF_SECQ256K1_URS, BULLETPROOF_ZORRO_URS, 7 | }; 8 | use ark_serialize::{CanonicalDeserialize, Compress, Validate}; 9 | use bulletproofs::BulletproofGens; 10 | use noah_algebra::secq256k1::Secq256k1BulletproofGens; 11 | use noah_algebra::zorro::ZorroBulletproofGens; 12 | 13 | /// The trait for Bulletproofs that can be used in Bulletproofs generators. 14 | pub trait BulletproofURS { 15 | /// Load the URS for Bulletproofs. 16 | fn load() -> Result 17 | where 18 | Self: Sized; 19 | 20 | /// Increase the Bulletproofs URS on demand. 21 | fn increase_circuit_gens(&mut self, new_size: usize); 22 | } 23 | 24 | impl BulletproofURS for BulletproofParams { 25 | fn load() -> Result { 26 | let urs = BULLETPROOF_CURVE25519_URS.ok_or(NoahError::MissingSRSError)?; 27 | 28 | let pp: BulletproofParams = 29 | bincode::deserialize(urs).map_err(|_| NoahError::DeserializationError)?; 30 | Ok(pp) 31 | } 32 | 33 | fn increase_circuit_gens(&mut self, new_size: usize) { 34 | self.bp_circuit_gens 35 | .increase_capacity(new_size.next_power_of_two()); 36 | } 37 | } 38 | 39 | impl BulletproofURS for Secq256k1BulletproofGens { 40 | fn load() -> Result { 41 | let urs = BULLETPROOF_SECQ256K1_URS.ok_or(NoahError::MissingSRSError)?; 42 | 43 | let reader = ark_std::io::BufReader::new(urs); 44 | let bp_gens = 45 | Secq256k1BulletproofGens::deserialize_with_mode(reader, Compress::No, Validate::No) 46 | .map_err(|_| NoahError::DeserializationError)?; 47 | Ok(bp_gens) 48 | } 49 | 50 | fn increase_circuit_gens(&mut self, new_size: usize) { 51 | self.increase_capacity(new_size.next_power_of_two()); 52 | } 53 | } 54 | 55 | impl BulletproofURS for ZorroBulletproofGens { 56 | fn load() -> Result { 57 | let urs = BULLETPROOF_ZORRO_URS.ok_or(NoahError::MissingSRSError)?; 58 | 59 | let reader = ark_std::io::BufReader::new(urs); 60 | let bp_gens = 61 | ZorroBulletproofGens::deserialize_with_mode(reader, Compress::No, Validate::No) 62 | .map_err(|_| NoahError::DeserializationError)?; 63 | Ok(bp_gens) 64 | } 65 | 66 | fn increase_circuit_gens(&mut self, new_size: usize) { 67 | self.increase_capacity(new_size.next_power_of_two()); 68 | } 69 | } 70 | 71 | /// The Bulletproofs URS. 72 | #[derive(Serialize, Deserialize)] 73 | pub struct BulletproofParams { 74 | /// The Bulletproofs generators. 75 | pub bp_gens: BulletproofGens, 76 | /// The Bulletproofs circuit generators. 77 | pub bp_circuit_gens: BulletproofGens, 78 | /// The number of bits in the range proof. 79 | pub range_proof_bits: usize, 80 | } 81 | 82 | impl Default for BulletproofParams { 83 | fn default() -> Self { 84 | let range_generators = 85 | BulletproofGens::new(BULLET_PROOF_RANGE, MAX_CONFIDENTIAL_RECORD_NUMBER); 86 | let circuit_generators = BulletproofGens::new(DEFAULT_BP_NUM_GENS, 1); 87 | 88 | BulletproofParams { 89 | bp_gens: range_generators, 90 | bp_circuit_gens: circuit_generators, 91 | range_proof_bits: BULLET_PROOF_RANGE, 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /crypto/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = 'noah-crypto' 3 | version = '0.5.0' 4 | authors = ['Findora '] 5 | edition = '2021' 6 | description = 'Noah Cryptographic Primitives and Protocols' 7 | 8 | [lib] 9 | name = 'noah_crypto' 10 | crate-type = ['rlib'] 11 | 12 | [[bench]] 13 | name = 'hashing' 14 | path = 'benches/hashing.rs' 15 | harness = false 16 | 17 | [dependencies] 18 | aes = '0.8.1' 19 | ctr = '0.9.1' 20 | digest = '0.10' 21 | itertools = '0.12.0' 22 | merlin = '3.0' 23 | rand_chacha = '0.3' 24 | serde = '1.0' 25 | serde_derive = '1.0' 26 | sha2 = '0.10' 27 | sha3 = { version = "0.10", default-features = false } 28 | 29 | [dependencies.noah-algebra] 30 | path = '../algebra' 31 | 32 | [dependencies.curve25519-dalek] 33 | package = "noah-curve25519-dalek" 34 | version = "4.0.0" 35 | default-features = false 36 | features = ['serde'] 37 | 38 | [dependencies.x25519-dalek] 39 | package = "noah-x25519-dalek" 40 | version = "4.0.0" 41 | 42 | [dependencies.ed25519-dalek] 43 | package = "noah-ed25519-dalek" 44 | version = "4.0.0" 45 | 46 | [dependencies.bulletproofs] 47 | package = "noah-bulletproofs" 48 | version = "4.1.0" 49 | 50 | [dependencies.ark-ec] 51 | version = '0.4.0' 52 | default-features = false 53 | 54 | [dependencies.ark-ff] 55 | version = '0.4.0' 56 | default-features = false 57 | features = ['asm'] 58 | 59 | [dependencies.ark-std] 60 | version = '0.4.0' 61 | default-features = false 62 | 63 | [dependencies.ark-ed25519] 64 | version = '0.4.0' 65 | default-features = false 66 | 67 | [dependencies.ark-secp256k1] 68 | version = '0.4.0' 69 | default-features = false 70 | 71 | [dependencies.ark-secq256k1] 72 | version = '0.4.0' 73 | default-features = false 74 | 75 | [dependencies.ark-bulletproofs] 76 | version = '4.1.0' 77 | default-features = false 78 | features = ['yoloproofs'] 79 | 80 | [dependencies.rand_core] 81 | version = '0.6' 82 | default-features = false 83 | features = ['alloc'] 84 | 85 | [dependencies.rand] 86 | version = '0.8' 87 | default-features = false 88 | 89 | [dependencies.wasm-bindgen] 90 | version = '0.2.50' 91 | features = ['serde-serialize'] 92 | 93 | [dependencies.num-integer] 94 | version = '0.1.43' 95 | 96 | [dependencies.num-traits] 97 | version = '0.2.12' 98 | 99 | [dependencies.num-bigint] 100 | version = '0.4.0' 101 | features = ['rand'] 102 | 103 | [dev-dependencies] 104 | bit-array = '0.4.3' 105 | lazy_static = '1.4.0' 106 | rmp-serde = '1.0.0' 107 | serde_json = '1.0' 108 | typenum = '1.11.2' 109 | criterion = { version = '0.5.0', default-features = false} 110 | 111 | [features] 112 | default = [ 113 | 'std', 114 | 'u64_backend', 115 | ] 116 | std = [ 117 | 'noah-algebra/std', 118 | 'curve25519-dalek/std', 119 | 'ark-bulletproofs/std', 120 | 'ark-std/std', 121 | 'ark-ec/std', 122 | 'ark-ff/std', 123 | 'ark-ed25519/std', 124 | 'ark-secp256k1/std', 125 | 'ark-secq256k1/std', 126 | 'ark-bulletproofs/std' 127 | ] 128 | alloc = ['curve25519-dalek/alloc'] 129 | nightly = [ 130 | 'curve25519-dalek/nightly', 131 | 'rand/nightly', 132 | ] 133 | u64_backend = ['curve25519-dalek/u64_backend'] 134 | u32_backend = ['curve25519-dalek/u32_backend'] 135 | avx2_backend = ['curve25519-dalek/avx2_backend'] 136 | print-trace = ['noah-algebra/print-trace'] 137 | parallel = [ 138 | 'noah-algebra/parallel', 139 | 'ark-std/parallel', 140 | 'ark-ec/parallel', 141 | 'ark-ff/parallel', 142 | 'ark-bulletproofs/parallel' 143 | ] 144 | -------------------------------------------------------------------------------- /crypto/benches/hashing.rs: -------------------------------------------------------------------------------- 1 | use criterion::{criterion_group, criterion_main, Criterion}; 2 | use noah_algebra::ed25519::{Ed25519Fq, Ed25519Point}; 3 | use noah_algebra::prelude::{test_rng, Scalar}; 4 | use noah_algebra::secp256k1::{SECP256K1Fq, SECP256K1G1}; 5 | use noah_crypto::hashing_to_the_curve::ed25519::elligator::Ed25519ElligatorParameters; 6 | use noah_crypto::hashing_to_the_curve::ed25519::sswu::Ed25519SSWUParameters; 7 | use noah_crypto::hashing_to_the_curve::ed25519::sw::Ed25519SWParameters; 8 | use noah_crypto::hashing_to_the_curve::models::elligator::Elligator; 9 | use noah_crypto::hashing_to_the_curve::models::sswu::SSWUMap; 10 | use noah_crypto::hashing_to_the_curve::models::sw::SWMap; 11 | use noah_crypto::hashing_to_the_curve::secp256k1::sswu::Secp256k1SSWUParameters; 12 | use noah_crypto::hashing_to_the_curve::secp256k1::sw::Secp256k1SWParameters; 13 | use noah_crypto::hashing_to_the_curve::traits::HashingToCurve; 14 | 15 | fn bench_ed25519_elligator(c: &mut Criterion) { 16 | let mut single_group = c.benchmark_group("ed25519_elligator"); 17 | single_group.bench_function("ed25519 elligator".to_string(), |b| { 18 | b.iter(|| { 19 | type M = Elligator; 20 | 21 | let mut rng = test_rng(); 22 | let t = Ed25519Fq::random(&mut rng); 23 | let _ = M::get_cofactor_uncleared_x(&t); 24 | }); 25 | }); 26 | single_group.finish(); 27 | } 28 | 29 | fn bench_ed25519_sswu_wb(c: &mut Criterion) { 30 | let mut single_group = c.benchmark_group("ed25519_sswu_wb"); 31 | single_group.bench_function("ed25519 simplified SWU map".to_string(), |b| { 32 | b.iter(|| { 33 | type M = SSWUMap; 34 | 35 | let mut rng = test_rng(); 36 | let t = Ed25519Fq::random(&mut rng); 37 | let _ = M::get_cofactor_uncleared_x(&t); 38 | }); 39 | }); 40 | single_group.finish(); 41 | } 42 | 43 | fn bench_ed25519_sw(c: &mut Criterion) { 44 | let mut single_group = c.benchmark_group("ed25519_sw"); 45 | single_group.bench_function("ed25519 SW map".to_string(), |b| { 46 | b.iter(|| { 47 | type M = SWMap; 48 | 49 | let mut rng = test_rng(); 50 | let t = Ed25519Fq::random(&mut rng); 51 | let _ = M::get_cofactor_uncleared_x(&t); 52 | }); 53 | }); 54 | single_group.finish(); 55 | } 56 | 57 | fn bench_secp256k1_sswu_wb(c: &mut Criterion) { 58 | let mut single_group = c.benchmark_group("secp256k1_sswu_wb"); 59 | single_group.bench_function("secp256k1 simplified SWU map".to_string(), |b| { 60 | b.iter(|| { 61 | type M = SSWUMap; 62 | 63 | let mut rng = test_rng(); 64 | let t = SECP256K1Fq::random(&mut rng); 65 | let _ = M::get_cofactor_uncleared_x(&t); 66 | }); 67 | }); 68 | single_group.finish(); 69 | } 70 | 71 | fn bench_secp256k1_sw(c: &mut Criterion) { 72 | let mut single_group = c.benchmark_group("secp256k1_sw"); 73 | single_group.bench_function("secp256k1 SW map".to_string(), |b| { 74 | b.iter(|| { 75 | type M = SWMap; 76 | 77 | let mut rng = test_rng(); 78 | let t = SECP256K1Fq::random(&mut rng); 79 | let _ = M::get_cofactor_uncleared_x(&t); 80 | }); 81 | }); 82 | single_group.finish(); 83 | } 84 | 85 | criterion_group!( 86 | benches, 87 | bench_ed25519_elligator, 88 | bench_ed25519_sswu_wb, 89 | bench_ed25519_sw, 90 | bench_secp256k1_sswu_wb, 91 | bench_secp256k1_sw 92 | ); 93 | criterion_main!(benches); 94 | -------------------------------------------------------------------------------- /crypto/src/anemoi_jive/mds.rs: -------------------------------------------------------------------------------- 1 | use noah_algebra::prelude::Scalar; 2 | 3 | /// The MDS matrix 4 | pub struct MDSMatrix(pub [[F; N]; N]); 5 | 6 | impl Default for MDSMatrix { 7 | fn default() -> Self { 8 | Self([[F::default(); N]; N]) 9 | } 10 | } 11 | 12 | /// The trait for MDS matrix that can be used in Anemoi-Jive CRH. 13 | pub trait ApplicableMDSMatrix { 14 | /// Construct the MDS matrix from the generator. 15 | fn from_generator(generator: &F) -> Self; 16 | 17 | /// Perform the permutation in place. 18 | fn permute_in_place(&self, x: &mut [F; N], y: &mut [F; N]); 19 | 20 | /// Perform the permutation and return the result. 21 | fn permute(&self, x: &[F; N], y: &[F; N]) -> ([F; N], [F; N]) { 22 | let mut x: [F; N] = *x; 23 | let mut y: [F; N] = *y; 24 | self.permute_in_place(&mut x, &mut y); 25 | (x, y) 26 | } 27 | } 28 | 29 | impl ApplicableMDSMatrix for MDSMatrix { 30 | fn from_generator(generator: &F) -> Self { 31 | // The matrix is: 32 | // ⌈ 1 g ⌉ 33 | // ⌊ g g^2 + 1 ⌋ 34 | Self([ 35 | [F::one(), *generator], 36 | [*generator, generator.square().add(F::one())], 37 | ]) 38 | } 39 | 40 | fn permute_in_place(&self, x: &mut [F; 2], y: &mut [F; 2]) { 41 | // Reminder: a different matrix is applied to x and y 42 | // The one for y has a simple word permutation. 43 | 44 | let old_x = *x; 45 | for (i, _x) in x.iter_mut().enumerate().take(2) { 46 | *_x = F::zero(); 47 | for (j, ox) in old_x.iter().enumerate() { 48 | *_x += &(self.0[i][j] * ox); 49 | } 50 | } 51 | 52 | // y has a simple word permutation. 53 | let old_y = [y[1], y[0]]; 54 | for (i, _y) in y.iter_mut().enumerate().take(2) { 55 | *_y = F::zero(); 56 | for (j, oy) in old_y.iter().enumerate() { 57 | *_y += &(self.0[i][j] * oy); 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /crypto/src/anemoi_jive/salts/mod.rs: -------------------------------------------------------------------------------- 1 | /// The salts for Anemoi-Jive on BLS12-381. 2 | mod bls12_381; 3 | /// The salts for Anemoi-Jive on BN254. 4 | mod bn254; 5 | 6 | pub use bls12_381::*; 7 | pub use bn254::*; 8 | -------------------------------------------------------------------------------- /crypto/src/anemoi_jive/tests/mod.rs: -------------------------------------------------------------------------------- 1 | /// The consistency tests for Anemoi-Jive on BLS12-381. 2 | #[cfg(test)] 3 | mod bls12_381; 4 | /// The consistency tests for the deprecated version of Anemoi-Jive on BLS12-381. 5 | #[cfg(test)] 6 | mod bls12_381_deprecated; 7 | /// The consistency tests for Anemoi-Jive on BN254. 8 | #[cfg(test)] 9 | mod bn254; 10 | -------------------------------------------------------------------------------- /crypto/src/bulletproofs/hashing_to_the_curve/mod.rs: -------------------------------------------------------------------------------- 1 | //! Module for hashing to the curve. 2 | 3 | /// Module for hashing to the curve proof on ed25519. 4 | pub mod ed25519_elligator; 5 | /// Module for hashing to the curve proof on secp256k1. 6 | pub mod secp256k1_sswu; 7 | -------------------------------------------------------------------------------- /crypto/src/bulletproofs/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod hashing_to_the_curve; 2 | pub mod mix; 3 | pub mod plume; 4 | pub mod range; 5 | pub mod scalar_mul; 6 | -------------------------------------------------------------------------------- /crypto/src/bulletproofs/plume/ed25519.rs: -------------------------------------------------------------------------------- 1 | use crate::bulletproofs::plume::Plume; 2 | use noah_algebra::ed25519::{Ed25519Fq, Ed25519Point}; 3 | use noah_algebra::new_ed25519_fq; 4 | use noah_algebra::prelude::*; 5 | 6 | /// The PLUME implementation for secp256k1. 7 | pub struct PlumeEd25519; 8 | 9 | impl Plume for PlumeEd25519 { 10 | fn get_generator_g() -> Ed25519Point { 11 | Ed25519Point::get_base() 12 | } 13 | 14 | fn get_generator_h() -> Ed25519Point { 15 | Ed25519Point::new( 16 | &new_ed25519_fq!( 17 | "1758682557278622166727084222880667175348907971062636411700231506689670444406" 18 | ), 19 | &new_ed25519_fq!( 20 | "18728682362703376192931234188131080883036471711603517790343415579409605924262" 21 | ), 22 | ) 23 | } 24 | } 25 | 26 | #[cfg(test)] 27 | mod test { 28 | use crate::bulletproofs::plume::ed25519::PlumeEd25519; 29 | use crate::bulletproofs::plume::Plume; 30 | use crate::hashing_to_the_curve::ed25519::elligator::Ed25519ElligatorParameters; 31 | use crate::hashing_to_the_curve::models::elligator::Elligator; 32 | use crate::hashing_to_the_curve::traits::HashingToCurve; 33 | use digest::Digest; 34 | use noah_algebra::ed25519::{Ed25519Fq, Ed25519Point}; 35 | use noah_algebra::prelude::*; 36 | use rand_chacha::ChaChaRng; 37 | use sha3::Sha3_512; 38 | 39 | #[test] 40 | fn generator_h_correctness() { 41 | let mut hash = Sha3_512::new(); 42 | Digest::update(&mut hash, b"Ed25519 PLUME Implementation"); 43 | let h = hash.finalize(); 44 | 45 | let mut res = [0u8; 32]; 46 | res.copy_from_slice(&h[..32]); 47 | 48 | let mut prng = ChaChaRng::from_seed(res); 49 | let hash_for_map = Ed25519Fq::random(&mut prng); 50 | 51 | let p = 52 | Elligator::::get_cofactor_uncleared_point( 53 | &hash_for_map, 54 | ) 55 | .unwrap(); 56 | 57 | let point = 58 | Elligator::::convert_to_group(&p.0, &p.1) 59 | .unwrap(); 60 | let point = point.double().double().double(); // clear the cofactor 61 | assert_eq!(PlumeEd25519::get_generator_h(), point); 62 | assert!(point.get_raw().is_in_correct_subgroup_assuming_on_curve()); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /crypto/src/bulletproofs/plume/mod.rs: -------------------------------------------------------------------------------- 1 | //! Module for the PLUME protocol. 2 | 3 | use crate::errors::Result; 4 | use noah_algebra::prelude::*; 5 | 6 | /// The module for the PLUME implementation over ed25519. 7 | pub mod ed25519; 8 | 9 | /// The module for the PLUME implementation over secp256k1. 10 | pub mod secp256k1; 11 | 12 | /// The committed input for the PLUME protocol, which would be bridged between the Plonk proof. 13 | #[derive(Clone, Default)] 14 | pub struct PlumeCommittedInput { 15 | /// The public key of the signature. 16 | pub pk: G, 17 | /// The signature. 18 | pub sigma: G, 19 | /// The hash of the message. 20 | pub msg_hash: G::BaseType, 21 | /// The hash commitment blinding factors. 22 | pub h_blinding_factors: Vec, 23 | } 24 | 25 | /// A PLUME proof. 26 | #[derive(Clone, Default)] 27 | pub struct PlumeProof { 28 | /// The Bulletproof. 29 | pub proof_star: Vec, 30 | /// The hash commitments. 31 | pub h: Vec, 32 | /// The randomized signature, divided by the cofactor if there is any. 33 | pub sigma_star_div_by_cofactor: G, 34 | /// The R1 point, divided by the cofactor if there is any. 35 | pub point_r_1_div_by_cofactor: G, 36 | /// The R2 point, divided by the cofactor if there is any. 37 | pub point_r_2_div_by_cofactor: G, 38 | /// The response to the challenge. 39 | pub s: G::ScalarType, 40 | } 41 | 42 | /// The struct of the input to the delegation (precomputation) algorithm. 43 | #[derive(Clone, Default)] 44 | pub struct PlumeDelegationInput { 45 | /// The randomized signature. 46 | pub sigma_star: G, 47 | /// The R1 point. 48 | pub point_r1: G, 49 | /// The R2 point. 50 | pub point_r2: G, 51 | /// The response to the challenge. 52 | pub s: G::ScalarType, 53 | /// The challenge. 54 | pub beta: G::ScalarType, 55 | } 56 | 57 | /// The struct of the delegation (precomputation) result for PLUME. 58 | #[derive(Clone, Default)] 59 | pub struct PlumeDelegationResult { 60 | /// The precomputed first left-hand-side result. 61 | pub lhs_1: G, 62 | /// The precomputed second left-hand-side result. 63 | pub lhs_2: G, 64 | /// The precomputed powers of point s^{-1} H. 65 | pub s_inv_point_h: Vec, 66 | /// The precomputed powers of point H. 67 | pub point_h: Vec, 68 | /// The precomputed powers of point beta H. 69 | pub beta_point_h: Vec, 70 | } 71 | 72 | /// The trait for a Plume implementation. 73 | pub trait Plume { 74 | /// Return the point G, the generator for the public key of the signature scheme. 75 | fn get_generator_g() -> G; 76 | /// Return the point H, the generator specifically for the randomizer used in the PLUME protocol. 77 | fn get_generator_h() -> G; 78 | 79 | /// Compute the delegated verification. 80 | fn do_delegation(input: &PlumeDelegationInput) -> Result> { 81 | let beta_point_r1 = input.point_r1.mul(&input.beta); 82 | let sigma_star_plus_beta_point_r1 = beta_point_r1 + &input.sigma_star; 83 | 84 | let s_inv = input.s.inv()?; 85 | let lhs_1 = sigma_star_plus_beta_point_r1.mul(&s_inv); 86 | 87 | let beta_point_r2 = input.point_r2.mul(&input.beta); 88 | let s_point_g = Self::get_generator_g().mul(&input.s); 89 | let lhs_2 = beta_point_r2 - &s_point_g; 90 | 91 | let point_h_base = Self::get_generator_h(); 92 | 93 | let s_inv_point_h_base = point_h_base.mul(&s_inv); 94 | let beta_point_h_base = point_h_base.mul(&input.beta); 95 | 96 | let mut s_inv_point_h = Vec::new(); 97 | let mut point_h = Vec::new(); 98 | let mut beta_point_h = Vec::new(); 99 | 100 | let num_scalar_bits = G::ScalarType::get_field_size_biguint().bits(); 101 | 102 | let mut cur = s_inv_point_h_base; 103 | s_inv_point_h.push(cur); 104 | for _ in 1..num_scalar_bits { 105 | cur = cur.double(); 106 | s_inv_point_h.push(cur); 107 | } 108 | 109 | let mut cur = point_h_base; 110 | point_h.push(cur); 111 | for _ in 1..num_scalar_bits { 112 | cur = cur.double(); 113 | point_h.push(cur); 114 | } 115 | 116 | let mut cur = beta_point_h_base; 117 | beta_point_h.push(cur); 118 | for _ in 1..num_scalar_bits { 119 | cur = cur.double(); 120 | beta_point_h.push(cur); 121 | } 122 | 123 | let res = PlumeDelegationResult:: { 124 | lhs_1, 125 | lhs_2, 126 | s_inv_point_h, 127 | point_h, 128 | beta_point_h, 129 | }; 130 | Ok(res) 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /crypto/src/bulletproofs/plume/secp256k1.rs: -------------------------------------------------------------------------------- 1 | use crate::bulletproofs::plume::Plume; 2 | use noah_algebra::new_secp256k1_fq; 3 | use noah_algebra::prelude::*; 4 | use noah_algebra::secp256k1::{SECP256K1Fq, SECP256K1G1}; 5 | 6 | /// The PLUME implementation for secp256k1. 7 | pub struct PlumeSecp256k1; 8 | 9 | impl Plume for PlumeSecp256k1 { 10 | fn get_generator_g() -> SECP256K1G1 { 11 | SECP256K1G1::get_base() 12 | } 13 | 14 | fn get_generator_h() -> SECP256K1G1 { 15 | SECP256K1G1::new( 16 | &new_secp256k1_fq!( 17 | "46190662746725679415425739992994142449475516927403715234504411186769117430887" 18 | ), 19 | &new_secp256k1_fq!( 20 | "69436746129075925653002611114933784451034614444154979397886909819606273822058" 21 | ), 22 | ) 23 | } 24 | } 25 | 26 | #[cfg(test)] 27 | mod test { 28 | use crate::bulletproofs::plume::secp256k1::PlumeSecp256k1; 29 | use crate::bulletproofs::plume::Plume; 30 | use crate::hashing_to_the_curve::models::sswu::SSWUMap; 31 | use crate::hashing_to_the_curve::secp256k1::sswu::Secp256k1SSWUParameters; 32 | use crate::hashing_to_the_curve::traits::HashingToCurve; 33 | use digest::Digest; 34 | use noah_algebra::prelude::*; 35 | use noah_algebra::secp256k1::{SECP256K1Fq, SECP256K1G1}; 36 | use rand_chacha::ChaChaRng; 37 | use sha3::Sha3_512; 38 | 39 | #[test] 40 | fn generator_h_correctness() { 41 | let mut hash = Sha3_512::new(); 42 | Digest::update(&mut hash, b"Secp256k1 PLUME Implementation"); 43 | let h = hash.finalize(); 44 | 45 | let mut res = [0u8; 32]; 46 | res.copy_from_slice(&h[..32]); 47 | 48 | let mut prng = ChaChaRng::from_seed(res); 49 | let hash_for_map = SECP256K1Fq::random(&mut prng); 50 | 51 | let p = SSWUMap::::get_cofactor_uncleared_point( 52 | &hash_for_map, 53 | ) 54 | .unwrap(); 55 | 56 | let point = 57 | SSWUMap::::convert_to_group(&p.0, &p.1).unwrap(); 58 | assert_eq!(PlumeSecp256k1::get_generator_h(), point); 59 | assert!(point.get_raw().is_in_correct_subgroup_assuming_on_curve()); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /crypto/src/bulletproofs/range.rs: -------------------------------------------------------------------------------- 1 | //! Module for the Bulletproof range proof scheme 2 | //! 3 | //! This is mostly a wrapper. 4 | 5 | use crate::errors::Result; 6 | use bulletproofs::{BulletproofGens, PedersenGens, RangeProof}; 7 | use merlin::Transcript; 8 | use noah_algebra::prelude::*; 9 | use noah_algebra::ristretto::CompressedRistretto; 10 | use noah_algebra::ristretto::RistrettoScalar as Scalar; 11 | 12 | /// Generate a Bulletproof range proof that values committed using `blindings` 13 | /// are within [0..2^{`log_range_upper_bound`}-1]. 14 | pub fn prove_ranges( 15 | bp_gens: &BulletproofGens, 16 | transcript: &mut Transcript, 17 | values: &[u64], 18 | blindings: &[Scalar], 19 | log_range_upper_bound: usize, 20 | ) -> Result<(RangeProof, Vec)> { 21 | let blindings = blindings.iter().map(|s| s.0).collect_vec(); 22 | let pc_gens = PedersenGens::default(); 23 | let (proof, coms) = RangeProof::prove_multiple( 24 | bp_gens, 25 | &pc_gens, 26 | transcript, 27 | values, 28 | &blindings, 29 | log_range_upper_bound, 30 | )?; 31 | let commitments = coms.iter().map(|x| CompressedRistretto(*x)).collect_vec(); 32 | Ok((proof, commitments)) 33 | } 34 | 35 | /// Batch-verify a set bulletproof range proofs 36 | /// State of transcripts should match the state just before each proof was computed 37 | pub fn batch_verify_ranges( 38 | prng: &mut R, 39 | bp_gens: &BulletproofGens, 40 | proofs: &[&RangeProof], 41 | transcripts: &mut [Transcript], 42 | commitments: &[&[CompressedRistretto]], 43 | log_range_upper_bound: usize, 44 | ) -> Result<()> { 45 | let pc_gens = PedersenGens::default(); 46 | let mut comms = vec![]; 47 | for slice in commitments { 48 | let v = slice.iter().map(|x| x.0).collect_vec(); 49 | comms.push(v); 50 | } 51 | let mut slices: Vec<&[curve25519_dalek::ristretto::CompressedRistretto]> = vec![]; 52 | for v in comms.iter() { 53 | slices.push(v.as_slice()); 54 | } 55 | 56 | RangeProof::batch_verify( 57 | prng, 58 | proofs, 59 | transcripts, 60 | slices.as_slice(), 61 | bp_gens, 62 | &pc_gens, 63 | log_range_upper_bound, 64 | )?; 65 | Ok(()) 66 | } 67 | -------------------------------------------------------------------------------- /crypto/src/bulletproofs/scalar_mul/mod.rs: -------------------------------------------------------------------------------- 1 | //! Module for the Bulletproof scalar mul proofs. 2 | 3 | /// Module for the Bulletproof scalar mul proof on ed25519. 4 | pub mod ed25519; 5 | /// Module for the Bulletproof scalar mul proof on secp256k1. 6 | pub mod secp256k1; 7 | -------------------------------------------------------------------------------- /crypto/src/doubly_snark_friendly/ecies_encryption.rs: -------------------------------------------------------------------------------- 1 | use crate::anemoi_jive::AnemoiJive; 2 | use noah_algebra::prelude::*; 3 | use rand_core::{CryptoRng, RngCore}; 4 | 5 | /// The encryption key is often also called public key. 6 | #[derive(Clone, Default, Debug, Eq, PartialEq)] 7 | pub struct ECIESEncryptionKey(pub G); 8 | 9 | /// The decryption key is also often called secret key. 10 | #[derive(Clone, Default, Debug, Eq, PartialEq)] 11 | pub struct ECIESDecryptionKey(pub G::ScalarType); 12 | 13 | /// The ciphertext. 14 | #[derive(Clone, Default, Debug, Eq, PartialEq)] 15 | pub struct ECIESCiphertext { 16 | /// The Diffie-Hellman key exchange group element divided by the cofactor. 17 | pub dh_point_div_by_cofactor: G, 18 | /// the ciphertexts. 19 | pub ciphertext: Vec, 20 | } 21 | 22 | /// The plaintext. 23 | #[derive(Clone, Default, Debug, Eq, PartialEq)] 24 | pub struct ECIESPlaintext(pub Vec); 25 | 26 | /// The keypair for the ECIES encryption. 27 | #[derive(Clone, Default, Debug, Eq, PartialEq)] 28 | pub struct ECIESKeyPair { 29 | /// The encryption key. 30 | pub(crate) encryption_key: ECIESEncryptionKey, 31 | /// The decryption key. 32 | pub(crate) decryption_key: ECIESDecryptionKey, 33 | } 34 | 35 | impl ECIESKeyPair { 36 | /// Sample the key pair. 37 | pub fn sample(prng: &mut R) -> Self { 38 | let decryption_key = G::ScalarType::random(prng); 39 | let encryption_key = G::get_base().mul(&decryption_key); 40 | 41 | Self { 42 | encryption_key: ECIESEncryptionKey(encryption_key), 43 | decryption_key: ECIESDecryptionKey(decryption_key), 44 | } 45 | } 46 | 47 | /// Get the encryption key. 48 | pub fn get_encryption_key(&self) -> ECIESEncryptionKey { 49 | self.encryption_key.clone() 50 | } 51 | 52 | /// Get the decryption key. 53 | pub fn get_decryption_key(&self) -> ECIESDecryptionKey { 54 | self.decryption_key.clone() 55 | } 56 | } 57 | 58 | impl ECIESDecryptionKey { 59 | /// Decrypt the ciphertext with the decryption key. 60 | pub fn decrypt(&self, ciphertext: &ECIESCiphertext) -> ECIESPlaintext 61 | where 62 | H: AnemoiJive, 63 | { 64 | let point = ciphertext 65 | .dh_point_div_by_cofactor 66 | .multiply_by_cofactor() 67 | .mul(&self.0); 68 | let mask = H::eval_stream_cipher( 69 | &[G::BaseType::zero(), point.get_x(), point.get_y()], 70 | ciphertext.ciphertext.len(), 71 | ); 72 | 73 | let mut plaintext = Vec::::with_capacity(ciphertext.ciphertext.len()); 74 | for (c, m) in ciphertext.ciphertext.iter().zip(mask.iter()) { 75 | plaintext.push(*c - m); 76 | } 77 | 78 | ECIESPlaintext(plaintext) 79 | } 80 | 81 | /// Get the raw scalar element. 82 | pub fn get_raw(&self) -> G::ScalarType { 83 | self.0 84 | } 85 | 86 | /// Reconstruct from the raw scalar element. 87 | pub fn from_raw(raw: G::ScalarType) -> Self { 88 | Self(raw) 89 | } 90 | 91 | /// Compute the corresponding encryption key. 92 | pub fn to_encryption_key(&self) -> ECIESEncryptionKey { 93 | ECIESEncryptionKey(G::get_base().mul(&self.0)) 94 | } 95 | } 96 | 97 | impl ECIESEncryptionKey { 98 | /// Encrypt the plaintext with the encryption key. 99 | pub fn encrypt(&self, prng: &mut R, plaintext: &ECIESPlaintext) -> ECIESCiphertext 100 | where 101 | H: AnemoiJive, 102 | R: CryptoRng + RngCore, 103 | { 104 | let k = G::ScalarType::random(prng); 105 | 106 | let point = self.0.mul(&k); 107 | let point_div_by_cofactor = G::get_point_div_by_cofactor().mul(&k); 108 | 109 | let mask = H::eval_stream_cipher( 110 | &[G::BaseType::zero(), point.get_x(), point.get_y()], 111 | plaintext.0.len(), 112 | ); 113 | 114 | let mut ciphertext = Vec::::with_capacity(plaintext.0.len()); 115 | for (p, m) in plaintext.0.iter().zip(mask.iter()) { 116 | ciphertext.push(*p + m); 117 | } 118 | 119 | ECIESCiphertext { 120 | dh_point_div_by_cofactor: point_div_by_cofactor, 121 | ciphertext, 122 | } 123 | } 124 | } 125 | 126 | #[cfg(test)] 127 | mod tests { 128 | use noah_algebra::{ 129 | baby_jubjub::BabyJubjubPoint, bn254::BN254Scalar, rand_helper::test_rng, traits::Scalar, 130 | }; 131 | 132 | use crate::anemoi_jive::AnemoiJive254; 133 | use crate::doubly_snark_friendly::ecies_encryption::{ECIESKeyPair, ECIESPlaintext}; 134 | 135 | #[test] 136 | fn test_ecies_encryption() { 137 | let mut rng = test_rng(); 138 | 139 | let key_pair = ECIESKeyPair::::sample(&mut rng); 140 | 141 | let encryption_key = key_pair.get_encryption_key(); 142 | let decryption_key = key_pair.get_decryption_key(); 143 | 144 | let msg = vec![ 145 | BN254Scalar::random(&mut rng), 146 | BN254Scalar::random(&mut rng), 147 | BN254Scalar::random(&mut rng), 148 | BN254Scalar::random(&mut rng), 149 | BN254Scalar::random(&mut rng), 150 | ]; 151 | 152 | let c = encryption_key.encrypt::(&mut rng, &ECIESPlaintext(msg.clone())); 153 | let p = decryption_key.decrypt::(&c); 154 | 155 | assert_eq!(msg, p.0); 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /crypto/src/doubly_snark_friendly/mod.rs: -------------------------------------------------------------------------------- 1 | /// The module for the Schnorr signature. 2 | pub mod schnorr_signature; 3 | 4 | /// The module for ECIES encryption. 5 | pub mod ecies_encryption; 6 | -------------------------------------------------------------------------------- /crypto/src/doubly_snark_friendly/schnorr_signature.rs: -------------------------------------------------------------------------------- 1 | use crate::anemoi_jive::AnemoiJive; 2 | use crate::errors::{CryptoError, Result}; 3 | use noah_algebra::prelude::*; 4 | 5 | /// The Schnorr signing key is often also called private key. 6 | #[derive(Clone, Default, Debug, Eq, PartialEq)] 7 | pub struct SchnorrSigningKey(pub G::ScalarType); 8 | 9 | /// The Schnorr verifying key is also often called public key. 10 | #[derive(Clone, Default, Debug, Eq, PartialEq)] 11 | pub struct SchnorrVerifyingKey(pub G); 12 | 13 | /// The Schnorr signature. 14 | #[derive(Clone, Default, Debug, Eq, PartialEq)] 15 | pub struct SchnorrSignature { 16 | /// The s element of the signature. 17 | pub schnorr_s: G::ScalarType, 18 | /// the e element of the signature. 19 | pub schnorr_e: G::BaseType, 20 | } 21 | 22 | /// The keypair for Schnorr signature. 23 | #[derive(Clone, Default, Debug, Eq, PartialEq)] 24 | pub struct SchnorrKeyPair { 25 | /// The verifying key. 26 | pub(crate) verifying_key: SchnorrVerifyingKey, 27 | /// The secret key. 28 | pub(crate) signing_key: SchnorrSigningKey, 29 | } 30 | 31 | impl SchnorrKeyPair { 32 | /// Sample the key pair. 33 | pub fn sample(prng: &mut R) -> Self { 34 | let signing_key = G::ScalarType::random(prng); 35 | let verifying_key = G::get_base().mul(&signing_key); 36 | 37 | Self { 38 | verifying_key: SchnorrVerifyingKey(verifying_key), 39 | signing_key: SchnorrSigningKey(signing_key), 40 | } 41 | } 42 | 43 | /// Get the verifying key. 44 | pub fn get_verifying_key(&self) -> SchnorrVerifyingKey { 45 | self.verifying_key.clone() 46 | } 47 | 48 | /// Get the signing key. 49 | pub fn get_signing_key(&self) -> SchnorrSigningKey { 50 | self.signing_key.clone() 51 | } 52 | } 53 | 54 | impl SchnorrSigningKey { 55 | /// Sign the message with the signing key. 56 | pub fn sign( 57 | &self, 58 | prng: &mut R, 59 | aux: G::BaseType, 60 | msg: &[G::BaseType], 61 | ) -> SchnorrSignature 62 | where 63 | H: AnemoiJive, 64 | R: CryptoRng + RngCore, 65 | { 66 | let k = G::ScalarType::random(prng); 67 | let point_r = G::get_base().mul(&k); 68 | 69 | let mut input = vec![aux, point_r.get_x(), point_r.get_y()]; 70 | input.extend_from_slice(msg); 71 | 72 | let e = H::eval_variable_length_hash(&input); 73 | 74 | // This will perform a modular reduction. 75 | let e_converted = G::ScalarType::from(&e.into()); 76 | 77 | let s = k - &(self.0 * e_converted); 78 | 79 | SchnorrSignature { 80 | schnorr_s: s, 81 | schnorr_e: e, 82 | } 83 | } 84 | 85 | /// Get the raw scalar element. 86 | pub fn get_raw(&self) -> G::ScalarType { 87 | self.0 88 | } 89 | 90 | /// Reconstruct from the raw scalar element. 91 | pub fn from_raw(raw: G::ScalarType) -> Self { 92 | Self(raw) 93 | } 94 | 95 | /// Compute the corresponding verifying key. 96 | pub fn to_verifying_key(&self) -> SchnorrVerifyingKey { 97 | SchnorrVerifyingKey(G::get_base().mul(&self.0)) 98 | } 99 | } 100 | 101 | impl SchnorrVerifyingKey { 102 | /// Verify the signature with the verifying key. 103 | pub fn verify( 104 | &self, 105 | signature: &SchnorrSignature, 106 | aux: G::BaseType, 107 | msg: &[G::BaseType], 108 | ) -> Result<()> 109 | where 110 | H: AnemoiJive, 111 | { 112 | let e_converted = G::ScalarType::from(&signature.schnorr_e.into()); 113 | 114 | let point_r_recovered = G::get_base().mul(&signature.schnorr_s) + &self.0.mul(&e_converted); 115 | 116 | let mut input = vec![aux, point_r_recovered.get_x(), point_r_recovered.get_y()]; 117 | input.extend_from_slice(msg); 118 | 119 | let e: G::BaseType = H::eval_variable_length_hash(&input); 120 | 121 | if e != signature.schnorr_e { 122 | Err(CryptoError::SignatureError) 123 | } else { 124 | Ok(()) 125 | } 126 | } 127 | } 128 | 129 | #[cfg(test)] 130 | mod tests { 131 | use noah_algebra::{ 132 | baby_jubjub::BabyJubjubPoint, bn254::BN254Scalar, rand_helper::test_rng, traits::Scalar, 133 | }; 134 | 135 | use crate::anemoi_jive::AnemoiJive254; 136 | 137 | use super::SchnorrKeyPair; 138 | 139 | #[test] 140 | fn test_schnorr_signature() { 141 | let mut rng = test_rng(); 142 | 143 | let key_pair = SchnorrKeyPair::::sample(&mut rng); 144 | 145 | let verifying_key = key_pair.get_verifying_key(); 146 | let signing_key = key_pair.get_signing_key(); 147 | 148 | let msg = vec![ 149 | BN254Scalar::random(&mut rng), 150 | BN254Scalar::random(&mut rng), 151 | BN254Scalar::random(&mut rng), 152 | BN254Scalar::random(&mut rng), 153 | BN254Scalar::random(&mut rng), 154 | ]; 155 | 156 | let aux = BN254Scalar::random(&mut rng); 157 | 158 | let sign = signing_key.sign::(&mut rng, aux, &msg); 159 | 160 | assert!(verifying_key 161 | .verify::(&sign, aux, &msg) 162 | .is_ok()); 163 | assert!(verifying_key 164 | .verify::(&sign, aux, &msg[..4]) 165 | .is_err()); 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /crypto/src/elgamal.rs: -------------------------------------------------------------------------------- 1 | use crate::errors::{CryptoError, Result}; 2 | use noah_algebra::ristretto::RistrettoPoint; 3 | use noah_algebra::{ 4 | hash::{Hash, Hasher}, 5 | prelude::*, 6 | }; 7 | 8 | #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] 9 | /// The ElGamal encryption key/public key. 10 | pub struct ElGamalEncKey(pub G); 11 | 12 | #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] 13 | /// The ElGamal decryption key/secret key. 14 | pub struct ElGamalDecKey(pub(crate) S); 15 | 16 | #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] 17 | /// An ElGamal ciphertext. 18 | pub struct ElGamalCiphertext { 19 | /// `e1` = `r * G` 20 | pub e1: G, 21 | /// `e2` = `m * G + r * pk` 22 | pub e2: G, 23 | } 24 | 25 | impl Hash for ElGamalEncKey { 26 | fn hash(&self, state: &mut H) { 27 | self.0.to_compressed_bytes().as_slice().hash(state); 28 | } 29 | } 30 | 31 | impl NoahFromToBytes for ElGamalCiphertext { 32 | fn noah_to_bytes(&self) -> Vec { 33 | let mut v = vec![]; 34 | v.extend_from_slice(self.e1.to_compressed_bytes().as_slice()); 35 | v.extend_from_slice(self.e2.to_compressed_bytes().as_slice()); 36 | v 37 | } 38 | fn noah_from_bytes(bytes: &[u8]) -> core::result::Result { 39 | let e1 = RistrettoPoint::from_compressed_bytes(&bytes[0..RistrettoPoint::COMPRESSED_LEN])?; 40 | let e2 = RistrettoPoint::from_compressed_bytes(&bytes[RistrettoPoint::COMPRESSED_LEN..])?; 41 | Ok(ElGamalCiphertext { e1, e2 }) 42 | } 43 | } 44 | 45 | /// Return an ElGamal key pair as `(sk, pk = sk * G)` 46 | pub fn elgamal_key_gen( 47 | prng: &mut R, 48 | ) -> (ElGamalDecKey, ElGamalEncKey) { 49 | let base = G::get_base(); 50 | let secret_key = ElGamalDecKey(G::ScalarType::random(prng)); 51 | let public_key = ElGamalEncKey(base.mul(&secret_key.0)); 52 | (secret_key, public_key) 53 | } 54 | 55 | /// Return an ElGamal ciphertext pair as `(r * G, m * G + r * pk)`, where `G` is a base point on the curve 56 | pub fn elgamal_encrypt( 57 | m: &G::ScalarType, 58 | r: &G::ScalarType, 59 | pub_key: &ElGamalEncKey, 60 | ) -> ElGamalCiphertext { 61 | let base = G::get_base(); 62 | let e1 = base.mul(r); 63 | let e2 = base.mul(m).add(&(pub_key.0).mul(r)); 64 | 65 | ElGamalCiphertext:: { e1, e2 } 66 | } 67 | 68 | /// Verify that the ElGamal ciphertext encrypts m by checking `ctext.e2 - ctext.e1 * sk = m * G` 69 | pub fn elgamal_verify( 70 | m: &G::ScalarType, 71 | ctext: &ElGamalCiphertext, 72 | sec_key: &ElGamalDecKey, 73 | ) -> Result<()> { 74 | let base = G::get_base(); 75 | if base.mul(m).add(&ctext.e1.mul(&sec_key.0)) == ctext.e2 { 76 | Ok(()) 77 | } else { 78 | Err(CryptoError::ElGamalVerificationError) 79 | } 80 | } 81 | 82 | /// Perform a partial decryption for the ElGamal ciphertext that returns `m * G` 83 | pub fn elgamal_partial_decrypt( 84 | ctext: &ElGamalCiphertext, 85 | sec_key: &ElGamalDecKey, 86 | ) -> G { 87 | ctext.e2.sub(&ctext.e1.mul(&sec_key.0)) 88 | } 89 | 90 | #[cfg(test)] 91 | mod elgamal_test { 92 | use noah_algebra::bls12_381::BLSGt; 93 | use noah_algebra::bls12_381::BLSG1; 94 | use noah_algebra::bls12_381::BLSG2; 95 | use noah_algebra::prelude::*; 96 | use noah_algebra::ristretto::RistrettoPoint; 97 | 98 | use crate::errors::CryptoError; 99 | 100 | fn verification() { 101 | let mut prng = test_rng(); 102 | 103 | let (secret_key, public_key) = super::elgamal_key_gen::<_, G>(&mut prng); 104 | 105 | let m = G::ScalarType::from(100u32); 106 | let r = G::ScalarType::random(&mut prng); 107 | let ctext = super::elgamal_encrypt::(&m, &r, &public_key); 108 | super::elgamal_verify::(&m, &ctext, &secret_key).unwrap(); 109 | 110 | let wrong_m = G::ScalarType::from(99u32); 111 | let err = super::elgamal_verify(&wrong_m, &ctext, &secret_key) 112 | .err() 113 | .unwrap(); 114 | assert_eq!(CryptoError::ElGamalVerificationError, err); 115 | } 116 | 117 | fn decryption() { 118 | let mut prng = test_rng(); 119 | let (secret_key, public_key) = super::elgamal_key_gen::<_, G>(&mut prng); 120 | 121 | let mu32 = 100u32; 122 | let m = G::ScalarType::from(mu32); 123 | let r = G::ScalarType::random(&mut prng); 124 | let ctext = super::elgamal_encrypt(&m, &r, &public_key); 125 | super::elgamal_verify(&m, &ctext, &secret_key).unwrap(); 126 | 127 | let m = G::ScalarType::from(u64::MAX); 128 | let ctext = super::elgamal_encrypt(&m, &r, &public_key); 129 | super::elgamal_verify(&m, &ctext, &secret_key).unwrap(); 130 | } 131 | 132 | #[test] 133 | fn verify() { 134 | verification::(); 135 | verification::(); 136 | verification::(); 137 | verification::(); 138 | } 139 | 140 | #[test] 141 | fn decrypt() { 142 | decryption::(); 143 | decryption::(); 144 | decryption::(); 145 | decryption::(); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /crypto/src/errors.rs: -------------------------------------------------------------------------------- 1 | use ark_bulletproofs::{r1cs::R1CSError as ArkR1CSError, ProofError as ArkProofError}; 2 | use ark_std::{boxed::Box, error, fmt, format}; 3 | use bulletproofs::{r1cs::R1CSError, ProofError}; 4 | use noah_algebra::prelude::AlgebraError; 5 | 6 | pub(crate) type Result = core::result::Result; 7 | 8 | #[derive(Debug, Clone, Eq, PartialEq)] 9 | #[allow(missing_docs)] 10 | pub enum CryptoError { 11 | ParameterError, 12 | SignatureError, 13 | AnonymousCredentialSignError, 14 | IdentityRevealVerifyError, 15 | ElGamalVerificationError, 16 | ZKProofVerificationError, 17 | ZKProofBatchVerificationError, 18 | Algebra(AlgebraError), 19 | R1CS(R1CSError), 20 | Bulletproofs(ProofError), 21 | ArkR1CS(ArkR1CSError), 22 | ArkBulletproofs(ArkProofError), 23 | } 24 | 25 | impl fmt::Display for CryptoError { 26 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 27 | use CryptoError::*; 28 | f.write_str(match self { 29 | ParameterError => "Unexpected parameter for method or function", 30 | SignatureError => "Signature verification failed", 31 | AnonymousCredentialSignError => "The number of attributes passed as parameter differs from the number of attributes of the AC issuer public key", 32 | IdentityRevealVerifyError => "Verification error for confidential identity reveal proof", 33 | ElGamalVerificationError => "ElGamal Ciphertext not valid for proposed scalar message", 34 | ZKProofVerificationError => "Invalid proof", 35 | ZKProofBatchVerificationError => "Batch proof instance contains an error", 36 | Algebra(e) => Box::leak(format!("Algebra: {}", e).into_boxed_str()), 37 | R1CS(e) => Box::leak(format!("R1CS: {}", e).into_boxed_str()), 38 | Bulletproofs(e) => Box::leak(format!("Bulletproofs: {}", e).into_boxed_str()), 39 | ArkR1CS(e) => Box::leak(format!("Ark R1CS: {}", e).into_boxed_str()), 40 | ArkBulletproofs(e) => Box::leak(format!("ArkBulletproofs: {}", e).into_boxed_str()), 41 | }) 42 | } 43 | } 44 | 45 | impl error::Error for CryptoError { 46 | #[cfg(feature = "std")] 47 | fn description(&self) -> &str { 48 | Box::leak(format!("{}", self).into_boxed_str()) 49 | } 50 | } 51 | 52 | impl From for CryptoError { 53 | fn from(e: R1CSError) -> CryptoError { 54 | CryptoError::R1CS(e) 55 | } 56 | } 57 | 58 | impl From for CryptoError { 59 | fn from(e: ProofError) -> CryptoError { 60 | CryptoError::Bulletproofs(e) 61 | } 62 | } 63 | 64 | impl From for CryptoError { 65 | fn from(e: ArkR1CSError) -> CryptoError { 66 | CryptoError::ArkR1CS(e) 67 | } 68 | } 69 | 70 | impl From for CryptoError { 71 | fn from(e: ArkProofError) -> CryptoError { 72 | CryptoError::ArkBulletproofs(e) 73 | } 74 | } 75 | 76 | impl From for CryptoError { 77 | fn from(e: AlgebraError) -> CryptoError { 78 | CryptoError::Algebra(e) 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /crypto/src/gapdh/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::errors::Result; 2 | use crate::hashing_to_the_curve::traits::HashingToCurve; 3 | use merlin::Transcript; 4 | use noah_algebra::prelude::*; 5 | 6 | /// The implementation for the hoisting version of the GDH undeniable signature. 7 | pub mod hoisting; 8 | /// The implementation for the standard version of the GDH undeniable signature. 9 | pub mod standard; 10 | 11 | /// A trait for gap Diffie-Hellman undeniable signature. 12 | pub trait GapDHSignature> { 13 | /// The struct of the proof. 14 | type Proof: Default + Clone; 15 | 16 | /// Generate the keys. 17 | fn keygen(prng: &mut R) -> (G::ScalarType, G) { 18 | let sk = G::ScalarType::random(prng); 19 | let pk = G::get_base().mul(&sk); 20 | 21 | (sk, pk) 22 | } 23 | 24 | /// Map the message into a point. 25 | fn map(m: &G::BaseType) -> Result { 26 | let (x, y) = H::get_cofactor_uncleared_point(m)?; 27 | let p = H::convert_to_group(&x, &y)?; 28 | 29 | Ok(p.multiply_by_cofactor()) 30 | } 31 | 32 | /// Create the undeniable signature. 33 | fn sign(sk: &G::ScalarType, m: &G) -> G; 34 | 35 | /// Compute the proof that confirms the undeniable signature. 36 | fn confirm( 37 | prng: &mut R, 38 | transcript: &mut Transcript, 39 | sk: &G::ScalarType, 40 | m: &G, 41 | sigma: &G, 42 | ) -> Self::Proof; 43 | 44 | /// Verify a undeniable signature with the proof. 45 | fn verify( 46 | transcript: &mut Transcript, 47 | pk: &G, 48 | m: &G, 49 | sigma: &G, 50 | proof: &Self::Proof, 51 | ) -> Result<()>; 52 | } 53 | -------------------------------------------------------------------------------- /crypto/src/gapdh/standard.rs: -------------------------------------------------------------------------------- 1 | use crate::errors::{CryptoError, Result}; 2 | use crate::gapdh::GapDHSignature; 3 | use crate::hashing_to_the_curve::traits::HashingToCurve; 4 | use crate::matrix_sigma::SigmaTranscript; 5 | use merlin::Transcript; 6 | use noah_algebra::prelude::*; 7 | use rand_chacha::ChaChaRng; 8 | 9 | /// The standard implementation of GDH undeniable signature. 10 | pub struct StandardGDH> { 11 | g_phantom: PhantomData, 12 | h_phantom: PhantomData, 13 | } 14 | 15 | /// The struct for a proof in the standard implementation. 16 | #[derive(Default, Clone)] 17 | pub struct StandardGDHProof { 18 | /// Point R1. 19 | pub point_r_1: G, 20 | /// Point R2. 21 | pub point_r_2: G, 22 | /// Response. 23 | pub response: G::ScalarType, 24 | } 25 | 26 | impl> GapDHSignature for StandardGDH { 27 | type Proof = StandardGDHProof; 28 | 29 | fn sign(sk: &G::ScalarType, m: &G) -> G { 30 | m.mul(sk) 31 | } 32 | 33 | fn confirm( 34 | prng: &mut R, 35 | transcript: &mut Transcript, 36 | sk: &G::ScalarType, 37 | m: &G, 38 | sigma: &G, 39 | ) -> Self::Proof { 40 | let r = G::ScalarType::random(prng); 41 | let pk = G::get_base().mul(sk); 42 | 43 | let point_r_1 = m.mul(&r); 44 | let point_r_2 = G::get_base().mul(&r); 45 | 46 | transcript.append_group_element(b"message", m); 47 | transcript.append_group_element(b"signature", sigma); 48 | transcript.append_group_element(b"public key", &pk); 49 | transcript.append_group_element(b"R1", &point_r_1); 50 | transcript.append_group_element(b"R2", &point_r_2); 51 | 52 | let mut bytes = [1u8; 32]; 53 | transcript.challenge_bytes(b"challenge", &mut bytes); 54 | 55 | let beta = { 56 | let mut rng = ChaChaRng::from_seed(bytes); 57 | G::ScalarType::random(&mut rng) 58 | }; 59 | 60 | let response = r * beta + sk; 61 | 62 | StandardGDHProof { 63 | point_r_1, 64 | point_r_2, 65 | response, 66 | } 67 | } 68 | 69 | fn verify( 70 | transcript: &mut Transcript, 71 | pk: &G, 72 | m: &G, 73 | sigma: &G, 74 | proof: &Self::Proof, 75 | ) -> Result<()> { 76 | transcript.append_group_element(b"message", m); 77 | transcript.append_group_element(b"signature", sigma); 78 | transcript.append_group_element(b"public key", pk); 79 | transcript.append_group_element(b"R1", &proof.point_r_1); 80 | transcript.append_group_element(b"R2", &proof.point_r_2); 81 | 82 | let mut bytes = [1u8; 32]; 83 | transcript.challenge_bytes(b"challenge", &mut bytes); 84 | 85 | let beta = { 86 | let mut rng = ChaChaRng::from_seed(bytes); 87 | G::ScalarType::random(&mut rng) 88 | }; 89 | 90 | let lhs = proof.point_r_1.mul(&beta) + sigma; 91 | let rhs = m.mul(&proof.response); 92 | 93 | if lhs != rhs { 94 | return Err(CryptoError::SignatureError); 95 | } 96 | 97 | let lhs = proof.point_r_2.mul(&beta) + pk; 98 | let rhs = G::get_base().mul(&proof.response); 99 | 100 | if lhs != rhs { 101 | return Err(CryptoError::SignatureError); 102 | } 103 | 104 | Ok(()) 105 | } 106 | } 107 | 108 | #[cfg(test)] 109 | mod test { 110 | use crate::gapdh::standard::StandardGDH; 111 | use crate::gapdh::GapDHSignature; 112 | use crate::hashing_to_the_curve::models::sw::SWMap; 113 | use crate::hashing_to_the_curve::secp256k1::sw::Secp256k1SWParameters; 114 | use merlin::Transcript; 115 | use noah_algebra::prelude::*; 116 | use noah_algebra::secp256k1::{SECP256K1Fq, SECP256K1G1}; 117 | 118 | type T = StandardGDH>; 119 | 120 | #[test] 121 | fn test_standard_correctness() { 122 | let mut prng = test_rng(); 123 | 124 | let (sk, pk) = T::keygen(&mut prng); 125 | let m = T::map(&SECP256K1Fq::random(&mut prng)).unwrap(); 126 | 127 | let sigma = T::sign(&sk, &m); 128 | 129 | let mut prover_transcript = Transcript::new(b"Test"); 130 | let proof = T::confirm(&mut prng, &mut prover_transcript, &sk, &m, &sigma); 131 | 132 | let mut verifier_transcript = Transcript::new(b"Test"); 133 | T::verify(&mut verifier_transcript, &pk, &m, &sigma, &proof).unwrap(); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /crypto/src/hashing_to_the_curve/ed25519/elligator.rs: -------------------------------------------------------------------------------- 1 | use crate::errors::Result; 2 | use crate::hashing_to_the_curve::ed25519::Y_SCALE_FACTOR; 3 | use crate::hashing_to_the_curve::models::elligator::ElligatorParameters; 4 | use noah_algebra::ed25519::Ed25519Point; 5 | use noah_algebra::prelude::*; 6 | use noah_algebra::{ed25519::Ed25519Fq, new_ed25519_fq}; 7 | 8 | /// Elligator map for Ed25519 9 | pub struct Ed25519ElligatorParameters; 10 | 11 | impl ElligatorParameters for Ed25519ElligatorParameters { 12 | const A: Ed25519Fq = new_ed25519_fq!("486662"); 13 | const B: Ed25519Fq = new_ed25519_fq!("1"); 14 | const QNR: Ed25519Fq = new_ed25519_fq!("2"); 15 | 16 | fn convert_to_group(x: &Ed25519Fq, y: &Ed25519Fq) -> Result { 17 | // from the Montgomery curve: y^2 = x^3 + 486662 x^2 + x 18 | // to the twisted Edwards curve: -x^2 + y^2 = 1 - (121665/121666) * x^2 * y^2 19 | 20 | let y_inv = y.inv()?; 21 | 22 | let new_x = Y_SCALE_FACTOR * x * y_inv; 23 | 24 | let x_minus_one = (*x) - &Ed25519Fq::one(); 25 | let x_plus_one = Ed25519Fq::one() + x; 26 | 27 | let x_plus_one_inv = x_plus_one.inv()?; 28 | 29 | let new_y = x_minus_one * x_plus_one_inv; 30 | 31 | Ok(Ed25519Point::new(&new_x, &new_y)) 32 | } 33 | 34 | fn convert_from_group(p: &Ed25519Point) -> Result<(Ed25519Fq, Ed25519Fq)> { 35 | let x = p.get_x(); 36 | let y = p.get_y(); 37 | 38 | let y_plus_1 = y + Ed25519Fq::one(); 39 | let y_sub_1 = Ed25519Fq::one() - &y; 40 | let y_sub_1_inv = y_sub_1.inv()?; 41 | let x_inv = x.inv()?; 42 | 43 | let new_x = y_plus_1 * y_sub_1_inv; 44 | let new_y = Y_SCALE_FACTOR * new_x * x_inv; 45 | 46 | Ok((new_x, new_y)) 47 | } 48 | } 49 | 50 | #[cfg(test)] 51 | mod tests { 52 | use crate::hashing_to_the_curve::ed25519::elligator::Ed25519ElligatorParameters; 53 | use crate::hashing_to_the_curve::models::elligator::Elligator; 54 | use crate::hashing_to_the_curve::traits::HashingToCurve; 55 | use noah_algebra::ed25519::{Ed25519Fq, Ed25519Point}; 56 | use noah_algebra::prelude::*; 57 | 58 | type M = Elligator; 59 | 60 | #[test] 61 | fn test_random_t() { 62 | for _ in 0..100 { 63 | let mut rng = test_rng(); 64 | let t = Ed25519Fq::random(&mut rng); 65 | 66 | let final_x = M::get_cofactor_uncleared_x(&t).unwrap(); 67 | let (final_x2, trace) = M::get_cofactor_uncleared_x_and_trace(&t).unwrap(); 68 | 69 | assert_eq!(final_x, final_x2); 70 | assert!(M::verify_trace(&t, &final_x, &trace)); 71 | assert!(M::is_x_on_curve(&final_x)); 72 | } 73 | } 74 | 75 | #[test] 76 | fn test_group_conversion() { 77 | for _ in 0..100 { 78 | let mut rng = test_rng(); 79 | let p = Ed25519Point::random(&mut rng); 80 | 81 | let p_conv = M::convert_from_group(&p).unwrap(); 82 | let p_rec = M::convert_to_group(&p_conv.0, &p_conv.1).unwrap(); 83 | assert_eq!(p, p_rec); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /crypto/src/hashing_to_the_curve/ed25519/mod.rs: -------------------------------------------------------------------------------- 1 | use noah_algebra::ed25519::Ed25519Fq; 2 | use noah_algebra::new_ed25519_fq; 3 | 4 | /// Elligator for ed25519. 5 | pub mod elligator; 6 | 7 | /// Simplified SWU map for ed25519. 8 | pub mod sswu; 9 | 10 | /// Shallue-van de Woestijne map for ed25519. 11 | pub mod sw; 12 | 13 | const Y_SCALE_FACTOR: Ed25519Fq = new_ed25519_fq!( 14 | "51042569399160536130206135233146329284152202253034631822681833788666877215207" 15 | ); 16 | -------------------------------------------------------------------------------- /crypto/src/hashing_to_the_curve/ed25519/sw.rs: -------------------------------------------------------------------------------- 1 | use crate::errors::Result; 2 | use crate::hashing_to_the_curve::ed25519::elligator::Ed25519ElligatorParameters; 3 | use crate::hashing_to_the_curve::models::elligator::ElligatorParameters; 4 | use crate::hashing_to_the_curve::models::sw::SWParameters; 5 | use noah_algebra::ed25519::Ed25519Point; 6 | use noah_algebra::{ed25519::Ed25519Fq, new_ed25519_fq}; 7 | 8 | /// The SW map for ed25519. 9 | pub struct Ed25519SWParameters; 10 | 11 | impl SWParameters for Ed25519SWParameters { 12 | const Z0: Ed25519Fq = new_ed25519_fq!( 13 | "7351004470711496783299639200077825248508346112056564349554070979984169706335" 14 | ); 15 | const C1: Ed25519Fq = new_ed25519_fq!( 16 | "7351004470711496783299639200077825248508346112056564349554070979984169463003" 17 | ); 18 | const C2: Ed25519Fq = new_ed25519_fq!( 19 | "14702008941422993566599278400155650497016692224113128699108141959968339412670" 20 | ); 21 | const C3: Ed25519Fq = new_ed25519_fq!("1946658"); 22 | const C4: Ed25519Fq = new_ed25519_fq!("-486664"); 23 | const C5: Ed25519Fq = new_ed25519_fq!("2"); 24 | const C6: Ed25519Fq = new_ed25519_fq!( 25 | "22595885493139578480537169384951274962349491958774703396425382945106958635058" 26 | ); 27 | const A: Ed25519Fq = new_ed25519_fq!("486662"); 28 | const B: Ed25519Fq = new_ed25519_fq!("1"); 29 | const C: Ed25519Fq = new_ed25519_fq!("0"); 30 | const QNR: Ed25519Fq = new_ed25519_fq!("2"); 31 | 32 | fn convert_to_group(x: &Ed25519Fq, y: &Ed25519Fq) -> Result { 33 | Ed25519ElligatorParameters::convert_to_group(x, y) 34 | } 35 | 36 | fn convert_from_group(p: &Ed25519Point) -> Result<(Ed25519Fq, Ed25519Fq)> { 37 | Ed25519ElligatorParameters::convert_from_group(p) 38 | } 39 | } 40 | 41 | #[cfg(test)] 42 | mod tests { 43 | use crate::hashing_to_the_curve::ed25519::sw::Ed25519SWParameters; 44 | use crate::hashing_to_the_curve::models::sw::SWMap; 45 | use crate::hashing_to_the_curve::traits::HashingToCurve; 46 | use noah_algebra::ed25519::{Ed25519Fq, Ed25519Point}; 47 | use noah_algebra::new_ed25519_fq; 48 | use noah_algebra::prelude::*; 49 | 50 | type M = SWMap; 51 | 52 | #[test] 53 | fn test_x_derivation() { 54 | let mut t: Ed25519Fq = new_ed25519_fq!("7836"); 55 | 56 | let x1 = M::x1(&t).unwrap(); 57 | let x2 = M::x2(&t, &x1).unwrap(); 58 | let x3 = M::x3(&t).unwrap(); 59 | 60 | assert_eq!( 61 | x1, 62 | new_ed25519_fq!( 63 | "35052544075417610700660092540301712605483067939443826766625142601993311385282" 64 | ) 65 | ); 66 | assert_eq!( 67 | x2, 68 | new_ed25519_fq!( 69 | "22843500543240487011125399964042241321151924393376455253103649401963252948003" 70 | ) 71 | ); 72 | assert_eq!( 73 | x3, 74 | new_ed25519_fq!( 75 | "55628280783676121122135371125950213811806717931300590918014233701929027895981" 76 | ) 77 | ); 78 | 79 | t = new_ed25519_fq!( 80 | "26261490946361586592261280563100114235157954222781295781974865328952772526824" 81 | ); 82 | 83 | let x1 = M::x1(&t).unwrap(); 84 | let x2 = M::x2(&t, &x1).unwrap(); 85 | let x3 = M::x3(&t).unwrap(); 86 | 87 | assert_eq!( 88 | x1, 89 | new_ed25519_fq!( 90 | "55662970774143248676152068296021054624113686786963469155330127785619018187083" 91 | ) 92 | ); 93 | assert_eq!( 94 | x2, 95 | new_ed25519_fq!( 96 | "2233073844514849035633424208322899302521305545856812864398664218337546146202" 97 | ) 98 | ); 99 | assert_eq!( 100 | x3, 101 | new_ed25519_fq!( 102 | "53840827294954389625880150540438237547370106120164461777668468238174198448700" 103 | ) 104 | ); 105 | } 106 | 107 | #[test] 108 | fn test_random_t() { 109 | for _ in 0..100 { 110 | let mut rng = test_rng(); 111 | let t = Ed25519Fq::random(&mut rng); 112 | 113 | let final_x = M::get_cofactor_uncleared_x(&t).unwrap(); 114 | let (final_x2, trace) = M::get_cofactor_uncleared_x_and_trace(&t).unwrap(); 115 | 116 | assert_eq!(final_x, final_x2); 117 | assert!(M::verify_trace(&t, &final_x, &trace)); 118 | assert!(M::is_x_on_curve(&final_x)); 119 | } 120 | } 121 | 122 | #[test] 123 | fn test_group_conversion() { 124 | for _ in 0..100 { 125 | let mut rng = test_rng(); 126 | let p = Ed25519Point::random(&mut rng); 127 | 128 | let p_conv = M::convert_from_group(&p).unwrap(); 129 | let p_rec = M::convert_to_group(&p_conv.0, &p_conv.1).unwrap(); 130 | assert_eq!(p, p_rec); 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /crypto/src/hashing_to_the_curve/mod.rs: -------------------------------------------------------------------------------- 1 | /// Module for the traits of maps. 2 | pub mod traits; 3 | 4 | /// Collections for models. 5 | pub mod models; 6 | 7 | /// Collections of implementations for ed25519. 8 | pub mod ed25519; 9 | 10 | /// Collections of implementations for secp256k1. 11 | pub mod secp256k1; 12 | -------------------------------------------------------------------------------- /crypto/src/hashing_to_the_curve/models/mod.rs: -------------------------------------------------------------------------------- 1 | /// Module for the Shallue-van de Woestijne map. 2 | pub mod sw; 3 | 4 | /// Module for the simplified SWU map. 5 | pub mod sswu; 6 | 7 | /// Module for elligator. 8 | pub mod elligator; 9 | -------------------------------------------------------------------------------- /crypto/src/hashing_to_the_curve/secp256k1/mod.rs: -------------------------------------------------------------------------------- 1 | /// Simplified SWU map for secp256k1. 2 | pub mod sswu; 3 | 4 | /// Shallue-van de Woestijne map for secp256k1. 5 | pub mod sw; 6 | -------------------------------------------------------------------------------- /crypto/src/hashing_to_the_curve/secp256k1/sw.rs: -------------------------------------------------------------------------------- 1 | use crate::errors::Result; 2 | use crate::hashing_to_the_curve::models::sw::SWParameters; 3 | use noah_algebra::prelude::*; 4 | use noah_algebra::secp256k1::SECP256K1G1; 5 | use noah_algebra::{new_secp256k1_fq, secp256k1::SECP256K1Fq}; 6 | 7 | /// The SW map for secp256k1. 8 | pub struct Secp256k1SWParameters; 9 | 10 | impl SWParameters for Secp256k1SWParameters { 11 | const Z0: SECP256K1Fq = new_secp256k1_fq!( 12 | "2301468970328204842700089520541121182249040118132057797950280022211810753577" 13 | ); 14 | const C1: SECP256K1Fq = new_secp256k1_fq!( 15 | "60197513588986302554485582024885075108884032450952339817679072026166228089409" 16 | ); 17 | const C2: SECP256K1Fq = new_secp256k1_fq!( 18 | "4602937940656409685400179041082242364498080236264115595900560044423621507154" 19 | ); 20 | const C3: SECP256K1Fq = new_secp256k1_fq!("6"); 21 | const C4: SECP256K1Fq = new_secp256k1_fq!("1"); 22 | const C5: SECP256K1Fq = new_secp256k1_fq!( 23 | "115792089237316195423570985008687907853269984665640564039457584007908834671662" 24 | ); 25 | const C6: SECP256K1Fq = new_secp256k1_fq!( 26 | "38597363079105398474523661669562635951089994888546854679819194669302944890554" 27 | ); 28 | const A: SECP256K1Fq = new_secp256k1_fq!("0"); 29 | const B: SECP256K1Fq = new_secp256k1_fq!("0"); 30 | const C: SECP256K1Fq = new_secp256k1_fq!("7"); 31 | const QNR: SECP256K1Fq = new_secp256k1_fq!("-1"); 32 | 33 | fn convert_to_group(x: &SECP256K1Fq, y: &SECP256K1Fq) -> Result { 34 | Ok(SECP256K1G1::new(x, y)) 35 | } 36 | 37 | fn convert_from_group(p: &SECP256K1G1) -> Result<(SECP256K1Fq, SECP256K1Fq)> { 38 | Ok((p.get_x(), p.get_y())) 39 | } 40 | } 41 | 42 | #[cfg(test)] 43 | mod tests { 44 | use crate::hashing_to_the_curve::models::sw::SWMap; 45 | use crate::hashing_to_the_curve::secp256k1::sw::Secp256k1SWParameters; 46 | use crate::hashing_to_the_curve::traits::HashingToCurve; 47 | use noah_algebra::new_secp256k1_fq; 48 | use noah_algebra::prelude::*; 49 | use noah_algebra::secp256k1::{SECP256K1Fq, SECP256K1G1}; 50 | 51 | type M = SWMap; 52 | 53 | #[test] 54 | fn test_x_derivation() { 55 | let mut t: SECP256K1Fq = new_secp256k1_fq!("7836"); 56 | 57 | let x1 = M::x1(&t).unwrap(); 58 | let x2 = M::x2(&t, &x1).unwrap(); 59 | let x3 = M::x3(&t).unwrap(); 60 | 61 | assert_eq!( 62 | x1, 63 | new_secp256k1_fq!( 64 | "12173361532131623274578764961252033537537011288282760545929785782471408876466" 65 | ) 66 | ); 67 | assert_eq!( 68 | x2, 69 | new_secp256k1_fq!( 70 | "103618727705184572148992220047435874315732973377357803493527798225437425795198" 71 | ) 72 | ); 73 | assert_eq!( 74 | x3, 75 | new_secp256k1_fq!( 76 | "74087608966983262623115840088572810691661208660740673962981321521047702830003" 77 | ) 78 | ); 79 | 80 | t = new_secp256k1_fq!( 81 | "26261490946361586592261280563100114235157954222781295781974865328952772526824" 82 | ); 83 | 84 | let x1 = M::x1(&t).unwrap(); 85 | let x2 = M::x2(&t, &x1).unwrap(); 86 | let x3 = M::x3(&t).unwrap(); 87 | 88 | assert_eq!( 89 | x1, 90 | new_secp256k1_fq!( 91 | "26139849459076662048090509060200323109571459447699535307492857403137446071407" 92 | ) 93 | ); 94 | assert_eq!( 95 | x2, 96 | new_secp256k1_fq!( 97 | "89652239778239533375480475948487584743698525217941028731964726604771388600257" 98 | ) 99 | ); 100 | assert_eq!( 101 | x3, 102 | new_secp256k1_fq!( 103 | "57498912498287391356729542970652380787836579419942546263322241630256315967730" 104 | ) 105 | ); 106 | } 107 | 108 | #[test] 109 | fn test_random_t() { 110 | for _ in 0..100 { 111 | let mut rng = test_rng(); 112 | let t = SECP256K1Fq::random(&mut rng); 113 | 114 | let final_x = M::get_cofactor_uncleared_x(&t).unwrap(); 115 | let (final_x2, trace) = M::get_cofactor_uncleared_x_and_trace(&t).unwrap(); 116 | 117 | assert_eq!(final_x, final_x2); 118 | assert!(M::verify_trace(&t, &final_x, &trace)); 119 | assert!(M::is_x_on_curve(&final_x)); 120 | } 121 | } 122 | 123 | #[test] 124 | fn test_group_conversion() { 125 | for _ in 0..100 { 126 | let mut rng = test_rng(); 127 | let p = SECP256K1G1::random(&mut rng); 128 | 129 | let p_conv = M::convert_from_group(&p).unwrap(); 130 | let p_rec = M::convert_to_group(&p_conv.0, &p_conv.1).unwrap(); 131 | assert_eq!(p, p_rec); 132 | } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /crypto/src/hashing_to_the_curve/traits.rs: -------------------------------------------------------------------------------- 1 | use crate::errors::Result; 2 | use noah_algebra::prelude::*; 3 | 4 | /// Trait for hashing to the curve. 5 | pub trait HashingToCurve { 6 | /// the type of the trace of the hashing to the curve. 7 | /// It would be used both for the hardware wallet and for the witness generation in SNARK. 8 | type Trace; 9 | 10 | /// get the x coordinate directly. 11 | fn get_cofactor_uncleared_x(t: &G::BaseType) -> Result; 12 | 13 | /// get the x coordinate as well as the trace. 14 | fn get_cofactor_uncleared_x_and_trace(t: &G::BaseType) -> Result<(G::BaseType, Self::Trace)>; 15 | 16 | /// get (x, y) before cofactor clearing. 17 | fn get_cofactor_uncleared_point(t: &G::BaseType) -> Result<(G::BaseType, G::BaseType)>; 18 | 19 | /// get (x, y) before cofactor clearing. 20 | fn get_cofactor_uncleared_point_and_trace( 21 | t: &G::BaseType, 22 | ) -> Result<(G::BaseType, G::BaseType, Self::Trace)>; 23 | 24 | /// verify the trace. 25 | fn verify_trace(t: &G::BaseType, final_x: &G::BaseType, trace: &Self::Trace) -> bool; 26 | 27 | /// convert to the default group element. 28 | fn convert_to_group(x: &G::BaseType, y: &G::BaseType) -> Result; 29 | 30 | /// convert from the default group element. 31 | fn convert_from_group(p: &G) -> Result<(G::BaseType, G::BaseType)>; 32 | } 33 | -------------------------------------------------------------------------------- /crypto/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! The crate implements the cryptography primitives (except TurboPlonk) for the Noah library, 2 | //! including Bulletproofs. 3 | #![cfg_attr(not(feature = "std"), no_std)] 4 | #![deny(unused_import_braces, unused_qualifications, trivial_casts)] 5 | #![deny(trivial_numeric_casts)] 6 | #![deny(stable_features, unreachable_pub, non_shorthand_field_patterns)] 7 | #![deny(unused_attributes, unused_imports, unused_mut, missing_docs)] 8 | #![deny(renamed_and_removed_lints, stable_features, unused_allocation)] 9 | #![deny(unused_comparisons, bare_trait_objects, unused_must_use)] 10 | #![doc(html_logo_url = "https://avatars.githubusercontent.com/u/74745723?s=200&v=4")] 11 | #![doc(html_playground_url = "https://play.rust-lang.org")] 12 | #![forbid(unsafe_code)] 13 | #![warn( 14 | unused, 15 | future_incompatible, 16 | nonstandard_style, 17 | rust_2018_idioms, 18 | rust_2021_compatibility 19 | )] 20 | #![allow(clippy::type_complexity, clippy::too_many_arguments)] 21 | 22 | #[macro_use] 23 | extern crate itertools; 24 | 25 | #[macro_use] 26 | extern crate serde_derive; 27 | 28 | /// The module for the Anemoi-Jive hash functions. 29 | pub mod anemoi_jive; 30 | /// The module for anonymous credentials. 31 | pub mod anon_creds; 32 | /// The library for Bulletproofs. 33 | pub mod bulletproofs; 34 | /// The module for the Chaum-Pedersen protocol. 35 | pub mod chaum_pedersen; 36 | /// The module for confidential anonymous credentials. 37 | pub mod confidential_anon_creds; 38 | /// The module for the delegated Schnorr protocol. 39 | pub mod delegated_schnorr; 40 | /// The module for the doubly SNARK-friendly primitives. 41 | pub mod doubly_snark_friendly; 42 | /// The module for the ElGamal encryption. 43 | pub mod elgamal; 44 | /// The module for error handling 45 | pub mod errors; 46 | /// The module for field simulation. 47 | pub mod field_simulation; 48 | /// The module for the (modified) gap Diffie-Hellman undeniable signature. 49 | pub mod gapdh; 50 | /// The module for hashing to the curve. 51 | pub mod hashing_to_the_curve; 52 | /// The module for hybrid encryption. 53 | pub mod hybrid_encryption; 54 | /// The module for the matrix Sigma protocol. 55 | pub mod matrix_sigma; 56 | /// The module for the equality proof between a Pedersen commitment and an ElGamal ciphertext. 57 | pub mod pedersen_elgamal; 58 | /// The module that contains some useful Schnorr gadgets. 59 | pub mod schnorr_gadgets; 60 | -------------------------------------------------------------------------------- /crypto/src/schnorr_gadgets/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::errors::Result; 2 | use merlin::Transcript; 3 | use noah_algebra::prelude::*; 4 | use noah_algebra::traits::CurveGroup; 5 | 6 | mod gadget1_square; 7 | pub use gadget1_square::*; 8 | 9 | mod gadget2_crossed_mul; 10 | pub use gadget2_crossed_mul::*; 11 | 12 | mod gadget3_move; 13 | pub use gadget3_move::*; 14 | 15 | mod gadget4_merged; 16 | pub use gadget4_merged::*; 17 | 18 | /// A trait for Schnorr gadgets. 19 | pub trait SchnorrGadget { 20 | /// The struct of the proof. 21 | type Proof: Default + Clone; 22 | /// The struct of the instance. 23 | type Instance; 24 | /// The struct of the witness. 25 | type Witness; 26 | 27 | /// Generate the Schnorr proof. 28 | fn prove( 29 | prng: &mut R, 30 | transcript: &mut Transcript, 31 | instance: &Self::Instance, 32 | witness: &Self::Witness, 33 | ) -> Self::Proof; 34 | 35 | /// Verify the Schnorr proof. 36 | fn verify( 37 | transcript: &mut Transcript, 38 | instance: &Self::Instance, 39 | proof: &Self::Proof, 40 | ) -> Result<()>; 41 | } 42 | -------------------------------------------------------------------------------- /plonk/Cargo.toml: -------------------------------------------------------------------------------- 1 | [[bench]] 2 | name = 'fft' 3 | path = 'benches/fft.rs' 4 | harness = false 5 | 6 | [[bench]] 7 | name = 'verifier' 8 | path = 'benches/verifier.rs' 9 | harness = false 10 | 11 | [package] 12 | name = 'noah-plonk' 13 | version = '0.5.0' 14 | authors = ['Findora '] 15 | edition = '2021' 16 | description = 'Noah TurboPLONK protocol' 17 | 18 | [lib] 19 | name = 'noah_plonk' 20 | crate-type = ['rlib'] 21 | 22 | [build-dependencies] 23 | rustc_version = "0.4" 24 | 25 | [dependencies] 26 | bincode = '1.3.1' 27 | criterion = { version = '0.5.0', default-features = false} 28 | merlin = '3.0.0' 29 | num-bigint = '0.4' 30 | num-integer = '0.1.43' 31 | serde_derive = '1.0.115' 32 | wasm-bindgen-test = "^0.3" 33 | 34 | [target.'cfg(target_arch = "wasm32")'.dependencies] 35 | wasm-bindgen = "0.2.50" 36 | 37 | [dependencies.noah-algebra] 38 | path = '../algebra' 39 | 40 | [dependencies.noah-crypto] 41 | path = '../crypto' 42 | 43 | [dependencies.ark-ff] 44 | version = '0.4.0' 45 | default-features = false 46 | 47 | [dependencies.ark-poly] 48 | version = '0.4.0' 49 | default-features = false 50 | 51 | [dependencies.ark-serialize] 52 | version = '0.4.0' 53 | default-features = false 54 | 55 | [dependencies.ark-std] 56 | version = '0.4.0' 57 | default-features = false 58 | 59 | [dependencies.rayon] 60 | version = '1.5' 61 | optional = true 62 | 63 | [dependencies.rand_chacha] 64 | version = '0.3' 65 | default-features = false 66 | 67 | [dependencies.serde] 68 | version = '1.0.115' 69 | features = ['derive'] 70 | 71 | [dev-dependencies] 72 | serde_json = '1.0' 73 | rand = "0.8" 74 | 75 | [dev-dependencies.num-bigint] 76 | version = '0.4' 77 | features = ['rand'] 78 | 79 | [features] 80 | default = ["std"] 81 | debug = [] 82 | std = ['ark-std/std', 'noah-algebra/std'] 83 | asm = ['noah-algebra/asm'] 84 | parallel = ['rayon', 'noah-algebra/parallel', 'ark-poly/parallel'] 85 | print-trace = ['noah-algebra/print-trace'] 86 | -------------------------------------------------------------------------------- /plonk/benches/fft.rs: -------------------------------------------------------------------------------- 1 | use criterion::{criterion_group, criterion_main, Criterion}; 2 | use noah_algebra::{bn254::BN254Scalar, prelude::*}; 3 | use noah_plonk::poly_commit::field_polynomial::FpPolynomial; 4 | 5 | fn bench_fft(c: &mut Criterion) { 6 | let mut prng = test_rng(); 7 | let n = 65536; 8 | 9 | let mut coefs = Vec::with_capacity(n); 10 | for _ in 0..n { 11 | coefs.push(BN254Scalar::random(&mut prng)); 12 | } 13 | let polynomial = FpPolynomial::from_coefs(coefs); 14 | 15 | let domain = FpPolynomial::::evaluation_domain(n).unwrap(); 16 | let fft = polynomial.fft_with_domain(&domain); 17 | assert_eq!(polynomial, FpPolynomial::ifft_with_domain(&domain, &fft)); 18 | 19 | let mut fft_group = c.benchmark_group("bench_fft"); 20 | fft_group.bench_function("fft".to_string(), |b| { 21 | b.iter(|| polynomial.fft_with_domain(&domain)); 22 | }); 23 | 24 | fft_group.bench_function("ifft".to_string(), |b| { 25 | b.iter(|| FpPolynomial::ifft_with_domain(&domain, &fft)); 26 | }); 27 | fft_group.finish(); 28 | } 29 | 30 | criterion_group!(benches, bench_fft); 31 | criterion_main!(benches); 32 | -------------------------------------------------------------------------------- /plonk/benches/verifier.rs: -------------------------------------------------------------------------------- 1 | use criterion::{criterion_group, criterion_main, Criterion}; 2 | use merlin::Transcript; 3 | use noah_algebra::bn254::BN254PairingEngine; 4 | use noah_algebra::{bn254::BN254Scalar, prelude::*}; 5 | use noah_crypto::anemoi_jive::{AnemoiJive, AnemoiJive254}; 6 | use noah_plonk::plonk::constraint_system::{ConstraintSystem, TurboCS}; 7 | use noah_plonk::plonk::indexer::indexer; 8 | use noah_plonk::plonk::prover::prover; 9 | use noah_plonk::plonk::verifier::verifier; 10 | use noah_plonk::poly_commit::kzg_poly_com::KZGCommitmentScheme; 11 | 12 | fn bench_verifier(c: &mut Criterion) { 13 | let mut prng = test_rng(); 14 | let pcs = KZGCommitmentScheme::::new(260, &mut prng); 15 | 16 | let output_len = 7; 17 | let trace = AnemoiJive254::eval_stream_cipher_with_trace( 18 | &[ 19 | BN254Scalar::from(1u64), 20 | BN254Scalar::from(2u64), 21 | BN254Scalar::from(3u64), 22 | BN254Scalar::from(4u64), 23 | ], 24 | output_len, 25 | ); 26 | 27 | let mut cs = TurboCS::new(); 28 | cs.load_anemoi_jive_parameters::(); 29 | 30 | let one = cs.new_variable(BN254Scalar::from(1u64)); 31 | let two = cs.new_variable(BN254Scalar::from(2u64)); 32 | let three = cs.new_variable(BN254Scalar::from(3u64)); 33 | let four = cs.new_variable(BN254Scalar::from(4u64)); 34 | 35 | let mut output_var = vec![]; 36 | for output in trace.output.iter() { 37 | output_var.push(cs.new_variable(output.clone())) 38 | } 39 | 40 | let _ = cs.anemoi_stream_cipher::(&trace, &[one, two, three, four], &output_var); 41 | cs.pad(); 42 | 43 | let witness = cs.get_and_clear_witness(); 44 | cs.verify_witness(&witness, &[]).unwrap(); 45 | 46 | let prover_params = indexer(&cs, &pcs).unwrap(); 47 | let verifier_params_ref = &prover_params.verifier_params; 48 | 49 | let mut transcript = Transcript::new(b"TestTurboPlonk"); 50 | let proof = prover( 51 | &mut prng, 52 | &mut transcript, 53 | &pcs, 54 | &cs, 55 | &prover_params, 56 | &witness, 57 | ) 58 | .unwrap(); 59 | 60 | let verifier_cs = cs.shrink_to_verifier_only(); 61 | 62 | let mut verifier_group = c.benchmark_group("bench_verifier"); 63 | verifier_group.bench_function("verifier".to_string(), |b| { 64 | b.iter(|| { 65 | let mut transcript = Transcript::new(b"TestTurboPlonk"); 66 | verifier( 67 | &mut transcript, 68 | &pcs, 69 | &verifier_cs, 70 | verifier_params_ref, 71 | &[], 72 | &proof, 73 | ) 74 | .unwrap() 75 | }) 76 | }); 77 | verifier_group.finish(); 78 | } 79 | 80 | criterion_group!(benches, bench_verifier); 81 | criterion_main!(benches); 82 | -------------------------------------------------------------------------------- /plonk/src/errors.rs: -------------------------------------------------------------------------------- 1 | use ark_std::{boxed::Box, error, fmt, format, string::String}; 2 | use noah_algebra::prelude::AlgebraError; 3 | 4 | pub(crate) type Result = core::result::Result; 5 | 6 | #[derive(Debug, Clone, Eq, PartialEq)] 7 | #[allow(missing_docs)] 8 | pub enum PlonkError { 9 | /// Algebra error 10 | Algebra(AlgebraError), 11 | /// Error with message 12 | Message(String), 13 | /// Group not found. 14 | GroupNotFound(usize), 15 | /// Group does not exist. 16 | GroupDoesNotExist, 17 | /// Error occurred when prove. 18 | ProofError, 19 | /// The witness if error when prove. 20 | ProofErrorInvalidWitness, 21 | /// Polynomial commitment error. 22 | CommitmentError, 23 | /// Error occurred when setup. 24 | SetupError, 25 | /// Error occurred when verify. 26 | VerificationError, 27 | /// Division by zero. 28 | DivisionByZero, 29 | /// Function params error. 30 | FuncParamsError, 31 | /// Challenge error 32 | ChallengeError, 33 | /// Cannot compute the proof as sumcheck fails. 34 | PCSProveEvalError, 35 | /// The degree of the polynomial is higher than the maximum degree supported. 36 | DegreeError, 37 | } 38 | 39 | impl fmt::Display for PlonkError { 40 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 41 | use PlonkError::*; 42 | f.write_str(match self { 43 | Algebra(e) => Box::leak(format!("Algebra: {}", e).into_boxed_str()), 44 | Message(e) => Box::leak(e.to_string().into_boxed_str()), 45 | GroupNotFound(_n) => "Group not found.", 46 | GroupDoesNotExist => "Group does not exist.", 47 | ProofError => "Proof error.", 48 | ProofErrorInvalidWitness => "Proof error invalid witness.", 49 | CommitmentError => "Commitment error.", 50 | SetupError => "Setup error.", 51 | VerificationError => "Verification error.", 52 | DivisionByZero => "Division by zero.", 53 | FuncParamsError => "Function params error", 54 | ChallengeError => "Challenge error", 55 | PCSProveEvalError => "Cannot compute the proof as sumcheck fails.", 56 | DegreeError => { 57 | "The degree of the polynomial is higher than the maximum degree supported." 58 | } 59 | }) 60 | } 61 | } 62 | 63 | impl error::Error for PlonkError { 64 | #[cfg(feature = "std")] 65 | fn description(&self) -> &str { 66 | Box::leak(format!("{}", self).into_boxed_str()) 67 | } 68 | } 69 | 70 | impl From for PlonkError { 71 | fn from(e: AlgebraError) -> PlonkError { 72 | PlonkError::Algebra(e) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /plonk/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! The crate for Plonk and polynomial commitment for the Noah library 2 | #![cfg_attr(not(feature = "std"), no_std)] 3 | #![deny(unused_import_braces, unused_qualifications, trivial_casts)] 4 | #![deny(trivial_numeric_casts)] 5 | #![deny(stable_features, unreachable_pub, non_shorthand_field_patterns)] 6 | #![deny(unused_attributes, unused_imports, unused_mut, missing_docs)] 7 | #![deny(renamed_and_removed_lints, stable_features, unused_allocation)] 8 | #![deny(unused_comparisons, bare_trait_objects, unused_must_use)] 9 | #![doc(html_logo_url = "https://avatars.githubusercontent.com/u/74745723?s=200&v=4")] 10 | #![doc(html_playground_url = "https://play.rust-lang.org")] 11 | #![forbid(unsafe_code)] 12 | #![warn( 13 | unused, 14 | future_incompatible, 15 | nonstandard_style, 16 | rust_2018_idioms, 17 | rust_2021_compatibility 18 | )] 19 | #![allow(clippy::too_many_arguments, clippy::type_complexity)] 20 | 21 | #[macro_use] 22 | extern crate serde_derive; 23 | 24 | /// Module for error handling 25 | pub mod errors; 26 | 27 | /// Module for the TurboPlonk systems. 28 | pub mod plonk; 29 | 30 | /// Module for the polynomial commitment. 31 | pub mod poly_commit; 32 | -------------------------------------------------------------------------------- /plonk/src/plonk/constraint_system/ecc/mod.rs: -------------------------------------------------------------------------------- 1 | /// Module for ECC where the base is a constant to the circuit. 2 | pub mod const_base_ecc; 3 | 4 | /// Module for ECC where the base is not a constant. 5 | pub mod nonconst_base_ecc; 6 | 7 | use crate::plonk::constraint_system::{TurboCS, VarIndex}; 8 | use noah_algebra::prelude::*; 9 | use noah_algebra::traits::TECurve; 10 | 11 | /// The witness indices for x/y-coordinates of a point 12 | pub struct PointVar(VarIndex, VarIndex); 13 | 14 | /// PointVar plus the corresponding point 15 | pub struct ExtendedPointVar(PointVar, T); 16 | 17 | impl ExtendedPointVar { 18 | /// Return the point variable. 19 | pub fn get_var(&self) -> &PointVar { 20 | &self.0 21 | } 22 | 23 | /// Return the point value. 24 | pub fn get_point(&self) -> &T { 25 | &self.1 26 | } 27 | 28 | /// Return the point variable 29 | pub fn into_point_var(self) -> PointVar { 30 | self.0 31 | } 32 | } 33 | 34 | impl PointVar { 35 | /// Crate a point variable. 36 | pub fn new(x_var: VarIndex, y_var: VarIndex) -> PointVar { 37 | PointVar(x_var, y_var) 38 | } 39 | 40 | /// Return x-coordinate of the point variable. 41 | pub fn get_x(&self) -> VarIndex { 42 | self.0 43 | } 44 | 45 | /// Return y-coordinate of the point variable. 46 | pub fn get_y(&self) -> VarIndex { 47 | self.1 48 | } 49 | } 50 | 51 | impl TurboCS { 52 | /// Create variables for a point. 53 | pub fn new_point_variable>(&mut self, point: T) -> PointVar { 54 | let x = self.new_variable(point.get_x()); 55 | let y = self.new_variable(point.get_y()); 56 | PointVar(x, y) 57 | } 58 | 59 | /// Insert constraint for a public IO point to be decided online. 60 | pub fn prepare_pi_point_variable(&mut self, point_var: PointVar) { 61 | self.prepare_pi_variable(point_var.0); 62 | self.prepare_pi_variable(point_var.1); 63 | } 64 | 65 | /// Insert a curve addition gate: (x1, y1) + (x2, y2) = (x3, y3) 66 | /// 67 | /// x-coordinate constraint: 68 | /// x3 = x1 * y2 + y1 * x2 - d * x1 * y1 * x2 * y2 * x3 69 | /// wirings: w1 = x1, w2 = y2, w3 = x2, w4 = y1, w_out = x3 70 | /// selectors: qm1 = 1, qm2 = 1, q_ecc = -d, qo = 1 71 | /// 72 | /// y-coordinate constraint: 73 | /// y3 = -a * x1 * x2 + y1 * y2 + d * x1 * y1 * x2 * y2 * y3 74 | /// wirings: w1 = x1, w2 = x2, w3 = y1, w4 = y2, w_out = y3 75 | /// selectors: qm1 = -a, qm2 = 1, q_ecc = d, qo = 1 76 | fn insert_ecc_add_gate>( 77 | &mut self, 78 | p1_var: &PointVar, 79 | p2_var: &PointVar, 80 | p_out_var: &PointVar, 81 | ) { 82 | assert!(p1_var.0 < self.num_vars, "p1.x variable index out of bound"); 83 | assert!(p1_var.1 < self.num_vars, "p1.y variable index out of bound"); 84 | assert!(p2_var.0 < self.num_vars, "p2.x variable index out of bound"); 85 | assert!(p2_var.1 < self.num_vars, "p2.y variable index out of bound"); 86 | assert!( 87 | p_out_var.0 < self.num_vars, 88 | "p_out.x variable index out of bound" 89 | ); 90 | assert!( 91 | p_out_var.1 < self.num_vars, 92 | "p_out.y variable index out of bound" 93 | ); 94 | 95 | let edwards_d = S::from_bytes(&T::get_edwards_d()).unwrap(); 96 | let edwards_a = S::from_bytes(&T::get_edwards_a()).unwrap(); 97 | 98 | // x-coordinate constraint 99 | let zero = S::zero(); 100 | let one = S::one(); 101 | self.push_add_selectors(zero, zero, zero, zero); 102 | self.push_mul_selectors(one, one); 103 | self.push_constant_selector(zero); 104 | self.push_ecc_selector(edwards_d.neg()); 105 | self.push_out_selector(one); 106 | 107 | self.wiring[0].push(p1_var.0); 108 | self.wiring[1].push(p2_var.1); 109 | self.wiring[2].push(p2_var.0); 110 | self.wiring[3].push(p1_var.1); 111 | self.wiring[4].push(p_out_var.0); 112 | self.size += 1; 113 | 114 | // y-coordinate constraint 115 | self.push_add_selectors(zero, zero, zero, zero); 116 | self.push_mul_selectors(edwards_a.neg(), one); 117 | self.push_constant_selector(zero); 118 | self.push_ecc_selector(edwards_d); 119 | self.push_out_selector(one); 120 | 121 | self.wiring[0].push(p1_var.0); 122 | self.wiring[1].push(p2_var.0); 123 | self.wiring[2].push(p1_var.1); 124 | self.wiring[3].push(p2_var.1); 125 | self.wiring[4].push(p_out_var.1); 126 | self.finish_new_gate(); 127 | } 128 | 129 | /// Given two elliptic curve point variables `[P1]` and `[P2]`, returns `[P1] + [P2]` 130 | pub fn ecc_add>( 131 | &mut self, 132 | p1_var: &PointVar, 133 | p2_var: &PointVar, 134 | p1_ext: &T, 135 | p2_ext: &T, 136 | ) -> ExtendedPointVar { 137 | assert!(p1_var.0 < self.num_vars, "p1.x variable index out of bound"); 138 | assert!(p1_var.1 < self.num_vars, "p1.y variable index out of bound"); 139 | assert!(p2_var.0 < self.num_vars, "p2.x variable index out of bound"); 140 | assert!(p2_var.1 < self.num_vars, "p2.y variable index out of bound"); 141 | let p_out_ext = p1_ext.add(p2_ext); 142 | let p_out_var = self.new_point_variable(p_out_ext); 143 | self.insert_ecc_add_gate::(p1_var, p2_var, &p_out_var); 144 | ExtendedPointVar(p_out_var, p_out_ext) 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /plonk/src/plonk/constraint_system/ecc/nonconst_base_ecc.rs: -------------------------------------------------------------------------------- 1 | use crate::plonk::constraint_system::ecc::{ExtendedPointVar, PointVar}; 2 | use crate::plonk::constraint_system::{TurboCS, VarIndex}; 3 | use noah_algebra::prelude::*; 4 | use noah_algebra::traits::TECurve; 5 | 6 | impl TurboCS { 7 | /// Returns an identity twisted Edwards point and its corresponding point variable 8 | fn get_identity>(&mut self) -> ExtendedPointVar { 9 | ExtendedPointVar(PointVar(self.zero_var(), self.one_var()), T::get_identity()) 10 | } 11 | 12 | /// Given two (extended) point variables `point0`, `point1`, and a Boolean variable `bit`, 13 | /// returns `point_bit`. 14 | fn select_nonconstant_points>( 15 | &mut self, 16 | point0: &ExtendedPointVar, 17 | point1: &ExtendedPointVar, 18 | bit: VarIndex, 19 | ) -> ExtendedPointVar { 20 | let point0_var = &point0.0; 21 | let point1_var = &point1.0; 22 | let x = self.select(point0_var.0, point1_var.0, bit); 23 | let y = self.select(point0_var.1, point1_var.1, bit); 24 | let res_point_var = PointVar(x, y); 25 | if self.witness[bit].is_zero() { 26 | ExtendedPointVar(res_point_var, point0.1) 27 | } else { 28 | ExtendedPointVar(res_point_var, point1.1) 29 | } 30 | } 31 | 32 | /// Non-constant-base scalar multiplication: 33 | /// Given a base point `[G]` and an `n_bits`-bit secret scalar `s`, returns `s * [G]`. 34 | /// `n_bits` should be a positive even number. 35 | pub fn nonconst_base_scalar_mul>( 36 | &mut self, 37 | base_var: PointVar, 38 | base: T, 39 | scalar_var: VarIndex, 40 | n_bits: usize, 41 | ) -> PointVar { 42 | assert!(n_bits > 0, "n_bits is not positive"); 43 | 44 | let b_scalar_var = self.range_check(scalar_var, n_bits); 45 | 46 | let mut res_ext = self.get_identity(); 47 | let identity = self.get_identity(); 48 | let extended_point = ExtendedPointVar(base_var, base); 49 | 50 | for &bit in b_scalar_var.iter().rev() { 51 | // doubling 52 | res_ext = self.ecc_add(&res_ext.0, &res_ext.0, &res_ext.1, &res_ext.1); 53 | // conditional addition 54 | let tmp_ext = self.select_nonconstant_points(&identity, &extended_point, bit); 55 | res_ext = self.ecc_add(&res_ext.0, &tmp_ext.0, &res_ext.1, &tmp_ext.1); 56 | } 57 | res_ext.0 58 | } 59 | } 60 | 61 | #[cfg(test)] 62 | mod test { 63 | use crate::plonk::constraint_system::TurboCS; 64 | use noah_algebra::{ 65 | baby_jubjub::BabyJubjubPoint, ed25519::Ed25519Point, jubjub::JubjubPoint, prelude::*, 66 | traits::TECurve, 67 | }; 68 | 69 | #[test] 70 | fn test_scalar_mul() { 71 | scalar_mul::(); 72 | scalar_mul::(); 73 | scalar_mul::(); 74 | } 75 | 76 | fn scalar_mul() { 77 | let mut cs = TurboCS::new(); 78 | 79 | // compute secret scalar 80 | let scalar_bytes = [ 81 | 17, 144, 47, 113, 34, 14, 11, 207, 13, 116, 200, 201, 17, 33, 101, 116, 0, 59, 51, 1, 82 | 2, 39, 13, 56, 69, 175, 41, 111, 134, 180, 0, 0, 83 | ]; 84 | let scalar = T::BaseType::from_bytes(&scalar_bytes).unwrap(); 85 | let jubjub_scalar = T::ScalarType::from_bytes(&scalar_bytes).unwrap(); // safe unwrap 86 | let base_ext = T::get_base(); 87 | let p_out_ext = base_ext.mul(&jubjub_scalar); 88 | let p_out_plus_ext = p_out_ext.add(&base_ext); 89 | 90 | // build circuit 91 | let base_var = cs.new_point_variable(base_ext); 92 | let scalar_var = cs.new_variable(scalar); 93 | let p_out_var = cs.nonconst_base_scalar_mul(base_var, base_ext, scalar_var, 256); 94 | let mut witness = cs.get_and_clear_witness(); 95 | cs.verify_witness(&witness[..], &[]).unwrap(); 96 | 97 | // wrong witness: point = GENERATOR * (scalar + 1) 98 | witness[p_out_var.0] = p_out_plus_ext.get_x(); 99 | witness[p_out_var.1] = p_out_plus_ext.get_y(); 100 | assert!(cs.verify_witness(&witness[..], &[]).is_err()); 101 | } 102 | 103 | #[test] 104 | fn test_scalar_mul_with_zero_scalar() { 105 | scalar_mul_with_zero_scalar::(); 106 | scalar_mul_with_zero_scalar::(); 107 | scalar_mul_with_zero_scalar::(); 108 | } 109 | 110 | fn scalar_mul_with_zero_scalar() { 111 | let mut cs = TurboCS::new(); 112 | let base_ext = T::get_base(); 113 | 114 | let base_var = cs.new_point_variable(base_ext); 115 | let scalar_var = cs.new_variable(T::BaseType::zero()); 116 | let p_out_var = cs.nonconst_base_scalar_mul(base_var, base_ext, scalar_var, 64); 117 | let mut witness = cs.get_and_clear_witness(); 118 | 119 | // check p_out is an identity point 120 | assert_eq!(witness[p_out_var.0], T::BaseType::zero()); 121 | assert_eq!(witness[p_out_var.1], T::BaseType::one()); 122 | cs.verify_witness(&witness[..], &[]).unwrap(); 123 | 124 | // wrong witness: p_out = GENERATOR 125 | witness[p_out_var.0] = base_ext.get_x(); 126 | witness[p_out_var.1] = base_ext.get_y(); 127 | assert!(cs.verify_witness(&witness[..], &[]).is_err()); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /plonk/src/plonk/constraint_system/field_simulation/mod.rs: -------------------------------------------------------------------------------- 1 | /// Module for `SimFr` CS. 2 | pub mod fr_var; 3 | 4 | /// pub `SimFrVar`. 5 | #[doc(hidden)] 6 | pub use fr_var::SimFrVar; 7 | 8 | /// Module for `SimFrMul` CS. 9 | pub mod fr_mul_var; 10 | 11 | /// pub `SimFrMulVar`. 12 | #[doc(hidden)] 13 | pub use fr_mul_var::SimFrMulVar; 14 | -------------------------------------------------------------------------------- /plonk/src/plonk/constraint_system/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::errors::Result; 2 | use noah_algebra::prelude::*; 3 | 4 | /// Module for Field Simulation Constrain System. 5 | pub mod field_simulation; 6 | 7 | /// Module for Turbo PLONK Constrain System. 8 | pub mod turbo; 9 | 10 | /// Module for ECC. 11 | pub mod ecc; 12 | 13 | /// Module for the Anemoi-Jive hash function. 14 | pub mod anemoi_jive; 15 | 16 | /// Default used constraint system. 17 | #[doc(hidden)] 18 | pub use turbo::TurboCS; 19 | 20 | /// Variable index 21 | pub type VarIndex = usize; 22 | 23 | /// Constraint index 24 | pub type CsIndex = usize; 25 | 26 | /// Trait for PLONK constraint systems. 27 | pub trait ConstraintSystem: Sized { 28 | /// Type of scalar field. 29 | type Field: Scalar; 30 | 31 | /// Return the number of constraints in the system. 32 | /// `size` should divide q-1 where q is the size of the prime field. 33 | /// This enables finding a multiplicative subgroup with order `size`. 34 | fn size(&self) -> usize; 35 | 36 | /// Return number of variables in the constrain system 37 | fn num_vars(&self) -> usize; 38 | 39 | /// Return the wiring of the constrain system 40 | fn wiring(&self) -> &[Vec]; 41 | 42 | /// Return the size of the evaluation domain for computing the quotient polynomial. 43 | /// `quot_eval_dom_size divides q-1 where q is the size of the prime field. 44 | /// `quot_eval_dom_size is larger than the degree of the quotient polynomial. 45 | /// `quot_eval_dom_size is a multiple of 'size'. 46 | fn quot_eval_dom_size(&self) -> usize; 47 | 48 | /// Return the number of wires in a single gate. 49 | fn n_wires_per_gate() -> usize; 50 | 51 | /// Return the number of selectors. 52 | fn num_selectors(&self) -> usize; 53 | 54 | /// Compute the permutation implied by the copy constraints. 55 | fn compute_permutation(&self) -> Vec { 56 | let n = self.size(); 57 | let n_wires_per_gate = Self::n_wires_per_gate(); 58 | let mut perm = vec![0usize; n_wires_per_gate * n]; 59 | let mut marked = vec![false; self.num_vars()]; 60 | let mut v = Vec::with_capacity(n_wires_per_gate * n); 61 | for wire_slice in self.wiring().iter() { 62 | v.extend_from_slice(wire_slice); 63 | } 64 | // form a cycle for each variable value 65 | // marked variables already processd 66 | // for each unmarked variable, find all position where this variable occurs to form a cycle. 67 | for (i, value) in v.iter().enumerate() { 68 | if marked[*value] { 69 | continue; 70 | } 71 | let first = i; 72 | let mut prev = i; 73 | for (j, current_value) in v[i + 1..].iter().enumerate() { 74 | if current_value == value { 75 | perm[prev] = i + 1 + j; //current index in v 76 | prev = i + 1 + j; 77 | } 78 | } 79 | perm[prev] = first; 80 | marked[*value] = true 81 | } 82 | perm 83 | } 84 | 85 | /// Compute the indices of the constraints related to public inputs. 86 | fn public_vars_constraint_indices(&self) -> &[usize]; 87 | 88 | /// Compute the indices of the witnesses related to public inputs. 89 | fn public_vars_witness_indices(&self) -> &[usize]; 90 | 91 | /// Compute the indices of the constraints that need a boolean constraint of the second, third, and fourth inputs. 92 | fn boolean_constraint_indices(&self) -> &[CsIndex]; 93 | 94 | /// Compute the Anemoi selectors. 95 | fn compute_anemoi_jive_selectors(&self) -> [Vec; 4]; 96 | 97 | /// Map the witnesses into the wires of the circuit. 98 | /// The (i * size + j)-th output element is the value of the i-th wire on the j-th gate. 99 | fn extend_witness(&self, witness: &[Self::Field]) -> Vec { 100 | let mut extended = Vec::with_capacity(Self::n_wires_per_gate() * self.size()); 101 | for wire_slice in self.wiring().iter() { 102 | for index in wire_slice.iter() { 103 | extended.push(witness[*index]); 104 | } 105 | } 106 | extended 107 | } 108 | 109 | /// Borrow the (index)-th selector vector. 110 | fn selector(&self, index: usize) -> Result<&[Self::Field]>; 111 | 112 | /// Evaluate the constraint equation given public input and the 113 | /// values of the wires and the selectors. 114 | fn eval_gate_func( 115 | wire_vals: &[&Self::Field], 116 | sel_vals: &[&Self::Field], 117 | pub_input: &Self::Field, 118 | ) -> Result; 119 | 120 | /// Given the wires values of a gate, evaluate the coefficients 121 | /// of the selectors in the constraint equation. 122 | fn eval_selector_multipliers(wire_vals: &[&Self::Field]) -> Result>; 123 | 124 | /// is only for verifier use. 125 | fn is_verifier_only(&self) -> bool { 126 | false 127 | } 128 | 129 | /// Shrink to only verifier use. 130 | fn shrink_to_verifier_only(&self) -> Self; 131 | 132 | /// Get the Anemoi generator and generator inverse. 133 | fn get_anemoi_parameters(&self) -> Result<(Self::Field, Self::Field)>; 134 | 135 | /// Get the hiding degree for each witness polynomial. 136 | fn get_hiding_degree(&self, idx: usize) -> usize; 137 | } 138 | -------------------------------------------------------------------------------- /plonk/src/plonk/mod.rs: -------------------------------------------------------------------------------- 1 | //! The TurboPlonk implementation. 2 | 3 | /// Module for help functions. 4 | pub(crate) mod helpers; 5 | 6 | /// Module for the constraint system. 7 | pub mod constraint_system; 8 | 9 | /// Module for prover. 10 | pub mod prover; 11 | 12 | /// Module for indexer. 13 | pub mod indexer; 14 | 15 | /// Module for transcript. 16 | pub mod transcript; 17 | 18 | /// Module for verifier. 19 | pub mod verifier; 20 | -------------------------------------------------------------------------------- /plonk/src/plonk/transcript.rs: -------------------------------------------------------------------------------- 1 | use crate::plonk::indexer::PlonkVerifierParams; 2 | use crate::poly_commit::{pcs::ToBytes, transcript::PolyComTranscript}; 3 | use merlin::Transcript; 4 | use noah_algebra::prelude::*; 5 | use noah_algebra::traits::Domain; 6 | use rand_chacha::ChaChaRng; 7 | 8 | /// Initialize the transcript when compute PLONK proof. 9 | pub(crate) fn transcript_init_plonk( 10 | transcript: &mut Transcript, 11 | params: &PlonkVerifierParams, 12 | pi_values: &[F], 13 | root: &F, 14 | ) { 15 | transcript.append_message(b"New Domain", b"PLONK"); 16 | 17 | transcript.append_u64(b"CS size", params.cs_size as u64); 18 | transcript.append_message(b"field size", &F::get_field_size_le_bytes()); 19 | for q in params.cm_q_vec.iter() { 20 | transcript.append_commitment(q); 21 | } 22 | for p in params.cm_s_vec.iter() { 23 | transcript.append_commitment(p); 24 | } 25 | transcript.append_field_elem(root); 26 | for generator in params.k.iter() { 27 | transcript.append_field_elem(generator); 28 | } 29 | for pi_value in pi_values.iter() { 30 | transcript.append_field_elem(pi_value); 31 | } 32 | } 33 | 34 | /// Return the challenge result. 35 | pub(crate) fn transcript_get_challenge_field_elem( 36 | transcript: &mut Transcript, 37 | group_order: usize, 38 | label: &'static [u8], 39 | ) -> F { 40 | let mut buff = [0u8; 32]; 41 | transcript.challenge_bytes(label, &mut buff); 42 | let mut prng = ChaChaRng::from_seed(buff); 43 | loop { 44 | let elem = F::random(&mut prng); 45 | // elem should not be root-of-unity 46 | if elem.pow(&[group_order as u64]) != F::one() { 47 | return elem; 48 | } 49 | } 50 | } 51 | 52 | /// Return the challenge result by label: "alpha". 53 | pub(crate) fn transcript_get_plonk_challenge_alpha( 54 | transcript: &mut Transcript, 55 | group_order: usize, 56 | ) -> F { 57 | transcript_get_challenge_field_elem(transcript, group_order, b"alpha") 58 | } 59 | 60 | /// Return the challenge result by label: "zeta". 61 | pub(crate) fn transcript_get_plonk_challenge_zeta( 62 | transcript: &mut Transcript, 63 | group_order: usize, 64 | ) -> F { 65 | transcript_get_challenge_field_elem(transcript, group_order, b"zeta") 66 | } 67 | 68 | /// Return the challenge result by label: "beta". 69 | pub(crate) fn transcript_get_plonk_challenge_beta( 70 | transcript: &mut Transcript, 71 | group_order: usize, 72 | ) -> F { 73 | transcript_get_challenge_field_elem(transcript, group_order, b"beta") 74 | } 75 | 76 | /// Return the challenge result by label: "gamma". 77 | pub(crate) fn transcript_get_plonk_challenge_gamma( 78 | transcript: &mut Transcript, 79 | group_order: usize, 80 | ) -> F { 81 | transcript_get_challenge_field_elem(transcript, group_order, b"gamma") 82 | } 83 | 84 | /// Return the challenge result by label: "u" 85 | pub(crate) fn transcript_get_plonk_challenge_u( 86 | transcript: &mut Transcript, 87 | group_order: usize, 88 | ) -> F { 89 | transcript_get_challenge_field_elem(transcript, group_order, b"u") 90 | } 91 | -------------------------------------------------------------------------------- /plonk/src/poly_commit/mod.rs: -------------------------------------------------------------------------------- 1 | /// Module for field polynomial. 2 | pub mod field_polynomial; 3 | 4 | /// Module for KZG polynomial commitment scheme. 5 | pub mod kzg_poly_com; 6 | 7 | /// Module for polynomial commitment traits. 8 | pub mod pcs; 9 | 10 | /// Module for polynomial commitment transcript. 11 | pub mod transcript; 12 | -------------------------------------------------------------------------------- /plonk/src/poly_commit/transcript.rs: -------------------------------------------------------------------------------- 1 | use crate::poly_commit::pcs::ToBytes; 2 | use merlin::Transcript; 3 | use noah_algebra::prelude::*; 4 | 5 | /// The trait for polynomial commitment transcript. 6 | pub trait PolyComTranscript { 7 | /// Append the commitment to the transcript. 8 | fn append_commitment(&mut self, commitment: &C); 9 | 10 | /// Append the field to the transcript. 11 | fn append_field_elem(&mut self, point: &F); 12 | 13 | /// Get challenge result. 14 | fn get_challenge_field_elem(&mut self, label: &'static [u8]) -> F; 15 | } 16 | 17 | impl PolyComTranscript for Transcript { 18 | fn append_commitment(&mut self, commitment: &C) { 19 | self.append_message(b"append commitment", &commitment.to_bytes()); 20 | } 21 | 22 | fn append_field_elem(&mut self, field_elem: &F) { 23 | self.append_message(b"append field point", &field_elem.to_bytes()); 24 | } 25 | 26 | fn get_challenge_field_elem(&mut self, label: &'static [u8]) -> F { 27 | let mut buff = [0u8; 32]; 28 | self.challenge_bytes(label, &mut buff[..]); 29 | F::random(&mut rand_chacha::ChaChaRng::from_seed(buff)) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /smoke-tests/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = 'noah-smoke-tests' 3 | version = '0.5.0' 4 | authors = ['Findora '] 5 | edition = '2021' 6 | description = 'Noah smoke tests' 7 | 8 | [dependencies] 9 | aes = '0.8.1' 10 | aes-gcm = '0.10.1' 11 | bincode = '1.3.1' 12 | digest = '0.10' 13 | lazy_static = "1.4.0" 14 | libsecp256k1 = '0.7' 15 | linear-map = '1.2.0' 16 | merlin = '3.0' 17 | rand_chacha = '0.3' 18 | rmp-serde = '1.0.0' 19 | serde = '1.0' 20 | serde_derive = '1.0' 21 | serde_str = '0.1.0' 22 | sha2 = '0.10' 23 | sha3 = '0.10' 24 | 25 | [dependencies.noah] 26 | path = '../api' 27 | 28 | [dependencies.noah-algebra] 29 | path = '../algebra' 30 | 31 | [dependencies.noah-crypto] 32 | path = '../crypto' 33 | 34 | [dependencies.noah-plonk] 35 | path = '../plonk' 36 | 37 | [dependencies.curve25519-dalek] 38 | package = "noah-curve25519-dalek" 39 | version = "4.0.0" 40 | default-features = false 41 | features = ['serde'] 42 | 43 | [dependencies.ed25519-dalek] 44 | package = "noah-ed25519-dalek" 45 | version = "4.0.0" 46 | 47 | [dependencies.bulletproofs] 48 | package = "noah-bulletproofs" 49 | version = "4.1.0" 50 | 51 | [dependencies.ark-serialize] 52 | version = '0.4.0' 53 | default-features = false 54 | 55 | [dependencies.ark-std] 56 | version = '0.4.0' 57 | default-features = false 58 | 59 | [dependencies.ark-bulletproofs] 60 | version = '4.1.0' 61 | default-features = false 62 | features = ['yoloproofs'] 63 | 64 | [dependencies.rand_core] 65 | version = '0.6' 66 | default-features = false 67 | features = ['alloc'] 68 | 69 | [dependencies.wasm-bindgen] 70 | version = '0.2.50' 71 | features = ['serde-serialize'] 72 | 73 | [dependencies.num-integer] 74 | version = '0.1.43' 75 | 76 | [dependencies.num-traits] 77 | version = '0.2.12' 78 | 79 | [dependencies.num-bigint] 80 | version = '0.4.0' 81 | features = ['rand'] 82 | 83 | [dependencies.rayon] 84 | version = '1.5' 85 | optional = true 86 | 87 | [dependencies.structopt] 88 | version = '0.3.26' 89 | optional = true 90 | 91 | [dev-dependencies] 92 | bit-array = '0.4.3' 93 | criterion = { version = '0.5.0', default-features = false } 94 | hex = '0.4' 95 | lazy_static = '1.4.0' 96 | serde_json = '1.0' 97 | typenum = '1.11.2' 98 | parking_lot = '0.12' 99 | wasm-bindgen-test = "0.3.34" 100 | getrandom = { version = "0.2.8", features = ['js'] } 101 | 102 | [dev-dependencies.noah-accumulators] 103 | path = '../accumulators' 104 | 105 | [dev-dependencies.storage] 106 | git = 'https://github.com/FindoraNetwork/storage.git' 107 | tag = 'v1.1.6' 108 | 109 | [dev-dependencies.mem_db] 110 | git = 'https://github.com/FindoraNetwork/storage.git' 111 | tag = 'v1.1.6' 112 | 113 | [dev-dependencies.rand] 114 | version = '0.8' 115 | default-features = false 116 | 117 | [features] 118 | default = [ 119 | 'std', 120 | ] 121 | debug = ['noah-plonk/debug', 'noah/debug'] 122 | std = ['curve25519-dalek/std', 'noah/std', 'bulletproofs/std', 'ark-bulletproofs/std', 'ark-std/std'] 123 | parallel = [ 124 | 'default', 125 | 'rayon', 126 | 'noah/parallel', 127 | 'noah-algebra/parallel', 128 | 'noah-plonk/parallel' 129 | ] 130 | xfr-tracing = ['noah/xfr-tracing'] 131 | -------------------------------------------------------------------------------- /smoke-tests/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests; 3 | -------------------------------------------------------------------------------- /smoke-tests/src/tests/mod.rs: -------------------------------------------------------------------------------- 1 | mod abar_merkle_tree; 2 | mod smoke_axfr; 3 | mod smoke_axfr_compatibility; 4 | mod smoke_axfr_secp256k1_address; 5 | #[cfg(target_arch = "wasm32")] 6 | mod smoke_axfr_wasm; 7 | mod smoke_xfr; 8 | mod smoke_xfr_compatibility; 9 | #[cfg(feature = "xfr-tracing")] 10 | mod smoke_xfr_identity; 11 | mod smoke_xfr_secp256k1_address; 12 | #[cfg(feature = "xfr-tracing")] 13 | mod smoke_xfr_tracing; 14 | #[cfg(feature = "xfr-tracing")] 15 | mod xfr_note_complex; 16 | -------------------------------------------------------------------------------- /smoke-tests/src/tests/smoke_xfr_compatibility.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod smoke_xfr_compatibility { 3 | use noah::parameters::bulletproofs::BulletproofParams; 4 | use noah::xfr::{structs::*, *}; 5 | use noah_algebra::prelude::*; 6 | 7 | #[test] 8 | fn compatibility_v1_bar_to_bar_no_trancing() { 9 | let body = r##" 10 | { 11 | "inputs":[ 12 | { 13 | "amount":{"Confidential":["5g8IfrT4NYp_61JJiax5CUAirCYpozEpAMhJCAOE0S4=","QDtwusr-UHTBrw0zG5KpSDCie9Y3dtCUkN2EsiATLhc="]}, 14 | "asset_type":{"Confidential":"TotuwivH9kNvnCZg8fCmPFMMNgOx1bXYl8tDhJWDzEk="},"public_key":"zpTV5hl3UDlSAU0wzByBMDTHu7jd52yLGclcHwE4HB0="} 15 | ], 16 | "outputs":[{"amount":{"NonConfidential":"10000"}, 17 | "asset_type":{"NonConfidential":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}, 18 | "public_key":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="}, 19 | {"amount":{"Confidential":["vh2zjBDXpN20c2i4WOpqr3VcsOJwjXRw_cwYACdq-Tk=","DLEPKxj5BgXVT-cNsHWhgds81yZ-G27sUWdSXdfUmWY="]}, 20 | "asset_type":{"Confidential":"LHOJXMsD4kP-Ni3ZyTuTBoTO-p06iXa4HBvWjEJAdBc="}, 21 | "public_key":"zpTV5hl3UDlSAU0wzByBMDTHu7jd52yLGclcHwE4HB0="}], 22 | "proofs":{ 23 | "asset_type_and_amount_proof":{ 24 | "ConfAll":[ 25 | {"range_proof":"Tr_LQl18i8AIuZqDNsrDGbp8pX_KT5gU3Le7gHEfSkTqwRWRCFYZzOzq6Wo7w3WKl_J8-C5Kz0zQQFIH0wNve3aZEHRu3KuxqSczwEQQIrdWq9jLEAzPSfQ4DC4-2qwABKCd0IaXYHROY482qEZMblCiVcYbEToA6J_uvkl3oUISC-GG9fEBURGsHNFEC4u88lPJ_-szQMY-pUiQ3bm7CF7B-sknvGjnWGjKVHWqXG2zDIIKpukxFNtNmnaE4YMD0TdlMG8F3YqFZwtuSvZiIQ1VV3aMIn39nl331CNlLQagJs-v7ZmrGdi_AfpVZ8nC5X7xFMfneUOYIoA06JySNswC7xo1k2E2WVJq9fPvlc2AOC0lNPogLSm20ebnWUEv_GFI_yav7gmgUi7sK6TKeG5bMYvIECT8KxvjOmdz4nYC3yfhPGXHYSEdRRGEZASZgtYipOaBax98Zivl4RN5NIwIvvJQtAj9j7aN3TTIhLMkvwn4roDpQMHdm8KKhWIFhA5i0PHuPibeeY-tP8RxPg4xKa4GwZG_B7I88uOqyVKUCzxkKI6Y15KYMoICD0AIcw8Dt4sHORX1EmcFyxahMuAkg9uECANXEkt6yRMK4u-fCvEz_l5kx2rZcGGYwAwLunrmmY8MISCd_gOqrYmyhmUHDjAoMY-hSMkVEetYXFgK3pVY7t0G1nYnS9LVkuNe9QnHBQEUEdLhdaLOoY2QAiyy0Tqk4HOfcPCKOYjUhdPQWi0-yx54K7HCoJxEp6wS0EWCdspldSrEFEBN4oMxccGky5ybIb_xyNqn8htJpgzokEStY5L71cGeTcFbhpP8dhcjb1LkNF2dNRJy7qheBup0jJT8QUQDwIL7HHv9nFy4TaFsQUSr0VAadsmWGl0Vnk4wUADGqFEaTeiywf8keexPZJW4mkvGtZpoOcJ8eQKSGsVhdsbFgKwh9DK-nRl9t-iJwH_wEpp89dlsOFhzcyTH2q4Ovhc3QT83JNiK8HAXbWgOBUxpZ6bffgzNuQANcO-B7xGUA5UenOXW8s6FPXjK8GdEq9M5TTgs-JiJ2Qg=", 26 | "xfr_diff_commitment_low":"3N1tvEXirnPAPSC4kBB0dhXnTZHgkDFWHa2GrK4qxDA=", 27 | "xfr_diff_commitment_high":"tg5SuaMqJFopA3T2sTTYuKtyi-cg_BaU2yZgt1y-I3M="}, 28 | {"c1_eq_c2":{"c3":"kEK1yXh2wl6qPooAxV3FILoii3OBi10G6MkIrkf6smk=","c4":"0CC-9-urVfiJqDIXapMsKtHccjE-Tps6jUOJNw0-a2c=","z1":"RSIl-0xYwA0NqquJE3YTm35ll1FGouOHSdAKHTeO9Qw=","z2":"dYxCFFo8nXrH_9K_t6y2xiVB_JXdvPSR--CTXptHggc=","z3":"PpXwARoiktXjcnsp4ulfzNWqjTsmEyxpEAoTq_BhgwM="}, 29 | "zero":{"c3":"Zk6NkzsDthU1A4miO4gtq0XFcTK3_x8pnoknYaF7AH4=","c4":"6HBX41mNk6drZ8wxpYkIfxPNDjGid0NKN2lhVR4VanQ=","z1":"JiWqImDX8-_xmjFsbQQBs6qqHIDzOVW6L0Tx2XpbewE=","z2":"XntbL9IUQqfgjwwyvCIK_w4fAGXAPtjp5IVdL7yPxAc=","z3":"Dn4dhElNF4iXN55Vm2kXGyoZ-o-eBbVR5qDWhF88XQU="}} 30 | ]}, 31 | "asset_tracing_proof":{ 32 | "asset_type_and_amount_proofs":[],"inputs_identity_proofs":[[]],"outputs_identity_proofs":[[],[]] 33 | } 34 | }, 35 | "asset_tracing_memos":[[],[],[]], 36 | "owners_memos":[null,{"blind_share":"DCwxC8OMKdoUrkH5upcMzEFrRtgx_QmNapPfYsoQzis=","lock":{"ciphertext":"B2krDhuxQYASoGUHQAtB0iUH2x8GwtwPxrhTEr1M7QWSq9E2xdURHg==","ephemeral_public_key":"YTQHBbPb8J8CS-2wDMl1adLrF_PWQYZ6nN9hsGwzUFk="}}] 37 | } 38 | "##; 39 | 40 | let body: XfrBody = serde_json::from_str(&body).unwrap(); 41 | 42 | let mut params = BulletproofParams::default(); 43 | let mut prng = test_rng(); 44 | let policies = XfrNotePolicies::empty_policies(body.inputs.len(), body.outputs.len()); 45 | let policies_ref = policies.to_ref(); 46 | 47 | assert!( 48 | batch_verify_xfr_bodies(&mut prng, &mut params, &[&body], &[&policies_ref]).is_ok() 49 | ); 50 | } 51 | } 52 | --------------------------------------------------------------------------------