├── .gitignore
├── res
└── bubblesort-zines-secret-messages-cover.jpeg
├── .travis.yml
├── docs
└── assets
│ └── rustdoc-include-katex-header.html
├── src
├── lib.rs
└── x25519.rs
├── benches
└── x25519.rs
├── CONTRIBUTING.md
├── LICENSE
├── Cargo.toml
├── CHANGELOG.md
├── .github
└── workflows
│ └── rust.yml
├── README.md
├── tests
└── x25519_tests.rs
└── Cargo.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | **/*.rs.bk
3 |
4 | .cargo
5 |
6 | *~
7 | \#*
8 | .\#*
9 | *.swp
10 | *.orig
11 | *.bak
12 |
13 | *.s
14 |
--------------------------------------------------------------------------------
/res/bubblesort-zines-secret-messages-cover.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dalek-cryptography/x25519-dalek/HEAD/res/bubblesort-zines-secret-messages-cover.jpeg
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: rust
2 |
3 | rust:
4 | - nightly
5 |
6 | env:
7 | - TEST_COMMAND=test EXTRA_FLAGS='' FEATURES='default'
8 | - TEST_COMMAND=test EXTRA_FLAGS='' FEATURES='nightly'
9 | - TEST_COMMAND=bench EXTRA_FLAGS='' FEATURES='default'
10 | - TEST_COMMAND=build EXTRA_FLAGS='--no-default-features' FEATURES='u32_backend nightly'
11 | - TEST_COMMAND=build EXTRA_FLAGS='--no-default-features' FEATURES='u64_backend nightly'
12 |
13 | matrix:
14 | include:
15 | - rust: stable
16 | env: TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std u64_backend'
17 | - rust: beta
18 | env: TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std u64_backend'
19 |
20 | script:
21 | - cargo $TEST_COMMAND --features="$FEATURES" $EXTRA_FLAGS
22 |
23 | notifications:
24 | slack:
25 | rooms:
26 | - dalek-cryptography:Xxv9WotKYWdSoKlgKNqXiHoD#dalek-bots
27 |
--------------------------------------------------------------------------------
/docs/assets/rustdoc-include-katex-header.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
9 |
10 |
13 |
--------------------------------------------------------------------------------
/src/lib.rs:
--------------------------------------------------------------------------------
1 | // -*- mode: rust; -*-
2 | //
3 | // This file is part of x25519-dalek.
4 | // Copyright (c) 2017-2021 isis lovecruft
5 | // Copyright (c) 2019-2021 DebugSteven
6 | // See LICENSE for licensing information.
7 | //
8 | // Authors:
9 | // - isis agora lovecruft
10 | // - DebugSteven
11 |
12 | // Refuse to compile if documentation is missing, but only on nightly.
13 | //
14 | // This means that missing docs will still fail CI, but means we can use
15 | // README.md as the crate documentation.
16 |
17 | #![no_std]
18 | #![cfg_attr(feature = "bench", feature(test))]
19 | #![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg, doc_cfg_hide))]
20 | #![cfg_attr(docsrs, doc(cfg_hide(docsrs)))]
21 | #![deny(missing_docs)]
22 | #![doc(
23 | html_logo_url = "https://cdn.jsdelivr.net/gh/dalek-cryptography/curve25519-dalek/docs/assets/dalek-logo-clear.png"
24 | )]
25 | #![doc = include_str!("../README.md")]
26 |
27 | //------------------------------------------------------------------------
28 | // x25519-dalek public API
29 | //------------------------------------------------------------------------
30 |
31 | mod x25519;
32 |
33 | pub use crate::x25519::*;
34 |
--------------------------------------------------------------------------------
/benches/x25519.rs:
--------------------------------------------------------------------------------
1 | // -*- mode: rust; -*-
2 | //
3 | // This file is part of x25519-dalek.
4 | // Copyright (c) 2017-2019 isis agora lovecruft
5 | // Copyright (c) 2019 DebugSteven
6 | // See LICENSE for licensing information.
7 | //
8 | // Authors:
9 | // - isis agora lovecruft
10 | // - DebugSteven
11 |
12 | //! Benchmark the Diffie-Hellman operation.
13 |
14 | use criterion::{criterion_group, criterion_main, Criterion};
15 |
16 | use rand_core::OsRng;
17 |
18 | use x25519_dalek::EphemeralSecret;
19 | use x25519_dalek::PublicKey;
20 |
21 | fn bench_diffie_hellman(c: &mut Criterion) {
22 | let bob_secret = EphemeralSecret::random_from_rng(OsRng);
23 | let bob_public = PublicKey::from(&bob_secret);
24 |
25 | c.bench_function("diffie_hellman", move |b| {
26 | b.iter_with_setup(
27 | || EphemeralSecret::random_from_rng(OsRng),
28 | |alice_secret| alice_secret.diffie_hellman(&bob_public),
29 | )
30 | });
31 | }
32 |
33 | criterion_group! {
34 | name = x25519_benches;
35 | config = Criterion::default();
36 | targets =
37 | bench_diffie_hellman,
38 | }
39 | criterion_main! {
40 | x25519_benches,
41 | }
42 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to curve25519-dalek
2 |
3 | If you have questions or comments, please feel free to email the
4 | authors.
5 |
6 | For feature requests, suggestions, and bug reports, please open an issue on
7 | [our Github](https://github.com/dalek-cryptography/x25519-dalek). (Or, send us
8 | an email if you're opposed to using Github for whatever reason.)
9 |
10 | Patches are welcomed as pull requests on
11 | [our Github](https://github.com/dalek-cryptography/x25519-dalek), as well as by
12 | email (preferably sent to all of the authors listed in `Cargo.toml`).
13 |
14 | All issues on curve25519-dalek are mentored, if you want help with a bug just
15 | ask @isislovecruft.
16 |
17 | Some issues are easier than others. The `easy` label can be used to find the
18 | easy issues. If you want to work on an issue, please leave a comment so that we
19 | can assign it to you!
20 |
21 | # Code of Conduct
22 |
23 | We follow the [Rust Code of Conduct](http://www.rust-lang.org/conduct.html),
24 | with the following additional clauses:
25 |
26 | * We respect the rights to privacy and anonymity for contributors and people in
27 | the community. If someone wishes to contribute under a pseudonym different to
28 | their primary identity, that wish is to be respected by all contributors.
29 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2017-2021 isis agora lovecruft. All rights reserved.
2 | Copyright (c) 2019-2021 DebugSteven. All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are
6 | met:
7 |
8 | 1. Redistributions of source code must retain the above copyright
9 | notice, this list of conditions and the following disclaimer.
10 |
11 | 2. Redistributions in binary form must reproduce the above copyright
12 | notice, this list of conditions and the following disclaimer in the
13 | documentation and/or other materials provided with the distribution.
14 |
15 | 3. Neither the name of the copyright holder nor the names of its
16 | contributors may be used to endorse or promote products derived from
17 | this software without specific prior written permission.
18 |
19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
20 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
25 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "x25519-dalek"
3 | edition = "2021"
4 | # Before changing this:
5 | # - update version in README.md
6 | # - update html_root_url
7 | # - update CHANGELOG
8 | # - if any changes were made to README.md, mirror them in src/lib.rs docs
9 | version = "2.0.0-rc.3"
10 | authors = [
11 | "Isis Lovecruft ",
12 | "DebugSteven ",
13 | "Henry de Valence ",
14 | ]
15 | readme = "README.md"
16 | license = "BSD-3-Clause"
17 | repository = "https://github.com/dalek-cryptography/x25519-dalek"
18 | homepage = "https://dalek.rs/"
19 | documentation = "https://docs.rs/x25519-dalek"
20 | categories = ["cryptography", "no-std"]
21 | keywords = ["cryptography", "curve25519", "key-exchange", "x25519", "diffie-hellman"]
22 | description = "X25519 elliptic curve Diffie-Hellman key exchange in pure-Rust, using curve25519-dalek."
23 | exclude = [
24 | ".gitignore",
25 | ".travis.yml",
26 | "CONTRIBUTING.md",
27 | ]
28 | rust-version = "1.60"
29 |
30 | [badges]
31 | travis-ci = { repository = "dalek-cryptography/x25519-dalek", branch = "master"}
32 |
33 | [package.metadata.docs.rs]
34 | rustdoc-args = [
35 | "--html-in-header", "docs/assets/rustdoc-include-katex-header.html",
36 | "--cfg", "docsrs",
37 | ]
38 | features = ["getrandom", "reusable_secrets", "serde", "static_secrets"]
39 |
40 | [dependencies]
41 | curve25519-dalek = { version = "=4.0.0-rc.3", default-features = false }
42 | rand_core = { version = "0.6", default-features = false }
43 | serde = { version = "1", default-features = false, optional = true, features = ["derive"] }
44 | zeroize = { version = "1", default-features = false, optional = true, features = ["zeroize_derive"] }
45 |
46 | [dev-dependencies]
47 | bincode = "1"
48 | criterion = "0.4.0"
49 | rand_core = { version = "0.6", default-features = false, features = ["getrandom"] }
50 |
51 | [[bench]]
52 | name = "x25519"
53 | harness = false
54 |
55 | [features]
56 | default = ["alloc", "precomputed-tables", "zeroize"]
57 | getrandom = ["rand_core/getrandom"]
58 | zeroize = ["dep:zeroize", "curve25519-dalek/zeroize"]
59 | serde = ["dep:serde", "curve25519-dalek/serde"]
60 | alloc = ["curve25519-dalek/alloc", "serde?/alloc", "zeroize?/alloc"]
61 | precomputed-tables = ["curve25519-dalek/precomputed-tables"]
62 | reusable_secrets = []
63 | static_secrets = []
64 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | Entries are listed in reverse chronological order.
4 |
5 | # 2.x Series
6 |
7 | * Note: All `x255919-dalek` 2.x releases are in sync with the underlying `curve25519-dalek` 4.x releases.
8 |
9 | ## 2.0.0-rc.3
10 |
11 | * `StaticSecret` serialization and `to_bytes()` no longer returns clamped integers. Clamping is still always done during scalar-point multiplication.
12 | * Update underlying `curve25519_dalek` library to `4.0.0-rc.3`. Notable changes:
13 | * [curve25519-dalek backend] now by default auto selects `simd` backend over `serial` where supported.
14 |
15 |
16 | ## 2.0.0-rc.2
17 |
18 | * Update MSRV to 1.60.
19 | * Update edition to 2021
20 | * Add `.as_bytes()` and `AsRef<[u8]>` for `Shared/StaticSecret`
21 | * Add `getrandom` feature to provide `random_from_rng` constructors
22 | * Make `StaticSecrets` optional via feature `static_secrets`
23 | * Update underlying `curve25519_dalek` library to `4.0.0-rc.2`. Notable changes:
24 | * [curve25519-dalek backend] additive features have been removed in favor of cfg based selection.
25 | * [curve25519-dalek backend] now by default auto selects the appropriate word size over the previous default `32`.
26 |
27 | ## 2.0.0-pre.1
28 |
29 | * Loosen restriction on zeroize dependency version from =1.3 to 1.
30 | * Update MSRV to 1.51.
31 |
32 | ## 2.0.0-pre.0
33 |
34 | * Update `rand_core` dependency to `0.6`.
35 |
36 | # 1.x Series
37 |
38 | ## 1.2
39 |
40 | * Add module documentation for using the bytes-oriented `x25519()` API.
41 | * Add implementation of `zeroize::Zeroize` for `PublicKey`.
42 | * Move unittests to a separate directory.
43 | * Add cargo feature flags `"fiat_u32_backend"` and `"fiat_u64_backend"` for
44 | activating the Fiat crypto field element implementations.
45 | * Fix issue with removed `feature(external_doc)` on nightly compilers.
46 | * Pin `zeroize` to version 1.3 to support a wider range of MSRVs.
47 | * Add CI via Github actions.
48 | * Fix breakage in the serde unittests.
49 | * MSRV is now 1.41 for production and 1.48 for development.
50 | * Add an optional check to `SharedSecret` for contibutory behaviour.
51 | * Add implementation of `ReusableSecret` keys which are non-ephemeral, but which
52 | cannot be serialised to discourage long-term use.
53 |
54 | ## 1.1.1
55 |
56 | * Fix a typo in the README.
57 |
58 | ## 1.1.0
59 |
60 | * Add impls of `PartialEq`, `Eq`, and `Hash` for `PublicKey` (by @jack-michaud)
61 |
62 | ## 1.0.1
63 |
64 | * Update underlying `curve25519_dalek` library to `3.0`.
65 |
66 | ## 1.0.0
67 |
68 | * Widen generic bound on `EphemeralSecret::new` and `StaticSecret::new` to
69 | allow owned as well as borrowed RNGs.
70 | * Add `PublicKey::to_bytes` and `SharedSecret::to_bytes`, returning owned byte
71 | arrays, complementing the existing `as_bytes` methods returning references.
72 | * Remove mention of deprecated `rand_os` crate from examples.
73 | * Clarify `EphemeralSecret`/`StaticSecret` distinction in documentation.
74 |
75 | # Pre-1.0.0
76 |
77 | ## 0.6.0
78 |
79 | * Updates `rand_core` version to `0.5`.
80 | * Adds `serde` support.
81 | * Replaces `clear_on_drop` with `zeroize`.
82 | * Use Rust 2018.
83 |
84 | ## 0.5.2
85 |
86 | * Implement `Clone` for `StaticSecret`.
87 |
88 | ## 0.5.1
89 |
90 | * Implement `Copy, Clone, Debug` for `PublicKey`.
91 | * Remove doctests.
92 |
93 | ## 0.5.0
94 |
95 | * Adds support for static and ephemeral keys.
96 |
97 | [curve25519-dalek backend]: https://github.com/dalek-cryptography/curve25519-dalek/#backends
98 |
99 |
--------------------------------------------------------------------------------
/.github/workflows/rust.yml:
--------------------------------------------------------------------------------
1 | name: Rust
2 |
3 | on:
4 | push:
5 | branches: [ '**' ]
6 | pull_request:
7 | branches: [ '**' ]
8 |
9 | env:
10 | CARGO_TERM_COLOR: always
11 | RUSTFLAGS: '-D warnings'
12 | RUSTDOCFLAGS: '-D warnings'
13 |
14 | jobs:
15 | test:
16 | name: Test with multiple feature combinations
17 | runs-on: ubuntu-latest
18 | strategy:
19 | matrix:
20 | include:
21 | # 32-bit target
22 | - target: i686-unknown-linux-gnu
23 | deps: sudo apt update && sudo apt install gcc-multilib
24 | # 64-bit target
25 | - target: x86_64-unknown-linux-gnu
26 | steps:
27 | - uses: actions/checkout@v3
28 | - uses: dtolnay/rust-toolchain@stable
29 | with:
30 | target: ${{ matrix.target }}
31 | - run: ${{ matrix.deps }}
32 | - run: cargo test --target ${{ matrix.target }} --no-default-features
33 | - run: cargo test --target ${{ matrix.target }} --no-default-features --features reusable_secrets
34 | - run: cargo test --target ${{ matrix.target }} --no-default-features --features static_secrets
35 | - run: cargo test --target ${{ matrix.target }}
36 | - run: cargo test --target ${{ matrix.target }} --all-features
37 |
38 | build-simd:
39 | name: Test simd backend (nightly)
40 | runs-on: ubuntu-latest
41 | steps:
42 | - uses: actions/checkout@v3
43 | - uses: dtolnay/rust-toolchain@nightly
44 | - env:
45 | RUSTFLAGS: '--cfg curve25519_dalek_backend="simd" -C target_feature=+avx2'
46 | run: cargo build --target x86_64-unknown-linux-gnu
47 | - env:
48 | RUSTFLAGS: '--cfg curve25519_dalek_backend="simd" -C target_feature=+avx512ifma'
49 | run: cargo build --target x86_64-unknown-linux-gnu
50 |
51 | msrv:
52 | name: Current MSRV is 1.60.0
53 | runs-on: ubuntu-latest
54 | steps:
55 | - uses: actions/checkout@v3
56 | # First delete the checked-in `Cargo.lock`. We're going to regenerate it
57 | - run: rm Cargo.lock
58 | # Now run `cargo +nightly -Z minimal-verisons check` in order to get a
59 | # Cargo.lock with the oldest possible deps
60 | - uses: dtolnay/rust-toolchain@nightly
61 | - run: cargo -Z minimal-versions check --no-default-features --features serde
62 | # Now check that `cargo build` works with respect to the oldest possible
63 | # deps and the stated MSRV
64 | - uses: dtolnay/rust-toolchain@1.60.0
65 | - run: cargo build
66 |
67 | # no_std support is pending feature, tracking:
68 | # https://github.com/dalek-cryptography/x25519-dalek/issues/111
69 | # # Test no_std integration with no features
70 | # build-nostd-base:
71 | # name: Build on no_std target (thumbv7em-none-eabi)
72 | # runs-on: ubuntu-latest
73 | # steps:
74 | # - uses: actions/checkout@v3
75 | # - uses: dtolnay/rust-toolchain@master
76 | # with:
77 | # toolchain: stable
78 | # targets: thumbv7em-none-eabi
79 | # - uses: taiki-e/install-action@cargo-hack
80 | # # No default features build
81 | # - run: cargo build --target thumbv7em-none-eabi --release --no-default-features
82 | #
83 | # # Test no_std integration with all no_std features
84 | # build-nostd-features:
85 | # name: Build on no_std target (thumbv7em-none-eabi)
86 | # runs-on: ubuntu-latest
87 | # steps:
88 | # - uses: actions/checkout@v3
89 | # - uses: dtolnay/rust-toolchain@master
90 | # with:
91 | # toolchain: stable
92 | # targets: thumbv7em-none-eabi
93 | # - uses: taiki-e/install-action@cargo-hack
94 | # # No default features build
95 | # - run: cargo hack build --target thumbv7em-none-eabi --release --each-feature --exclude-features default,std
96 |
97 | bench:
98 | name: Check that benchmarks compile
99 | runs-on: ubuntu-latest
100 | steps:
101 | - uses: actions/checkout@v3
102 | - uses: dtolnay/rust-toolchain@stable
103 | - run: cargo build --benches
104 |
105 | rustfmt:
106 | name: Check formatting
107 | runs-on: ubuntu-latest
108 | steps:
109 | - uses: actions/checkout@v3
110 | - uses: dtolnay/rust-toolchain@stable
111 | with:
112 | components: rustfmt
113 | - run: cargo fmt --all -- --check
114 |
115 | clippy:
116 | name: Check that clippy is happy
117 | runs-on: ubuntu-latest
118 | steps:
119 | - uses: actions/checkout@v3
120 | - uses: dtolnay/rust-toolchain@1.65
121 | with:
122 | components: clippy
123 | - run: cargo clippy
124 |
125 | doc:
126 | runs-on: ubuntu-latest
127 | steps:
128 | - uses: actions/checkout@v3
129 | - uses: dtolnay/rust-toolchain@stable
130 | with:
131 | toolchain: stable
132 | - run: cargo doc --all-features
133 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ARCHIVED
2 |
3 | This repo has been [moved](https://github.com/dalek-cryptography/curve25519-dalek). Please direct all issues and pull requests to the new repo.
4 |
5 | This repo will remain here in a read-only state for historical purposes.
6 |
7 | ---
8 |
9 | # x25519-dalek [](https://crates.io/crates/x25519-dalek) [](https://docs.rs/x25519-dalek) [](https://travis-ci.org/dalek-cryptography/x25519-dalek)
10 |
11 | A pure-Rust implementation of x25519 elliptic curve Diffie-Hellman key exchange,
12 | with curve operations provided by
13 | [curve25519-dalek](https://github.com/dalek-cryptography/curve25519-dalek).
14 |
15 | This crate provides two levels of API: a bare byte-oriented `x25519`
16 | function which matches the function specified in [RFC7748][rfc7748], as
17 | well as a higher-level Rust API for static and ephemeral Diffie-Hellman.
18 |
19 | ## Examples
20 |
21 |
22 |
25 |
26 |
27 | Alice and Bob are two adorable kittens who have lost their mittens, and they
28 | wish to be able to send secret messages to each other to coordinate finding
29 | them, otherwise—if their caretaker cat finds out—they will surely be called
30 | naughty kittens and be given no pie!
31 |
32 | But the two kittens are quite clever. Even though their paws are still too big
33 | and the rest of them is 90% fuzziness, these clever kittens have been studying
34 | up on modern public key cryptography and have learned a nifty trick called
35 | *elliptic curve Diffie-Hellman key exchange*. With the right incantations, the
36 | kittens will be able to secretly organise to find their mittens, and then spend
37 | the rest of the afternoon nomming some yummy pie!
38 |
39 | First, Alice uses `EphemeralSecret::random()` and then
40 | `PublicKey::from()` to produce her secret and public keys:
41 |
42 | ```ignore
43 | use x25519_dalek::{EphemeralSecret, PublicKey};
44 |
45 | let alice_secret = EphemeralSecret::random();
46 | let alice_public = PublicKey::from(&alice_secret);
47 | ```
48 |
49 | Bob does the same:
50 |
51 | ```ignore
52 | # use x25519_dalek::{EphemeralSecret, PublicKey};
53 | let bob_secret = EphemeralSecret::random();
54 | let bob_public = PublicKey::from(&bob_secret);
55 | ```
56 |
57 | Alice meows across the room, telling `alice_public` to Bob, and Bob
58 | loudly meows `bob_public` back to Alice. Alice now computes her
59 | shared secret with Bob by doing:
60 |
61 | ```rust
62 | # use rand_core::OsRng;
63 | # use x25519_dalek::{EphemeralSecret, PublicKey};
64 | # let alice_secret = EphemeralSecret::new(OsRng);
65 | # let alice_public = PublicKey::from(&alice_secret);
66 | # let bob_secret = EphemeralSecret::new(OsRng);
67 | # let bob_public = PublicKey::from(&bob_secret);
68 | let alice_shared_secret = alice_secret.diffie_hellman(&bob_public);
69 | ```
70 |
71 | Similarly, Bob computes a shared secret by doing:
72 |
73 | ```rust
74 | # use rand_core::OsRng;
75 | # use x25519_dalek::{EphemeralSecret, PublicKey};
76 | # let alice_secret = EphemeralSecret::new(OsRng);
77 | # let alice_public = PublicKey::from(&alice_secret);
78 | # let bob_secret = EphemeralSecret::new(OsRng);
79 | # let bob_public = PublicKey::from(&bob_secret);
80 | let bob_shared_secret = bob_secret.diffie_hellman(&alice_public);
81 | ```
82 |
83 | These secrets are the same:
84 |
85 | ```rust
86 | # use rand_core::OsRng;
87 | # use x25519_dalek::{EphemeralSecret, PublicKey};
88 | # let alice_secret = EphemeralSecret::new(OsRng);
89 | # let alice_public = PublicKey::from(&alice_secret);
90 | # let bob_secret = EphemeralSecret::new(OsRng);
91 | # let bob_public = PublicKey::from(&bob_secret);
92 | # let alice_shared_secret = alice_secret.diffie_hellman(&bob_public);
93 | # let bob_shared_secret = bob_secret.diffie_hellman(&alice_public);
94 | assert_eq!(alice_shared_secret.as_bytes(), bob_shared_secret.as_bytes());
95 | ```
96 |
97 | Voilà! Alice and Bob can now use their shared secret to encrypt their
98 | meows, for example, by using it to generate a key and nonce for an
99 | authenticated-encryption cipher.
100 |
101 | This example used the ephemeral DH API, which ensures that secret keys
102 | cannot be reused; Alice and Bob could instead use the static DH API
103 | and load a long-term secret key.
104 |
105 | # Installation
106 |
107 | To install, add the following to your project's `Cargo.toml`:
108 |
109 | ```toml
110 | [dependencies]
111 | x25519-dalek = "2.0.0-rc.3"
112 | ```
113 |
114 | # MSRV
115 |
116 | Current MSRV is 1.60.
117 |
118 | # Documentation
119 |
120 | Documentation is available [here](https://docs.rs/x25519-dalek).
121 |
122 | # Performance and backend selection
123 |
124 | Performance is a secondary goal behind correctness, safety, and clarity, but we aim to be competitive with other implementations. To this end, we allow users to choose their _backend_, i.e., the underlying implementation of elliptic curve and scalar arithmetic. Different backends have different use cases. For example, if you demand formally verified code, you want to use the `fiat` backend (as it was generated from [Fiat Crypto][fiat]).
125 |
126 | Further instructions and details regarding backends can be found in the [curve25519-dalek docs](https://github.com/dalek-cryptography/curve25519-dalek#backends).
127 |
128 | # Note
129 |
130 | This code matches the [RFC7748][rfc7748] test vectors.
131 | The elliptic curve
132 | operations are provided by `curve25519-dalek`, which makes a best-effort
133 | attempt to prevent software side-channels.
134 |
135 | "Secret Messages" cover image and [zine](https://shop.bubblesort.io/products/secret-messages-zine)
136 | copyright © Amy Wibowo ([@sailorhg](https://twitter.com/sailorhg))
137 |
138 | [rfc7748]: https://tools.ietf.org/html/rfc7748
139 |
140 | # See also
141 |
142 | - [crypto_box]: pure Rust public-key authenticated encryption compatible with
143 | the NaCl family of encryption libraries (libsodium, TweetNaCl) which uses
144 | `x25519-dalek` for key agreement
145 |
146 | [fiat]: https://github.com/mit-plv/fiat-crypto
147 | [crypto_box]: https://github.com/RustCrypto/nacl-compat/tree/master/crypto_box
148 |
--------------------------------------------------------------------------------
/tests/x25519_tests.rs:
--------------------------------------------------------------------------------
1 | use curve25519_dalek::edwards::EdwardsPoint;
2 |
3 | use x25519_dalek::*;
4 |
5 | #[test]
6 | fn byte_basepoint_matches_edwards_scalar_mul() {
7 | let mut scalar_bytes = [0x37; 32];
8 |
9 | for i in 0..32 {
10 | scalar_bytes[i] += 2;
11 |
12 | let result = x25519(scalar_bytes, X25519_BASEPOINT_BYTES);
13 | let expected = EdwardsPoint::mul_base_clamped(scalar_bytes)
14 | .to_montgomery()
15 | .to_bytes();
16 |
17 | assert_eq!(result, expected);
18 | }
19 | }
20 |
21 | #[test]
22 | #[cfg(feature = "serde")]
23 | fn serde_bincode_public_key_roundtrip() {
24 | use bincode;
25 |
26 | let public_key = PublicKey::from(X25519_BASEPOINT_BYTES);
27 |
28 | let encoded = bincode::serialize(&public_key).unwrap();
29 | let decoded: PublicKey = bincode::deserialize(&encoded).unwrap();
30 |
31 | assert_eq!(encoded.len(), 32);
32 | assert_eq!(decoded.as_bytes(), public_key.as_bytes());
33 | }
34 |
35 | #[test]
36 | #[cfg(feature = "serde")]
37 | fn serde_bincode_public_key_matches_from_bytes() {
38 | use bincode;
39 |
40 | let expected = PublicKey::from(X25519_BASEPOINT_BYTES);
41 | let decoded: PublicKey = bincode::deserialize(&X25519_BASEPOINT_BYTES).unwrap();
42 |
43 | assert_eq!(decoded.as_bytes(), expected.as_bytes());
44 | }
45 |
46 | #[test]
47 | #[cfg(feature = "serde")]
48 | fn serde_bincode_static_secret_roundtrip() {
49 | use bincode;
50 |
51 | let static_secret = StaticSecret::from([0x24; 32]);
52 | let encoded = bincode::serialize(&static_secret).unwrap();
53 | let decoded: StaticSecret = bincode::deserialize(&encoded).unwrap();
54 |
55 | assert_eq!(encoded.len(), 32);
56 | assert_eq!(decoded.to_bytes(), static_secret.to_bytes());
57 | }
58 |
59 | #[test]
60 | #[cfg(feature = "serde")]
61 | fn serde_bincode_static_secret_matches_from_bytes() {
62 | use bincode;
63 |
64 | let expected = StaticSecret::from([0x24; 32]);
65 | let decoded: StaticSecret = bincode::deserialize(&[0x24; 32]).unwrap();
66 |
67 | assert_eq!(decoded.to_bytes(), expected.to_bytes());
68 | }
69 |
70 | fn do_rfc7748_ladder_test1(input_scalar: [u8; 32], input_point: [u8; 32], expected: [u8; 32]) {
71 | let result = x25519(input_scalar, input_point);
72 |
73 | assert_eq!(result, expected);
74 | }
75 |
76 | #[test]
77 | fn rfc7748_ladder_test1_vectorset1() {
78 | let input_scalar: [u8; 32] = [
79 | 0xa5, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d, 0x3b, 0x16, 0x15, 0x4b, 0x82, 0x46, 0x5e,
80 | 0xdd, 0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc, 0x5a, 0x18, 0x50, 0x6a, 0x22, 0x44, 0xba, 0x44,
81 | 0x9a, 0xc4,
82 | ];
83 | let input_point: [u8; 32] = [
84 | 0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb, 0x35, 0x94, 0xc1, 0xa4, 0x24, 0xb1, 0x5f,
85 | 0x7c, 0x72, 0x66, 0x24, 0xec, 0x26, 0xb3, 0x35, 0x3b, 0x10, 0xa9, 0x03, 0xa6, 0xd0, 0xab,
86 | 0x1c, 0x4c,
87 | ];
88 | let expected: [u8; 32] = [
89 | 0xc3, 0xda, 0x55, 0x37, 0x9d, 0xe9, 0xc6, 0x90, 0x8e, 0x94, 0xea, 0x4d, 0xf2, 0x8d, 0x08,
90 | 0x4f, 0x32, 0xec, 0xcf, 0x03, 0x49, 0x1c, 0x71, 0xf7, 0x54, 0xb4, 0x07, 0x55, 0x77, 0xa2,
91 | 0x85, 0x52,
92 | ];
93 |
94 | do_rfc7748_ladder_test1(input_scalar, input_point, expected);
95 | }
96 |
97 | #[test]
98 | fn rfc7748_ladder_test1_vectorset2() {
99 | let input_scalar: [u8; 32] = [
100 | 0x4b, 0x66, 0xe9, 0xd4, 0xd1, 0xb4, 0x67, 0x3c, 0x5a, 0xd2, 0x26, 0x91, 0x95, 0x7d, 0x6a,
101 | 0xf5, 0xc1, 0x1b, 0x64, 0x21, 0xe0, 0xea, 0x01, 0xd4, 0x2c, 0xa4, 0x16, 0x9e, 0x79, 0x18,
102 | 0xba, 0x0d,
103 | ];
104 | let input_point: [u8; 32] = [
105 | 0xe5, 0x21, 0x0f, 0x12, 0x78, 0x68, 0x11, 0xd3, 0xf4, 0xb7, 0x95, 0x9d, 0x05, 0x38, 0xae,
106 | 0x2c, 0x31, 0xdb, 0xe7, 0x10, 0x6f, 0xc0, 0x3c, 0x3e, 0xfc, 0x4c, 0xd5, 0x49, 0xc7, 0x15,
107 | 0xa4, 0x93,
108 | ];
109 | let expected: [u8; 32] = [
110 | 0x95, 0xcb, 0xde, 0x94, 0x76, 0xe8, 0x90, 0x7d, 0x7a, 0xad, 0xe4, 0x5c, 0xb4, 0xb8, 0x73,
111 | 0xf8, 0x8b, 0x59, 0x5a, 0x68, 0x79, 0x9f, 0xa1, 0x52, 0xe6, 0xf8, 0xf7, 0x64, 0x7a, 0xac,
112 | 0x79, 0x57,
113 | ];
114 |
115 | do_rfc7748_ladder_test1(input_scalar, input_point, expected);
116 | }
117 |
118 | #[test]
119 | #[ignore] // Run only if you want to burn a lot of CPU doing 1,000,000 DH operations
120 | fn rfc7748_ladder_test2() {
121 | use curve25519_dalek::constants::X25519_BASEPOINT;
122 |
123 | let mut k: [u8; 32] = X25519_BASEPOINT.0;
124 | let mut u: [u8; 32] = X25519_BASEPOINT.0;
125 | let mut result: [u8; 32];
126 |
127 | macro_rules! do_iterations {
128 | ($n:expr) => {
129 | for _ in 0..$n {
130 | result = x25519(k, u);
131 | // OBVIOUS THING THAT I'M GOING TO NOTE ANYWAY BECAUSE I'VE
132 | // SEEN PEOPLE DO THIS WITH GOLANG'S STDLIB AND YOU SURE AS
133 | // HELL SHOULDN'T DO HORRIBLY STUPID THINGS LIKE THIS WITH
134 | // MY LIBRARY:
135 | //
136 | // NEVER EVER TREAT SCALARS AS POINTS AND/OR VICE VERSA.
137 | //
138 | // ↓↓ DON'T DO THIS ↓↓
139 | u = k.clone();
140 | k = result;
141 | }
142 | };
143 | }
144 |
145 | // After one iteration:
146 | // 422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854b783c60e80311ae3079
147 | // After 1,000 iterations:
148 | // 684cf59ba83309552800ef566f2f4d3c1c3887c49360e3875f2eb94d99532c51
149 | // After 1,000,000 iterations:
150 | // 7c3911e0ab2586fd864497297e575e6f3bc601c0883c30df5f4dd2d24f665424
151 |
152 | do_iterations!(1);
153 | assert_eq!(
154 | k,
155 | [
156 | 0x42, 0x2c, 0x8e, 0x7a, 0x62, 0x27, 0xd7, 0xbc, 0xa1, 0x35, 0x0b, 0x3e, 0x2b, 0xb7,
157 | 0x27, 0x9f, 0x78, 0x97, 0xb8, 0x7b, 0xb6, 0x85, 0x4b, 0x78, 0x3c, 0x60, 0xe8, 0x03,
158 | 0x11, 0xae, 0x30, 0x79,
159 | ]
160 | );
161 | do_iterations!(999);
162 | assert_eq!(
163 | k,
164 | [
165 | 0x68, 0x4c, 0xf5, 0x9b, 0xa8, 0x33, 0x09, 0x55, 0x28, 0x00, 0xef, 0x56, 0x6f, 0x2f,
166 | 0x4d, 0x3c, 0x1c, 0x38, 0x87, 0xc4, 0x93, 0x60, 0xe3, 0x87, 0x5f, 0x2e, 0xb9, 0x4d,
167 | 0x99, 0x53, 0x2c, 0x51,
168 | ]
169 | );
170 | do_iterations!(999_000);
171 | assert_eq!(
172 | k,
173 | [
174 | 0x7c, 0x39, 0x11, 0xe0, 0xab, 0x25, 0x86, 0xfd, 0x86, 0x44, 0x97, 0x29, 0x7e, 0x57,
175 | 0x5e, 0x6f, 0x3b, 0xc6, 0x01, 0xc0, 0x88, 0x3c, 0x30, 0xdf, 0x5f, 0x4d, 0xd2, 0xd2,
176 | 0x4f, 0x66, 0x54, 0x24,
177 | ]
178 | );
179 | }
180 |
181 | mod rand_core {
182 |
183 | use super::*;
184 | use ::rand_core::OsRng;
185 |
186 | #[test]
187 | fn ephemeral_from_rng() {
188 | #[allow(deprecated)]
189 | EphemeralSecret::new(OsRng);
190 | EphemeralSecret::random_from_rng(OsRng);
191 | }
192 |
193 | #[test]
194 | #[cfg(feature = "reusable_secrets")]
195 | fn reusable_from_rng() {
196 | #[allow(deprecated)]
197 | ReusableSecret::new(OsRng);
198 | ReusableSecret::random_from_rng(OsRng);
199 | }
200 |
201 | #[test]
202 | #[cfg(feature = "static_secrets")]
203 | fn static_from_rng() {
204 | #[allow(deprecated)]
205 | StaticSecret::new(OsRng);
206 | StaticSecret::random_from_rng(OsRng);
207 | }
208 | }
209 |
210 | #[cfg(feature = "getrandom")]
211 | mod getrandom {
212 |
213 | use super::*;
214 |
215 | #[test]
216 | fn ephemeral_random() {
217 | EphemeralSecret::random();
218 | }
219 |
220 | #[test]
221 | #[cfg(feature = "reusable_secrets")]
222 | fn reusable_random() {
223 | ReusableSecret::random();
224 | }
225 |
226 | #[test]
227 | #[cfg(feature = "static_secrets")]
228 | fn static_random() {
229 | StaticSecret::random();
230 | }
231 | }
232 |
--------------------------------------------------------------------------------
/src/x25519.rs:
--------------------------------------------------------------------------------
1 | // -*- mode: rust; -*-
2 | //
3 | // This file is part of x25519-dalek.
4 | // Copyright (c) 2017-2021 isis lovecruft
5 | // Copyright (c) 2019-2021 DebugSteven
6 | // See LICENSE for licensing information.
7 | //
8 | // Authors:
9 | // - isis agora lovecruft
10 | // - DebugSteven
11 |
12 | //! x25519 Diffie-Hellman key exchange
13 | //!
14 | //! This implements x25519 key exchange as specified by Mike Hamburg
15 | //! and Adam Langley in [RFC7748](https://tools.ietf.org/html/rfc7748).
16 |
17 | use curve25519_dalek::{edwards::EdwardsPoint, montgomery::MontgomeryPoint, traits::IsIdentity};
18 |
19 | use rand_core::CryptoRng;
20 | use rand_core::RngCore;
21 |
22 | #[cfg(feature = "zeroize")]
23 | use zeroize::Zeroize;
24 |
25 | /// A Diffie-Hellman public key
26 | ///
27 | /// We implement `Zeroize` so that downstream consumers may derive it for `Drop`
28 | /// should they wish to erase public keys from memory. Note that this erasure
29 | /// (in this crate) does *not* automatically happen, but either must be derived
30 | /// for Drop or explicitly called.
31 | #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
32 | #[cfg_attr(feature = "zeroize", derive(Zeroize))]
33 | #[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
34 | pub struct PublicKey(pub(crate) MontgomeryPoint);
35 |
36 | impl From<[u8; 32]> for PublicKey {
37 | /// Given a byte array, construct a x25519 `PublicKey`.
38 | fn from(bytes: [u8; 32]) -> PublicKey {
39 | PublicKey(MontgomeryPoint(bytes))
40 | }
41 | }
42 |
43 | impl PublicKey {
44 | /// Convert this public key to a byte array.
45 | #[inline]
46 | pub fn to_bytes(&self) -> [u8; 32] {
47 | self.0.to_bytes()
48 | }
49 |
50 | /// View this public key as a byte array.
51 | #[inline]
52 | pub fn as_bytes(&self) -> &[u8; 32] {
53 | self.0.as_bytes()
54 | }
55 | }
56 |
57 | impl AsRef<[u8]> for PublicKey {
58 | /// View this public key as a byte array.
59 | #[inline]
60 | fn as_ref(&self) -> &[u8] {
61 | self.as_bytes()
62 | }
63 | }
64 |
65 | /// A short-lived Diffie-Hellman secret key that can only be used to compute a single
66 | /// [`SharedSecret`].
67 | ///
68 | /// This type is identical to the `StaticSecret` type, except that the
69 | /// [`EphemeralSecret::diffie_hellman`] method consumes and then wipes the secret key, and there
70 | /// are no serialization methods defined. This means that [`EphemeralSecret`]s can only be
71 | /// generated from fresh randomness where the compiler statically checks that the resulting
72 | /// secret is used at most once.
73 | #[cfg_attr(feature = "zeroize", derive(Zeroize))]
74 | #[cfg_attr(feature = "zeroize", zeroize(drop))]
75 | pub struct EphemeralSecret(pub(crate) [u8; 32]);
76 |
77 | impl EphemeralSecret {
78 | /// Perform a Diffie-Hellman key agreement between `self` and
79 | /// `their_public` key to produce a [`SharedSecret`].
80 | pub fn diffie_hellman(self, their_public: &PublicKey) -> SharedSecret {
81 | SharedSecret(their_public.0.mul_clamped(self.0))
82 | }
83 |
84 | /// Generate a new [`EphemeralSecret`] with the supplied RNG.
85 | #[deprecated(
86 | since = "2.0.0",
87 | note = "Renamed to `random_from_rng`. This will be removed in 2.1.0"
88 | )]
89 | pub fn new(mut csprng: T) -> Self {
90 | Self::random_from_rng(&mut csprng)
91 | }
92 |
93 | /// Generate a new [`EphemeralSecret`] with the supplied RNG.
94 | pub fn random_from_rng(mut csprng: T) -> Self {
95 | // The secret key is random bytes. Clamping is done later.
96 | let mut bytes = [0u8; 32];
97 | csprng.fill_bytes(&mut bytes);
98 | EphemeralSecret(bytes)
99 | }
100 |
101 | /// Generate a new [`EphemeralSecret`].
102 | #[cfg(feature = "getrandom")]
103 | pub fn random() -> Self {
104 | Self::random_from_rng(&mut rand_core::OsRng)
105 | }
106 | }
107 |
108 | impl<'a> From<&'a EphemeralSecret> for PublicKey {
109 | /// Given an x25519 [`EphemeralSecret`] key, compute its corresponding [`PublicKey`].
110 | fn from(secret: &'a EphemeralSecret) -> PublicKey {
111 | PublicKey(EdwardsPoint::mul_base_clamped(secret.0).to_montgomery())
112 | }
113 | }
114 |
115 | /// A Diffie-Hellman secret key which may be used more than once, but is
116 | /// purposefully not serialiseable in order to discourage key-reuse. This is
117 | /// implemented to facilitate protocols such as Noise (e.g. Noise IK key usage,
118 | /// etc.) and X3DH which require an "ephemeral" key to conduct the
119 | /// Diffie-Hellman operation multiple times throughout the protocol, while the
120 | /// protocol run at a higher level is only conducted once per key.
121 | ///
122 | /// Similarly to [`EphemeralSecret`], this type does _not_ have serialisation
123 | /// methods, in order to discourage long-term usage of secret key material. (For
124 | /// long-term secret keys, see `StaticSecret`.)
125 | ///
126 | /// # Warning
127 | ///
128 | /// If you're uncertain about whether you should use this, then you likely
129 | /// should not be using this. Our strongly recommended advice is to use
130 | /// [`EphemeralSecret`] at all times, as that type enforces at compile-time that
131 | /// secret keys are never reused, which can have very serious security
132 | /// implications for many protocols.
133 | #[cfg(feature = "reusable_secrets")]
134 | #[cfg_attr(feature = "zeroize", derive(Zeroize))]
135 | #[cfg_attr(feature = "zeroize", zeroize(drop))]
136 | #[derive(Clone)]
137 | pub struct ReusableSecret(pub(crate) [u8; 32]);
138 |
139 | #[cfg(feature = "reusable_secrets")]
140 | impl ReusableSecret {
141 | /// Perform a Diffie-Hellman key agreement between `self` and
142 | /// `their_public` key to produce a [`SharedSecret`].
143 | pub fn diffie_hellman(&self, their_public: &PublicKey) -> SharedSecret {
144 | SharedSecret(their_public.0.mul_clamped(self.0))
145 | }
146 |
147 | /// Generate a new [`ReusableSecret`] with the supplied RNG.
148 | #[deprecated(
149 | since = "2.0.0",
150 | note = "Renamed to `random_from_rng`. This will be removed in 2.1.0."
151 | )]
152 | pub fn new(mut csprng: T) -> Self {
153 | Self::random_from_rng(&mut csprng)
154 | }
155 |
156 | /// Generate a new [`ReusableSecret`] with the supplied RNG.
157 | pub fn random_from_rng(mut csprng: T) -> Self {
158 | // The secret key is random bytes. Clamping is done later.
159 | let mut bytes = [0u8; 32];
160 | csprng.fill_bytes(&mut bytes);
161 | ReusableSecret(bytes)
162 | }
163 |
164 | /// Generate a new [`ReusableSecret`].
165 | #[cfg(feature = "getrandom")]
166 | pub fn random() -> Self {
167 | Self::random_from_rng(&mut rand_core::OsRng)
168 | }
169 | }
170 |
171 | #[cfg(feature = "reusable_secrets")]
172 | impl<'a> From<&'a ReusableSecret> for PublicKey {
173 | /// Given an x25519 [`ReusableSecret`] key, compute its corresponding [`PublicKey`].
174 | fn from(secret: &'a ReusableSecret) -> PublicKey {
175 | PublicKey(EdwardsPoint::mul_base_clamped(secret.0).to_montgomery())
176 | }
177 | }
178 |
179 | /// A Diffie-Hellman secret key that can be used to compute multiple [`SharedSecret`]s.
180 | ///
181 | /// This type is identical to the [`EphemeralSecret`] type, except that the
182 | /// [`StaticSecret::diffie_hellman`] method does not consume the secret key, and the type provides
183 | /// serialization methods to save and load key material. This means that the secret may be used
184 | /// multiple times (but does not *have to be*).
185 | ///
186 | /// # Warning
187 | ///
188 | /// If you're uncertain about whether you should use this, then you likely
189 | /// should not be using this. Our strongly recommended advice is to use
190 | /// [`EphemeralSecret`] at all times, as that type enforces at compile-time that
191 | /// secret keys are never reused, which can have very serious security
192 | /// implications for many protocols.
193 | #[cfg(feature = "static_secrets")]
194 | #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
195 | #[cfg_attr(feature = "zeroize", derive(Zeroize))]
196 | #[cfg_attr(feature = "zeroize", zeroize(drop))]
197 | #[derive(Clone)]
198 | pub struct StaticSecret([u8; 32]);
199 |
200 | #[cfg(feature = "static_secrets")]
201 | impl StaticSecret {
202 | /// Perform a Diffie-Hellman key agreement between `self` and
203 | /// `their_public` key to produce a `SharedSecret`.
204 | pub fn diffie_hellman(&self, their_public: &PublicKey) -> SharedSecret {
205 | SharedSecret(their_public.0.mul_clamped(self.0))
206 | }
207 |
208 | /// Generate a new [`StaticSecret`] with the supplied RNG.
209 | #[deprecated(
210 | since = "2.0.0",
211 | note = "Renamed to `random_from_rng`. This will be removed in 2.1.0"
212 | )]
213 | pub fn new(mut csprng: T) -> Self {
214 | Self::random_from_rng(&mut csprng)
215 | }
216 |
217 | /// Generate a new [`StaticSecret`] with the supplied RNG.
218 | pub fn random_from_rng(mut csprng: T) -> Self {
219 | // The secret key is random bytes. Clamping is done later.
220 | let mut bytes = [0u8; 32];
221 | csprng.fill_bytes(&mut bytes);
222 | StaticSecret(bytes)
223 | }
224 |
225 | /// Generate a new [`StaticSecret`].
226 | #[cfg(feature = "getrandom")]
227 | pub fn random() -> Self {
228 | Self::random_from_rng(&mut rand_core::OsRng)
229 | }
230 |
231 | /// Extract this key's bytes for serialization.
232 | #[inline]
233 | pub fn to_bytes(&self) -> [u8; 32] {
234 | self.0
235 | }
236 |
237 | /// View this key as a byte array.
238 | #[inline]
239 | pub fn as_bytes(&self) -> &[u8; 32] {
240 | &self.0
241 | }
242 | }
243 |
244 | #[cfg(feature = "static_secrets")]
245 | impl From<[u8; 32]> for StaticSecret {
246 | /// Load a secret key from a byte array.
247 | fn from(bytes: [u8; 32]) -> StaticSecret {
248 | StaticSecret(bytes)
249 | }
250 | }
251 |
252 | #[cfg(feature = "static_secrets")]
253 | impl<'a> From<&'a StaticSecret> for PublicKey {
254 | /// Given an x25519 [`StaticSecret`] key, compute its corresponding [`PublicKey`].
255 | fn from(secret: &'a StaticSecret) -> PublicKey {
256 | PublicKey(EdwardsPoint::mul_base_clamped(secret.0).to_montgomery())
257 | }
258 | }
259 |
260 | #[cfg(feature = "static_secrets")]
261 | impl AsRef<[u8]> for StaticSecret {
262 | /// View this key as a byte array.
263 | #[inline]
264 | fn as_ref(&self) -> &[u8] {
265 | self.as_bytes()
266 | }
267 | }
268 |
269 | /// The result of a Diffie-Hellman key exchange.
270 | ///
271 | /// Each party computes this using their [`EphemeralSecret`] or [`StaticSecret`] and their
272 | /// counterparty's [`PublicKey`].
273 | #[cfg_attr(feature = "zeroize", derive(Zeroize))]
274 | #[cfg_attr(feature = "zeroize", zeroize(drop))]
275 | pub struct SharedSecret(pub(crate) MontgomeryPoint);
276 |
277 | impl SharedSecret {
278 | /// Convert this shared secret to a byte array.
279 | #[inline]
280 | pub fn to_bytes(&self) -> [u8; 32] {
281 | self.0.to_bytes()
282 | }
283 |
284 | /// View this shared secret key as a byte array.
285 | #[inline]
286 | pub fn as_bytes(&self) -> &[u8; 32] {
287 | self.0.as_bytes()
288 | }
289 |
290 | /// Ensure in constant-time that this shared secret did not result from a
291 | /// key exchange with non-contributory behaviour.
292 | ///
293 | /// In some more exotic protocols which need to guarantee "contributory"
294 | /// behaviour for both parties, that is, that each party contributed a public
295 | /// value which increased the security of the resulting shared secret.
296 | /// To take an example protocol attack where this could lead to undesirable
297 | /// results [from Thái "thaidn" Dương](https://vnhacker.blogspot.com/2015/09/why-not-validating-curve25519-public.html):
298 | ///
299 | /// > If Mallory replaces Alice's and Bob's public keys with zero, which is
300 | /// > a valid Curve25519 public key, he would be able to force the ECDH
301 | /// > shared value to be zero, which is the encoding of the point at infinity,
302 | /// > and thus get to dictate some publicly known values as the shared
303 | /// > keys. It still requires an active man-in-the-middle attack to pull the
304 | /// > trick, after which, however, not only Mallory can decode Alice's data,
305 | /// > but everyone too! It is also impossible for Alice and Bob to detect the
306 | /// > intrusion, as they still share the same keys, and can communicate with
307 | /// > each other as normal.
308 | ///
309 | /// The original Curve25519 specification argues that checks for
310 | /// non-contributory behaviour are "unnecessary for Diffie-Hellman".
311 | /// Whether this check is necessary for any particular given protocol is
312 | /// often a matter of debate, which we will not re-hash here, but simply
313 | /// cite some of the [relevant] [public] [discussions].
314 | ///
315 | /// # Returns
316 | ///
317 | /// Returns `true` if the key exchange was contributory (good), and `false`
318 | /// otherwise (can be bad for some protocols).
319 | ///
320 | /// [relevant]: https://tools.ietf.org/html/rfc7748#page-15
321 | /// [public]: https://vnhacker.blogspot.com/2015/09/why-not-validating-curve25519-public.html
322 | /// [discussions]: https://vnhacker.blogspot.com/2016/08/the-internet-of-broken-protocols.html
323 | #[must_use]
324 | pub fn was_contributory(&self) -> bool {
325 | !self.0.is_identity()
326 | }
327 | }
328 |
329 | impl AsRef<[u8]> for SharedSecret {
330 | /// View this shared secret key as a byte array.
331 | #[inline]
332 | fn as_ref(&self) -> &[u8] {
333 | self.as_bytes()
334 | }
335 | }
336 |
337 | /// The bare, byte-oriented x25519 function, exactly as specified in RFC7748.
338 | ///
339 | /// This can be used with [`X25519_BASEPOINT_BYTES`] for people who
340 | /// cannot use the better, safer, and faster ephemeral DH API.
341 | ///
342 | /// # Example
343 | #[cfg_attr(feature = "static_secrets", doc = "```")]
344 | #[cfg_attr(not(feature = "static_secrets"), doc = "```ignore")]
345 | /// use rand_core::OsRng;
346 | /// use rand_core::RngCore;
347 | ///
348 | /// use x25519_dalek::x25519;
349 | /// use x25519_dalek::StaticSecret;
350 | /// use x25519_dalek::PublicKey;
351 | ///
352 | /// // Generate Alice's key pair.
353 | /// let alice_secret = StaticSecret::random_from_rng(&mut OsRng);
354 | /// let alice_public = PublicKey::from(&alice_secret);
355 | ///
356 | /// // Generate Bob's key pair.
357 | /// let bob_secret = StaticSecret::random_from_rng(&mut OsRng);
358 | /// let bob_public = PublicKey::from(&bob_secret);
359 | ///
360 | /// // Alice and Bob should now exchange their public keys.
361 | ///
362 | /// // Once they've done so, they may generate a shared secret.
363 | /// let alice_shared = x25519(alice_secret.to_bytes(), bob_public.to_bytes());
364 | /// let bob_shared = x25519(bob_secret.to_bytes(), alice_public.to_bytes());
365 | ///
366 | /// assert_eq!(alice_shared, bob_shared);
367 | /// ```
368 | pub fn x25519(k: [u8; 32], u: [u8; 32]) -> [u8; 32] {
369 | MontgomeryPoint(u).mul_clamped(k).to_bytes()
370 | }
371 |
372 | /// The X25519 basepoint, for use with the bare, byte-oriented x25519
373 | /// function. This is provided for people who cannot use the typed
374 | /// DH API for some reason.
375 | pub const X25519_BASEPOINT_BYTES: [u8; 32] = [
376 | 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
377 | ];
378 |
--------------------------------------------------------------------------------
/Cargo.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Cargo.
2 | # It is not intended for manual editing.
3 | version = 3
4 |
5 | [[package]]
6 | name = "anes"
7 | version = "0.1.6"
8 | source = "registry+https://github.com/rust-lang/crates.io-index"
9 | checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
10 |
11 | [[package]]
12 | name = "atty"
13 | version = "0.2.14"
14 | source = "registry+https://github.com/rust-lang/crates.io-index"
15 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
16 | dependencies = [
17 | "hermit-abi 0.1.19",
18 | "libc",
19 | "winapi",
20 | ]
21 |
22 | [[package]]
23 | name = "autocfg"
24 | version = "1.1.0"
25 | source = "registry+https://github.com/rust-lang/crates.io-index"
26 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
27 |
28 | [[package]]
29 | name = "bincode"
30 | version = "1.3.3"
31 | source = "registry+https://github.com/rust-lang/crates.io-index"
32 | checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
33 | dependencies = [
34 | "serde",
35 | ]
36 |
37 | [[package]]
38 | name = "bitflags"
39 | version = "1.3.2"
40 | source = "registry+https://github.com/rust-lang/crates.io-index"
41 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
42 |
43 | [[package]]
44 | name = "bumpalo"
45 | version = "3.12.0"
46 | source = "registry+https://github.com/rust-lang/crates.io-index"
47 | checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535"
48 |
49 | [[package]]
50 | name = "cast"
51 | version = "0.3.0"
52 | source = "registry+https://github.com/rust-lang/crates.io-index"
53 | checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
54 |
55 | [[package]]
56 | name = "cfg-if"
57 | version = "1.0.0"
58 | source = "registry+https://github.com/rust-lang/crates.io-index"
59 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
60 |
61 | [[package]]
62 | name = "ciborium"
63 | version = "0.2.0"
64 | source = "registry+https://github.com/rust-lang/crates.io-index"
65 | checksum = "b0c137568cc60b904a7724001b35ce2630fd00d5d84805fbb608ab89509d788f"
66 | dependencies = [
67 | "ciborium-io",
68 | "ciborium-ll",
69 | "serde",
70 | ]
71 |
72 | [[package]]
73 | name = "ciborium-io"
74 | version = "0.2.0"
75 | source = "registry+https://github.com/rust-lang/crates.io-index"
76 | checksum = "346de753af073cc87b52b2083a506b38ac176a44cfb05497b622e27be899b369"
77 |
78 | [[package]]
79 | name = "ciborium-ll"
80 | version = "0.2.0"
81 | source = "registry+https://github.com/rust-lang/crates.io-index"
82 | checksum = "213030a2b5a4e0c0892b6652260cf6ccac84827b83a85a534e178e3906c4cf1b"
83 | dependencies = [
84 | "ciborium-io",
85 | "half",
86 | ]
87 |
88 | [[package]]
89 | name = "clap"
90 | version = "3.2.23"
91 | source = "registry+https://github.com/rust-lang/crates.io-index"
92 | checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5"
93 | dependencies = [
94 | "bitflags",
95 | "clap_lex",
96 | "indexmap",
97 | "textwrap",
98 | ]
99 |
100 | [[package]]
101 | name = "clap_lex"
102 | version = "0.2.4"
103 | source = "registry+https://github.com/rust-lang/crates.io-index"
104 | checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
105 | dependencies = [
106 | "os_str_bytes",
107 | ]
108 |
109 | [[package]]
110 | name = "cpufeatures"
111 | version = "0.2.8"
112 | source = "registry+https://github.com/rust-lang/crates.io-index"
113 | checksum = "03e69e28e9f7f77debdedbaafa2866e1de9ba56df55a8bd7cfc724c25a09987c"
114 | dependencies = [
115 | "libc",
116 | ]
117 |
118 | [[package]]
119 | name = "criterion"
120 | version = "0.4.0"
121 | source = "registry+https://github.com/rust-lang/crates.io-index"
122 | checksum = "e7c76e09c1aae2bc52b3d2f29e13c6572553b30c4aa1b8a49fd70de6412654cb"
123 | dependencies = [
124 | "anes",
125 | "atty",
126 | "cast",
127 | "ciborium",
128 | "clap",
129 | "criterion-plot",
130 | "itertools",
131 | "lazy_static",
132 | "num-traits",
133 | "oorandom",
134 | "plotters",
135 | "rayon",
136 | "regex",
137 | "serde",
138 | "serde_derive",
139 | "serde_json",
140 | "tinytemplate",
141 | "walkdir",
142 | ]
143 |
144 | [[package]]
145 | name = "criterion-plot"
146 | version = "0.5.0"
147 | source = "registry+https://github.com/rust-lang/crates.io-index"
148 | checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1"
149 | dependencies = [
150 | "cast",
151 | "itertools",
152 | ]
153 |
154 | [[package]]
155 | name = "crossbeam-channel"
156 | version = "0.5.7"
157 | source = "registry+https://github.com/rust-lang/crates.io-index"
158 | checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c"
159 | dependencies = [
160 | "cfg-if",
161 | "crossbeam-utils",
162 | ]
163 |
164 | [[package]]
165 | name = "crossbeam-deque"
166 | version = "0.8.3"
167 | source = "registry+https://github.com/rust-lang/crates.io-index"
168 | checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
169 | dependencies = [
170 | "cfg-if",
171 | "crossbeam-epoch",
172 | "crossbeam-utils",
173 | ]
174 |
175 | [[package]]
176 | name = "crossbeam-epoch"
177 | version = "0.9.14"
178 | source = "registry+https://github.com/rust-lang/crates.io-index"
179 | checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695"
180 | dependencies = [
181 | "autocfg",
182 | "cfg-if",
183 | "crossbeam-utils",
184 | "memoffset",
185 | "scopeguard",
186 | ]
187 |
188 | [[package]]
189 | name = "crossbeam-utils"
190 | version = "0.8.15"
191 | source = "registry+https://github.com/rust-lang/crates.io-index"
192 | checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b"
193 | dependencies = [
194 | "cfg-if",
195 | ]
196 |
197 | [[package]]
198 | name = "curve25519-dalek"
199 | version = "4.0.0-rc.3"
200 | source = "registry+https://github.com/rust-lang/crates.io-index"
201 | checksum = "436ace70fc06e06f7f689d2624dc4e2f0ea666efb5aa704215f7249ae6e047a7"
202 | dependencies = [
203 | "cfg-if",
204 | "cpufeatures",
205 | "curve25519-dalek-derive",
206 | "fiat-crypto",
207 | "platforms",
208 | "rustc_version",
209 | "serde",
210 | "subtle",
211 | "zeroize",
212 | ]
213 |
214 | [[package]]
215 | name = "curve25519-dalek-derive"
216 | version = "0.1.0"
217 | source = "registry+https://github.com/rust-lang/crates.io-index"
218 | checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b"
219 | dependencies = [
220 | "proc-macro2",
221 | "quote",
222 | "syn 2.0.12",
223 | ]
224 |
225 | [[package]]
226 | name = "either"
227 | version = "1.8.1"
228 | source = "registry+https://github.com/rust-lang/crates.io-index"
229 | checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
230 |
231 | [[package]]
232 | name = "fiat-crypto"
233 | version = "0.1.19"
234 | source = "registry+https://github.com/rust-lang/crates.io-index"
235 | checksum = "93ace6ec7cc19c8ed33a32eaa9ea692d7faea05006b5356b9e2b668ec4bc3955"
236 |
237 | [[package]]
238 | name = "getrandom"
239 | version = "0.2.8"
240 | source = "registry+https://github.com/rust-lang/crates.io-index"
241 | checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
242 | dependencies = [
243 | "cfg-if",
244 | "libc",
245 | "wasi",
246 | ]
247 |
248 | [[package]]
249 | name = "half"
250 | version = "1.8.2"
251 | source = "registry+https://github.com/rust-lang/crates.io-index"
252 | checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
253 |
254 | [[package]]
255 | name = "hashbrown"
256 | version = "0.12.3"
257 | source = "registry+https://github.com/rust-lang/crates.io-index"
258 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
259 |
260 | [[package]]
261 | name = "hermit-abi"
262 | version = "0.1.19"
263 | source = "registry+https://github.com/rust-lang/crates.io-index"
264 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
265 | dependencies = [
266 | "libc",
267 | ]
268 |
269 | [[package]]
270 | name = "hermit-abi"
271 | version = "0.2.6"
272 | source = "registry+https://github.com/rust-lang/crates.io-index"
273 | checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
274 | dependencies = [
275 | "libc",
276 | ]
277 |
278 | [[package]]
279 | name = "indexmap"
280 | version = "1.9.3"
281 | source = "registry+https://github.com/rust-lang/crates.io-index"
282 | checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
283 | dependencies = [
284 | "autocfg",
285 | "hashbrown",
286 | ]
287 |
288 | [[package]]
289 | name = "itertools"
290 | version = "0.10.5"
291 | source = "registry+https://github.com/rust-lang/crates.io-index"
292 | checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
293 | dependencies = [
294 | "either",
295 | ]
296 |
297 | [[package]]
298 | name = "itoa"
299 | version = "1.0.6"
300 | source = "registry+https://github.com/rust-lang/crates.io-index"
301 | checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
302 |
303 | [[package]]
304 | name = "js-sys"
305 | version = "0.3.61"
306 | source = "registry+https://github.com/rust-lang/crates.io-index"
307 | checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730"
308 | dependencies = [
309 | "wasm-bindgen",
310 | ]
311 |
312 | [[package]]
313 | name = "lazy_static"
314 | version = "1.4.0"
315 | source = "registry+https://github.com/rust-lang/crates.io-index"
316 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
317 |
318 | [[package]]
319 | name = "libc"
320 | version = "0.2.140"
321 | source = "registry+https://github.com/rust-lang/crates.io-index"
322 | checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c"
323 |
324 | [[package]]
325 | name = "log"
326 | version = "0.4.17"
327 | source = "registry+https://github.com/rust-lang/crates.io-index"
328 | checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
329 | dependencies = [
330 | "cfg-if",
331 | ]
332 |
333 | [[package]]
334 | name = "memoffset"
335 | version = "0.8.0"
336 | source = "registry+https://github.com/rust-lang/crates.io-index"
337 | checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1"
338 | dependencies = [
339 | "autocfg",
340 | ]
341 |
342 | [[package]]
343 | name = "num-traits"
344 | version = "0.2.15"
345 | source = "registry+https://github.com/rust-lang/crates.io-index"
346 | checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
347 | dependencies = [
348 | "autocfg",
349 | ]
350 |
351 | [[package]]
352 | name = "num_cpus"
353 | version = "1.15.0"
354 | source = "registry+https://github.com/rust-lang/crates.io-index"
355 | checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
356 | dependencies = [
357 | "hermit-abi 0.2.6",
358 | "libc",
359 | ]
360 |
361 | [[package]]
362 | name = "once_cell"
363 | version = "1.17.1"
364 | source = "registry+https://github.com/rust-lang/crates.io-index"
365 | checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
366 |
367 | [[package]]
368 | name = "oorandom"
369 | version = "11.1.3"
370 | source = "registry+https://github.com/rust-lang/crates.io-index"
371 | checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
372 |
373 | [[package]]
374 | name = "os_str_bytes"
375 | version = "6.5.0"
376 | source = "registry+https://github.com/rust-lang/crates.io-index"
377 | checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267"
378 |
379 | [[package]]
380 | name = "platforms"
381 | version = "3.0.2"
382 | source = "registry+https://github.com/rust-lang/crates.io-index"
383 | checksum = "e3d7ddaed09e0eb771a79ab0fd64609ba0afb0a8366421957936ad14cbd13630"
384 |
385 | [[package]]
386 | name = "plotters"
387 | version = "0.3.4"
388 | source = "registry+https://github.com/rust-lang/crates.io-index"
389 | checksum = "2538b639e642295546c50fcd545198c9d64ee2a38620a628724a3b266d5fbf97"
390 | dependencies = [
391 | "num-traits",
392 | "plotters-backend",
393 | "plotters-svg",
394 | "wasm-bindgen",
395 | "web-sys",
396 | ]
397 |
398 | [[package]]
399 | name = "plotters-backend"
400 | version = "0.3.4"
401 | source = "registry+https://github.com/rust-lang/crates.io-index"
402 | checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142"
403 |
404 | [[package]]
405 | name = "plotters-svg"
406 | version = "0.3.3"
407 | source = "registry+https://github.com/rust-lang/crates.io-index"
408 | checksum = "f9a81d2759aae1dae668f783c308bc5c8ebd191ff4184aaa1b37f65a6ae5a56f"
409 | dependencies = [
410 | "plotters-backend",
411 | ]
412 |
413 | [[package]]
414 | name = "proc-macro2"
415 | version = "1.0.54"
416 | source = "registry+https://github.com/rust-lang/crates.io-index"
417 | checksum = "e472a104799c74b514a57226160104aa483546de37e839ec50e3c2e41dd87534"
418 | dependencies = [
419 | "unicode-ident",
420 | ]
421 |
422 | [[package]]
423 | name = "quote"
424 | version = "1.0.26"
425 | source = "registry+https://github.com/rust-lang/crates.io-index"
426 | checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc"
427 | dependencies = [
428 | "proc-macro2",
429 | ]
430 |
431 | [[package]]
432 | name = "rand_core"
433 | version = "0.6.4"
434 | source = "registry+https://github.com/rust-lang/crates.io-index"
435 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
436 | dependencies = [
437 | "getrandom",
438 | ]
439 |
440 | [[package]]
441 | name = "rayon"
442 | version = "1.7.0"
443 | source = "registry+https://github.com/rust-lang/crates.io-index"
444 | checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b"
445 | dependencies = [
446 | "either",
447 | "rayon-core",
448 | ]
449 |
450 | [[package]]
451 | name = "rayon-core"
452 | version = "1.11.0"
453 | source = "registry+https://github.com/rust-lang/crates.io-index"
454 | checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d"
455 | dependencies = [
456 | "crossbeam-channel",
457 | "crossbeam-deque",
458 | "crossbeam-utils",
459 | "num_cpus",
460 | ]
461 |
462 | [[package]]
463 | name = "regex"
464 | version = "1.7.3"
465 | source = "registry+https://github.com/rust-lang/crates.io-index"
466 | checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d"
467 | dependencies = [
468 | "regex-syntax",
469 | ]
470 |
471 | [[package]]
472 | name = "regex-syntax"
473 | version = "0.6.29"
474 | source = "registry+https://github.com/rust-lang/crates.io-index"
475 | checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
476 |
477 | [[package]]
478 | name = "rustc_version"
479 | version = "0.4.0"
480 | source = "registry+https://github.com/rust-lang/crates.io-index"
481 | checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
482 | dependencies = [
483 | "semver",
484 | ]
485 |
486 | [[package]]
487 | name = "ryu"
488 | version = "1.0.13"
489 | source = "registry+https://github.com/rust-lang/crates.io-index"
490 | checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
491 |
492 | [[package]]
493 | name = "same-file"
494 | version = "1.0.6"
495 | source = "registry+https://github.com/rust-lang/crates.io-index"
496 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
497 | dependencies = [
498 | "winapi-util",
499 | ]
500 |
501 | [[package]]
502 | name = "scopeguard"
503 | version = "1.1.0"
504 | source = "registry+https://github.com/rust-lang/crates.io-index"
505 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
506 |
507 | [[package]]
508 | name = "semver"
509 | version = "1.0.17"
510 | source = "registry+https://github.com/rust-lang/crates.io-index"
511 | checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
512 |
513 | [[package]]
514 | name = "serde"
515 | version = "1.0.159"
516 | source = "registry+https://github.com/rust-lang/crates.io-index"
517 | checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065"
518 | dependencies = [
519 | "serde_derive",
520 | ]
521 |
522 | [[package]]
523 | name = "serde_derive"
524 | version = "1.0.159"
525 | source = "registry+https://github.com/rust-lang/crates.io-index"
526 | checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585"
527 | dependencies = [
528 | "proc-macro2",
529 | "quote",
530 | "syn 2.0.12",
531 | ]
532 |
533 | [[package]]
534 | name = "serde_json"
535 | version = "1.0.95"
536 | source = "registry+https://github.com/rust-lang/crates.io-index"
537 | checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744"
538 | dependencies = [
539 | "itoa",
540 | "ryu",
541 | "serde",
542 | ]
543 |
544 | [[package]]
545 | name = "subtle"
546 | version = "2.5.0"
547 | source = "registry+https://github.com/rust-lang/crates.io-index"
548 | checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
549 |
550 | [[package]]
551 | name = "syn"
552 | version = "1.0.109"
553 | source = "registry+https://github.com/rust-lang/crates.io-index"
554 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
555 | dependencies = [
556 | "proc-macro2",
557 | "quote",
558 | "unicode-ident",
559 | ]
560 |
561 | [[package]]
562 | name = "syn"
563 | version = "2.0.12"
564 | source = "registry+https://github.com/rust-lang/crates.io-index"
565 | checksum = "79d9531f94112cfc3e4c8f5f02cb2b58f72c97b7efd85f70203cc6d8efda5927"
566 | dependencies = [
567 | "proc-macro2",
568 | "quote",
569 | "unicode-ident",
570 | ]
571 |
572 | [[package]]
573 | name = "textwrap"
574 | version = "0.16.0"
575 | source = "registry+https://github.com/rust-lang/crates.io-index"
576 | checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
577 |
578 | [[package]]
579 | name = "tinytemplate"
580 | version = "1.2.1"
581 | source = "registry+https://github.com/rust-lang/crates.io-index"
582 | checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
583 | dependencies = [
584 | "serde",
585 | "serde_json",
586 | ]
587 |
588 | [[package]]
589 | name = "unicode-ident"
590 | version = "1.0.8"
591 | source = "registry+https://github.com/rust-lang/crates.io-index"
592 | checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
593 |
594 | [[package]]
595 | name = "walkdir"
596 | version = "2.3.3"
597 | source = "registry+https://github.com/rust-lang/crates.io-index"
598 | checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698"
599 | dependencies = [
600 | "same-file",
601 | "winapi-util",
602 | ]
603 |
604 | [[package]]
605 | name = "wasi"
606 | version = "0.11.0+wasi-snapshot-preview1"
607 | source = "registry+https://github.com/rust-lang/crates.io-index"
608 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
609 |
610 | [[package]]
611 | name = "wasm-bindgen"
612 | version = "0.2.84"
613 | source = "registry+https://github.com/rust-lang/crates.io-index"
614 | checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b"
615 | dependencies = [
616 | "cfg-if",
617 | "wasm-bindgen-macro",
618 | ]
619 |
620 | [[package]]
621 | name = "wasm-bindgen-backend"
622 | version = "0.2.84"
623 | source = "registry+https://github.com/rust-lang/crates.io-index"
624 | checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9"
625 | dependencies = [
626 | "bumpalo",
627 | "log",
628 | "once_cell",
629 | "proc-macro2",
630 | "quote",
631 | "syn 1.0.109",
632 | "wasm-bindgen-shared",
633 | ]
634 |
635 | [[package]]
636 | name = "wasm-bindgen-macro"
637 | version = "0.2.84"
638 | source = "registry+https://github.com/rust-lang/crates.io-index"
639 | checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5"
640 | dependencies = [
641 | "quote",
642 | "wasm-bindgen-macro-support",
643 | ]
644 |
645 | [[package]]
646 | name = "wasm-bindgen-macro-support"
647 | version = "0.2.84"
648 | source = "registry+https://github.com/rust-lang/crates.io-index"
649 | checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6"
650 | dependencies = [
651 | "proc-macro2",
652 | "quote",
653 | "syn 1.0.109",
654 | "wasm-bindgen-backend",
655 | "wasm-bindgen-shared",
656 | ]
657 |
658 | [[package]]
659 | name = "wasm-bindgen-shared"
660 | version = "0.2.84"
661 | source = "registry+https://github.com/rust-lang/crates.io-index"
662 | checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d"
663 |
664 | [[package]]
665 | name = "web-sys"
666 | version = "0.3.61"
667 | source = "registry+https://github.com/rust-lang/crates.io-index"
668 | checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97"
669 | dependencies = [
670 | "js-sys",
671 | "wasm-bindgen",
672 | ]
673 |
674 | [[package]]
675 | name = "winapi"
676 | version = "0.3.9"
677 | source = "registry+https://github.com/rust-lang/crates.io-index"
678 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
679 | dependencies = [
680 | "winapi-i686-pc-windows-gnu",
681 | "winapi-x86_64-pc-windows-gnu",
682 | ]
683 |
684 | [[package]]
685 | name = "winapi-i686-pc-windows-gnu"
686 | version = "0.4.0"
687 | source = "registry+https://github.com/rust-lang/crates.io-index"
688 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
689 |
690 | [[package]]
691 | name = "winapi-util"
692 | version = "0.1.5"
693 | source = "registry+https://github.com/rust-lang/crates.io-index"
694 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
695 | dependencies = [
696 | "winapi",
697 | ]
698 |
699 | [[package]]
700 | name = "winapi-x86_64-pc-windows-gnu"
701 | version = "0.4.0"
702 | source = "registry+https://github.com/rust-lang/crates.io-index"
703 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
704 |
705 | [[package]]
706 | name = "x25519-dalek"
707 | version = "2.0.0-rc.3"
708 | dependencies = [
709 | "bincode",
710 | "criterion",
711 | "curve25519-dalek",
712 | "rand_core",
713 | "serde",
714 | "zeroize",
715 | ]
716 |
717 | [[package]]
718 | name = "zeroize"
719 | version = "1.6.0"
720 | source = "registry+https://github.com/rust-lang/crates.io-index"
721 | checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9"
722 | dependencies = [
723 | "zeroize_derive",
724 | ]
725 |
726 | [[package]]
727 | name = "zeroize_derive"
728 | version = "1.4.2"
729 | source = "registry+https://github.com/rust-lang/crates.io-index"
730 | checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
731 | dependencies = [
732 | "proc-macro2",
733 | "quote",
734 | "syn 2.0.12",
735 | ]
736 |
--------------------------------------------------------------------------------