├── .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 | 
2 | 
3 | 
4 | 
5 | 
6 | 
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::