├── .github ├── settings.yml └── workflows │ └── rust.yml ├── .gitignore ├── CHANGELOG ├── CODEOWNERS ├── CONTRIBUTING.md ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── MAINTAINERS.md ├── README.md ├── RELEASES.md ├── SECURITY.md ├── docker ├── centos │ └── Dockerfile ├── fedora │ └── Dockerfile ├── suse │ └── Dockerfile └── ubuntu │ ├── Dockerfile │ ├── ursa-bionic.dockerfile │ ├── ursa-fossa.dockerfile │ └── ursa-xenial.dockerfile ├── docs ├── Makefile ├── build-environment.md └── source │ ├── community.rst │ ├── community │ ├── code_of_conduct.rst │ ├── contributing.rst │ ├── issue_tracking.rst │ └── join_the_discussion.rst │ ├── conf.py │ ├── contents.rst │ └── introduction.rst ├── libursa ├── .rpm │ └── ursa.spec ├── Cargo.lock ├── Cargo.toml ├── benches │ ├── bls.rs │ ├── cks_revok.rs │ └── encryption.rs ├── bin │ ├── test_aescbc.rs │ ├── test_aesgcm.rs │ ├── test_ed25519.rs │ ├── test_secp256k1.rs │ └── test_xchacha20poly1305.rs ├── cmake-build-debug │ └── CMakeFiles │ │ └── clion-log.txt ├── docs │ └── anoncreds-design.md ├── include │ ├── ursa_crypto.h │ ├── ursa_crypto_ed25519.h │ └── ursa_crypto_encryption.h ├── packaging │ └── publish_to_crates_io.pl ├── src │ ├── bls │ │ └── mod.rs │ ├── bn │ │ ├── openssl.rs │ │ └── rust.rs │ ├── cl │ │ ├── constants.rs │ │ ├── datastructures.rs │ │ ├── hash.rs │ │ ├── helpers.rs │ │ ├── issuer.rs │ │ ├── mod.rs │ │ ├── prover.rs │ │ └── verifier.rs │ ├── encryption │ │ ├── mod.rs │ │ └── symm │ │ │ ├── aescbc.rs │ │ │ ├── aescbc_asm.rs │ │ │ ├── aesgcm.rs │ │ │ ├── aesgcm_asm.rs │ │ │ ├── chacha20poly1305.rs │ │ │ ├── mod.rs │ │ │ └── xchacha20poly1305.rs │ ├── errors │ │ └── mod.rs │ ├── ffi │ │ ├── bls.rs │ │ ├── cl │ │ │ ├── issuer.rs │ │ │ ├── mod.rs │ │ │ ├── prover.rs │ │ │ └── verifier.rs │ │ ├── encryption │ │ │ └── mod.rs │ │ ├── logger.rs │ │ ├── mod.rs │ │ └── signatures │ │ │ ├── ed25519.rs │ │ │ └── mod.rs │ ├── hash │ │ ├── blake2.rs │ │ └── mod.rs │ ├── kex │ │ ├── mod.rs │ │ ├── secp256k1.rs │ │ └── x25519.rs │ ├── keys.rs │ ├── lib.rs │ ├── pair │ │ └── amcl.rs │ ├── sharing │ │ ├── mod.rs │ │ └── shamir.rs │ ├── signatures │ │ ├── bls.rs │ │ ├── ed25519.rs │ │ ├── mod.rs │ │ └── secp256k1.rs │ ├── utils │ │ ├── commitment.rs │ │ ├── ctypes.rs │ │ ├── logger.rs │ │ ├── macros.rs │ │ └── mod.rs │ └── wasm │ │ ├── bls.rs │ │ ├── cl.rs │ │ ├── ed25519.rs │ │ ├── encryption.rs │ │ ├── macros.rs │ │ ├── mod.rs │ │ ├── secp256k1.rs │ │ └── x25519.rs └── tests │ ├── cl.rs │ └── test_bench.rs ├── libzmix ├── Cargo.toml ├── README.md ├── bbs │ ├── Cargo.toml │ ├── README.md │ ├── src │ │ ├── errors.rs │ │ ├── issuer.rs │ │ ├── keys.rs │ │ ├── lib.rs │ │ ├── macros.rs │ │ ├── messages.rs │ │ ├── pok_sig.rs │ │ ├── pok_vc.rs │ │ ├── prover.rs │ │ ├── signature.rs │ │ └── verifier.rs │ └── tests │ │ └── bbs.rs ├── benches │ └── bbs_vs_ps.rs ├── bulletproofs_amcl │ ├── .gitignore │ ├── Cargo.toml │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── benches │ │ └── vec_poly_eval.rs │ ├── src │ │ ├── errors.rs │ │ ├── ipp.rs │ │ ├── lib.rs │ │ ├── r1cs │ │ │ ├── constraint_system.rs │ │ │ ├── gadgets │ │ │ │ ├── README.md │ │ │ │ ├── bound_check.rs │ │ │ │ ├── hamming_distance.rs │ │ │ │ ├── helper_constraints │ │ │ │ │ ├── bit.rs │ │ │ │ │ ├── mimc.rs │ │ │ │ │ ├── mod.rs │ │ │ │ │ ├── non_zero.rs │ │ │ │ │ ├── poseidon.rs │ │ │ │ │ ├── positive_no.rs │ │ │ │ │ ├── sparse_merkle_tree_4_ary.rs │ │ │ │ │ ├── sparse_merkle_tree_8_ary.rs │ │ │ │ │ └── vector_sum.rs │ │ │ │ ├── merkle_tree_hash.rs │ │ │ │ ├── mimc.rs │ │ │ │ ├── mod.rs │ │ │ │ ├── non_zero.rs │ │ │ │ ├── poseidon_constants.rs │ │ │ │ ├── poseidon_hash.rs │ │ │ │ ├── randomizer.rs │ │ │ │ ├── sage │ │ │ │ │ ├── calc_round_numbers.py │ │ │ │ │ ├── create_mds_pf.sage │ │ │ │ │ └── create_rcs_grain.sage │ │ │ │ ├── set_membership.rs │ │ │ │ ├── set_membership_alt.rs │ │ │ │ ├── set_non_membership.rs │ │ │ │ ├── sparse_merkle_tree_4_ary.rs │ │ │ │ └── sparse_merkle_tree_8_ary.rs │ │ │ ├── linear_combination.rs │ │ │ ├── mod.rs │ │ │ ├── proof.rs │ │ │ ├── prover.rs │ │ │ └── verifier.rs │ │ ├── transcript.rs │ │ └── utils │ │ │ ├── hash_db.rs │ │ │ ├── mod.rs │ │ │ └── vector_poly.rs │ └── tests │ │ ├── mod.rs │ │ ├── multiple_constraint_systems.rs │ │ ├── r1cs.rs │ │ └── utils │ │ ├── mimc.rs │ │ └── mod.rs ├── docs │ ├── VerifiableCredentials.md │ ├── flow-diagram.png │ ├── flow.puml │ └── zklang_proof_spec.json ├── src │ ├── commitments │ │ ├── mod.rs │ │ ├── pedersen_BLS12_381.rs │ │ └── pok_vc.rs │ ├── errors.rs │ ├── ffi │ │ └── mod.rs │ ├── hash_functions │ │ ├── bls12_381_hash.rs │ │ └── mod.rs │ ├── lib.rs │ ├── prf │ │ └── mod.rs │ ├── signatures │ │ ├── delg_cred_cdd │ │ │ ├── README.md │ │ │ ├── attribute_token.rs │ │ │ ├── errors.rs │ │ │ ├── groth_sig.rs │ │ │ ├── issuer.rs │ │ │ └── mod.rs │ │ ├── mod.rs │ │ └── ps │ │ │ ├── README.md │ │ │ ├── blind_signature.rs │ │ │ ├── errors.rs │ │ │ ├── keys.rs │ │ │ ├── mod.rs │ │ │ ├── pok_sig.rs │ │ │ └── signature.rs │ ├── utils │ │ ├── mod.rs │ │ └── random.rs │ ├── verifiable_encryption │ │ ├── cs_verifiable_encryption.rs │ │ └── mod.rs │ └── zkl │ │ ├── mod.rs │ │ └── spec.rs └── tests │ └── ps_sig_complete_scenario.rs ├── rustfmt.toml ├── src ├── lib.rs └── prelude.rs ├── ursa_accumulators ├── Cargo.toml └── src │ └── lib.rs ├── ursa_core ├── .gitignore ├── Cargo.toml └── src │ ├── error.rs │ └── lib.rs ├── ursa_encryption ├── Cargo.toml └── src │ └── lib.rs ├── ursa_sharing ├── Cargo.toml ├── README.md ├── examples │ ├── bls12381.rs │ ├── bn3072.rs │ ├── curve25519.rs │ ├── k256.rs │ └── p256.rs ├── run_examples.bat ├── run_examples.sh └── src │ ├── error.rs │ ├── feldman.rs │ ├── lib.rs │ ├── pedersen.rs │ ├── shamir.rs │ └── tests.rs ├── ursa_shortgroupsignatures ├── Cargo.toml └── src │ └── lib.rs └── ursa_signatures ├── Cargo.toml └── src └── lib.rs /.github/settings.yml: -------------------------------------------------------------------------------- 1 | # 2 | # SPDX-License-Identifier: Apache-2.0 3 | # 4 | 5 | repository: 6 | name: ursa 7 | description: Hyperledger Ursa (a shared cryptographic library) has moved to end-of-life status, with the components of Ursa still in use moved to their relevant Hyperledger projects (AnonCreds, Indy, Aries and Iroha). 8 | homepage: https://wiki.hyperledger.org/display/ursa 9 | default_branch: main 10 | has_downloads: true 11 | has_issues: true 12 | has_projects: false 13 | has_wiki: false 14 | archived: true 15 | private: false 16 | allow_squash_merge: false 17 | allow_merge_commit: false 18 | allow_rebase_merge: true 19 | -------------------------------------------------------------------------------- /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Ursa CI 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | workflow_dispatch: 9 | 10 | env: 11 | CARGO_TERM_COLOR: always 12 | SODIUM_BUILD_STATIC: 1 13 | 14 | jobs: 15 | Build: 16 | 17 | runs-on: ubuntu-latest 18 | 19 | strategy: 20 | matrix: 21 | workdir: [ ".", "./libursa" ] 22 | 23 | steps: 24 | - uses: actions/checkout@v3 25 | 26 | - name: Build 27 | working-directory: ${{ matrix.workdir }} 28 | run: cargo build --verbose 29 | if: always() 30 | 31 | - name: Format 32 | working-directory: ${{ matrix.workdir }} 33 | run: cargo fmt --all -- --check 34 | if: always() 35 | 36 | - name: Docs 37 | working-directory: ${{ matrix.workdir }} 38 | run: cargo doc --no-deps 39 | if: always() 40 | 41 | - name: Clippy 42 | working-directory: ${{ matrix.workdir }} 43 | run: cargo clippy --all -- -W clippy::not_unsafe_ptr_arg_deref -A clippy::many_single_char_names 44 | if: always() 45 | 46 | - name: Check 47 | working-directory: ${{ matrix.workdir }} 48 | run: cargo check 49 | if: always() 50 | 51 | - name: Tests 52 | working-directory: ${{ matrix.workdir }} 53 | run: cargo test --release 54 | if: always() 55 | 56 | # - name: Audit 57 | # working-directory: ${{ matrix.workdir }} 58 | # run: cargo audit 59 | # if: always() 60 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | cargo-registry 2 | target 3 | pkg 4 | build 5 | .idea 6 | *.iml 7 | .venv 8 | .cache 9 | .DS_Store 10 | **/*.rs.bk 11 | Podfile.lock 12 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | ## 0.3.7 (2021-09) 2 | 3 | - Package refactor into multiple subcrates (WIP) 4 | - Migrate from libsecp256k1 to k256 5 | - Upgrade dependencies 6 | 7 | ## 0.1.0 (2019-03-21) 8 | 9 | - Initial release 10 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @hyperledger/ursa-maintainers 2 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Hyperledger Ursa 2 | 3 | Hyperledger Ursa is Apache 2.0 licensed and accepts contributions via 4 | [GitHub](https://github.com/hyperledger/ursa) pull requests. 5 | 6 | # Ways to contribute to Ursa 7 | 8 | - Bugs or issues: Report problems or defects found to the [ursa Rocket.Chat channel](https://chat.hyperledger.org/channel/ursa) 9 | - Features and enhancements: Provide expanded capabilities or optimizations 10 | - Documentation: Improve existing documentation or create new information 11 | - Tests for events and results: 12 | - Functional 13 | - Performance 14 | - Usability 15 | - Security 16 | - Localization 17 | 18 | # The Commit Process 19 | 20 | When contributing code, please follow these guidelines: 21 | 22 | - Fork the repository and make your changes in a feature branch 23 | - Include unit and integration tests for any new features and updates to existing tests 24 | - Ensure that the unit and integration tests run successfully. 25 | - Check that the lint tests pass 26 | 27 | ## Important 28 | Use `git rebase origin/main` to limit creating merge commits 29 | 30 | ## Signed-off-by 31 | Each commit must include a "Signed-off-by" line in the commit message (`git commit -s`). This sign-off indicates that you agree the commit satifies the [Developer Certificate of Origin](https://developercertificate.org). 32 | 33 | ## Commit Email Address 34 | Your commit email address must match your GitHub or GitLab email address. For more information, see https://help.github.com/articles/setting-your-commit-email-address-in-git/. 35 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["The Hyperledger Ursa Contributors"] 3 | description = "A collection of cryptography primitives for implementing blockchain transactions and secure communication" 4 | documentation = "https://docs.rs/ursa" 5 | edition = "2018" 6 | homepage = "https://crates.io/crates/ursa" 7 | keywords = ["cryptography", "zero-knowledge"] 8 | license = "Apache-2.0" 9 | name = "ursa" 10 | readme = "README.md" 11 | repository = "https://github.com/hyperledger/ursa" 12 | version = "0.5.0" 13 | 14 | [badges] 15 | maintenance = { status = "deprecated" } 16 | 17 | [lib] 18 | crate-type = ["cdylib", "staticlib", "rlib"] 19 | 20 | [profile.release] 21 | lto = true 22 | 23 | [workspace] 24 | members = [ 25 | "ursa_accumulators", 26 | "ursa_core", 27 | "ursa_encryption", 28 | "ursa_sharing", 29 | "ursa_shortgroupsignatures", 30 | "ursa_signatures" 31 | ] 32 | 33 | exclude = [ 34 | "libursa" 35 | ] 36 | 37 | [features] 38 | default = ["sharing"] 39 | sharing = ["ursa_sharing"] 40 | 41 | [dependencies] 42 | ursa_sharing = { version = "0.1", path = "ursa_sharing", optional = true } 43 | -------------------------------------------------------------------------------- /MAINTAINERS.md: -------------------------------------------------------------------------------- 1 | ## Maintainers 2 | 3 | ### Active Maintainers 4 | | name | Github | Discord | 5 | |--------------|------------------------------------------------|----------------| 6 | | Brent Zundel | [@brentzundel](https://github.com/brentzundel) | brent#0347 | 7 | | Aleksandr Petrosyan | [@appetrosyan](https://github.com/appetrosyan) | a-p-petrosyan#9734 | 8 | | Mike Lodder | [@mikelodder7](https://github.com/mikelodder7) | - | 9 | | Roman Shanin | [@Erigara](https://github.com/Erigara) | Erigara#4366 | 10 | 11 | ### Emeritus Maintainers 12 | | name | Github | Discord | 13 | |--------------|------------------------------------------------|----------------| 14 | | Cam Parra | [@mac-arrap](https://github.com/mac-arrap) | cam-parra#1919 | 15 | -------------------------------------------------------------------------------- /RELEASES.md: -------------------------------------------------------------------------------- 1 | # How Ursa Releases 2 | 3 | Releases are made after enough features and improvements have been made as decided by the Ursa working group. 4 | When a release is going to be done the following process is followed: 5 | 6 | - An RC branch is forked from `main` with the name `rcvx.x.x` 7 | - Additional tests are made that are not covered by the CI pipeline line external audits or penetration tests. 8 | - When enough testing has been applied, the RC branch is merged with main 9 | - main is tagged with the release number `vx.x.x` 10 | - A rust crate is published with this version number 11 | 12 | If fixes are needed from previous versions, branches would be made so work can be done directly at that point. For example, if 2.0 and 1.0 have been released by a security fix is needed in 1.0, a 1.0 branch will be made and the newer version would be 1.0.1. 13 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Hyperledger Security Policy 2 | 3 | ## Reporting a Security Bug 4 | 5 | If you think you have discovered a security issue in any of the Hyperledger projects, we'd love to hear from you. We will take all security bugs seriously and if confirmed upon investigation we will patch it within a reasonable amount of time and release a public security bulletin discussing the impact and credit the discoverer. 6 | 7 | There are two ways to report a security bug. The easiest is to email a description of the flaw and any related information (e.g. reproduction steps, version) to [security at hyperledger dot org](mailto:security@hyperledger.org). 8 | 9 | The other way is to file a confidential security bug in our [JIRA bug tracking system](https://jira.hyperledger.org). Be sure to set the “Security Level” to “Security issue”. 10 | 11 | The process by which the Hyperledger Security Team handles security bugs is documented further in our [Defect Response page](https://wiki.hyperledger.org/display/HYP/Defect+Response) on our [wiki](https://wiki.hyperledger.org). 12 | 13 | -------------------------------------------------------------------------------- /docker/centos/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM centos:7 2 | 3 | LABEL maintainer="Michael Lodder " 4 | 5 | ENV PATH /root/.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin 6 | ENV LD_LIBRARY_PATH /usr/local/lib 7 | 8 | WORKDIR /root 9 | 10 | RUN yum -y update \ 11 | && yum -y install sudo make autoconf libtool curl python3 pkg-config openssl-devel 2>&1 > /dev/null \ 12 | && curl https://sh.rustup.rs -sSf | sh -s -- -y 13 | -------------------------------------------------------------------------------- /docker/fedora/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM fedora:29 2 | 3 | LABEL maintainer="Michael Lodder " 4 | 5 | ENV PATH /root/.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin 6 | ENV LD_LIBRARY_PATH /usr/local/lib 7 | 8 | WORKDIR /root 9 | 10 | RUN yum -y update \ 11 | && yum -y install sudo make autoconf libtool curl python3 pkg-config openssl-devel 2>&1 > /dev/null \ 12 | && curl https://sh.rustup.rs -sSf | sh -s -- -y 13 | -------------------------------------------------------------------------------- /docker/suse/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM opensuse:leap 2 | 3 | LABEL maintainer="Michael Lodder " 4 | 5 | ENV PATH /root/.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin 6 | ENV LD_LIBRARY_PATH /usr/local/lib 7 | 8 | WORKDIR /root 9 | 10 | RUN zypper --non-interactive update \ 11 | && zypper --non-interactive install sudo make gcc autoconf libtool curl python3 pkg-config openssl-devel 2>&1 > /dev/null \ 12 | && curl https://sh.rustup.rs -sSf | sh -s -- -y 13 | -------------------------------------------------------------------------------- /docker/ubuntu/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright contributors to Hyperledger Ursa 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | FROM ubuntu:18.04 5 | 6 | ENV PATH /root/.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin 7 | ENV LD_LIBRARY_PATH /usr/local/lib 8 | ARG DEBIAN_FRONTEND=noninteractive 9 | 10 | RUN apt-get update && apt-get dist-upgrade -y 11 | 12 | # Install dependencies and required tools 13 | RUN apt-get install -y \ 14 | git \ 15 | vim \ 16 | cmake \ 17 | sudo \ 18 | autoconf \ 19 | libtool \ 20 | curl \ 21 | python3 \ 22 | pkg-config \ 23 | libssl1.0.0 \ 24 | libssl-dev \ 25 | llvm \ 26 | llvm-dev \ 27 | clang 28 | 29 | WORKDIR /root 30 | 31 | RUN cd /usr/lib/x86_64-linux-gnu \ 32 | && ln -s libssl.so.1.0.0 libssl.so.10 \ 33 | && ln -s libcrypto.so.1.0.0 libcrypto.so.10 \ 34 | && curl https://sh.rustup.rs -sSf | sh -s -- -y \ 35 | && cargo install cargo-deb 36 | -------------------------------------------------------------------------------- /docker/ubuntu/ursa-bionic.dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright contributors to Hyperledger Ursa 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | FROM ubuntu:18.04 5 | 6 | ENV PATH /root/.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin 7 | ENV LD_LIBRARY_PATH /usr/local/lib 8 | ARG DEBIAN_FRONTEND=noninteractive 9 | 10 | RUN apt-get update && apt-get dist-upgrade -y 11 | 12 | # Install dependencies and required tools 13 | RUN apt-get install -y \ 14 | git \ 15 | vim \ 16 | cmake \ 17 | sudo \ 18 | autoconf \ 19 | libtool \ 20 | curl \ 21 | python3 \ 22 | pkg-config \ 23 | libssl1.0.0 \ 24 | libssl-dev \ 25 | llvm \ 26 | llvm-dev \ 27 | clang 28 | 29 | WORKDIR /root 30 | 31 | RUN cd /usr/lib/x86_64-linux-gnu \ 32 | && ln -s libssl.so.1.0.0 libssl.so.10 \ 33 | && ln -s libcrypto.so.1.0.0 libcrypto.so.10 \ 34 | && curl https://sh.rustup.rs -sSf | sh -s -- -y \ 35 | && cargo install cargo-deb 36 | -------------------------------------------------------------------------------- /docker/ubuntu/ursa-fossa.dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright contributors to Hyperledger Ursa 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | FROM ubuntu:20.04 5 | 6 | ENV PATH /root/.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin 7 | ENV LD_LIBRARY_PATH /usr/local/lib 8 | ARG DEBIAN_FRONTEND=noninteractive 9 | 10 | RUN apt-get update && apt-get dist-upgrade -y 11 | 12 | # Install dependencies and required tools 13 | RUN apt-get install -y \ 14 | git \ 15 | vim \ 16 | cmake \ 17 | sudo \ 18 | autoconf \ 19 | libtool \ 20 | curl \ 21 | python3 \ 22 | pkg-config \ 23 | libssl1.0.0 \ 24 | libssl-dev \ 25 | llvm \ 26 | llvm-dev \ 27 | clang 28 | 29 | WORKDIR /root 30 | 31 | RUN cd /usr/lib/x86_64-linux-gnu \ 32 | && ln -s libssl.so.1.0.0 libssl.so.10 \ 33 | && ln -s libcrypto.so.1.0.0 libcrypto.so.10 \ 34 | && curl https://sh.rustup.rs -sSf | sh -s -- -y \ 35 | && cargo install cargo-deb 36 | -------------------------------------------------------------------------------- /docker/ubuntu/ursa-xenial.dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright contributors to Hyperledger Ursa 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | FROM ubuntu:16.04 5 | 6 | ENV PATH /root/.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin 7 | ENV LD_LIBRARY_PATH /usr/local/lib 8 | ARG DEBIAN_FRONTEND=noninteractive 9 | 10 | RUN apt-get update && apt-get dist-upgrade -y 11 | 12 | # Install dependencies and required tools 13 | RUN apt-get install -y \ 14 | git \ 15 | vim \ 16 | cmake \ 17 | sudo \ 18 | autoconf \ 19 | libtool \ 20 | curl \ 21 | python3 \ 22 | pkg-config \ 23 | libssl1.0.0 \ 24 | libssl-dev \ 25 | llvm \ 26 | llvm-dev \ 27 | clang 28 | 29 | WORKDIR /root 30 | 31 | RUN cd /usr/lib/x86_64-linux-gnu \ 32 | && ln -s libssl.so.1.0.0 libssl.so.10 \ 33 | && ln -s libcrypto.so.1.0.0 libcrypto.so.10 \ 34 | && curl https://sh.rustup.rs -sSf | sh -s -- -y \ 35 | && cargo install cargo-deb 36 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SOURCEDIR = source 8 | BUILDDIR = build 9 | 10 | # Put it first so that "make" without argument is like "make help". 11 | help: 12 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 13 | 14 | .PHONY: help Makefile 15 | 16 | # Catch-all target: route all unknown targets to Sphinx using the new 17 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 18 | %: Makefile 19 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /docs/build-environment.md: -------------------------------------------------------------------------------- 1 | # Setup your build environment 2 | 3 | The instructions below show the necessary steps to configure the environment to build all modes of libursa. There are convenience docker images in the **docker** folder that can be used. 4 | 5 | ## Fedora, RedHat, CentOS 6 | 7 | 1. Install build tools 8 | 9 | ```bash 10 | yum -y install make autoconf libtool curl python3 pkg-config openssl-devel 11 | ``` 12 | 13 | 2. Install rust 14 | 15 | ```bash 16 | curl -sSf https://sh.rustup.rs | sh -s -- -y 17 | ``` 18 | 19 | 3. Initialize rust environment 20 | 21 | ```bash 22 | source ~/.cargo/env 23 | ``` 24 | 25 | ## OpenSUSE 26 | 27 | 1. Install build tools 28 | 29 | ```bash 30 | zypper --non-interactive install make gcc autoconf libtool curl python3 pkg-config openssl-devel 31 | ``` 32 | 33 | 2. Install rust 34 | 35 | ```bash 36 | curl -sSf https://sh.rustup.rs | sh -s -- -y 37 | ``` 38 | 39 | 3. Initialize rust environment 40 | 41 | ```bash 42 | source ~/.cargo/env 43 | ``` 44 | 45 | ## Debian, Ubuntu 46 | 47 | 1. Install build tools 48 | 49 | ```bash 50 | apt-get install -y cmake autoconf libtool curl python3 pkg-config libssl-dev 51 | ``` 52 | 53 | 2. Install rust 54 | 55 | ```bash 56 | curl -sSf https://sh.rustup.rs | sh -s -- -y 57 | ``` 58 | 59 | 3. Initialize rust environment 60 | 61 | ```bash 62 | source ~/.cargo/env 63 | ``` 64 | 65 | ## Mac OS X 66 | 67 | 1. Install xcode command line tools 68 | 69 | ```bash 70 | xcode-select --install 71 | ``` 72 | 73 | 2. Install rust 74 | 75 | ```bash 76 | curl -sSf https://sh.rustup.rs | sh -s -- -y 77 | ``` 78 | 79 | 3. Install brew 80 | 81 | ```bash 82 | /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" 83 | ``` 84 | 85 | 4. Install build tools 86 | 87 | ```bash 88 | brew install pkg-config 89 | brew install automake 90 | brew install autoconf 91 | brew install cmake 92 | brew install libtool 93 | ``` 94 | 95 | 5. Initialize rust environment 96 | 97 | ```bash 98 | source ~/.cargo/env 99 | ``` 100 | 101 | ## Windows 10 102 | 103 | 1. Download the most recent Visual Studio Community Edition [here](https://visualstudio.microsoft.com/vs/). This is currently the 2019 version. 104 | - Check the box for _Desktop development with C++_ 105 | - In the small menu on the right hand side also check the box for _C++/CLI support_ 106 | 1. Download git-scm for windows [here](https://git-scm.com/download/win) 107 | - Install git for windows using: 108 | - _Use Git from Git Bash Only_ so it doesn't change any path settings of the command prompt 109 | - _Checkout as is, commit Unix-style line endings_ 110 | - _Use MinTTY_ 111 | - Check all the boxes for: 112 | 1. Enable file system caching 113 | 1. Enable Git Credential Manager 114 | 1. Enable symbolic links 115 | 1. Download rust for windows [here](https://rustup.rs) 116 | - Choose option 1: proceed with installation (default) 117 | - Note: if you have antivirus software on your computer, you will likely have to disable it for Rust to correctly install. In addition, it is advisable to install in a terminal that is "run as an administrator." 118 | 1. Download the most recent OpenSSL for windows [here](https://slproweb.com/products/Win32OpenSSL.html) 119 | - Choose for "Copy OpenSSL DLLs to:" _The OpenSSL binaries (/bin) directory_ 120 | 1. Set the environment variables 121 | - Note that these may vary. If your Ursa build fails because it cannot find OpenSSL, check your environment variables! 122 | - Windows command prompt: 123 | `set OPENSSL_DIR "C:\Program Files\OpenSSL-Win64"` 124 | - Git Bash 125 | `export OPENSSL_DIR=/c/Program Files/OpenSSL-Win64` 126 | -------------------------------------------------------------------------------- /docs/source/community.rst: -------------------------------------------------------------------------------- 1 | ********* 2 | Community 3 | ********* 4 | 5 | Welcome to the Ursa community! 6 | 7 | For help topics, see "Joining the Discussion" linked below. 8 | 9 | .. toctree:: 10 | :maxdepth: 2 11 | 12 | community/join_the_discussion 13 | community/issue_tracking 14 | community/contributing 15 | community/code_of_conduct 16 | 17 | 18 | .. Licensed under Creative Commons Attribution 4.0 International License 19 | .. https://creativecommons.org/licenses/by/4.0/ 20 | -------------------------------------------------------------------------------- /docs/source/community/code_of_conduct.rst: -------------------------------------------------------------------------------- 1 | 2 | Code of Conduct 3 | =============== 4 | 5 | When participating, please be respectful and courteous. 6 | 7 | Hyperledger Ursa uses the `Hyperledger Project Code of Conduct 8 | `_. 9 | 10 | .. Licensed under Creative Commons Attribution 4.0 International License 11 | .. https://creativecommons.org/licenses/by/4.0/ 12 | -------------------------------------------------------------------------------- /docs/source/community/contributing.rst: -------------------------------------------------------------------------------- 1 | ------------ 2 | Contributing 3 | ------------ 4 | 5 | ========================================== 6 | Ways to Contribute to Hyperledger Ursa 7 | ========================================== 8 | 9 | Contributions from the development community help improve the capabilities of 10 | Hyperledger Ursa. These contributions are the most effective way to 11 | make a positive impact on the project. 12 | 13 | Ways you can contribute: 14 | 15 | * Bugs or issues: Report problems or defects found when working with Ursa 16 | * Core features and enhancements: Provide expanded capabilities or optimizations 17 | * Documentation: Improve existing documentation or create new information 18 | * Tests: Add functional, performance, or scalability tests 19 | 20 | Hyperledger Ursa issues can be found in :ref:`jira`. Any unassigned items 21 | are probably still open. When in doubt, ask on RocketChat about 22 | a specific JIRA issue (see :doc:`join_the_discussion`). 23 | 24 | ================== 25 | The Commit Process 26 | ================== 27 | 28 | Hyperledger Ursa is Apache 2.0 licensed and accepts contributions 29 | via `GitHub `_ 30 | pull requests. When contributing code, please follow these guidelines: 31 | 32 | * Fork the repository and make your changes in a feature branch 33 | * Include unit and integration tests for any new features and updates 34 | to existing tests 35 | * Ensure that the unit and integration tests run successfully. 36 | 37 | **Pull Request Guidelines** 38 | 39 | A pull request can contain a single commit or multiple commits. The most 40 | important guideline is that a single commit should map to a single fix or 41 | enhancement. Here are some example scenarios: 42 | 43 | * If a pull request adds a feature but also fixes two bugs, the pull 44 | request should have three commits: one commit for the feature change and 45 | two commits for the bug fixes. 46 | * If a PR is opened with five commits that contain changes to fix a single 47 | issue, the PR should be rebased to a single commit. 48 | * If a PR is opened with several commits, where the first commit fixes one issue 49 | and the rest fix a separate issue, the PR should be rebased to two 50 | commits (one for each issue). 51 | 52 | **Important:** 53 | Your pull request should be rebased against the current main branch. Do 54 | not merge the current main branch in with your topic branch. Do not use the 55 | Update Branch button provided by GitHub on the pull request page. 56 | 57 | **Commit Messages** 58 | 59 | Commit messages should follow common Git conventions, such as using the 60 | imperative mood, separate subject lines, and a line length of 72 characters. 61 | These rules are well documented in `Chris Beam's blog post 62 | `_. 63 | 64 | **Signed-off-by** 65 | 66 | Each commit must include a "Signed-off-by" line in the commit message 67 | (``git commit -s``). This sign-off indicates that you agree the commit satisfies 68 | the `Developer Certificate of Origin (DCO) `_. 69 | 70 | **Commit Email Address** 71 | 72 | Your commit email address must match your GitHub email address. For more 73 | information, see 74 | https://help.github.com/articles/setting-your-commit-email-address-in-git/ 75 | 76 | **Important GitHub Requirements** 77 | 78 | A pull request cannot merged until it has passed these status checks: 79 | 80 | * The build must pass on Jenkins 81 | * The PR must be approved by at least two maintainers without any 82 | outstanding requests for changes 83 | * Any non-black-box use of an algorithm must include a theoretical maintainer 84 | as one of the two reviewers. 85 | 86 | **Integrating GitHub Commits with JIRA** 87 | 88 | You can link JIRA issues to your commits, which will integrate 89 | developer activity with the associated issue. JIRA uses the issue key to 90 | associate the commit with the issue, so that the commit can be summarized in the 91 | development panel for the JIRA issue. 92 | 93 | When you make a commit, add the JIRA issue key to the end of the commit message 94 | or to the branch name. Either method should integrate your commit with the JIRA 95 | issue that it references. 96 | 97 | .. Licensed under Creative Commons Attribution 4.0 International License 98 | .. https://creativecommons.org/licenses/by/4.0/ 99 | -------------------------------------------------------------------------------- /docs/source/community/issue_tracking.rst: -------------------------------------------------------------------------------- 1 | *************** 2 | Tracking Issues 3 | *************** 4 | 5 | A great way to contribute is by reporting issues. Before reporting an issue, 6 | please review the current open issues to see if someone has already reported 7 | the issue. 8 | 9 | .. _jira: 10 | 11 | Using JIRA 12 | ========== 13 | 14 | Hyperledger Ursa uses JIRA as our issue tracking system: 15 | 16 | https://jira.hyperledger.org/projects/ 17 | 18 | 19 | How to Report an Issue 20 | ====================== 21 | 22 | If you believe the issue impacts the security of a production release of a 23 | Hyperledger project please use the responsible reporting mechanism found here: 24 | https://wiki.hyperledger.org/security 25 | 26 | To report all other issues, log into `jira.hyperledger.org 27 | `_, which requires a 28 | `Linux Foundation Account `_. 29 | 30 | Create issues in JIRA under the Hyperledger Ursa project. 31 | 32 | When reporting an issue, please provide as much detail as possible about how 33 | to reproduce it. If possible, explain how to reproduce the issue. 34 | Details are very helpful. Please include the following information: 35 | 36 | * OS version 37 | * Ursa version 38 | * Environment details (virtual, physical, etc.) 39 | * Steps to reproduce the issue 40 | * Actual results 41 | * Expected results 42 | 43 | If you would like, you could also describe the issue on RocketChat 44 | (see :doc:`join_the_discussion`) 45 | for initial feedback before submitting the issue in JIRA. 46 | 47 | .. Licensed under Creative Commons Attribution 4.0 International License 48 | .. https://creativecommons.org/licenses/by/4.0/ 49 | -------------------------------------------------------------------------------- /docs/source/community/join_the_discussion.rst: -------------------------------------------------------------------------------- 1 | ********************** 2 | Joining the Discussion 3 | ********************** 4 | 5 | Chat 6 | ==== 7 | 8 | Hyperledger's RocketChat server is the place to go for real-time chat about everything from quick 9 | help to involved discussions. Be mindful that chat can sometimes exclude participants who are not 10 | available at that time. Discussions with broad impact to the community should take place on the 11 | mail list. 12 | 13 | `#ursa `_ 14 | 15 | 16 | 17 | Mailing Lists 18 | ============= 19 | 20 | The Hyperledger Ursa mailing list is the preferred place for discussions about decisional matters 21 | for the project: 22 | 23 | `Hyperledger Ursa Mailing List `_ 24 | 25 | 26 | .. Licensed under Creative Commons Attribution 4.0 International License 27 | .. https://creativecommons.org/licenses/by/4.0/ 28 | -------------------------------------------------------------------------------- /docs/source/contents.rst: -------------------------------------------------------------------------------- 1 | 2 | Table of Contents 3 | ================= 4 | 5 | .. toctree:: 6 | 7 | introduction.rst 8 | community.rst 9 | 10 | Indices and tables 11 | ================== 12 | 13 | * :ref:`genindex` 14 | * :ref:`modindex` 15 | * :ref:`search` 16 | 17 | .. Licensed under Creative Commons Attribution 4.0 International License 18 | .. https://creativecommons.org/licenses/by/4.0/ 19 | 20 | 21 | -------------------------------------------------------------------------------- /docs/source/introduction.rst: -------------------------------------------------------------------------------- 1 | ************ 2 | Introduction 3 | ************ 4 | 5 | Hyperledger Ursa is a cryptography library designed to support Hyperledger 6 | projects and experimentation. This project is just getting started and should 7 | not yet be considered stable or reviewed for production uses. 8 | 9 | Ursa is an open source project under the Hyperledger umbrella. For 10 | information on how to contribute, see `Join the Ursa Community`_. 11 | 12 | 13 | Get the Ursa Software 14 | ------------------------- 15 | 16 | The Ursa software is distributed as source code with an Apache 2.0 license. 17 | 18 | `ursa `_: 19 | * libursa: 20 | Contains the main interface and wrappers for the selected libraries. 21 | 22 | * zmix: 23 | Contains interfaces for zero-knowledge proofs. 24 | 25 | 26 | Join the Ursa Community 27 | --------------------------- 28 | 29 | Ursa is an open source project under the Hyperledger umbrella. We welcome 30 | working with individuals and companies interested in advancing distributed 31 | ledger technology. Please see :doc:`/community` for ways to become a part of 32 | the Ursa community. 33 | 34 | 35 | .. Licensed under Creative Commons Attribution 4.0 International License 36 | .. https://creativecommons.org/licenses/by/4.0/ 37 | -------------------------------------------------------------------------------- /libursa/.rpm/ursa.spec: -------------------------------------------------------------------------------- 1 | %define __spec_install_post %{nil} 2 | %define __os_install_post %{_dbpath}/brp-compress 3 | %define debug_package %{nil} 4 | 5 | Name: ursa 6 | Summary: This is the shared crypto library for Hyperledger components. 7 | Version: @@VERSION@@ 8 | Release: 1 9 | License: MIT or ASL 2.0 10 | Group: Applications/System 11 | Source0: %{name}-%{version}.tar.gz 12 | 13 | BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root 14 | 15 | %description 16 | %{summary} 17 | 18 | %prep 19 | %setup -q 20 | 21 | %install 22 | rm -rf %{buildroot} 23 | mkdir -p %{buildroot} 24 | cp -a * %{buildroot} 25 | 26 | %clean 27 | rm -rf %{buildroot} 28 | 29 | %files 30 | %defattr(-,root,root,-) 31 | %{_bindir}/* 32 | -------------------------------------------------------------------------------- /libursa/benches/encryption.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate criterion; 3 | extern crate rand; 4 | extern crate ursa; 5 | 6 | use criterion::Criterion; 7 | use rand::{thread_rng, RngCore}; 8 | use ursa::encryption::symm::prelude::*; 9 | 10 | macro_rules! make_bench { 11 | ($name:ident, $algorithm:ident) => { 12 | fn $name(c: &mut Criterion) { 13 | let mut rng = thread_rng(); 14 | for msg_len in vec![128, 1024, 16384, 1048576] { 15 | let mut msg = vec![0u8; msg_len]; 16 | rng.fill_bytes(msg.as_mut_slice()); 17 | let aad = b"Encrypt/Decrypt test"; 18 | let encryptor = SymmetricEncryptor::<$algorithm>::default(); 19 | c.bench_function( 20 | format!( 21 | "Encrypt/Decrypt for {} for {} bytes", 22 | stringify!($algorithm), 23 | msg_len 24 | ) 25 | .as_str(), 26 | move |b| { 27 | b.iter(|| { 28 | let ciphertext = encryptor.encrypt_easy(&aad[..], &msg[..]).unwrap(); 29 | encryptor 30 | .decrypt_easy(&aad[..], ciphertext.as_slice()) 31 | .unwrap(); 32 | }) 33 | }, 34 | ); 35 | } 36 | } 37 | }; 38 | } 39 | 40 | make_bench!(bench_aes128_cbc_hmac256, Aes128CbcHmac256); 41 | make_bench!(bench_aes256_cbc_hmac512, Aes256CbcHmac512); 42 | make_bench!(bench_aes128_gcm, Aes128Gcm); 43 | make_bench!(bench_aes256_gcm, Aes256Gcm); 44 | make_bench!(bench_xchacha20_poly1305, XChaCha20Poly1305); 45 | 46 | criterion_group!( 47 | name = bench_encryption; 48 | config = Criterion::default(); 49 | targets = bench_aes128_cbc_hmac256, bench_aes256_cbc_hmac512, bench_aes128_gcm, bench_aes256_gcm, bench_xchacha20_poly1305 50 | ); 51 | 52 | criterion_main!(bench_encryption); 53 | -------------------------------------------------------------------------------- /libursa/bin/test_aesgcm.rs: -------------------------------------------------------------------------------- 1 | extern crate openssl; 2 | extern crate ursa; 3 | 4 | use openssl::symm::{ 5 | decrypt_aead as openssl_decrypt, encrypt_aead as openssl_encrypt, Cipher as OpenSslCipher, 6 | }; 7 | 8 | use ursa::encryption::random_vec; 9 | use ursa::encryption::symm::prelude::*; 10 | 11 | use std::io; 12 | use std::io::Write; 13 | use std::time::Instant; 14 | 15 | fn main() { 16 | let aad = b"test_aesgcm"; 17 | let msg = b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/-_"; 18 | let trials = 2000; 19 | println!( 20 | "Running 2 tests for AesCbcHmac encryption of {} messages", 21 | trials 22 | ); 23 | print!("This library Aes128Gcm - "); 24 | io::stdout().flush().unwrap(); 25 | let encryptor = SymmetricEncryptor::::default(); 26 | 27 | let mut now = Instant::now(); 28 | 29 | for _ in 0..trials { 30 | let ciphertext = encryptor.encrypt_easy(&aad[..], &msg[..]).unwrap(); 31 | encryptor.decrypt_easy(&aad[..], &ciphertext).unwrap(); 32 | } 33 | let elapsed = now.elapsed(); 34 | println!("{}.{:03}", elapsed.as_secs(), elapsed.subsec_millis()); 35 | 36 | print!("openssl based aes-128-gcm - "); 37 | io::stdout().flush().unwrap(); 38 | 39 | let key = random_vec(16).unwrap(); 40 | now = Instant::now(); 41 | for _ in 0..trials { 42 | let ciphertext = aes_128_gcm_encrypt(key.as_slice(), &aad[..], &msg[..]); 43 | aes_128_gcm_decrypt(key.as_slice(), &aad[..], ciphertext.as_slice()).unwrap(); 44 | } 45 | 46 | let elapsed = now.elapsed(); 47 | println!("{}.{:03}", elapsed.as_secs(), elapsed.subsec_millis()); 48 | 49 | print!("This library Aes256Gcm - "); 50 | io::stdout().flush().unwrap(); 51 | let encryptor = SymmetricEncryptor::::default(); 52 | 53 | let mut now = Instant::now(); 54 | 55 | for _ in 0..trials { 56 | let ciphertext = encryptor.encrypt_easy(&aad[..], &msg[..]).unwrap(); 57 | encryptor.decrypt_easy(&aad[..], &ciphertext).unwrap(); 58 | } 59 | let elapsed = now.elapsed(); 60 | println!("{}.{:03}", elapsed.as_secs(), elapsed.subsec_millis()); 61 | 62 | print!("openssl based aes-256-gcm - "); 63 | io::stdout().flush().unwrap(); 64 | 65 | let key = random_vec(32).unwrap(); 66 | now = Instant::now(); 67 | for _ in 0..trials { 68 | let ciphertext = aes_256_gcm_encrypt(key.as_slice(), &aad[..], &msg[..]); 69 | aes_256_gcm_decrypt(key.as_slice(), &aad[..], ciphertext.as_slice()).unwrap(); 70 | } 71 | 72 | let elapsed = now.elapsed(); 73 | println!("{}.{:03}", elapsed.as_secs(), elapsed.subsec_millis()); 74 | } 75 | 76 | macro_rules! aes_gcm_impl { 77 | ($encrypt:ident, $decrypt:ident, $cipherid:ident) => { 78 | fn $encrypt(key: &[u8], aad: &[u8], msg: &[u8]) -> Vec { 79 | let mut nonce = random_vec(12).unwrap(); 80 | let mut tag = vec![0u8; 16]; 81 | 82 | let ciphertext = openssl_encrypt( 83 | OpenSslCipher::$cipherid(), 84 | key, 85 | Some(nonce.as_slice()), 86 | aad, 87 | msg, 88 | tag.as_mut_slice(), 89 | ) 90 | .unwrap(); 91 | nonce.extend_from_slice(ciphertext.as_slice()); 92 | nonce.extend_from_slice(tag.as_slice()); 93 | nonce 94 | } 95 | 96 | fn $decrypt(key: &[u8], aad: &[u8], ciphertext: &[u8]) -> Result, &'static str> { 97 | if ciphertext.len() < 28 { 98 | return Err("Invalid ciphertext length"); 99 | } 100 | 101 | let nonce = Vec::from(&ciphertext[..12]); 102 | let ciphertext = Vec::from(&ciphertext[12..]); 103 | 104 | let tag_start = ciphertext.len() - 16; 105 | let plaintext = openssl_decrypt( 106 | OpenSslCipher::$cipherid(), 107 | key, 108 | Some(nonce.as_slice()), 109 | aad, 110 | &ciphertext[..tag_start], 111 | &ciphertext[tag_start..], 112 | ) 113 | .map_err(|_| "Decryption Error")?; 114 | Ok(plaintext) 115 | } 116 | }; 117 | } 118 | 119 | aes_gcm_impl!(aes_128_gcm_encrypt, aes_128_gcm_decrypt, aes_128_gcm); 120 | aes_gcm_impl!(aes_256_gcm_encrypt, aes_256_gcm_decrypt, aes_256_gcm); 121 | -------------------------------------------------------------------------------- /libursa/bin/test_ed25519.rs: -------------------------------------------------------------------------------- 1 | extern crate ursa; 2 | 3 | use ursa::signatures::prelude::*; 4 | 5 | use std::io; 6 | use std::io::Write; 7 | use std::time::Instant; 8 | 9 | fn main() { 10 | let letters = b"abcdefghijklmnopqrstuvwxyz"; 11 | let trials = 200; 12 | println!("Running test for ed25519 signing of {} messages", trials); 13 | io::stdout().flush().unwrap(); 14 | let scheme = Ed25519Sha512::new(); 15 | let (p, s) = scheme.keypair(None).unwrap(); 16 | let now = Instant::now(); 17 | 18 | for _ in 0..trials { 19 | let signature = scheme.sign(&letters[..], &s).unwrap(); 20 | scheme.verify(&letters[..], &signature, &p).unwrap(); 21 | } 22 | let elapsed = now.elapsed(); 23 | println!("{}.{:03}", elapsed.as_secs(), elapsed.subsec_millis()); 24 | } 25 | -------------------------------------------------------------------------------- /libursa/bin/test_secp256k1.rs: -------------------------------------------------------------------------------- 1 | extern crate openssl; 2 | extern crate secp256k1; 3 | extern crate ursa; 4 | 5 | use openssl::bn::{BigNum, BigNumContext}; 6 | use openssl::ec::{EcGroup, EcKey, EcPoint}; 7 | use openssl::ecdsa::EcdsaSig; 8 | use openssl::nid::Nid; 9 | use ursa::hash::sha2::{Digest, Sha256}; 10 | use ursa::signatures::secp256k1::EcdsaSecp256k1Sha256; 11 | use ursa::signatures::{EcdsaPublicKeyHandler, SignatureScheme}; 12 | 13 | use std::io; 14 | use std::io::Write; 15 | use std::time::Instant; 16 | 17 | fn main() { 18 | let letters = b"abcdefghijklmnopqrstuvwxyz"; 19 | let trials = 200; 20 | println!( 21 | "Running 3 tests for secp256k1 signing of {} messages", 22 | trials 23 | ); 24 | print!("This library - "); 25 | io::stdout().flush().unwrap(); 26 | let scheme = EcdsaSecp256k1Sha256::new(); 27 | let (p, s) = scheme.keypair(None).unwrap(); 28 | let mut now = Instant::now(); 29 | 30 | for _ in 0..trials { 31 | let signature = scheme.sign(&letters[..], &s).unwrap(); 32 | scheme.verify(&letters[..], &signature, &p).unwrap(); 33 | } 34 | let elapsed = now.elapsed(); 35 | println!("{}.{:03}", elapsed.as_secs(), elapsed.subsec_millis()); 36 | 37 | print!("C based secp256k1 - "); 38 | io::stdout().flush().unwrap(); 39 | let context = secp256k1::Secp256k1::new(); 40 | let sk = secp256k1::key::SecretKey::from_slice(&s[..]).unwrap(); 41 | let pk = secp256k1::key::PublicKey::from_slice(&p[..]).unwrap(); 42 | 43 | now = Instant::now(); 44 | for _ in 0..trials { 45 | let hash = Sha256::digest(&letters[..]); 46 | let msg = secp256k1::Message::from_slice(&hash[..]).unwrap(); 47 | let sig_1 = context.sign(&msg, &sk); 48 | context.verify(&msg, &sig_1, &pk).unwrap(); 49 | } 50 | 51 | let elapsed = now.elapsed(); 52 | println!("{}.{:03}", elapsed.as_secs(), elapsed.subsec_millis()); 53 | 54 | print!("Openssl based secp256k1 - "); 55 | io::stdout().flush().unwrap(); 56 | let openssl_group = EcGroup::from_curve_name(Nid::SECP256K1).unwrap(); 57 | let mut ctx = BigNumContext::new().unwrap(); 58 | let openssl_point = EcPoint::from_bytes( 59 | &openssl_group, 60 | &scheme.public_key_uncompressed(&p)[..], 61 | &mut ctx, 62 | ) 63 | .unwrap(); 64 | let openssl_pkey = EcKey::from_public_key(&openssl_group, &openssl_point).unwrap(); 65 | let openssl_skey = EcKey::from_private_components( 66 | &openssl_group, 67 | &BigNum::from_slice(&s[..]).unwrap(), 68 | &openssl_point, 69 | ) 70 | .unwrap(); 71 | 72 | now = Instant::now(); 73 | for _ in 0..trials { 74 | let hash = Sha256::digest(&letters[..]); 75 | let openssl_sig = EcdsaSig::sign(&hash, &openssl_skey).unwrap(); 76 | openssl_sig.verify(&hash, &openssl_pkey).unwrap(); 77 | } 78 | 79 | let elapsed = now.elapsed(); 80 | println!("{}.{:03}", elapsed.as_secs(), elapsed.subsec_millis()); 81 | } 82 | -------------------------------------------------------------------------------- /libursa/bin/test_xchacha20poly1305.rs: -------------------------------------------------------------------------------- 1 | extern crate ursa; 2 | 3 | use ursa::encryption::symm::prelude::*; 4 | 5 | use std::io; 6 | use std::io::Write; 7 | use std::time::Instant; 8 | 9 | fn main() { 10 | let aad = b"test_xchacha20poly1305"; 11 | let msg = b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/-_"; 12 | let trials = 2000; 13 | println!( 14 | "Running test for XChaCha20Poly1305 encryption of {} messages", 15 | trials 16 | ); 17 | io::stdout().flush().unwrap(); 18 | let encryptor = SymmetricEncryptor::::default(); 19 | 20 | let now = Instant::now(); 21 | 22 | for _ in 0..trials { 23 | let ciphertext = encryptor.encrypt_easy(&aad[..], &msg[..]).unwrap(); 24 | encryptor.decrypt_easy(&aad[..], &ciphertext).unwrap(); 25 | } 26 | let elapsed = now.elapsed(); 27 | println!("{}.{:03}", elapsed.as_secs(), elapsed.subsec_millis()); 28 | } 29 | -------------------------------------------------------------------------------- /libursa/cmake-build-debug/CMakeFiles/clion-log.txt: -------------------------------------------------------------------------------- 1 | CMakeLists.txt not found in /home/lovesh/dev/evernym/ursa/libursa Select CMakeLists.txt file... 2 | -------------------------------------------------------------------------------- /libursa/include/ursa_crypto.h: -------------------------------------------------------------------------------- 1 | #ifndef __ursa__crypto__included__ 2 | #define __ursa__crypto__included__ 3 | 4 | #include 5 | 6 | typedef enum { 7 | SUCCESS = 0, 8 | KEYPAIR_ERROR = 1, 9 | SIGNING_ERROR = 2, 10 | VERIFY_ERROR = 3, 11 | INVALID_PARAM1 = 4, 12 | INVALID_PARAM2 = 5, 13 | ENCRYPTION_ERROR = 6, 14 | DECRYPTION_ERROR = 7, 15 | INVALID_KEY_LENGTH = 8, 16 | INVALID_NONCE_LENGTH = 9, 17 | RANDOM_BYTES_ERROR = 10, 18 | INVALID_CIPHER = 11, 19 | } ursa_error_t; 20 | 21 | struct ByteBuffer { 22 | int64_t len; 23 | uint8_t *data; 24 | }; 25 | 26 | struct ExternError { 27 | ursa_error_t code; 28 | char* message; /* note: nullable */ 29 | }; 30 | 31 | extern void ursa_bytebuffer_free(struct ByteBuffer buffer); 32 | extern void ursa_string_free(char *s); 33 | 34 | #include "ursa_crypto_ed25519.h" 35 | #include "ursa_crypto_encryption.h" 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /libursa/include/ursa_crypto_ed25519.h: -------------------------------------------------------------------------------- 1 | #ifndef __ursa__crypto__ed25519__included__ 2 | #define __ursa__crypto__ed25519__included__ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | extern int32_t ursa_ed25519_get_public_key_size(void); 9 | extern int32_t ursa_ed25519_get_private_key_size(void); 10 | extern int32_t ursa_ed25519_get_signature_size(void); 11 | 12 | extern int32_t ursa_ed25519_keypair_new(const struct ByteBuffer* public_key, 13 | const struct ByteBuffer* private_key, 14 | const struct ExternError* err); 15 | 16 | extern int32_t ursa_ed25519_keypair_from_seed(const struct ByteBuffer* const seed, 17 | const struct ByteBuffer* public_key, 18 | const struct ByteBuffer* private_key, 19 | const struct ExternError* err); 20 | 21 | extern int32_t ursa_ed25519_get_public_key(const struct ByteBuffer* const private_key, 22 | const struct ByteBuffer* public_key, 23 | const struct ExternError* err); 24 | 25 | extern int32_t ursa_ed25519_sign(const struct ByteBuffer* const message, 26 | const struct ByteBuffer* const private_key, 27 | const struct ByteBuffer* signature, 28 | const struct ExternError* err); 29 | 30 | extern int32_t ursa_ed25519_verify(const struct ByteBuffer* const message, 31 | const struct ByteBuffer* const signature, 32 | const struct ByteBuffer* const public_key, 33 | const struct ExternError* err); 34 | #ifdef __cplusplus 35 | } 36 | #endif 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /libursa/packaging/publish_to_crates_io.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use v5.18; 4 | use Cwd qw(abs_path); 5 | use File::Basename; 6 | use File::Copy; 7 | use File::Find; 8 | use File::Path; 9 | use File::Spec; 10 | 11 | ## Figure out where the libursa folder is 12 | ## Depends on where the script is executed 13 | my ($script, $dirs, $suffix) = File::Basename::fileparse( $0 ); 14 | my $src_dir = ""; 15 | if ($dirs eq "./") { 16 | $src_dir = Cwd::getcwd(); 17 | } else { 18 | if ( $dirs =~ m/^\// ) { 19 | $src_dir = $dirs; 20 | } else { 21 | $src_dir = File::Spec->join( Cwd::getcwd(), $dirs ); 22 | } 23 | } 24 | $src_dir =~ s{(?:/|\\)$}{}; #Remove trailing path separator 25 | my @src_dirs = File::Spec->splitdir( $src_dir ); 26 | pop( @src_dirs ); 27 | $src_dir = File::Spec->join( @src_dirs ); 28 | pop( @src_dirs ); 29 | my $root_dir = File::Spec->join( @src_dirs ); 30 | my $tgt_dir = File::Spec->join( File::Spec->tmpdir(), "libursa_packaging"); 31 | 32 | if ( -d $tgt_dir ) { 33 | File::Path::remove_tree( $tgt_dir ); 34 | } 35 | 36 | File::Path::make_path($tgt_dir); 37 | 38 | my $cargo = find_cargo(); 39 | 40 | unless ( $cargo ) { 41 | die( "Unable to find 'cargo' command" ); 42 | } 43 | 44 | my @files = `$cargo package --manifest-path=$src_dir/Cargo.toml --allow-dirty --list 2>/dev/null`; 45 | 46 | foreach my $file ( @files ) { 47 | chomp($file); 48 | if ( $file =~ m/^Cargo\.lock$/o ) { 49 | next; 50 | } 51 | my $src = File::Spec->join( $src_dir, $file ); 52 | my $tgt = File::Spec->join( $tgt_dir, $file ); 53 | 54 | my ($f, $dir, $s) = File::Basename::fileparse( $tgt ); 55 | File::Path::make_path( $dir ); 56 | File::Copy::copy( $src, $tgt ); 57 | } 58 | 59 | File::Copy::copy( File::Spec->join( $root_dir, "LICENSE" ), File::Spec->join( $tgt_dir, "LICENSE" ) ); 60 | File::Copy::copy( File::Spec->join( $root_dir, "CHANGELOG" ), File::Spec->join( $tgt_dir, "CHANGELOG" ) ); 61 | File::Copy::copy( File::Spec->join( $root_dir, "README.md" ), File::Spec->join( $tgt_dir, "README.md" ) ); 62 | 63 | my $cargo_toml = File::Spec->join( $tgt_dir, "Cargo.toml" ); 64 | open( my $TOML, $cargo_toml ) or die( "Unable to read '$cargo_toml'" ); 65 | binmode( $TOML ); 66 | my @lines = <$TOML>; 67 | close( $TOML ); 68 | 69 | my $version = ""; 70 | 71 | say "Updating Cargo.toml"; 72 | open( $TOML, ">", $cargo_toml ) or die( "Unable to write '$cargo_toml'" ); 73 | binmode( $TOML ); 74 | 75 | my $skip = 0; 76 | foreach my $line ( @lines ) { 77 | chomp( $line ); 78 | if ( $line eq "[[bin]]" || $line eq "[[bench]]") { 79 | $skip = 1; 80 | } 81 | elsif ( $line =~ m/^readme/mo ) { 82 | $line =~ s{\.\./}{}o; 83 | } 84 | elsif ( $line =~ m/^ version \s* = \s* "( [^"]+ )" \s* $/mox ) { 85 | $version = $1; 86 | } 87 | elsif ( $line =~ m/default \s* = \s* /mox ) { 88 | $line =~ s/"ffi"\s*,\s*//o; 89 | } 90 | if ( $skip ) { 91 | if ( $line =~ m/^\[ ( .+ ) \]$/mox ) { 92 | if ( $1 ne "[bin]" && $1 ne "[bench]" ) { 93 | $skip = 0; 94 | } 95 | } 96 | } 97 | if ( !$skip ) { 98 | say $TOML $line; 99 | } 100 | } 101 | close( $TOML ); 102 | 103 | unless ( $version ) { 104 | die("Missing required 'version' name in $cargo_toml"); 105 | } 106 | 107 | my $res = system("$cargo publish --manifest-path=$tgt_dir/Cargo.toml --allow-dirty --dry-run"); 108 | if ( $res ) { 109 | exit(1); 110 | } 111 | my $package_dir = File::Spec->join( $tgt_dir, "target", "package", "ursa-$version" ); 112 | opendir( my $DIR, $package_dir ) or die( "Unable to find '$package_dir'" ); 113 | @files = grep( !/^\.\.?$/, readdir( $DIR ) ); 114 | close( $DIR ); 115 | 116 | say ""; 117 | say "Contents for $package_dir"; 118 | say "included in the ursa-$version.crate"; 119 | print "$/"; 120 | 121 | foreach my $file ( sort grep(! /target/, @files ) ) { 122 | say $file; 123 | } 124 | say ""; 125 | say "Does this look correct?"; 126 | say "Only 'yes' will be accepted to approve"; 127 | my $answer = <>; 128 | chomp( $answer ); 129 | unless ( $answer eq 'yes' ) { 130 | say "Exiting..."; 131 | exit(0); 132 | } 133 | 134 | system( "$cargo publish --manifest-path=$tgt_dir/Cargo.toml --allow-dirty" ); 135 | 136 | sub find_cargo { 137 | my $bin = $^O eq 'MSWin32' ? "cargo.exe" : "cargo"; 138 | foreach my $path ( split( /:/, $ENV{"PATH"} ) ) { 139 | my $cargo = File::Spec->join( $path, $bin ); 140 | if ( -f $cargo ) { 141 | return $cargo; 142 | } 143 | } 144 | return ""; 145 | } 146 | -------------------------------------------------------------------------------- /libursa/src/cl/constants.rs: -------------------------------------------------------------------------------- 1 | use crate::bn::{BigNumber, BIGNUMBER_2}; 2 | 3 | pub const LARGE_MASTER_SECRET: usize = 256; 4 | pub const LARGE_E_START: usize = 596; 5 | pub const LARGE_E_END_RANGE: usize = 119; 6 | pub const LARGE_PRIME: usize = 1024; 7 | pub const LARGE_VPRIME: usize = 2128; 8 | pub const LARGE_VPRIME_PRIME: usize = 2724; 9 | pub const LARGE_MVECT: usize = 592; 10 | pub const LARGE_ETILDE: usize = 456; 11 | pub const LARGE_VTILDE: usize = 3060; 12 | pub const LARGE_UTILDE: usize = 592; 13 | pub const LARGE_MTILDE: usize = 593; 14 | pub const LARGE_VPRIME_TILDE: usize = 673; 15 | pub const LARGE_RTILDE: usize = 672; 16 | pub const ITERATION: usize = 4; 17 | /* 18 | LARGE_M1_TILDE: now it differs from the paper v0.3, but author of the paper, 19 | Dmitry Khovratovich, suggests to use same size as LARGE_MVECT 20 | FIXME sync the paper and remove this comment 21 | */ 22 | pub const LARGE_NONCE: usize = 80; // number of bits 23 | pub const LARGE_ALPHATILDE: usize = 2787; 24 | 25 | // Constants that are used throughout the CL signatures code, so avoiding recomputation. 26 | lazy_static! { 27 | pub static ref LARGE_E_START_VALUE: BigNumber = BIGNUMBER_2 28 | .exp(&BigNumber::from_u32(LARGE_E_START).unwrap(), None) 29 | .unwrap(); 30 | pub static ref LARGE_E_END_RANGE_VALUE: BigNumber = BIGNUMBER_2 31 | .exp(&BigNumber::from_u32(LARGE_E_END_RANGE).unwrap(), None) 32 | .unwrap() 33 | .add(&LARGE_E_START_VALUE) 34 | .unwrap(); 35 | pub static ref LARGE_VPRIME_PRIME_VALUE: BigNumber = BIGNUMBER_2 36 | .exp(&BigNumber::from_u32(LARGE_VPRIME_PRIME - 1).unwrap(), None) 37 | .unwrap(); 38 | } 39 | -------------------------------------------------------------------------------- /libursa/src/cl/datastructures.rs: -------------------------------------------------------------------------------- 1 | macro_rules! hashset { 2 | ( $( $x:expr ),* ) => { 3 | { 4 | let mut set = ::std::collections::HashSet::new(); 5 | $( 6 | set.insert($x); 7 | )* 8 | set 9 | } 10 | } 11 | } 12 | 13 | macro_rules! hashmap { 14 | ($( $key: expr => $val: expr ),*) => { 15 | { 16 | let mut map = ::std::collections::HashMap::new(); 17 | $( 18 | map.insert($key, $val); 19 | )* 20 | map 21 | } 22 | } 23 | } 24 | 25 | macro_rules! btreeset { 26 | ( $( $x:expr ),* ) => { 27 | { 28 | let mut set = ::std::collections::BTreeSet::new(); 29 | $( 30 | set.insert($x); 31 | )* 32 | set 33 | } 34 | } 35 | } 36 | 37 | macro_rules! btreemap { 38 | ($( $key: expr => $val: expr ),*) => { 39 | { 40 | let mut map = ::std::collections::BTreeMap::new(); 41 | $( 42 | map.insert($key, $val); 43 | )* 44 | map 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /libursa/src/cl/hash.rs: -------------------------------------------------------------------------------- 1 | use crate::bn::BigNumber; 2 | use crate::errors::prelude::*; 3 | 4 | pub fn get_hash_as_int(nums: &[Vec]) -> UrsaCryptoResult { 5 | trace!("Helpers::get_hash_as_int: >>> nums: {:?}", nums); 6 | 7 | let hash = BigNumber::from_bytes(&BigNumber::hash_array(nums)?); 8 | 9 | trace!("Helpers::get_hash_as_int: <<< hash: {:?}", hash); 10 | 11 | hash 12 | } 13 | 14 | #[cfg(test)] 15 | mod tests { 16 | use super::*; 17 | 18 | #[test] 19 | fn get_hash_as_int_works() { 20 | let nums = vec![ 21 | BigNumber::from_hex("ff9d2eedfee9cffd9ef6dbffedff3fcbef4caecb9bffe79bfa94d3fdf6abfbff") 22 | .unwrap() 23 | .to_bytes() 24 | .unwrap(), 25 | BigNumber::from_hex("ff9d2eedfee9cffd9ef6dbffedff3fcbef4caecb9bffe79bfa9168615ccbc546") 26 | .unwrap() 27 | .to_bytes() 28 | .unwrap(), 29 | ]; 30 | let res = get_hash_as_int(&nums); 31 | 32 | assert!(res.is_ok()); 33 | assert_eq!( 34 | "2C2566C22E04AB3F18B3BA693823175002F10F400811363D26BBB33633AC8BAD", 35 | res.unwrap().to_hex().unwrap() 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /libursa/src/encryption/mod.rs: -------------------------------------------------------------------------------- 1 | //! Encryption is categorized as public key encryption or symmetric encryption 2 | //! `symm` provides symmetric AEAD cryptographic algorithms. 3 | use aead::generic_array::{ArrayLength, GenericArray}; 4 | use aead::Error; 5 | use rand::{rngs::OsRng, RngCore}; 6 | 7 | pub mod symm; 8 | 9 | // Helpful for generating bytes using the operating system random number generator 10 | pub fn random_vec(bytes: usize) -> Result, Error> { 11 | let mut value = vec![0u8; bytes]; 12 | OsRng.fill_bytes(value.as_mut_slice()); 13 | Ok(value) 14 | } 15 | 16 | pub fn random_bytes>() -> Result, Error> { 17 | Ok(GenericArray::clone_from_slice( 18 | random_vec(T::to_usize())?.as_slice(), 19 | )) 20 | } 21 | -------------------------------------------------------------------------------- /libursa/src/encryption/symm/aescbc.rs: -------------------------------------------------------------------------------- 1 | use super::Encryptor; 2 | use aead::{ 3 | generic_array::{ 4 | typenum::{Unsigned, U0, U16, U32, U48, U64}, 5 | GenericArray, 6 | }, 7 | Aead, Error, NewAead, Payload, 8 | }; 9 | use aes::{Aes128, Aes256}; 10 | use block_modes::block_padding::Pkcs7; 11 | use block_modes::{BlockMode, Cbc}; 12 | use hmac::{Hmac, Mac}; 13 | #[cfg(feature = "serde")] 14 | use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer}; 15 | use sha2::{Sha256, Sha512}; 16 | use subtle::ConstantTimeEq; 17 | use zeroize::Zeroize; 18 | 19 | type Aes128Cbc = Cbc; 20 | type Aes256Cbc = Cbc; 21 | type HmacSha256 = Hmac; 22 | type HmacSha512 = Hmac; 23 | 24 | macro_rules! aes_cbc_hmac_impl { 25 | ($name:ident, $algokeysize:ident, $keysize:ident, $noncesize:ident, $tagsize:ident, $algo:ident, $hash:ident, $visitor:ident) => { 26 | #[derive(Debug, Clone, Eq, PartialEq)] 27 | pub struct $name { 28 | key: GenericArray, 29 | } 30 | 31 | impl Encryptor for $name { 32 | type MinSize = U48; 33 | } 34 | 35 | impl NewAead for $name { 36 | type KeySize = $keysize; 37 | 38 | fn new(key: &GenericArray) -> Self { 39 | Self { key: *key } 40 | } 41 | } 42 | 43 | impl Aead for $name { 44 | type NonceSize = $noncesize; 45 | type TagSize = $tagsize; 46 | type CiphertextOverhead = U0; 47 | 48 | fn encrypt<'msg, 'aad>( 49 | &self, 50 | nonce: &GenericArray, 51 | plaintext: impl Into>, 52 | ) -> Result, Error> { 53 | let payload = plaintext.into(); 54 | let encryptor = 55 | $algo::new_var(&self.key[..$algokeysize::to_usize()], &nonce.as_slice()) 56 | .map_err(|_| Error)?; 57 | let mut ciphertext = encryptor.encrypt_vec(payload.msg); 58 | let mut hmac = $hash::new_from_slice(&self.key[$algokeysize::to_usize()..]) 59 | .map_err(|_| Error)?; 60 | hmac.update(payload.aad); 61 | hmac.update(nonce.as_slice()); 62 | hmac.update(ciphertext.as_slice()); 63 | let hash = hmac.finalize().into_bytes(); 64 | ciphertext.extend_from_slice(hash.as_slice()); 65 | Ok(ciphertext) 66 | } 67 | 68 | fn decrypt<'msg, 'aad>( 69 | &self, 70 | nonce: &GenericArray, 71 | ciphertext: impl Into>, 72 | ) -> Result, Error> { 73 | let payload = ciphertext.into(); 74 | 75 | if payload.msg.len() < Self::TagSize::to_usize() + $algokeysize::to_usize() { 76 | return Err(Error); 77 | } 78 | 79 | let tag_start = payload.msg.len() - Self::TagSize::to_usize(); 80 | let buffer = Vec::from(&payload.msg[..tag_start]); 81 | let tag = Vec::from(&payload.msg[tag_start..]); 82 | 83 | let mut hmac = $hash::new_from_slice(&self.key[$algokeysize::to_usize()..]) 84 | .map_err(|_| Error)?; 85 | hmac.update(payload.aad); 86 | hmac.update(nonce.as_slice()); 87 | hmac.update(buffer.as_slice()); 88 | let expected_tag = hmac.finalize().into_bytes(); 89 | 90 | if expected_tag.ct_eq(&tag).unwrap_u8() == 1 { 91 | let decryptor = 92 | $algo::new_var(&self.key[..$algokeysize::to_usize()], &nonce.as_slice()) 93 | .map_err(|_| Error)?; 94 | let plaintext = decryptor 95 | .decrypt_vec(buffer.as_slice()) 96 | .map_err(|_| Error)?; 97 | Ok(plaintext) 98 | } else { 99 | Err(Error) 100 | } 101 | } 102 | } 103 | 104 | default_impl!($name); 105 | drop_impl!($name); 106 | #[cfg(feature = "serde")] 107 | serialize_impl!($name, $visitor); 108 | }; 109 | } 110 | 111 | aes_cbc_hmac_impl!( 112 | Aes128CbcHmac256, 113 | U16, 114 | U32, 115 | U16, 116 | U32, 117 | Aes128Cbc, 118 | HmacSha256, 119 | Aes128CbcHmac256Visitor 120 | ); 121 | aes_cbc_hmac_impl!( 122 | Aes256CbcHmac512, 123 | U32, 124 | U64, 125 | U16, 126 | U64, 127 | Aes256Cbc, 128 | HmacSha512, 129 | Aes256CbcHmac512Visitor 130 | ); 131 | 132 | #[cfg(test)] 133 | mod aes128_cbc_hmac256_tests { 134 | tests_impl!(Aes128CbcHmac256); 135 | } 136 | 137 | #[cfg(test)] 138 | mod aes256_cbc_hmac512_tests { 139 | tests_impl!(Aes256CbcHmac512); 140 | } 141 | -------------------------------------------------------------------------------- /libursa/src/encryption/symm/aesgcm.rs: -------------------------------------------------------------------------------- 1 | use super::Encryptor; 2 | use aead::{ 3 | generic_array::{ 4 | typenum::{Unsigned, U0, U12, U16, U32}, 5 | GenericArray, 6 | }, 7 | Aead, Error, NewAead, Payload, 8 | }; 9 | use aes_gcm::{Aes128Gcm as SysAes128Gcm, Aes256Gcm as SysAes256Gcm}; 10 | #[cfg(feature = "serde")] 11 | use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer}; 12 | use zeroize::Zeroize; 13 | 14 | macro_rules! aes_gcm_impl { 15 | ($name:ident, $algoname:ident, $keysize:ident, $visitor:ident) => { 16 | #[derive(Debug, Clone, Eq, PartialEq)] 17 | pub struct $name { 18 | key: GenericArray, 19 | } 20 | 21 | impl Encryptor for $name { 22 | type MinSize = U32; 23 | } 24 | 25 | impl NewAead for $name { 26 | type KeySize = $keysize; 27 | 28 | fn new(key: &GenericArray) -> Self { 29 | Self { key: *key } 30 | } 31 | } 32 | 33 | impl Aead for $name { 34 | type NonceSize = U12; 35 | type TagSize = U16; 36 | type CiphertextOverhead = U0; 37 | 38 | fn encrypt<'msg, 'aad>( 39 | &self, 40 | nonce: &GenericArray, 41 | plaintext: impl Into>, 42 | ) -> Result, Error> { 43 | let payload = plaintext.into(); 44 | let aes = $algoname::new(&self.key); 45 | aes.encrypt(nonce, payload) 46 | } 47 | 48 | fn decrypt<'msg, 'aad>( 49 | &self, 50 | nonce: &GenericArray, 51 | ciphertext: impl Into>, 52 | ) -> Result, Error> { 53 | let payload = ciphertext.into(); 54 | 55 | if payload.msg.len() < Self::TagSize::to_usize() + Self::NonceSize::to_usize() { 56 | return Err(Error); 57 | } 58 | 59 | let aes = $algoname::new(&self.key); 60 | aes.decrypt(nonce, payload) 61 | } 62 | } 63 | 64 | default_impl!($name); 65 | drop_impl!($name); 66 | #[cfg(feature = "serde")] 67 | serialize_impl!($name, $visitor); 68 | }; 69 | } 70 | 71 | aes_gcm_impl!(Aes128Gcm, SysAes128Gcm, U16, Aes128GcmVisitor); 72 | aes_gcm_impl!(Aes256Gcm, SysAes256Gcm, U32, Aes256GcmVisitor); 73 | 74 | #[cfg(test)] 75 | mod aes128_gcm_tests { 76 | tests_impl!(Aes128Gcm); 77 | } 78 | 79 | #[cfg(test)] 80 | mod aes256_gcm_tests { 81 | tests_impl!(Aes256Gcm); 82 | } 83 | -------------------------------------------------------------------------------- /libursa/src/encryption/symm/aesgcm_asm.rs: -------------------------------------------------------------------------------- 1 | use super::Encryptor; 2 | use aead::{ 3 | generic_array::{ 4 | typenum::{Unsigned, U0, U12, U16, U32}, 5 | GenericArray, 6 | }, 7 | Aead, Error, NewAead, Payload, 8 | }; 9 | use openssl::symm::{ 10 | decrypt_aead as openssl_decrypt, encrypt_aead as openssl_encrypt, Cipher as OpenSslCipher, 11 | }; 12 | #[cfg(feature = "serde")] 13 | use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer}; 14 | use zeroize::Zeroize; 15 | 16 | macro_rules! aes_gcm_impl { 17 | ($name:ident, $cipherid:ident, $keysize:ident, $visitor:ident) => { 18 | #[derive(Debug, Clone, Eq, PartialEq)] 19 | pub struct $name { 20 | key: GenericArray, 21 | } 22 | 23 | impl Encryptor for $name { 24 | type MinSize = U32; 25 | } 26 | 27 | impl NewAead for $name { 28 | type KeySize = $keysize; 29 | 30 | fn new(key: &GenericArray) -> Self { 31 | Self { key: *key } 32 | } 33 | } 34 | 35 | impl Aead for $name { 36 | type NonceSize = U12; 37 | type TagSize = U16; 38 | type CiphertextOverhead = U0; 39 | 40 | fn encrypt<'msg, 'aad>( 41 | &self, 42 | nonce: &GenericArray, 43 | plaintext: impl Into>, 44 | ) -> Result, Error> { 45 | let payload = plaintext.into(); 46 | let mut tag = vec![0u8; Self::TagSize::to_usize()]; 47 | 48 | let mut ciphertext = openssl_encrypt( 49 | OpenSslCipher::$cipherid(), 50 | self.key.as_slice(), 51 | Some(nonce.as_slice()), 52 | payload.aad, 53 | payload.msg, 54 | tag.as_mut_slice(), 55 | ) 56 | .map_err(|_| Error)?; 57 | ciphertext.extend_from_slice(tag.as_slice()); 58 | Ok(ciphertext) 59 | } 60 | 61 | fn decrypt<'msg, 'aad>( 62 | &self, 63 | nonce: &GenericArray, 64 | ciphertext: impl Into>, 65 | ) -> Result, Error> { 66 | let payload = ciphertext.into(); 67 | 68 | if payload.msg.len() < Self::TagSize::to_usize() + Self::NonceSize::to_usize() { 69 | return Err(Error); 70 | } 71 | 72 | let tag_start = payload.msg.len() - Self::TagSize::to_usize(); 73 | let plaintext = openssl_decrypt( 74 | OpenSslCipher::$cipherid(), 75 | self.key.as_slice(), 76 | Some(nonce.as_slice()), 77 | payload.aad, 78 | &payload.msg[..tag_start], 79 | &payload.msg[tag_start..], 80 | ) 81 | .map_err(|_| Error)?; 82 | Ok(plaintext) 83 | } 84 | } 85 | 86 | default_impl!($name); 87 | drop_impl!($name); 88 | #[cfg(feature = "serde")] 89 | serialize_impl!($name, $visitor); 90 | }; 91 | } 92 | 93 | aes_gcm_impl!(Aes128Gcm, aes_128_gcm, U16, Aes128GcmVisitor); 94 | aes_gcm_impl!(Aes256Gcm, aes_256_gcm, U32, Aes256GcmVisitor); 95 | 96 | #[cfg(test)] 97 | mod aes128_gcm_tests { 98 | tests_impl!(Aes128Gcm); 99 | } 100 | 101 | #[cfg(test)] 102 | mod aes256_gcm_tests { 103 | tests_impl!(Aes256Gcm); 104 | } 105 | -------------------------------------------------------------------------------- /libursa/src/encryption/symm/chacha20poly1305.rs: -------------------------------------------------------------------------------- 1 | use super::Encryptor; 2 | use aead::{ 3 | generic_array::{ 4 | typenum::{U0, U12, U16, U32, U36}, 5 | GenericArray, 6 | }, 7 | Aead, Error, NewAead, Payload, 8 | }; 9 | use rustchacha20poly1305::ChaCha20Poly1305 as SysChaCha20Poly1305; 10 | #[cfg(feature = "serde")] 11 | use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer}; 12 | use zeroize::Zeroize; 13 | 14 | #[derive(Debug, Clone, Eq, PartialEq)] 15 | pub struct ChaCha20Poly1305 { 16 | key: GenericArray, 17 | } 18 | 19 | impl Encryptor for ChaCha20Poly1305 { 20 | type MinSize = U36; 21 | } 22 | 23 | impl NewAead for ChaCha20Poly1305 { 24 | type KeySize = U32; 25 | 26 | fn new(key: &GenericArray) -> Self { 27 | Self { key: *key } 28 | } 29 | } 30 | 31 | impl Aead for ChaCha20Poly1305 { 32 | type NonceSize = U12; 33 | type TagSize = U16; 34 | type CiphertextOverhead = U0; 35 | 36 | fn encrypt<'msg, 'aad>( 37 | &self, 38 | nonce: &GenericArray, 39 | plaintext: impl Into>, 40 | ) -> Result, Error> { 41 | let aead = SysChaCha20Poly1305::new(&self.key); 42 | let ciphertext = aead.encrypt(nonce, plaintext)?; 43 | Ok(ciphertext) 44 | } 45 | 46 | fn decrypt<'msg, 'aad>( 47 | &self, 48 | nonce: &GenericArray, 49 | ciphertext: impl Into>, 50 | ) -> Result, Error> { 51 | let aead = SysChaCha20Poly1305::new(&self.key); 52 | let plaintext = aead.decrypt(nonce, ciphertext)?; 53 | Ok(plaintext) 54 | } 55 | } 56 | 57 | default_impl!(ChaCha20Poly1305); 58 | drop_impl!(ChaCha20Poly1305); 59 | #[cfg(feature = "serde")] 60 | serialize_impl!(ChaCha20Poly1305, ChaCha20Poly1305Visitor); 61 | 62 | #[cfg(test)] 63 | mod tests { 64 | tests_impl!(ChaCha20Poly1305); 65 | } 66 | -------------------------------------------------------------------------------- /libursa/src/encryption/symm/xchacha20poly1305.rs: -------------------------------------------------------------------------------- 1 | use super::Encryptor; 2 | use aead::{ 3 | generic_array::{ 4 | typenum::{U0, U16, U24, U32, U48}, 5 | GenericArray, 6 | }, 7 | Aead, Error, NewAead, Payload, 8 | }; 9 | use rustchacha20poly1305::XChaCha20Poly1305 as SysXChaCha20Poly1305; 10 | #[cfg(feature = "serde")] 11 | use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer}; 12 | use zeroize::Zeroize; 13 | 14 | #[derive(Debug, Clone, Eq, PartialEq)] 15 | pub struct XChaCha20Poly1305 { 16 | key: GenericArray, 17 | } 18 | 19 | impl Encryptor for XChaCha20Poly1305 { 20 | type MinSize = U48; 21 | } 22 | 23 | impl NewAead for XChaCha20Poly1305 { 24 | type KeySize = U32; 25 | 26 | fn new(key: &GenericArray) -> Self { 27 | Self { key: *key } 28 | } 29 | } 30 | 31 | impl Aead for XChaCha20Poly1305 { 32 | type NonceSize = U24; 33 | type TagSize = U16; 34 | type CiphertextOverhead = U0; 35 | 36 | fn encrypt<'msg, 'aad>( 37 | &self, 38 | nonce: &GenericArray, 39 | plaintext: impl Into>, 40 | ) -> Result, Error> { 41 | let aead = SysXChaCha20Poly1305::new(&self.key); 42 | let ciphertext = aead.encrypt(nonce, plaintext)?; 43 | Ok(ciphertext) 44 | } 45 | 46 | fn decrypt<'msg, 'aad>( 47 | &self, 48 | nonce: &GenericArray, 49 | ciphertext: impl Into>, 50 | ) -> Result, Error> { 51 | let aead = SysXChaCha20Poly1305::new(&self.key); 52 | let plaintext = aead.decrypt(nonce, ciphertext)?; 53 | Ok(plaintext) 54 | } 55 | } 56 | 57 | default_impl!(XChaCha20Poly1305); 58 | drop_impl!(XChaCha20Poly1305); 59 | #[cfg(feature = "serde")] 60 | serialize_impl!(XChaCha20Poly1305, XChaCha20Poly1305Visitor); 61 | 62 | #[cfg(test)] 63 | mod tests { 64 | tests_impl!(XChaCha20Poly1305); 65 | } 66 | -------------------------------------------------------------------------------- /libursa/src/ffi/logger.rs: -------------------------------------------------------------------------------- 1 | use std::os::raw::{c_char, c_void}; 2 | 3 | use crate::errors::prelude::*; 4 | use crate::ffi::ErrorCode; 5 | 6 | extern crate log; 7 | 8 | use crate::utils::ctypes::*; 9 | use crate::utils::logger::{EnabledCB, FlushCB, HLCryptoDefaultLogger, HLCryptoLogger, LogCB}; 10 | 11 | /// Set custom logger implementation. 12 | /// 13 | /// Allows library user to provide custom logger implementation as set of handlers. 14 | /// 15 | /// #Params 16 | /// context: pointer to some logger context that will be available in logger handlers. 17 | /// enabled: (optional) "enabled" operation handler - calls to determines if a log record would be logged. (false positive if not specified) 18 | /// log: "log" operation handler - calls to logs a record. 19 | /// flush: (optional) "flush" operation handler - calls to flushes buffered records (in case of crash or signal). 20 | /// 21 | /// #Returns 22 | /// Error code 23 | #[no_mangle] 24 | pub extern "C" fn ursa_set_logger( 25 | context: *const c_void, 26 | enabled: Option, 27 | log: Option, 28 | flush: Option, 29 | ) -> ErrorCode { 30 | trace!( 31 | "ursa_set_logger >>> context: {:?}, enabled: {:?}, log: {:?}, flush: {:?}", 32 | context, 33 | log, 34 | enabled, 35 | flush 36 | ); 37 | 38 | check_useful_c_callback!(log, ErrorCode::CommonInvalidParam3); 39 | 40 | let res = match HLCryptoLogger::init(context, enabled, log, flush) { 41 | Ok(()) => ErrorCode::Success, 42 | Err(err) => err.into(), 43 | }; 44 | 45 | trace!("ursa_set_logger: <<< res: {:?}", res); 46 | 47 | res 48 | } 49 | 50 | /// Set default logger implementation. 51 | /// 52 | /// Allows library user use `env_logger` logger as default implementation. 53 | /// More details about `env_logger` and its customization can be found [here](https://crates.io/crates/env_logger) 54 | /// 55 | /// #Params 56 | /// pattern: (optional) pattern that corresponds with the log messages to show. 57 | /// 58 | /// NOTE: You should specify either `pattern` parameter or `RUST_LOG` environment variable to init logger. 59 | /// 60 | /// #Returns 61 | /// Error code 62 | #[no_mangle] 63 | pub extern "C" fn ursa_set_default_logger(pattern: *const c_char) -> ErrorCode { 64 | trace!("ursa_set_default_logger >>> pattern: {:?}", pattern); 65 | 66 | check_useful_opt_c_str!(pattern, ErrorCode::CommonInvalidParam1); 67 | 68 | trace!( 69 | "ursa_set_default_logger: entities >>> pattern: {:?}", 70 | pattern 71 | ); 72 | 73 | let res = match HLCryptoDefaultLogger::init(pattern) { 74 | Ok(()) => ErrorCode::Success, 75 | Err(err) => err.into(), 76 | }; 77 | 78 | trace!("ursa_set_default_logger: <<< res: {:?}", res); 79 | 80 | res 81 | } 82 | -------------------------------------------------------------------------------- /libursa/src/ffi/signatures/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod ed25519; 2 | -------------------------------------------------------------------------------- /libursa/src/hash/blake2.rs: -------------------------------------------------------------------------------- 1 | #[cfg(target_pointer_width = "64")] 2 | pub use crate::blake2::Blake2b as Blake2; 3 | #[cfg(target_pointer_width = "32")] 4 | pub use crate::blake2::Blake2s as Blake2; 5 | -------------------------------------------------------------------------------- /libursa/src/hash/mod.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "sha2")] 2 | pub use sha2; 3 | #[cfg(feature = "sha3")] 4 | pub use sha3; 5 | 6 | #[cfg(feature = "sha2")] 7 | pub use sha2::Digest; 8 | 9 | #[cfg(feature = "blake2")] 10 | pub mod blake2; 11 | -------------------------------------------------------------------------------- /libursa/src/kex/mod.rs: -------------------------------------------------------------------------------- 1 | //! A suite of Diffie-Hellman key exchange methods. 2 | 3 | use crate::keys::{KeyGenOption, PrivateKey, PublicKey, SessionKey}; 4 | use crate::CryptoError; 5 | 6 | /// A Generic trait for key exchange schemes. Each scheme provides a way to generate keys and 7 | /// do a diffie-hellman computation 8 | pub trait KeyExchangeScheme { 9 | /// Generate a new instance of the scheme 10 | fn new() -> Self; 11 | /// Create new keypairs. If 12 | /// `options` is None, the keys are generated ephemerally from the `OsRng` 13 | /// `options` is UseSeed, the keys are generated ephemerally from the sha256 hash of the seed which is 14 | /// then used to seed the ChaChaRng 15 | /// `options` is FromPrivateKey, the corresponding public key is returned. This should be used for 16 | /// static Diffie-Hellman and loading a long-term key. 17 | fn keypair( 18 | &self, 19 | options: Option, 20 | ) -> Result<(PublicKey, PrivateKey), CryptoError>; 21 | /// Compute the diffie-hellman shared secret. 22 | /// `local_private_key` is the key generated from calling `keypair` while 23 | /// `remote_public_key` is the key received from a different call to `keypair` from another party. 24 | fn compute_shared_secret( 25 | &self, 26 | local_private_key: &PrivateKey, 27 | remote_public_key: &PublicKey, 28 | ) -> Result; 29 | 30 | fn shared_secret_size() -> usize; 31 | fn public_key_size() -> usize; 32 | fn private_key_size() -> usize; 33 | } 34 | 35 | #[cfg(any(feature = "x25519", feature = "x25519_asm"))] 36 | pub mod x25519; 37 | 38 | #[cfg(any( 39 | feature = "ecdh_secp256k1", 40 | feature = "ecdh_secp256k1_native", 41 | feature = "ecdh_secp256k1_asm" 42 | ))] 43 | pub mod secp256k1; 44 | -------------------------------------------------------------------------------- /libursa/src/kex/x25519.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use rand::rngs::OsRng; 3 | use rand::SeedableRng; 4 | use rand_chacha::ChaChaRng; 5 | use sha2::Digest; 6 | use x25519_dalek::{PublicKey as X25519PublicKey, StaticSecret}; 7 | use zeroize::Zeroize; 8 | 9 | use crate::CryptoError; 10 | 11 | pub struct X25519Sha256; 12 | 13 | impl KeyExchangeScheme for X25519Sha256 { 14 | fn new() -> Self { 15 | Self 16 | } 17 | 18 | fn keypair( 19 | &self, 20 | option: Option, 21 | ) -> Result<(PublicKey, PrivateKey), CryptoError> { 22 | let (pk, sk) = match option { 23 | Some(mut o) => match o { 24 | KeyGenOption::UseSeed(ref mut s) => { 25 | let hash = sha2::Sha256::digest(s.as_slice()); 26 | s.zeroize(); 27 | let mut rng = ChaChaRng::from_seed(*array_ref!(hash.as_slice(), 0, 32)); 28 | let sk = StaticSecret::new(&mut rng); 29 | let pk = X25519PublicKey::from(&sk); 30 | (pk, sk) 31 | } 32 | KeyGenOption::FromSecretKey(ref s) => { 33 | let sk = StaticSecret::from(*array_ref!(&s[..], 0, 32)); 34 | let pk = X25519PublicKey::from(&sk); 35 | (pk, sk) 36 | } 37 | }, 38 | None => { 39 | let mut rng = OsRng::default(); 40 | let sk = StaticSecret::new(&mut rng); 41 | let pk = X25519PublicKey::from(&sk); 42 | (pk, sk) 43 | } 44 | }; 45 | Ok(( 46 | PublicKey(pk.as_bytes().to_vec()), 47 | PrivateKey(sk.to_bytes().to_vec()), 48 | )) 49 | } 50 | 51 | fn compute_shared_secret( 52 | &self, 53 | local_private_key: &PrivateKey, 54 | remote_public_key: &PublicKey, 55 | ) -> Result { 56 | let sk = StaticSecret::from(*array_ref!(&local_private_key[..], 0, 32)); 57 | let pk = X25519PublicKey::from(*array_ref!(&remote_public_key[..], 0, 32)); 58 | let shared_secret = sk.diffie_hellman(&pk); 59 | let hash = sha2::Sha256::digest(shared_secret.as_bytes()); 60 | Ok(SessionKey(hash.as_slice().to_vec())) 61 | } 62 | 63 | fn public_key_size() -> usize { 64 | 32 65 | } 66 | fn private_key_size() -> usize { 67 | 32 68 | } 69 | fn shared_secret_size() -> usize { 70 | 32 71 | } 72 | } 73 | 74 | #[cfg(test)] 75 | mod tests { 76 | use super::*; 77 | 78 | #[cfg(any(feature = "ed25519", feature = "ed25519_asm"))] 79 | #[test] 80 | fn convert_from_sig_keys() { 81 | use crate::signatures::{ed25519::Ed25519Sha512, SignatureScheme}; 82 | let sig_scheme = Ed25519Sha512::new(); 83 | let (pk, sk) = sig_scheme.keypair(None).unwrap(); 84 | let res = Ed25519Sha512::ver_key_to_key_exchange(&pk); 85 | assert!(res.is_ok()); 86 | let pk1 = res.unwrap(); 87 | let kex_scheme = X25519Sha256::new(); 88 | let res = kex_scheme.compute_shared_secret(&sk, &pk1); 89 | assert!(res.is_ok()); 90 | } 91 | 92 | #[test] 93 | fn key_exchange() { 94 | let scheme = X25519Sha256::new(); 95 | let res = scheme.keypair(None); 96 | assert!(res.is_ok()); 97 | let (pk, sk) = res.unwrap(); 98 | let res = scheme.compute_shared_secret(&sk, &pk); 99 | assert!(res.is_ok()); 100 | let res = scheme.keypair(None); 101 | assert!(res.is_ok()); 102 | let (pk1, sk1) = res.unwrap(); 103 | let res = scheme.compute_shared_secret(&sk1, &pk); 104 | assert!(res.is_ok()); 105 | let res = scheme.compute_shared_secret(&sk, &pk1); 106 | assert!(res.is_ok()); 107 | 108 | let res = scheme.keypair(Some(KeyGenOption::FromSecretKey(sk.clone()))); 109 | assert!(res.is_ok()); 110 | let (pk1, sk1) = res.unwrap(); 111 | assert_eq!(pk1, pk); 112 | assert_eq!(sk1, sk); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /libursa/src/keys.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "serde")] 2 | use serde::{Deserialize, Serialize}; 3 | use std::ops::Drop; 4 | use zeroize::Zeroize; 5 | 6 | // A private key instance. 7 | /// The underlying content is dependent on implementation. 8 | pub struct PrivateKey(pub Vec); 9 | impl_bytearray!(PrivateKey); 10 | 11 | pub struct PublicKey(pub Vec); 12 | impl_bytearray!(PublicKey); 13 | 14 | pub struct SessionKey(pub Vec); 15 | impl_bytearray!(SessionKey); 16 | 17 | pub struct MacKey(pub Vec); 18 | impl_bytearray!(MacKey); 19 | 20 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 21 | #[derive(Debug, PartialEq, Eq)] 22 | pub enum KeyGenOption { 23 | UseSeed(Vec), 24 | FromSecretKey(PrivateKey), 25 | } 26 | 27 | impl Drop for KeyGenOption { 28 | fn drop(&mut self) { 29 | match self { 30 | KeyGenOption::UseSeed(ref mut v) => v.zeroize(), 31 | KeyGenOption::FromSecretKey(ref mut s) => s.zeroize(), 32 | } 33 | } 34 | } 35 | 36 | #[cfg(feature = "serde")] 37 | #[test] 38 | fn serialize_tests() { 39 | let t = vec![1u8, 1u8, 2u8, 2u8, 3u8, 3u8, 4u8, 4u8]; 40 | let e = KeyGenOption::UseSeed(t[..].to_vec()); 41 | let s = serde_json::to_string(&e).unwrap(); 42 | assert_eq!(r#"{"UseSeed":[1,1,2,2,3,3,4,4]}"#, s); 43 | let f: KeyGenOption = serde_json::from_str(&s).unwrap(); 44 | assert_eq!(KeyGenOption::UseSeed(t), f); 45 | let sk = PrivateKey(vec![1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 2u8]); 46 | let e = KeyGenOption::FromSecretKey(sk); 47 | assert_eq!( 48 | r#"{"FromSecretKey":"01010101010102"}"#, 49 | serde_json::to_string(&e).unwrap() 50 | ); 51 | } 52 | -------------------------------------------------------------------------------- /libursa/src/sharing/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod shamir; 2 | -------------------------------------------------------------------------------- /libursa/src/signatures/mod.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "bls_bls12381")] 2 | pub mod bls; 3 | #[cfg(any(feature = "ed25519", feature = "ed25519_asm"))] 4 | pub mod ed25519; 5 | #[cfg(any( 6 | feature = "ecdsa_secp256k1", 7 | feature = "ecdsa_secp256k1_native", 8 | feature = "ecdsa_secp256k1_asm" 9 | ))] 10 | pub mod secp256k1; 11 | 12 | pub mod prelude { 13 | #[cfg(any(feature = "ed25519", feature = "ed25519_asm"))] 14 | pub use super::ed25519::Ed25519Sha512; 15 | #[cfg(any( 16 | feature = "ecdsa_secp256k1", 17 | feature = "ecdsa_secp256k1_native", 18 | feature = "ecdsa_secp256k1_asm" 19 | ))] 20 | pub use super::{secp256k1::EcdsaSecp256k1Sha256, EcdsaPublicKeyHandler}; 21 | pub use super::{SignatureScheme, Signer}; 22 | } 23 | 24 | use crate::keys::{KeyGenOption, PrivateKey, PublicKey}; 25 | use crate::CryptoError; 26 | 27 | pub trait SignatureScheme { 28 | fn new() -> Self; 29 | fn keypair( 30 | &self, 31 | options: Option, 32 | ) -> Result<(PublicKey, PrivateKey), CryptoError>; 33 | fn sign(&self, message: &[u8], sk: &PrivateKey) -> Result, CryptoError>; 34 | fn verify(&self, message: &[u8], signature: &[u8], pk: &PublicKey) 35 | -> Result; 36 | fn signature_size() -> usize; 37 | fn private_key_size() -> usize; 38 | fn public_key_size() -> usize; 39 | } 40 | 41 | pub struct Signer<'a, 'b, T: 'a + SignatureScheme> { 42 | scheme: &'a T, 43 | key: &'b PrivateKey, 44 | } 45 | 46 | impl<'a, 'b, T: 'a + SignatureScheme> Signer<'a, 'b, T> { 47 | /// Constructs a new Signer 48 | /// 49 | /// # Arguments 50 | /// 51 | /// * `scheme` - a cryptographic signature scheme 52 | /// * `private_key` - private key 53 | pub fn new(scheme: &'a T, key: &'b PrivateKey) -> Self { 54 | Signer { scheme, key } 55 | } 56 | 57 | /// Signs the given message. 58 | /// 59 | /// # Arguments 60 | /// 61 | /// * `message` - the message bytes 62 | /// 63 | /// # Returns 64 | /// 65 | /// * `signature` - the signature bytes 66 | pub fn sign(&self, message: &[u8]) -> Result, CryptoError> { 67 | self.scheme.sign(message, self.key) 68 | } 69 | 70 | /// Return the public key for this Signer instance. 71 | /// 72 | /// # Returns 73 | /// 74 | /// * `public_key` - the public key instance 75 | pub fn get_public_key(&self) -> Result { 76 | let sk = PrivateKey(self.key[..].to_vec()); 77 | let (pubk, _) = self 78 | .scheme 79 | .keypair(Some(KeyGenOption::FromSecretKey(sk))) 80 | .unwrap(); 81 | Ok(pubk) 82 | } 83 | } 84 | 85 | #[cfg(any( 86 | feature = "ecdsa_secp256k1", 87 | feature = "ecdsa_secp256k1_native", 88 | feature = "ecdsa_secp256k1_asm" 89 | ))] 90 | pub trait EcdsaPublicKeyHandler { 91 | /// Returns the compressed bytes 92 | fn public_key_compressed(&self, pk: &PublicKey) -> Vec; 93 | /// Returns the uncompressed bytes 94 | fn public_key_uncompressed(&self, pk: &PublicKey) -> Vec; 95 | /// Read raw bytes into key struct. Can be either compressed or uncompressed 96 | fn parse(&self, data: &[u8]) -> Result; 97 | fn public_key_uncompressed_size() -> usize; 98 | } 99 | -------------------------------------------------------------------------------- /libursa/src/utils/commitment.rs: -------------------------------------------------------------------------------- 1 | use crate::bn::{BigNumber, BigNumberContext}; 2 | use crate::errors::prelude::*; 3 | 4 | /// Generate a pedersen commitment to a given number 5 | /// 6 | /// # Arguments 7 | /// * `gen_1` - first generator 8 | /// * `m` - exponent of the first generator 9 | /// * `gen_2` - second generator 10 | /// * `r` - exponent of the second generator 11 | /// * `modulus` - all computations are done this modulo 12 | /// * `ctx` - big number context 13 | /// 14 | /// # Result 15 | /// Return the pedersen commitment, i.e `(gen_1^m)*(gen_2^r)` 16 | pub fn get_pedersen_commitment( 17 | gen_1: &BigNumber, 18 | m: &BigNumber, 19 | gen_2: &BigNumber, 20 | r: &BigNumber, 21 | modulus: &BigNumber, 22 | ctx: &mut BigNumberContext, 23 | ) -> UrsaCryptoResult { 24 | let commitment = gen_1.mod_exp(m, modulus, Some(ctx))?.mod_mul( 25 | &gen_2.mod_exp(r, modulus, Some(ctx))?, 26 | modulus, 27 | Some(ctx), 28 | )?; 29 | Ok(commitment) 30 | } 31 | -------------------------------------------------------------------------------- /libursa/src/utils/logger.rs: -------------------------------------------------------------------------------- 1 | extern crate env_logger; 2 | extern crate log; 3 | 4 | use self::env_logger::Builder; 5 | use self::log::LevelFilter; 6 | use log::{Metadata, Record}; 7 | use std::env; 8 | use std::io::Write; 9 | 10 | use crate::errors::prelude::*; 11 | 12 | use std::ffi::CString; 13 | use std::os::raw::{c_char, c_void}; 14 | use std::ptr; 15 | 16 | pub type EnabledCB = 17 | extern "C" fn(context: *const c_void, level: u32, target: *const c_char) -> bool; 18 | 19 | pub type LogCB = extern "C" fn( 20 | context: *const c_void, 21 | level: u32, 22 | target: *const c_char, 23 | message: *const c_char, 24 | module_path: *const c_char, 25 | file: *const c_char, 26 | line: u32, 27 | ); 28 | 29 | pub type FlushCB = extern "C" fn(context: *const c_void); 30 | 31 | pub struct HLCryptoLogger { 32 | context: *const c_void, 33 | enabled: Option, 34 | log: LogCB, 35 | flush: Option, 36 | } 37 | 38 | impl HLCryptoLogger { 39 | fn new( 40 | context: *const c_void, 41 | enabled: Option, 42 | log: LogCB, 43 | flush: Option, 44 | ) -> Self { 45 | HLCryptoLogger { 46 | context, 47 | enabled, 48 | log, 49 | flush, 50 | } 51 | } 52 | } 53 | 54 | impl log::Log for HLCryptoLogger { 55 | fn enabled(&self, metadata: &Metadata) -> bool { 56 | if let Some(enabled_cb) = self.enabled { 57 | let level = metadata.level() as u32; 58 | let target = CString::new(metadata.target()).unwrap(); 59 | 60 | enabled_cb(self.context, level, target.as_ptr()) 61 | } else { 62 | true 63 | } 64 | } 65 | 66 | fn log(&self, record: &Record) { 67 | let log_cb = self.log; 68 | 69 | let level = record.level() as u32; 70 | let target = CString::new(record.target()).unwrap(); 71 | let message = CString::new(record.args().to_string()).unwrap(); 72 | 73 | let module_path = record.module_path().map(|a| CString::new(a).unwrap()); 74 | let file = record.file().map(|a| CString::new(a).unwrap()); 75 | let line = record.line().unwrap_or(0); 76 | 77 | log_cb( 78 | self.context, 79 | level, 80 | target.as_ptr(), 81 | message.as_ptr(), 82 | module_path 83 | .as_ref() 84 | .map(|p| p.as_ptr()) 85 | .unwrap_or(ptr::null()), 86 | file.as_ref().map(|p| p.as_ptr()).unwrap_or(ptr::null()), 87 | line, 88 | ) 89 | } 90 | 91 | fn flush(&self) { 92 | if let Some(flush) = self.flush { 93 | flush(self.context) 94 | } 95 | } 96 | } 97 | 98 | unsafe impl Sync for HLCryptoLogger {} 99 | 100 | unsafe impl Send for HLCryptoLogger {} 101 | 102 | impl HLCryptoLogger { 103 | pub fn init( 104 | context: *const c_void, 105 | enabled: Option, 106 | log: LogCB, 107 | flush: Option, 108 | ) -> Result<(), UrsaCryptoError> { 109 | let logger = HLCryptoLogger::new(context, enabled, log, flush); 110 | 111 | log::set_boxed_logger(Box::new(logger))?; 112 | log::set_max_level(LevelFilter::Trace); 113 | 114 | Ok(()) 115 | } 116 | } 117 | 118 | pub struct HLCryptoDefaultLogger; 119 | 120 | impl HLCryptoDefaultLogger { 121 | pub fn init(pattern: Option) -> Result<(), UrsaCryptoError> { 122 | let pattern = pattern.or_else(|| env::var("RUST_LOG").ok()); 123 | 124 | Builder::new() 125 | .format(|buf, record| { 126 | writeln!( 127 | buf, 128 | "{:>5}|{:<30}|{:>35}:{:<4}| {}", 129 | record.level(), 130 | record.target(), 131 | record.file().get_or_insert(""), 132 | record.line().get_or_insert(0), 133 | record.args() 134 | ) 135 | }) 136 | .filter(None, LevelFilter::Off) 137 | .parse_filters(pattern.as_deref().unwrap_or("")) 138 | .try_init()?; 139 | 140 | Ok(()) 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /libursa/src/utils/mod.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "ffi")] 2 | #[macro_use] 3 | pub mod ctypes; 4 | #[macro_use] 5 | pub mod macros; 6 | #[cfg(feature = "logger")] 7 | #[macro_use] 8 | pub mod logger; 9 | #[cfg(any(feature = "cl", feature = "cl_native"))] 10 | pub mod commitment; 11 | -------------------------------------------------------------------------------- /libursa/src/wasm/ed25519.rs: -------------------------------------------------------------------------------- 1 | use keys::KeyGenOption; 2 | use signatures::{prelude::Ed25519Sha512 as Ed25519Sha512Impl, SignatureScheme}; 3 | 4 | use wasm_bindgen::prelude::*; 5 | 6 | use crate::keys::{PrivateKey, PublicKey}; 7 | 8 | use super::KeyPair; 9 | 10 | #[wasm_bindgen] 11 | pub struct Ed25519Sha512 { 12 | keypair: KeyPair, 13 | } 14 | 15 | #[wasm_bindgen] 16 | impl Ed25519Sha512 { 17 | #[wasm_bindgen(constructor)] 18 | pub fn new() -> Result { 19 | let scheme = Ed25519Sha512Impl {}; 20 | let (pk, sk) = maperr!(scheme.keypair(None)); 21 | Ok(Self { 22 | keypair: KeyPair { 23 | pk: pk.into(), 24 | sk: sk.into(), 25 | }, 26 | }) 27 | } 28 | 29 | #[wasm_bindgen(js_name = fromSeed)] 30 | pub fn from_seed(seed: &[u8]) -> Result { 31 | let scheme = Ed25519Sha512Impl {}; 32 | let (pk, sk) = maperr!(scheme.keypair(Some(KeyGenOption::UseSeed(seed.to_vec())))); 33 | Ok(Self { 34 | keypair: KeyPair { 35 | pk: pk.into(), 36 | sk: sk.into(), 37 | }, 38 | }) 39 | } 40 | 41 | #[wasm_bindgen(js_name = fromPrivateKey)] 42 | pub fn from_private_key(sk: &[u8]) -> Result { 43 | let scheme = Ed25519Sha512Impl {}; 44 | let pk = PrivateKey(sk.into()); 45 | let (pk, sk) = maperr!(scheme.keypair(Some(KeyGenOption::FromSecretKey(pk)))); 46 | Ok(Self { 47 | keypair: KeyPair { 48 | pk: pk.into(), 49 | sk: sk.into(), 50 | }, 51 | }) 52 | } 53 | 54 | #[wasm_bindgen(js_name = getPulicKey)] 55 | pub fn get_public_key(&self) -> Result, JsValue> { 56 | let sk = &self.keypair.sk; 57 | let scheme = Ed25519Sha512Impl {}; 58 | let (pk, _) = maperr!(scheme.keypair(Some(KeyGenOption::FromSecretKey(sk.into())))); 59 | Ok(pk.0.to_vec()) 60 | } 61 | 62 | pub fn sign(&self, message: &[u8]) -> Result, JsValue> { 63 | let sk = &self.keypair.sk; 64 | let scheme = Ed25519Sha512Impl {}; 65 | let sig = maperr!(scheme.sign(message, &sk.into())); 66 | Ok(sig) 67 | } 68 | 69 | pub fn verify(message: &[u8], signature: &[u8], pk: &[u8]) -> Result { 70 | let pk = PublicKey(pk.into()); 71 | let scheme = Ed25519Sha512Impl {}; 72 | Ok(maperr!(scheme.verify(message, signature, &pk))) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /libursa/src/wasm/encryption.rs: -------------------------------------------------------------------------------- 1 | use aead::{generic_array::typenum::Unsigned, NewAead}; 2 | use encryption::random_vec; 3 | use encryption::symm::prelude::*; 4 | use serde::{Deserialize, Serialize}; 5 | use std::str::FromStr; 6 | use wasm_bindgen::prelude::*; 7 | 8 | #[wasm_bindgen] 9 | #[derive(Debug, Serialize, Deserialize)] 10 | pub struct WasmCipherKey { 11 | cipher: EncryptorType, 12 | key: String, 13 | } 14 | 15 | macro_rules! operation_impl { 16 | ($name:ident) => { 17 | fn $name(cipher_key: WasmCipherKey, aad: &[u8], input: &[u8]) -> Result, JsValue> { 18 | let symmkey = maperr!(hex::decode(cipher_key.key)); 19 | if !cipher_key.cipher.is_valid_keysize(symmkey.len()) { 20 | return Err(JsValue::from_str("Invalid key length")); 21 | } 22 | let encryptor = cipher_key.cipher.gen_encryptor(symmkey.as_slice()); 23 | Ok(maperr!(encryptor.$name(aad, input))) 24 | } 25 | }; 26 | } 27 | 28 | #[wasm_bindgen] 29 | pub struct UrsaEncryptor {} 30 | 31 | #[wasm_bindgen] 32 | impl UrsaEncryptor { 33 | pub fn new(cipher: &str) -> Result { 34 | let cipher = maperr!(EncryptorType::from_str(cipher)); 35 | let key_size = get_keysize(cipher); 36 | 37 | Ok(WasmCipherKey { 38 | cipher, 39 | key: hex::encode(&maperr!(random_vec(key_size))), 40 | }) 41 | } 42 | 43 | #[wasm_bindgen(js_name = withKey)] 44 | pub fn with_key(cipher: &str, key: &str) -> Result { 45 | let cipher = maperr!(EncryptorType::from_str(cipher)); 46 | let key_size = get_keysize(cipher); 47 | if key_size == maperr!(hex::decode(key)).len() { 48 | Ok(WasmCipherKey { 49 | cipher, 50 | key: key.to_string(), 51 | }) 52 | } else { 53 | Err(JsValue::from_str("Invalid key length for given cipher")) 54 | } 55 | } 56 | 57 | pub fn encrypt( 58 | &self, 59 | cipher_key: WasmCipherKey, 60 | aad: &[u8], 61 | input: &[u8], 62 | ) -> Result, JsValue> { 63 | encrypt_easy(cipher_key, aad, input) 64 | } 65 | 66 | pub fn decrypt( 67 | &self, 68 | cipher_key: WasmCipherKey, 69 | aad: &[u8], 70 | input: &[u8], 71 | ) -> Result, JsValue> { 72 | decrypt_easy(cipher_key, aad, input) 73 | } 74 | } 75 | 76 | fn get_keysize(cipher: EncryptorType) -> usize { 77 | match cipher { 78 | EncryptorType::Aes128CbcHmac256 => { 79 | <::KeySize as Unsigned>::to_usize() 80 | } 81 | EncryptorType::Aes256CbcHmac512 => { 82 | <::KeySize as Unsigned>::to_usize() 83 | } 84 | EncryptorType::Aes128Gcm => <::KeySize as Unsigned>::to_usize(), 85 | EncryptorType::Aes256Gcm => <::KeySize as Unsigned>::to_usize(), 86 | EncryptorType::XChaCha20Poly1305 => { 87 | <::KeySize as Unsigned>::to_usize() 88 | } 89 | } 90 | } 91 | 92 | operation_impl!(encrypt_easy); 93 | operation_impl!(decrypt_easy); 94 | -------------------------------------------------------------------------------- /libursa/src/wasm/macros.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "cl")] 2 | macro_rules! check_opt_reference { 3 | ($ref:ident, $thing:tt) => { 4 | if $ref.is_null() { 5 | None 6 | } else { 7 | let item: $thing = convert_from_js($ref)?; 8 | Some(item.0) 9 | } 10 | }; 11 | } 12 | 13 | macro_rules! maperr { 14 | ($expr:expr) => { 15 | $expr.map_err(|_e| stringify!(_e))? 16 | }; 17 | } 18 | 19 | #[cfg(feature = "cl")] 20 | macro_rules! finalize { 21 | ($expr:expr) => { 22 | $expr.0.finalize().map_err(|e| e.to_string())? 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /libursa/src/wasm/mod.rs: -------------------------------------------------------------------------------- 1 | use errors::{UrsaCryptoError, UrsaCryptoErrorKind}; 2 | use keys::{PrivateKey, PublicKey, SessionKey}; 3 | use serde::{Deserialize, Serialize}; 4 | use wasm_bindgen::prelude::*; 5 | 6 | #[macro_use] 7 | mod macros; 8 | #[cfg(feature = "bls_bn254")] 9 | pub mod bls; 10 | #[cfg(feature = "cl")] 11 | pub mod cl; 12 | #[cfg(feature = "ed25519")] 13 | pub mod ed25519; 14 | #[cfg(feature = "encryption")] 15 | pub mod encryption; 16 | #[cfg(feature = "ecdsa_secp256k1")] 17 | pub mod secp256k1; 18 | #[cfg(feature = "x25519")] 19 | pub mod x25519; 20 | 21 | #[wasm_bindgen] 22 | #[derive(Debug, Serialize, Deserialize)] 23 | pub struct WasmPrivateKey(String); 24 | 25 | #[wasm_bindgen] 26 | #[derive(Debug, Serialize, Deserialize)] 27 | pub struct WasmPublicKey(String); 28 | 29 | #[wasm_bindgen] 30 | impl WasmPublicKey { 31 | #[wasm_bindgen(constructor)] 32 | pub fn new(key: &[u8]) -> Result { 33 | Ok(WasmPublicKey(hex::encode(&key[..]))) 34 | } 35 | } 36 | 37 | #[wasm_bindgen] 38 | #[derive(Debug, Serialize, Deserialize)] 39 | pub struct WasmSessionKey(String); 40 | 41 | #[wasm_bindgen] 42 | #[derive(Debug, Serialize, Deserialize)] 43 | pub struct KeyPair { 44 | pk: WasmPublicKey, 45 | sk: WasmPrivateKey, 46 | } 47 | 48 | impl From<&PublicKey> for WasmPublicKey { 49 | fn from(pk: &PublicKey) -> WasmPublicKey { 50 | WasmPublicKey(hex::encode(&pk[..])) 51 | } 52 | } 53 | 54 | impl From for WasmPublicKey { 55 | fn from(pk: PublicKey) -> WasmPublicKey { 56 | WasmPublicKey(hex::encode(&pk[..])) 57 | } 58 | } 59 | 60 | impl From> for WasmPublicKey { 61 | fn from(value: Vec) -> WasmPublicKey { 62 | WasmPublicKey(hex::encode(value.as_slice())) 63 | } 64 | } 65 | 66 | impl From<&WasmPublicKey> for PublicKey { 67 | fn from(pk: &WasmPublicKey) -> PublicKey { 68 | PublicKey(hex::decode(&pk.0).unwrap().to_vec()) 69 | } 70 | } 71 | impl From for PublicKey { 72 | fn from(pk: WasmPublicKey) -> PublicKey { 73 | PublicKey(hex::decode(&pk.0).unwrap().to_vec()) 74 | } 75 | } 76 | 77 | impl From<&PrivateKey> for WasmPrivateKey { 78 | fn from(sk: &PrivateKey) -> WasmPrivateKey { 79 | WasmPrivateKey(hex::encode(&sk[..])) 80 | } 81 | } 82 | 83 | impl From for WasmPrivateKey { 84 | fn from(sk: PrivateKey) -> WasmPrivateKey { 85 | WasmPrivateKey(hex::encode(&sk[..])) 86 | } 87 | } 88 | 89 | impl From<&WasmPrivateKey> for PrivateKey { 90 | fn from(pk: &WasmPrivateKey) -> PrivateKey { 91 | PrivateKey(hex::decode(&pk.0).unwrap().to_vec()) 92 | } 93 | } 94 | 95 | impl From for PrivateKey { 96 | fn from(pk: WasmPrivateKey) -> PrivateKey { 97 | PrivateKey(hex::decode(&pk.0).unwrap().to_vec()) 98 | } 99 | } 100 | 101 | impl From for WasmSessionKey { 102 | fn from(secret: SessionKey) -> WasmSessionKey { 103 | WasmSessionKey(hex::encode(&secret[..])) 104 | } 105 | } 106 | 107 | impl From for JsValue { 108 | fn from(err: UrsaCryptoError) -> JsValue { 109 | JsValue::from_serde(&err.to_string()).unwrap() 110 | } 111 | } 112 | 113 | fn convert_from_js(val: &JsValue) -> Result 114 | where 115 | for<'a> T: serde::Deserialize<'a>, 116 | { 117 | match val.into_serde() { 118 | Ok(unwrapped) => Ok(unwrapped), 119 | Err(_) => Err(UrsaCryptoError::from_msg( 120 | UrsaCryptoErrorKind::InvalidStructure, 121 | "Invalid argument".to_string(), 122 | )), 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /libursa/src/wasm/secp256k1.rs: -------------------------------------------------------------------------------- 1 | use kex::{secp256k1::EcdhSecp256k1Sha256 as EcdhSecp256k1Sha256Impl, KeyExchangeScheme}; 2 | use keys::{KeyGenOption, PrivateKey, PublicKey}; 3 | use signatures::{ 4 | secp256k1::EcdsaSecp256k1Sha256 as EcdsaSecp256k1Sha256Impl, EcdsaPublicKeyHandler, 5 | SignatureScheme, 6 | }; 7 | 8 | use wasm_bindgen::prelude::*; 9 | 10 | use super::{KeyPair, WasmPrivateKey, WasmPublicKey, WasmSessionKey}; 11 | 12 | #[wasm_bindgen] 13 | pub struct EcdsaSecp256k1Sha256(EcdsaSecp256k1Sha256Impl); 14 | 15 | #[wasm_bindgen] 16 | impl EcdsaSecp256k1Sha256 { 17 | #[wasm_bindgen(constructor)] 18 | pub fn new() -> Self { 19 | EcdsaSecp256k1Sha256(EcdsaSecp256k1Sha256Impl::new()) 20 | } 21 | 22 | pub fn keypair(&self) -> Result { 23 | let (pk, sk) = maperr!(self.0.keypair(None)); 24 | let pk = WasmPublicKey::from(&pk); 25 | let sk = WasmPrivateKey::from(&sk); 26 | Ok(KeyPair { pk, sk }) 27 | } 28 | 29 | #[wasm_bindgen(js_name = keypairFromSeed)] 30 | pub fn keypair_from_seed(&self, seed: &[u8]) -> Result { 31 | let (pk, sk) = maperr!(self.0.keypair(Some(KeyGenOption::UseSeed(seed.to_vec())))); 32 | let pk = WasmPublicKey::from(&pk); 33 | let sk = WasmPrivateKey::from(&sk); 34 | Ok(KeyPair { pk, sk }) 35 | } 36 | 37 | #[wasm_bindgen(js_name = getPublicKey)] 38 | pub fn get_public_key(&self, sk: &WasmPrivateKey) -> Result { 39 | let sk = PrivateKey::from(sk); 40 | let (pk, _) = maperr!(self 41 | .0 42 | .keypair(Some(KeyGenOption::FromSecretKey(sk.clone())))); 43 | let pk = WasmPublicKey::from(&pk); 44 | Ok(pk) 45 | } 46 | 47 | pub fn sign(&self, message: &[u8], sk: &WasmPrivateKey) -> Result, JsValue> { 48 | let sk = PrivateKey::from(sk); 49 | let sig = maperr!(self.0.sign(message, &sk)); 50 | Ok(sig) 51 | } 52 | 53 | pub fn verify( 54 | &self, 55 | message: &[u8], 56 | signature: &[u8], 57 | pk: &WasmPublicKey, 58 | ) -> Result { 59 | let pk = PublicKey::from(pk); 60 | Ok(maperr!(self.0.verify(message, signature, &pk))) 61 | } 62 | 63 | #[wasm_bindgen(js_name = normalizeS)] 64 | pub fn normalize_s(&self, signature: &mut [u8]) -> Result<(), JsValue> { 65 | maperr!(self.0.normalize_s(signature)); 66 | Ok(()) 67 | } 68 | 69 | #[wasm_bindgen(js_name = publicKeyCompressed)] 70 | pub fn public_key_compressed(&self, pk: &WasmPublicKey) -> WasmPublicKey { 71 | let pk = PublicKey::from(pk); 72 | WasmPublicKey::from(self.0.public_key_compressed(&pk)) 73 | } 74 | 75 | #[wasm_bindgen(js_name = publicKeyUnCompressed)] 76 | pub fn public_key_uncompressed(&self, pk: &WasmPublicKey) -> WasmPublicKey { 77 | let pk = PublicKey::from(pk); 78 | WasmPublicKey::from(self.0.public_key_uncompressed(&pk)) 79 | } 80 | 81 | #[wasm_bindgen(js_name = parseToPublicKey)] 82 | pub fn parse_to_public_key(&self, bytes: &[u8]) -> Result { 83 | let pk = maperr!(self.0.parse(bytes)); 84 | Ok(WasmPublicKey::from(&pk)) 85 | } 86 | } 87 | 88 | #[wasm_bindgen] 89 | pub struct EcdhSecp256k1Sha256(EcdhSecp256k1Sha256Impl); 90 | 91 | #[wasm_bindgen] 92 | impl EcdhSecp256k1Sha256 { 93 | #[wasm_bindgen(constructor)] 94 | pub fn new() -> Self { 95 | EcdhSecp256k1Sha256(EcdhSecp256k1Sha256Impl::new()) 96 | } 97 | 98 | pub fn keypair(&self) -> Result { 99 | let (pk, sk) = maperr!(self.0.keypair(None)); 100 | let pk = WasmPublicKey::from(&pk); 101 | let sk = WasmPrivateKey::from(&sk); 102 | Ok(KeyPair { pk, sk }) 103 | } 104 | 105 | #[wasm_bindgen(js_name = keypair_from_seed)] 106 | pub fn keypair_from_seed(&self, seed: &[u8]) -> Result { 107 | let (pk, sk) = maperr!(self.0.keypair(Some(KeyGenOption::UseSeed(seed.to_vec())))); 108 | let pk = WasmPublicKey::from(&pk); 109 | let sk = WasmPrivateKey::from(&sk); 110 | Ok(KeyPair { pk, sk }) 111 | } 112 | 113 | #[wasm_bindgen(js_name = getPublicKey)] 114 | pub fn get_public_key(&self, sk: &WasmPrivateKey) -> Result { 115 | let sk = PrivateKey::from(sk); 116 | let (pk, _) = maperr!(self 117 | .0 118 | .keypair(Some(KeyGenOption::FromSecretKey(sk.clone())))); 119 | let pk = WasmPublicKey::from(&pk); 120 | Ok(pk) 121 | } 122 | 123 | #[wasm_bindgen(js_name = computeSharedSecret)] 124 | pub fn compute_shared_secret( 125 | &self, 126 | sk: &WasmPrivateKey, 127 | pk: &WasmPublicKey, 128 | ) -> Result { 129 | let sk = PrivateKey::from(sk); 130 | let pk = PublicKey::from(pk); 131 | let secret = maperr!(self.0.compute_shared_secret(&sk, &pk)); 132 | let secret = WasmSessionKey::from(secret); 133 | Ok(secret) 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /libursa/src/wasm/x25519.rs: -------------------------------------------------------------------------------- 1 | use kex::{x25519::X25519Sha256 as X25519Sha256Impl, KeyExchangeScheme}; 2 | use keys::{KeyGenOption, PrivateKey, PublicKey}; 3 | 4 | use wasm_bindgen::prelude::*; 5 | 6 | use super::{KeyPair, WasmPrivateKey, WasmPublicKey, WasmSessionKey}; 7 | 8 | #[wasm_bindgen] 9 | pub struct X25519Sha256; 10 | 11 | #[wasm_bindgen] 12 | impl X25519Sha256 { 13 | #[wasm_bindgen(constructor)] 14 | pub fn new() -> Self { 15 | Self 16 | } 17 | 18 | pub fn keypair(&self) -> Result { 19 | let scheme = X25519Sha256Impl {}; 20 | let (pk, sk) = maperr!(scheme.keypair(None)); 21 | Ok(KeyPair { 22 | pk: pk.into(), 23 | sk: sk.into(), 24 | }) 25 | } 26 | 27 | #[wasm_bindgen(js_name = keypair_from_seed)] 28 | pub fn key_pair_from_seed(&self, seed: &[u8]) -> Result { 29 | let scheme = X25519Sha256Impl {}; 30 | let (pk, sk) = maperr!(scheme.keypair(Some(KeyGenOption::UseSeed(seed.to_vec())))); 31 | Ok(KeyPair { 32 | pk: pk.into(), 33 | sk: sk.into(), 34 | }) 35 | } 36 | 37 | #[wasm_bindgen(js_name = getPublicKey)] 38 | pub fn get_public_key(&self, sk: &WasmPrivateKey) -> Result { 39 | let sk = sk.into(); 40 | let scheme = X25519Sha256Impl {}; 41 | let (pk, _) = maperr!(scheme.keypair(Some(KeyGenOption::FromSecretKey(sk)))); 42 | Ok(pk.into()) 43 | } 44 | 45 | #[wasm_bindgen(js_name = computeSharedSecret)] 46 | pub fn compute_shared_secret( 47 | &self, 48 | sk: &WasmPrivateKey, 49 | pk: &WasmPublicKey, 50 | ) -> Result { 51 | let sk = PrivateKey::from(sk); 52 | let pk = PublicKey::from(pk); 53 | let scheme = X25519Sha256Impl {}; 54 | let secret = maperr!(scheme.compute_shared_secret(&sk, &pk)); 55 | let secret = WasmSessionKey::from(secret); 56 | Ok(secret) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /libzmix/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "zmix" 3 | version = "0.3.1" 4 | authors = ["The Hyperledger Ursa Contributors"] 5 | license = "Apache-2.0" 6 | description = "A library for doing zero-knowledge proofs" 7 | keywords = ["cryptography", "aead", "hash", "signature", "zkp", "zero-knowledge"] 8 | 9 | [lib] 10 | name = "zmix" 11 | crate-type = ["rlib", "staticlib", "cdylib"] 12 | 13 | [features] 14 | default = ["std", "ursa/default"] 15 | portable = ["std", "ursa/portable"] 16 | asm = ["std", "sha2/asm", "ursa/asm"] 17 | std = ["bbs", "ver_enc", "PS_Signature_G2", "sha2/std"] 18 | ver_enc = [] 19 | PS_Signature_G2 = [] 20 | PS_Signature_G1 = [] 21 | 22 | [dependencies] 23 | arrayref = "0.3.6" 24 | bulletproofs_amcl = { version = "0.2.0", path = "./bulletproofs_amcl" } 25 | bbs = { version = "0.4.0", path = "./bbs", optional = true } 26 | criterion = "0.3" 27 | failure = "0.1" 28 | lazy_static = "1.4" 29 | merlin = "1" 30 | rand = "0.7" 31 | serde = { version = "1.0", features = ["derive"] } 32 | serde_json = "1.0" 33 | sha2 = { version = "0.8", default-features = false, optional = true } 34 | sha3 = { version = "0.8", default-features = false, optional = true } 35 | ursa = { version = "0.3", path = "../libursa", default-features = false, optional = true } 36 | zeroize = { version = "1.1", features = ["zeroize_derive"] } 37 | hex = "0.4.2" 38 | 39 | [[bench]] 40 | name = "bbs_vs_ps" 41 | harness = false 42 | 43 | [dev-dependencies] 44 | rand_chacha = "0.2" 45 | serde_json = "1.0" 46 | 47 | [dependencies.amcl_wrapper] 48 | version = "0.3.5" 49 | default-features = false 50 | features = ["bls381"] 51 | -------------------------------------------------------------------------------- /libzmix/README.md: -------------------------------------------------------------------------------- 1 | # Short Description 2 | z-mix is a general purpose library to create Zero-Knowledge proofs, proving statements about multiple cryptographic building blocks, containing signatures, commitments, and verifiable encryption. 3 | z-mix facilitates 4 | 5 | Multiple existing Hyperledger projects require Zero-Knowledge proofs, e.g., Fabric and Indy. The goal of this library is to provide a single flexible and secure implementation to construct such proofs. 6 | z-mix is a C callable library but there are also convenience wrappers for various programming languages. 7 | 8 | # Spec 9 | z-mix uses JSON objects to provide a *zero knowledge language (ZKL)* to express 10 | 11 | * Requests of attested attribute values 12 | * Resolutions for requests that can be validated 13 | * Proofs that satisfy requests 14 | 15 | ### Process 16 | z-mix translates a ZKL-ProofSpec and a corresponding ZKL-Witness, both represented as JSON objects, into a ZKL-Proof JSON object. 17 | 18 | The **ZKL-ProofSpec** defines the statement to be proven and contains all public information needed by a verifier \[e.g., Credential Definitions, Revocation Authority, Pseudonyms]. 19 | 20 | The **ZKL-Witness** contains the secrets required to compute a proof \[e.g. secret keys, all attribute values, the credentials involved, the randomness used to compute a pseudonym]. 21 | 22 | The **ZKL Proof** is the data that satisfies the statement to be proven. 23 | 24 | ### Examples 25 | 26 | z-mix is written in Rust. z-mix can be included into other Rust projects by adding the following to the Cargo.toml: 27 | 28 | ```toml 29 | z_mix = { version = "0.1", git = "https://github.com/hyperledger-labs/z-mix.git" } 30 | ``` 31 | 32 | An example how to use in your rust project 33 | 34 | ```rust 35 | extern crate zmix; 36 | 37 | use zmix::zkl::{Parser, Witness}; 38 | use zmix::zkl::spec::ProofSpecBuilder; 39 | 40 | fn main() { 41 | let mut proof_spec_builder = ProofSpecBuilder::new(); 42 | 43 | // Add proof spec data 44 | 45 | // Add witness data 46 | 47 | let proof_spec = proof_spec_builder.finalize(); 48 | let witness = Witness {}; 49 | 50 | match Parser::parse(&proof_spec, &witness) { 51 | Ok(proof) => { 52 | match proof.verify(&proof_spec) { 53 | Ok(v) => println!("Proof result - {}", v), 54 | Err(pe) => panic!("Proof::verify encountered an error - {:?}", pe) 55 | } 56 | }, 57 | Err(e) => panic!("Parser::parse encountered an error - {:?}", e) 58 | }; 59 | } 60 | ``` 61 | 62 | -------------------------------------------------------------------------------- /libzmix/bbs/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["The Hyperledger Ursa Contributors"] 3 | description = "The BBS+ signature scheme" 4 | documentation = "https://docs.rs/bbs" 5 | edition = "2018" 6 | license = "Apache-2.0" 7 | name = "bbs" 8 | readme = "README.md" 9 | repository = "https://github.com/hyperledger/ursa" 10 | version = "0.4.2" 11 | 12 | [badges] 13 | maintenance = { status = "actively-developed" } 14 | 15 | [lib] 16 | crate-type = ["cdylib", "rlib"] 17 | 18 | [features] 19 | default = ["rayon"] 20 | wasm = ["serde-wasm-bindgen", "wasm-bindgen"] 21 | 22 | [dependencies] 23 | arrayref = "0.3" 24 | blake2 = "0.8" 25 | failure = "0.1" 26 | ff-zeroize = "0.6" 27 | hex = "0.4" 28 | hkdf = "0.8" 29 | rayon = { version = "1.3", optional = true } 30 | rand = "0.7" 31 | pairing-plus = "0.19" 32 | serde = { version = "1.0", features = ["serde_derive"] } 33 | serde-wasm-bindgen = { version = "0.1", optional = true } 34 | subtle = "2.2" 35 | wasm-bindgen = { version = "0.2", optional = true } 36 | zeroize = "1.1" 37 | 38 | [dev-dependencies] 39 | -------------------------------------------------------------------------------- /libzmix/bbs/src/issuer.rs: -------------------------------------------------------------------------------- 1 | use crate::errors::prelude::*; 2 | use crate::keys::prelude::*; 3 | use crate::signature::prelude::*; 4 | /// The issuer generates keys and uses those to sign 5 | /// credentials. There are two types of public keys: 6 | /// `PublicKey` which generates all generators at random and 7 | /// `DeterministicPublicKey` which only generates the commitment 8 | /// to the secret key. `DeterministicPublicKey` can be converted to a 9 | /// `PublicKey` later. The latter is primarily used for storing a shorter 10 | /// key and looks just like a regular ECC key. 11 | use crate::{BlindSignatureContext, ProofNonce, RandomElem, SignatureMessage}; 12 | use std::collections::{BTreeMap, BTreeSet}; 13 | 14 | /// This struct represents an Issuer of signatures or Signer. 15 | /// Provided are methods for signing regularly where all messages are known 16 | /// and 2PC where some are only known to the holder and a blind signature 17 | /// is created. 18 | pub struct Issuer; 19 | 20 | impl Issuer { 21 | /// Create a keypair capable of signing `message_count` messages 22 | pub fn new_keys(message_count: usize) -> Result<(PublicKey, SecretKey), BBSError> { 23 | generate(message_count) 24 | } 25 | 26 | /// Create a keypair that uses the short public key 27 | pub fn new_short_keys( 28 | option: Option, 29 | ) -> Result<(DeterministicPublicKey, SecretKey), BBSError> { 30 | DeterministicPublicKey::new(option) 31 | } 32 | 33 | /// Create a signature with no hidden messages 34 | pub fn sign( 35 | messages: &[SignatureMessage], 36 | signkey: &SecretKey, 37 | verkey: &PublicKey, 38 | ) -> Result { 39 | Signature::new(messages, signkey, verkey) 40 | } 41 | 42 | /// Verify a proof of committed messages and generate a blind signature 43 | pub fn blind_sign( 44 | ctx: &BlindSignatureContext, 45 | messages: &BTreeMap, 46 | signkey: &SecretKey, 47 | verkey: &PublicKey, 48 | nonce: &ProofNonce, 49 | ) -> Result { 50 | let revealed_messages: BTreeSet = messages.keys().copied().collect(); 51 | if ctx.verify(&revealed_messages, verkey, nonce)? { 52 | BlindSignature::new(&ctx.commitment, messages, signkey, verkey) 53 | } else { 54 | Err(BBSErrorKind::GeneralError { 55 | msg: "Invalid proof of committed messages".to_string(), 56 | } 57 | .into()) 58 | } 59 | } 60 | 61 | /// Create a nonce used for the blind signing context 62 | pub fn generate_signing_nonce() -> ProofNonce { 63 | ProofNonce::random() 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /libzmix/bbs/src/messages.rs: -------------------------------------------------------------------------------- 1 | /// Creates the BTreeMap used for blind signing 2 | #[macro_export] 3 | macro_rules! sm_map { 4 | ($($index:expr => $data:expr),*) => { 5 | { 6 | let mut msgs = std::collections::BTreeMap::new(); 7 | $( 8 | msgs.insert($index, crate::SignatureMessage::hash($data)); 9 | )* 10 | msgs 11 | } 12 | }; 13 | } 14 | 15 | /// Creates a proof message to be revealed 16 | #[macro_export] 17 | macro_rules! pm_revealed { 18 | ($data:expr) => { 19 | ProofMessage::Revealed(SignatureMessage::hash($data)) 20 | }; 21 | } 22 | 23 | /// Wrap a raw message in a revealed enum 24 | #[macro_export] 25 | macro_rules! pm_revealed_raw { 26 | ($data:expr) => { 27 | ProofMessage::Revealed($data) 28 | }; 29 | } 30 | 31 | /// Creates a proof message that is hidden based on the number of parameters 32 | /// One means hidden and only used in this proof 33 | /// Two means hidden but can be used in other proofs 34 | #[macro_export] 35 | macro_rules! pm_hidden { 36 | ($data:expr) => { 37 | ProofMessage::Hidden(HiddenMessage::ProofSpecificBlinding( 38 | SignatureMessage::hash($data), 39 | )) 40 | }; 41 | ($data:expr, $bf:expr) => { 42 | ProofMessage::Hidden(HiddenMessage::ExternalBlinding( 43 | SignatureMessage::hash($data), 44 | $bf, 45 | )) 46 | }; 47 | } 48 | 49 | /// Wrap a raw message in its respective hidden 50 | #[macro_export] 51 | macro_rules! pm_hidden_raw { 52 | ($data:expr) => { 53 | ProofMessage::Hidden(HiddenMessage::ProofSpecificBlinding($data)) 54 | }; 55 | ($data:expr, $bf:expr) => { 56 | ProofMessage::Hidden(HiddenMessage::ExternalBlinding($data, $bf)) 57 | }; 58 | } 59 | 60 | use crate::{ProofNonce, SignatureMessage}; 61 | 62 | /// A message classification by the prover 63 | pub enum ProofMessage { 64 | /// Message will be revealed to a verifier 65 | Revealed(SignatureMessage), 66 | /// Message will be hidden from a verifier 67 | Hidden(HiddenMessage), 68 | } 69 | 70 | impl ProofMessage { 71 | /// Extract the internal message 72 | pub fn get_message(&self) -> SignatureMessage { 73 | match *self { 74 | ProofMessage::Revealed(ref r) => *r, 75 | ProofMessage::Hidden(HiddenMessage::ProofSpecificBlinding(ref p)) => *p, 76 | ProofMessage::Hidden(HiddenMessage::ExternalBlinding(ref m, _)) => *m, 77 | } 78 | } 79 | } 80 | 81 | /// Two types of hidden messages 82 | pub enum HiddenMessage { 83 | /// Indicates the message is hidden and no other work is involved 84 | /// so a blinding factor will be generated specific to this proof 85 | ProofSpecificBlinding(SignatureMessage), 86 | /// Indicates the message is hidden but it is involved with other proofs 87 | /// like boundchecks, set memberships or inequalities, so the blinding factor 88 | /// is provided from an external source. 89 | ExternalBlinding(SignatureMessage, ProofNonce), 90 | } 91 | -------------------------------------------------------------------------------- /libzmix/bbs/src/verifier.rs: -------------------------------------------------------------------------------- 1 | use crate::errors::prelude::*; 2 | use crate::keys::prelude::*; 3 | use crate::pok_sig::prelude::*; 4 | /// The verifier of a signature or credential asks for messages to be revealed from 5 | /// a prover and checks the signature proof of knowledge against a trusted issuer's public key. 6 | use crate::{ 7 | HashElem, ProofChallenge, ProofNonce, ProofRequest, RandomElem, SignatureMessage, 8 | SignatureProof, 9 | }; 10 | use std::collections::BTreeSet; 11 | 12 | /// This struct represents an Verifier of signatures. 13 | /// Provided are methods for generating a context to ask for revealed messages 14 | /// and the prover keep all others hidden. 15 | pub struct Verifier; 16 | 17 | impl Verifier { 18 | /// Create a nonce used for the zero-knowledge proof context 19 | /// verkey: issuer's public key 20 | pub fn new_proof_request( 21 | revealed_message_indices: &[usize], 22 | verkey: &PublicKey, 23 | ) -> Result { 24 | let revealed_messages = revealed_message_indices 25 | .iter() 26 | .copied() 27 | .collect::>(); 28 | for i in &revealed_messages { 29 | if *i > verkey.h.len() { 30 | return Err(BBSErrorKind::PublicKeyGeneratorMessageCountMismatch( 31 | *i, 32 | verkey.h.len(), 33 | ) 34 | .into()); 35 | } 36 | } 37 | Ok(ProofRequest { 38 | revealed_messages, 39 | verification_key: verkey.clone(), 40 | }) 41 | } 42 | 43 | /// Check a signature proof of knowledge and selective disclosure proof 44 | pub fn verify_signature_pok( 45 | proof_request: &ProofRequest, 46 | signature_proof: &SignatureProof, 47 | nonce: &ProofNonce, 48 | ) -> Result, BBSError> { 49 | let mut challenge_bytes = signature_proof.proof.get_bytes_for_challenge( 50 | proof_request.revealed_messages.clone(), 51 | &proof_request.verification_key, 52 | ); 53 | challenge_bytes.extend_from_slice(&nonce.to_bytes_uncompressed_form()[..]); 54 | 55 | let challenge_verifier = ProofChallenge::hash(&challenge_bytes); 56 | match signature_proof.proof.verify( 57 | &proof_request.verification_key, 58 | &signature_proof.revealed_messages, 59 | &challenge_verifier, 60 | )? { 61 | PoKOfSignatureProofStatus::Success => Ok(signature_proof 62 | .revealed_messages 63 | .iter() 64 | .map(|(_, m)| *m) 65 | .collect::>()), 66 | e => Err(BBSErrorKind::InvalidProof { status: e }.into()), 67 | } 68 | } 69 | 70 | /// Create a nonce used for the proof request context 71 | pub fn generate_proof_nonce() -> ProofNonce { 72 | ProofNonce::random() 73 | } 74 | 75 | /// create the challenge hash for a set of proofs 76 | /// 77 | /// # Arguments 78 | /// * `proofs` - a slice of SignatureProof objects 79 | /// * `proof_requests` - a corresponding slice of ProofRequest objects 80 | /// * `nonce` - a SignatureNonce 81 | /// * `claims` - an optional slice of bytes the prover wishes to include in the challenge 82 | pub fn create_challenge_hash( 83 | proofs: &[SignatureProof], 84 | proof_requests: &[ProofRequest], 85 | nonce: &ProofNonce, 86 | claims: Option<&[&[u8]]>, 87 | ) -> Result { 88 | let mut bytes = Vec::new(); 89 | 90 | for pr in proofs.iter().zip(proof_requests.iter()) { 91 | let (p, r) = pr; 92 | bytes.extend_from_slice( 93 | p.proof 94 | .get_bytes_for_challenge(r.revealed_messages.clone(), &r.verification_key) 95 | .as_slice(), 96 | ); 97 | } 98 | bytes.extend_from_slice(&nonce.to_bytes_uncompressed_form()[..]); 99 | if let Some(claim) = claims { 100 | for c in claim { 101 | bytes.extend_from_slice(c); 102 | } 103 | } 104 | let challenge = ProofChallenge::hash(&bytes); 105 | Ok(challenge) 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /libzmix/bulletproofs_amcl/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | .idea/ 5 | amcl/target/ -------------------------------------------------------------------------------- /libzmix/bulletproofs_amcl/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bulletproofs_amcl" 3 | version = "0.2.0" 4 | authors = ["Hyperledger Ursa Maintainers"] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | rand = "0.7" 9 | lazy_static = "1.3.0" 10 | merlin = "1" 11 | byteorder = "1.3.1" 12 | serde = "1.0" 13 | serde_json = "1.0" 14 | serde_derive = "1.0" 15 | criterion = "0.3" 16 | failure = "0.1" 17 | 18 | [dependencies.amcl_wrapper] 19 | version = "0.3.5" 20 | default-features = false 21 | features = ["bls381"] 22 | 23 | [features] 24 | default = ["bls381"] 25 | bls381 = ["amcl_wrapper/bls381"] 26 | bn254 = ["amcl_wrapper/bn254"] 27 | secp256k1 = ["amcl_wrapper/secp256k1"] 28 | ed25519 = ["amcl_wrapper/ed25519"] 29 | 30 | [[bench]] 31 | name = "vec_poly_eval" 32 | harness = false -------------------------------------------------------------------------------- /libzmix/bulletproofs_amcl/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Chain, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /libzmix/bulletproofs_amcl/README.md: -------------------------------------------------------------------------------- 1 | # Bulletproofs 2 | 3 | 1. Bulletproofs, based on the paper [Bulletproofs: Short Proofs for Confidential Transactions and More](https://eprint.iacr.org/2017/1066) 4 | 1. Implementation primarily intended for a pairing friendly curve. Only 2 curves are supported, BLS12-381 and BN254 for now. 5 | Defaults to BLS12-381. Curve can be changed by changing default feature. 6 | 1. Largely based on [dalek's Bulletproof implementation](https://github.com/dalek-cryptography/bulletproofs). 7 | dalek's is not used since it works over Ristretto curve but since Ursa's credentials are on a pairing friendly curve, 8 | the Bulletproof needs to work over the same curve. The code is distributed under the terms of both the MIT license and the Apache 2.0 License. 9 | 1. Uses [Apache Milagro](https://github.com/milagro-crypto/amcl) for finite field and elliptic curve operations. 10 | 1. R1CS support is present though the API differs from dalek's. For gadgets, check [here](src/r1cs/gadgets). 11 | 12 | ## License 13 | Licensed under either of 14 | - Apache License, Version 2.0, ([LICENSE-APACHE](./LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) 15 | - MIT license ([LICENSE-MIT](./LICENSE-MIT) or http://opensource.org/licenses/MIT) 16 | at your option. -------------------------------------------------------------------------------- /libzmix/bulletproofs_amcl/benches/vec_poly_eval.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate criterion; 3 | extern crate bulletproofs_amcl; 4 | 5 | use criterion::Criterion; 6 | 7 | use amcl_wrapper::field_elem::{FieldElement, FieldElementVector}; 8 | use bulletproofs_amcl::utils::vector_poly::VecPoly3; 9 | 10 | /// Benchmark evaluation of vector polynomial 11 | fn eval_benchmark(c: &mut Criterion) { 12 | for n in vec![10, 50, 100, 500, 1000] { 13 | let p1_0 = FieldElementVector::random(n); 14 | let p1_1 = FieldElementVector::random(n); 15 | let p1_2 = FieldElementVector::random(n); 16 | let p1_3 = FieldElementVector::random(n); 17 | let p1 = VecPoly3(p1_0, p1_1, p1_2, p1_3); 18 | let x = FieldElement::random(); 19 | 20 | c.bench_function(format!("eval for {} elements", n).as_str(), |b| { 21 | b.iter(|| p1.eval(&x)) 22 | }); 23 | 24 | c.bench_function(format!("eval_alt for {} elements", n).as_str(), |b| { 25 | b.iter(|| p1.eval_alt(&x)) 26 | }); 27 | } 28 | } 29 | 30 | criterion_group!( 31 | name = bench_eval; 32 | config = Criterion::default(); 33 | targets = eval_benchmark 34 | ); 35 | 36 | criterion_main!(bench_eval); 37 | -------------------------------------------------------------------------------- /libzmix/bulletproofs_amcl/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | 3 | extern crate lazy_static; 4 | 5 | extern crate amcl_wrapper; 6 | 7 | extern crate serde; 8 | 9 | #[macro_use] 10 | extern crate serde_derive; 11 | 12 | extern crate serde_json; 13 | 14 | extern crate failure; 15 | 16 | #[macro_use] 17 | pub mod errors; 18 | 19 | #[macro_use] 20 | pub mod utils; 21 | 22 | mod transcript; 23 | 24 | pub mod ipp; 25 | 26 | pub mod r1cs; 27 | -------------------------------------------------------------------------------- /libzmix/bulletproofs_amcl/src/r1cs/gadgets/README.md: -------------------------------------------------------------------------------- 1 | Each gadgets contains a method like 2 | 3 | - `gen_proof....` which are used to generate the proof. It also returns the commitments that need to be given to the verifier. Apart from inputs, it optionally takes the randomness for commitments in case gadget is part of a sub-protocol. 4 | - `verify_proof.....` which will be used to verify the proof. 5 | -------------------------------------------------------------------------------- /libzmix/bulletproofs_amcl/src/r1cs/gadgets/helper_constraints/bit.rs: -------------------------------------------------------------------------------- 1 | use crate::errors::R1CSError; 2 | use crate::r1cs::linear_combination::AllocatedQuantity; 3 | use crate::r1cs::{ConstraintSystem, LinearCombination}; 4 | use amcl_wrapper::field_elem::FieldElement; 5 | 6 | // Ensure `v` is a bit, hence 0 or 1 7 | pub fn bit_gadget( 8 | cs: &mut CS, 9 | v: &AllocatedQuantity, 10 | ) -> Result<(), R1CSError> { 11 | // TODO: Possible to save reallocation of `v` in `bit`? 12 | let (a, b, o) = cs.allocate_multiplier( 13 | v.assignment 14 | .as_ref() 15 | .map(|bit| ((FieldElement::one() - bit), bit.clone())), 16 | )?; 17 | 18 | // Might not be necessary if above TODO is addressed 19 | // Variable b is same as v so b + (-v) = 0 20 | let neg_v: LinearCombination = vec![(v.variable, FieldElement::minus_one())] 21 | .iter() 22 | .collect(); 23 | cs.constrain(b + neg_v); 24 | 25 | // Enforce a * b = 0, so one of (a,b) is zero 26 | cs.constrain(o.into()); 27 | 28 | // Might not be necessary if above TODO is addressed 29 | // Enforce that a = 1 - b, so they both are either 1 or 0 and their sum is 1. 30 | cs.constrain(a + (b - FieldElement::one())); 31 | 32 | Ok(()) 33 | } 34 | -------------------------------------------------------------------------------- /libzmix/bulletproofs_amcl/src/r1cs/gadgets/helper_constraints/mimc.rs: -------------------------------------------------------------------------------- 1 | use crate::errors::R1CSError; 2 | use crate::r1cs::{ConstraintSystem, LinearCombination, Variable}; 3 | use amcl_wrapper::field_elem::FieldElement; 4 | 5 | use crate::r1cs::gadgets::helper_constraints::constrain_lc_with_scalar; 6 | 7 | /// Taken from https://eprint.iacr.org/2016/492, section 2.1, MiMC-2n/n (Feistel). 8 | /// For each round: xl = (xl + constants[i])^3 + xr, xr = xl. Output is xl of last round. 9 | pub fn mimc(xl: &FieldElement, xr: &FieldElement, constants: &[FieldElement]) -> FieldElement { 10 | let mut xl = xl.clone(); 11 | let mut xr = xr.clone(); 12 | 13 | for i in 0..constants.len() { 14 | let tmp1 = &xl + &constants[i]; 15 | let mut tmp2 = tmp1.square() * &tmp1; 16 | tmp2 += &xr; 17 | xr = xl; 18 | xl = tmp2; 19 | } 20 | xl 21 | } 22 | 23 | /// Enforces the constraints of MiMC and check that the output equals `image` 24 | pub fn mimc_gadget( 25 | cs: &mut CS, 26 | left: LinearCombination, 27 | right: LinearCombination, 28 | mimc_constants: &[FieldElement], 29 | image: &FieldElement, 30 | ) -> Result<(), R1CSError> { 31 | let res_v = enforce_mimc_2_inputs::(cs, left, right, mimc_constants)?; 32 | constrain_lc_with_scalar::(cs, res_v, image); 33 | Ok(()) 34 | } 35 | 36 | /// Constraints for MiMC 37 | pub fn enforce_mimc_2_inputs( 38 | cs: &mut CS, 39 | left: LinearCombination, 40 | right: LinearCombination, 41 | mimc_constants: &[FieldElement], 42 | ) -> Result { 43 | let mut left_v = left; 44 | let mut right_v = right; 45 | 46 | for j in 0..mimc_constants.len() { 47 | // xL, xR := xR + (xL + Ci)^3, xL 48 | 49 | let const_lc: LinearCombination = vec![(Variable::One(), mimc_constants[j].clone())] 50 | .iter() 51 | .collect(); 52 | 53 | let left_plus_const: LinearCombination = left_v.clone() + const_lc; 54 | 55 | let (l, _, l_sqr) = cs.multiply(left_plus_const.clone(), left_plus_const); 56 | let (_, _, l_cube) = cs.multiply(l_sqr.into(), l.into()); 57 | 58 | let tmp = l_cube + right_v; 59 | right_v = left_v; 60 | left_v = tmp; 61 | } 62 | Ok(left_v) 63 | } 64 | -------------------------------------------------------------------------------- /libzmix/bulletproofs_amcl/src/r1cs/gadgets/helper_constraints/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::errors::{R1CSError, R1CSErrorKind}; 2 | use crate::r1cs::linear_combination::AllocatedQuantity; 3 | use crate::r1cs::{ConstraintSystem, LinearCombination, Variable}; 4 | use amcl_wrapper::constants::MODBYTES; 5 | use amcl_wrapper::field_elem::FieldElement; 6 | 7 | use rand::{CryptoRng, Rng}; 8 | 9 | pub mod bit; 10 | pub mod mimc; 11 | pub mod non_zero; 12 | pub mod poseidon; 13 | pub mod positive_no; 14 | pub mod sparse_merkle_tree_4_ary; 15 | pub mod sparse_merkle_tree_8_ary; 16 | pub mod vector_sum; 17 | 18 | /// Constrain a linear combination to be equal to a scalar 19 | pub fn constrain_lc_with_scalar( 20 | cs: &mut CS, 21 | lc: LinearCombination, 22 | scalar: &FieldElement, 23 | ) { 24 | cs.constrain(lc - LinearCombination::from(scalar.clone())); 25 | } 26 | 27 | /// Get byte size of number in given `base` with `num_digits` digits in that base 28 | fn get_byte_size(num_digits: usize, base: u8) -> usize { 29 | let num_bits = get_bit_count(num_digits, base); 30 | num_bits / 8 + { 31 | if num_bits % 8 == 0 { 32 | 0 33 | } else { 34 | 1 35 | } 36 | } 37 | } 38 | 39 | /// Get max number of bits in given `base` with `num_digits` digits in that base 40 | fn get_bit_count(num_digits: usize, base: u8) -> usize { 41 | assert!(base.is_power_of_two()); 42 | let num_bits_per_digit = base.trailing_zeros() as usize; 43 | num_digits * num_bits_per_digit 44 | } 45 | 46 | /// Get representation in a base that is a `n`th power of 2 of the given `scalar`. Assumes n <= 8 as 47 | /// n > 8 is not needed anyway where this is being used. Only return `num_digits` of the representation 48 | pub fn get_repr_in_power_2_base(n: u8, scalar: &FieldElement, num_digits: usize) -> Vec { 49 | assert!(n <= 8); 50 | let mut s = scalar.to_bignum(); 51 | s.norm(); 52 | 53 | let mut base_n = vec![]; 54 | while (base_n.len() != num_digits) && (!s.iszilch()) { 55 | base_n.push(s.lastbits(n as usize) as u8); 56 | s.fshr(n as usize); 57 | } 58 | while base_n.len() != num_digits { 59 | base_n.push(0); 60 | } 61 | 62 | base_n.reverse(); 63 | base_n 64 | } 65 | 66 | fn allocated_leaf_index_to_bytes(leaf_index: AllocatedQuantity) -> Option<[u8; MODBYTES]> { 67 | leaf_index.assignment.map(|l| { 68 | let mut b: [u8; MODBYTES] = [0u8; MODBYTES]; 69 | let mut m = l.to_bignum(); 70 | m.tobytes(&mut b); 71 | b.reverse(); 72 | b 73 | }) 74 | } 75 | 76 | /// When doing merkle proofs, the prover might want to hide the leaf index and leaf value both or 77 | /// might only want to hide lead index but reveal leaf value. The following enum is used to indicate 78 | /// whether the prover is hiding the leaf value or (`LeafValueType::Hidden`) or not (`LeafValueType::Known`). 79 | /// Hence the leaf value type being passed to the gadget must be of the required type. 80 | pub enum LeafValueType { 81 | Hidden(Variable), 82 | Known(FieldElement), 83 | } 84 | 85 | impl From for LinearCombination { 86 | fn from(v: LeafValueType) -> LinearCombination { 87 | match v { 88 | LeafValueType::Hidden(v) => LinearCombination::from(v), 89 | LeafValueType::Known(v) => LinearCombination::from(v), 90 | } 91 | } 92 | } 93 | 94 | /// Either get the blindings from the given Option or generate by using the given random number 95 | /// generator. It returns 1 or 2 blindings depending on whether the leaf value is hidden from the 96 | /// verifier or not 97 | pub(crate) fn get_blinding_for_merkle_tree_prover( 98 | hide_leaf: bool, 99 | blindings: Option>, 100 | rng: Option<&mut R>, 101 | ) -> Result, R1CSError> { 102 | if hide_leaf { 103 | // Randomness is only provided for leaf value and leaf index 104 | let blindings = blindings.unwrap_or_else(|| { 105 | let r = rng.unwrap(); 106 | vec![ 107 | FieldElement::random_using_rng(r), 108 | FieldElement::random_using_rng(r), 109 | ] 110 | }); 111 | 112 | if blindings.len() != 2 { 113 | return Err(R1CSErrorKind::GadgetError { 114 | description: String::from("Provided randomness should have size 2"), 115 | } 116 | .into()); 117 | } 118 | Ok(blindings) 119 | } else { 120 | // Randomness is only provided for the leaf index 121 | let blindings = blindings.unwrap_or_else(|| { 122 | let r = rng.unwrap(); 123 | vec![FieldElement::random_using_rng(r)] 124 | }); 125 | 126 | if blindings.len() != 1 { 127 | return Err(R1CSErrorKind::GadgetError { 128 | description: String::from("Provided randomness should have size 1"), 129 | } 130 | .into()); 131 | } 132 | Ok(blindings) 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /libzmix/bulletproofs_amcl/src/r1cs/gadgets/helper_constraints/non_zero.rs: -------------------------------------------------------------------------------- 1 | use crate::errors::R1CSError; 2 | use crate::r1cs::{ConstraintSystem, LinearCombination, Variable}; 3 | use amcl_wrapper::field_elem::FieldElement; 4 | 5 | /// Enforces that x is not 0. 6 | /// Takes x and x_inv as input. 7 | /// The idea is described in the Pinocchio paper in section 3.2, "Zero-Equality Gate". Quoting the paper, 8 | /// "Y = (X! = 0)?1 : 0 is is equivalent to satisfying the following two constraints: X · M −Y = 0 and 9 | /// (1 −Y)· X = 0 for some value M". The constraint is satisfied when M is taken as inverse of x. 10 | /// I first saw it in https://github.com/HarryR/ethsnarks/blob/master/src/gadgets/isnonzero.cpp 11 | pub fn is_nonzero_gadget( 12 | cs: &mut CS, 13 | x: Variable, 14 | x_inv: Variable, 15 | ) -> Result<(), R1CSError> { 16 | let x_lc = LinearCombination::from(x); 17 | let y_lc = LinearCombination::from(FieldElement::one()); 18 | let one_minus_y_lc = LinearCombination::from(Variable::One()) - y_lc.clone(); 19 | 20 | // Question: Maybe the multiplication constraint is not needed, linear constraint might be ok. 21 | // x * (1-y) = 0 22 | let (_, _, o1) = cs.multiply(x_lc.clone(), one_minus_y_lc); 23 | cs.constrain(o1.into()); 24 | 25 | // x * x_inv = y 26 | let inv_lc: LinearCombination = vec![(x_inv, FieldElement::one())].iter().collect(); 27 | let (_, _, o2) = cs.multiply(x_lc.clone(), inv_lc.clone()); 28 | // Output wire should have value `y` 29 | cs.constrain(o2 - y_lc); 30 | 31 | Ok(()) 32 | } 33 | -------------------------------------------------------------------------------- /libzmix/bulletproofs_amcl/src/r1cs/gadgets/helper_constraints/positive_no.rs: -------------------------------------------------------------------------------- 1 | use crate::errors::R1CSError; 2 | use crate::r1cs::ConstraintSystem; 3 | use amcl_wrapper::field_elem::FieldElement; 4 | 5 | use crate::r1cs::linear_combination::AllocatedQuantity; 6 | 7 | /// Enforces that the quantity of v is in the range [0, 2^n). 8 | /// TODO: Explain the "how" and find the origin 9 | pub fn positive_no_gadget( 10 | cs: &mut CS, 11 | v: AllocatedQuantity, 12 | n: usize, 13 | ) -> Result<(), R1CSError> { 14 | let mut constraint_v = vec![(v.variable, FieldElement::minus_one())]; 15 | let mut exp_2 = FieldElement::one(); 16 | for i in 0..n { 17 | // Create low-level variables and add them to constraints 18 | let (a, b, o) = cs.allocate_multiplier(v.assignment.as_ref().map(|q| { 19 | if (q.shift_right(i)).is_odd() { 20 | (FieldElement::zero(), FieldElement::one()) 21 | } else { 22 | (FieldElement::one(), FieldElement::zero()) 23 | } 24 | }))?; 25 | 26 | // Enforce a * b = 0, so one of (a,b) is zero 27 | cs.constrain(o.into()); 28 | 29 | // Enforce that a = 1 - b, so they both are 1 or 0. 30 | cs.constrain(a + (b - FieldElement::one())); 31 | 32 | constraint_v.push((b, exp_2.clone())); 33 | exp_2 = &exp_2 + &exp_2; 34 | } 35 | 36 | // Enforce that -v + Sum(b_i * 2^i, i = 0..n-1) = 0 => Sum(b_i * 2^i, i = 0..n-1) = v 37 | cs.constrain(constraint_v.iter().collect()); 38 | 39 | Ok(()) 40 | } 41 | -------------------------------------------------------------------------------- /libzmix/bulletproofs_amcl/src/r1cs/gadgets/helper_constraints/vector_sum.rs: -------------------------------------------------------------------------------- 1 | use crate::r1cs::{ConstraintSystem, Variable}; 2 | use amcl_wrapper::field_elem::FieldElement; 3 | 4 | // Ensure sum of items of `vector` is `sum` 5 | pub fn vector_sum_constraints(cs: &mut CS, vector: Vec, sum: u64) { 6 | let mut constraints = vec![(Variable::One(), FieldElement::from(sum).negation())]; 7 | for i in vector { 8 | constraints.push((i, FieldElement::one())); 9 | } 10 | cs.constrain(constraints.iter().collect()); 11 | } 12 | -------------------------------------------------------------------------------- /libzmix/bulletproofs_amcl/src/r1cs/gadgets/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | 3 | extern crate merlin; 4 | extern crate rand; 5 | 6 | pub mod bound_check; 7 | // TODO: Uncomment 8 | //pub mod hamming_distance; 9 | pub mod helper_constraints; 10 | pub mod mimc; 11 | pub mod non_zero; 12 | pub mod poseidon_constants; 13 | pub mod poseidon_hash; 14 | // TODO: Uncomment 15 | //pub mod randomizer; 16 | pub mod merkle_tree_hash; 17 | pub mod set_membership; 18 | pub mod set_membership_alt; 19 | pub mod set_non_membership; 20 | pub mod sparse_merkle_tree_4_ary; 21 | pub mod sparse_merkle_tree_8_ary; 22 | -------------------------------------------------------------------------------- /libzmix/bulletproofs_amcl/src/r1cs/gadgets/non_zero.rs: -------------------------------------------------------------------------------- 1 | use super::helper_constraints::non_zero::is_nonzero_gadget; 2 | use crate::errors::{R1CSError, R1CSErrorKind}; 3 | use crate::r1cs::{Prover, R1CSProof, Verifier}; 4 | use amcl_wrapper::field_elem::FieldElement; 5 | use amcl_wrapper::group_elem_g1::{G1Vector, G1}; 6 | use merlin::Transcript; 7 | use rand::{CryptoRng, Rng}; 8 | 9 | pub fn prove_non_zero_val( 10 | value: FieldElement, 11 | blinding: Option, 12 | rng: Option<&mut R>, 13 | prover: &mut Prover, 14 | ) -> Result, R1CSError> { 15 | check_for_blindings_or_rng!(blinding, rng)?; 16 | 17 | let inv = value.inverse(); 18 | let mut comms = vec![]; 19 | 20 | let (com_val, var_val) = prover.commit( 21 | value, 22 | blinding.unwrap_or_else(|| FieldElement::random_using_rng(rng.unwrap())), 23 | ); 24 | 25 | comms.push(com_val); 26 | 27 | let (com_val_inv, var_val_inv) = prover.commit(inv, FieldElement::random()); 28 | 29 | comms.push(com_val_inv); 30 | 31 | is_nonzero_gadget(prover, var_val, var_val_inv)?; 32 | 33 | Ok(comms) 34 | } 35 | 36 | pub fn verify_non_zero_val( 37 | mut commitments: Vec, 38 | verifier: &mut Verifier, 39 | ) -> Result<(), R1CSError> { 40 | let var_val = verifier.commit(commitments.remove(0)); 41 | 42 | let var_val_inv = verifier.commit(commitments.remove(0)); 43 | 44 | is_nonzero_gadget(verifier, var_val, var_val_inv)?; 45 | 46 | Ok(()) 47 | } 48 | 49 | /// Accepts the num which is to be proved non-zero and optionally the randomness used in committing to that number. 50 | /// This randomness argument is accepted so that this can be used as a sub-protocol where the protocol on upper layer will create the commitment. 51 | pub fn gen_proof_of_non_zero_val( 52 | value: FieldElement, 53 | blinding: Option, 54 | rng: Option<&mut R>, 55 | transcript_label: &'static [u8], 56 | g: &G1, 57 | h: &G1, 58 | G: &G1Vector, 59 | H: &G1Vector, 60 | ) -> Result<(R1CSProof, Vec), R1CSError> { 61 | let mut prover_transcript = Transcript::new(transcript_label); 62 | let mut prover = Prover::new(g, h, &mut prover_transcript); 63 | 64 | let comms = prove_non_zero_val(value, blinding, rng, &mut prover)?; 65 | let proof = prover.prove(G, H)?; 66 | 67 | Ok((proof, comms)) 68 | } 69 | 70 | pub fn verify_proof_of_non_zero_val( 71 | proof: R1CSProof, 72 | commitments: Vec, 73 | transcript_label: &'static [u8], 74 | g: &G1, 75 | h: &G1, 76 | G: &G1Vector, 77 | H: &G1Vector, 78 | ) -> Result<(), R1CSError> { 79 | let mut verifier_transcript = Transcript::new(transcript_label); 80 | let mut verifier = Verifier::new(&mut verifier_transcript); 81 | 82 | verify_non_zero_val(commitments, &mut verifier)?; 83 | verifier.verify(&proof, g, h, G, H) 84 | } 85 | 86 | #[cfg(test)] 87 | mod tests { 88 | use super::*; 89 | use crate::utils::get_generators; 90 | use amcl_wrapper::group_elem::GroupElement; 91 | 92 | #[test] 93 | fn test_non_zero_gadget() { 94 | let mut rng = rand::thread_rng(); 95 | 96 | let value = FieldElement::random(); 97 | 98 | let G: G1Vector = get_generators("G", 32).into(); 99 | let H: G1Vector = get_generators("H", 32).into(); 100 | let g = G1::from_msg_hash("g".as_bytes()); 101 | let h = G1::from_msg_hash("h".as_bytes()); 102 | 103 | let label = b"NonZero"; 104 | let (proof, commitments) = 105 | gen_proof_of_non_zero_val(value, None, Some(&mut rng), label, &g, &h, &G, &H).unwrap(); 106 | 107 | verify_proof_of_non_zero_val(proof, commitments, label, &g, &h, &G, &H).unwrap(); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /libzmix/bulletproofs_amcl/src/r1cs/gadgets/sage/create_mds_pf.sage: -------------------------------------------------------------------------------- 1 | # For GF(p) 2 | 3 | if len(sys.argv) < 4: 4 | print "Usage: