From 3702a7c5980be2c69ab9daad12352c4f318c202e Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 14 Sep 2017 00:25:34 +0000 Subject: [PATCH] Initial commit. --- .gitignore | 14 ++ .travis.yml | 19 ++ CONTRIBUTING.md | 28 +++ Cargo.toml | 32 ++++ LICENSE | 28 +++ README.md | 98 ++++++++++ ...ubblesort-zines-secret-messages-cover.jpeg | Bin 0 -> 74941 bytes src/lib.rs | 140 ++++++++++++++ src/x25519.rs | 172 ++++++++++++++++++ 9 files changed, 531 insertions(+) create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 CONTRIBUTING.md create mode 100644 Cargo.toml create mode 100644 LICENSE create mode 100644 README.md create mode 100644 res/bubblesort-zines-secret-messages-cover.jpeg create mode 100644 src/lib.rs create mode 100644 src/x25519.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2328c9d --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +target/ +**/*.rs.bk +Cargo.lock + +.cargo + +*~ +\#* +.\#* +*.swp +*.orig +*.bak + +*.s diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..2080ffd --- /dev/null +++ b/.travis.yml @@ -0,0 +1,19 @@ +language: rust + +rust: + - nightly + +env: + - TEST_COMMAND=test EXTRA_FLAGS='' FEATURES='' + - TEST_COMMAND=bench EXTRA_FLAGS='' FEATURES='bench' + - TEST_COMMAND=build EXTRA_FLAGS='--no-default-features' FEATURES='nightly' + +matrix: + include: + - rust: stable + env: TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std' + - rust: beta + env: TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std' + +script: + - cargo $TEST_COMMAND --features="$FEATURES" $EXTRA_FLAGS diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..b60e709 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,28 @@ +# Contributing to curve25519-dalek + +If you have questions or comments, please feel free to email the +authors. + +For feature requests, suggestions, and bug reports, please open an issue on +[our Github](https://github.com/isislovecruft/x25519-dalek). (Or, send us +an email if you're opposed to using Github for whatever reason.) + +Patches are welcomed as pull requests on +[our Github](https://github.com/isislovecruft/x25519-dalek), as well as by +email (preferably sent to all of the authors listed in `Cargo.toml`). + +All issues on curve25519-dalek are mentored, if you want help with a bug just +ask @isislovecruft. + +Some issues are easier than others. The `easy` label can be used to find the +easy issues. If you want to work on an issue, please leave a comment so that we +can assign it to you! + +# Code of Conduct + +We follow the [Rust Code of Conduct](http://www.rust-lang.org/conduct.html), +with the following additional clauses: + +* We respect the rights to privacy and anonymity for contributors and people in + the community. If someone wishes to contribute under a pseudonym different to + their primary identity, that wish is to be respected by all contributors. diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..bd2d974 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "x25519-dalek" +version = "0.0.0" +authors = ["Isis Lovecruft "] +readme = "README.md" +license = "BSD-3-Clause" +repository = "https://github.com/isislovecruft/x25519-dalek" +documentation = "https://docs.rs/x25519-dalek" +categories = ["cryptography", "no-std"] +keywords = ["cryptography", "curve25519", "key-exchange", "x25519", "diffie-hellman"] +description = "X25519 elliptic curve Diffie-Hellman key exchange in pure-Rust, using curve25519-dalek." +exclude = [ + ".gitignore", + ".travis.yml", + "CONTRIBUTING.md", +] + +[badges] +travis-ci = { repository = "isislovecruft/x25519-dalek", branch = "master"} + +[dependencies.curve25519-dalek] +version = "^0.12" + +[dependencies.rand] +optional = true +version = "^0.3" + +[features] +bench = [] +default = ["std", "nightly"] +std = ["rand", "curve25519-dalek/std"] +nightly = ["curve25519-dalek/nightly"] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..20dcc41 --- /dev/null +++ b/LICENSE @@ -0,0 +1,28 @@ +Copyright (c) 2017 Isis Agora Lovecruft. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..fa6eb02 --- /dev/null +++ b/README.md @@ -0,0 +1,98 @@ + +# x25519-dalek [![](https://img.shields.io/crates/v/x25519-dalek.svg)](https://crates.io/crates/x25519-dalek) [![](https://docs.rs/x25519-dalek/badge.svg)](https://docs.rs/x25519-dalek) [![](https://travis-ci.org/isislovecruft/x25519-dalek.svg?branch=master)](https://travis-ci.org/isislovecruft/x25519-dalek) + +A pure-Rust implementation of x25519 elliptic curve Diffie-Hellman key exchange, +as specified by Mike Hamburg and Adam Langley in +[RFC7748](https://tools.ietf.org/html/rfc7748), using +[curve25519-dalek](https://github.com/isislovecruft/curve25519-dalek). + +## Examples + +[![](https://raw.githubusercontent.com/isislovecruft/x25519-dalek/master/res/bubblesort-zines-secret-messages-cover.jpeg)](https://shop.bubblesort.io) + +"Secret Messages" cover image and [zine](https://shop.bubblesort.io/products/secret-messages-zine) +copyright © Amy Wibowo ([@sailorhg](https://twitter.com/sailorhg)) + +Alice and Bob are two adorable kittens who have lost their mittens, and they +wish to be able to send secret messages to each other to coordinate finding +them, otherwise—if their caretaker cat finds out—they will surely be called +naughty kittens and be given no pie! + +But the two kittens are quite clever. Even though their paws are still too big +and the rest of them is 90% fuzziness, these clever kittens have been studying +up on modern public key cryptography and have learned a nifty trick called +*elliptic curve Diffie-Hellman key exchange*. With the right incantations, the +kittens will be able to secretly organise to find their mittens, and then spend +the rest of the afternoon nomming some yummy pie! + +First, Alice uses `x25519_dalek::generate_secret()` and then +`x25519_dalek::generate_public()` to produce her secret and public keys: + +```rust +extern crate x25519_dalek; +extern crate rand; + +use x25519_dalek::generate_secret; +use x25519_dalek::generate_public; +use rand::OsRng; + +let mut alice_csprng = OsRng::new().unwrap(); +let alice_secret = generate_secret(&mut alice_csprng); +let alice_public = generate_public(&alice_secret); +``` + +Bob does the same: + +```rust +let mut bob_csprng = OsRng::new().unwrap(); +let bob_secret = generate_secret(&mut bob_csprng); +let bob_public = generate_public(&bob_secret); +``` + +Alice meows across the room, telling `alice_public` to Bob, and Bob +loudly meows `bob_public` back to Alice. Alice now computes her +shared secret with Bob by doing: + +```rust +use x25519_dalek::diffie_hellman; + +let shared_secret = diffie_hellman(&alice_secret, &bob_public.as_bytes()); +``` + +Similarly, Bob computes the same shared secret by doing: + +```rust +let shared_secret = diffie_hellman(&bob_secret, &alice_public.as_bytes()); +``` + +Voilá! Alice and Bob can now use their shared secret to encrypt their +meows, for example, by using it to generate a key and nonce for an +authenticated-encryption cipher. + +# Warnings + +[Our elliptic curve library](https://github.com/isislovecruft/curve25519-dalek) +(which this code uses) has received *one* formal cryptographic and security +review. It has not yet received what we would consider *sufficient* peer +review by other qualified cryptographers to be considered in any way, shape, +or form, safe. + +This code matches the test vectors, as specified in +[RFC7748](https://tools.ietf.org/html/rfc7748), however: + +**USE AT YOUR OWN RISK.** + +# Documentation + +Documentation is available [here](https://docs.rs/x25519-dalek). + +# Installation + +To install, add the following to your project's `Cargo.toml`: + + [dependencies.x25519-dalek] + version = "^0.0" + +Then, in your library or executable source, add: + + extern crate x25519_dalek diff --git a/res/bubblesort-zines-secret-messages-cover.jpeg b/res/bubblesort-zines-secret-messages-cover.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..ca33298327849319aefb35ab9f8c2424caa0ab5a GIT binary patch literal 74941 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%0DDSW%hZg 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 literal 0 HcmV?d00001 diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..4297c57 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,140 @@ +// -*- mode: rust; -*- +// +// This file is part of x25519-dalek. +// Copyright (c) 2017 Isis Lovecruft +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft + +//! x25519 Diffie-Hellman key exchange +//! +//! A pure-Rust implementation of x25519 elliptic curve Diffie-Hellman key +//! exchange as specified by Mike Hamburg and Adam Langley in +//! [RFC7748](https://tools.ietf.org/html/rfc7748). +//! +//! # Examples +//! +//! [![](https://raw.githubusercontent.com/isislovecruft/x25519-dalek/master/res/bubblesort-zines-secret-messages-cover.jpeg)](https://shop.bubblesort.io) +//! +//! "Secret Messages" cover image and [zine](https://shop.bubblesort.io/products/secret-messages-zine) +//! copyright © Amy Wibowo ([@sailorhg](https://twitter.com/sailorhg)) +//! +//! Alice and Bob are two adorable kittens who have lost their mittens, and they +//! wish to be able to send secret messages to each other to coordinate finding +//! them, otherwise—if their caretaker cat finds out—they will surely be called +//! naughty kittens and be given no pie! +//! +//! But the two kittens are quite clever. Even though their paws are still too +//! big and the rest of them is 90% fuzziness, these clever kittens have been +//! studying up on modern public key cryptography and have learned a nifty trick +//! called *elliptic curve Diffie-Hellman key exchange*. With the right +//! incantations, the kittens will be able to secretly organise to find their +//! mittens, and then spend the rest of the afternoon nomming some yummy pie! +//! +//! First, Alice uses `x25519_dalek::generate_secret()` and +//! `x25519_dalek::generate_public()` to produce her secret and public keys: +//! +//! ``` +//! extern crate x25519_dalek; +//! extern crate rand; +//! +//! # fn main() { +//! use x25519_dalek::generate_secret; +//! use x25519_dalek::generate_public; +//! use rand::OsRng; +//! +//! let mut alice_csprng = OsRng::new().unwrap(); +//! let alice_secret = generate_secret(&mut alice_csprng); +//! let alice_public = generate_public(&alice_secret); +//! # } +//! ``` +//! +//! Bob does the same: +//! +//! ``` +//! # extern crate x25519_dalek; +//! # extern crate rand; +//! # +//! # fn main() { +//! # use x25519_dalek::generate_secret; +//! # use x25519_dalek::generate_public; +//! # use rand::OsRng; +//! # +//! let mut bob_csprng = OsRng::new().unwrap(); +//! let bob_secret = generate_secret(&mut bob_csprng); +//! let bob_public = generate_public(&bob_secret); +//! # } +//! ``` +//! +//! Alice meows across the room, telling `alice_public` to Bob, and Bob +//! loudly meows `bob_public` back to Alice. Alice now computes her +//! shared secret with Bob by doing: +//! +//! ``` +//! # extern crate x25519_dalek; +//! # extern crate rand; +//! # +//! # fn main() { +//! # use x25519_dalek::generate_secret; +//! # use x25519_dalek::generate_public; +//! # use rand::OsRng; +//! # +//! # let mut alice_csprng = OsRng::new().unwrap(); +//! # let alice_secret = generate_secret(&mut alice_csprng); +//! # let alice_public = generate_public(&alice_secret); +//! # +//! # let mut bob_csprng = OsRng::new().unwrap(); +//! # let bob_secret = generate_secret(&mut bob_csprng); +//! # let bob_public = generate_public(&bob_secret); +//! # +//! use x25519_dalek::diffie_hellman; +//! +//! let shared_secret = diffie_hellman(&alice_secret, &bob_public.as_bytes()); +//! # } +//! ``` +//! +//! Similarly, Bob computes the same shared secret by doing: +//! +//! ``` +//! # extern crate x25519_dalek; +//! # extern crate rand; +//! # +//! # fn main() { +//! # use x25519_dalek::diffie_hellman; +//! # use x25519_dalek::generate_secret; +//! # use x25519_dalek::generate_public; +//! # use rand::OsRng; +//! # +//! # let mut alice_csprng = OsRng::new().unwrap(); +//! # let alice_secret = generate_secret(&mut alice_csprng); +//! # let alice_public = generate_public(&alice_secret); +//! # +//! # let mut bob_csprng = OsRng::new().unwrap(); +//! # let bob_secret = generate_secret(&mut bob_csprng); +//! # let bob_public = generate_public(&bob_secret); +//! # +//! let shared_secret = diffie_hellman(&bob_secret, &alice_public.as_bytes()); +//! # } +//! ``` +//! +//! Voilá! Alice and Bob can now use their shared secret to encrypt their +//! meows, for example, by using it to generate a key and nonce for an +//! authenticated-encryption cipher. + +#![no_std] +#![cfg_attr(feature = "bench", feature(test))] +#![deny(missing_docs)] + +extern crate curve25519_dalek; + +#[cfg(feature = "std")] +extern crate rand; + +#[cfg(all(test, feature = "bench"))] +extern crate test; + +mod x25519; + +#[allow(missing_docs)] +pub use x25519::*; diff --git a/src/x25519.rs b/src/x25519.rs new file mode 100644 index 0000000..a86fc11 --- /dev/null +++ b/src/x25519.rs @@ -0,0 +1,172 @@ +// -*- mode: rust; -*- +// +// This file is part of x25519-dalek. +// Copyright (c) 2017 Isis Lovecruft +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft + +//! x25519 Diffie-Hellman key exchange +//! +//! This implements x25519 key exchange as specified by Mike Hamburg +//! and Adam Langley in [RFC7748](https://tools.ietf.org/html/rfc7748). + +use curve25519_dalek::constants::ED25519_BASEPOINT_TABLE; +use curve25519_dalek::montgomery::CompressedMontgomeryU; +use curve25519_dalek::montgomery::MontgomeryPoint; +use curve25519_dalek::scalar::Scalar; + +#[cfg(feature = "std")] +use rand::Rng; + +/// "Decode" a scalar from a 32-byte array. +/// +/// By "decode" here, what is really meant is applying key clamping by twiddling +/// some bits. +/// +/// # Returns +/// +/// A `Scalar`. +fn decode_scalar(scalar: &[u8; 32]) -> Scalar { + let mut s: [u8; 32] = scalar.clone(); + + s[0] &= 248; + s[31] &= 127; + s[31] |= 64; + + Scalar(s) +} + +/// Generate an x25519 secret key. +#[cfg(feature = "std")] +pub fn generate_secret(csprng: &mut T) -> [u8; 32] { + let mut bytes = [0u8; 32]; + csprng.fill_bytes(&mut bytes); + bytes +} + +/// Given an x25519 secret key, compute its corresponding public key. +pub fn generate_public(secret: &[u8; 32]) -> CompressedMontgomeryU { + (&decode_scalar(secret) * &ED25519_BASEPOINT_TABLE).to_montgomery().compress() +} + +/// The x25519 function, as specified in RFC7748. +pub fn x25519(scalar: &Scalar, point: &CompressedMontgomeryU) -> CompressedMontgomeryU { + let k: Scalar = decode_scalar(scalar.as_bytes()); + let u: MontgomeryPoint = point.decompress(); + + (&k * &u).compress() +} + +/// Utility function to make it easier to call `x25519()` with byte arrays as +/// inputs and outputs. +pub fn diffie_hellman(my_secret: &[u8; 32], their_public: &[u8; 32]) -> [u8; 32] { + x25519(&Scalar(*my_secret), &CompressedMontgomeryU(*their_public)).to_bytes() +} + + +#[cfg(test)] +mod test { + use curve25519_dalek::constants::BASE_COMPRESSED_MONTGOMERY; + use super::*; + + fn do_rfc7748_ladder_test1(input_scalar: &Scalar, + input_point: &CompressedMontgomeryU, + expected: &[u8; 32]) { + let result = x25519(&input_scalar, &input_point); + + assert_eq!(result.0, *expected); + } + + #[test] + fn rfc7748_ladder_test1_vectorset1() { + let input_scalar: Scalar = Scalar([ + 0xa5, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d, + 0x3b, 0x16, 0x15, 0x4b, 0x82, 0x46, 0x5e, 0xdd, + 0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc, 0x5a, 0x18, + 0x50, 0x6a, 0x22, 0x44, 0xba, 0x44, 0x9a, 0xc4, ]); + let input_point: CompressedMontgomeryU = CompressedMontgomeryU([ + 0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb, + 0x35, 0x94, 0xc1, 0xa4, 0x24, 0xb1, 0x5f, 0x7c, + 0x72, 0x66, 0x24, 0xec, 0x26, 0xb3, 0x35, 0x3b, + 0x10, 0xa9, 0x03, 0xa6, 0xd0, 0xab, 0x1c, 0x4c, ]); + let expected: [u8; 32] = [ + 0xc3, 0xda, 0x55, 0x37, 0x9d, 0xe9, 0xc6, 0x90, + 0x8e, 0x94, 0xea, 0x4d, 0xf2, 0x8d, 0x08, 0x4f, + 0x32, 0xec, 0xcf, 0x03, 0x49, 0x1c, 0x71, 0xf7, + 0x54, 0xb4, 0x07, 0x55, 0x77, 0xa2, 0x85, 0x52, ]; + + do_rfc7748_ladder_test1(&input_scalar, &input_point, &expected); + } + + #[test] + fn rfc7748_ladder_test1_vectorset2() { + let input_scalar: Scalar = Scalar([ + 0x4b, 0x66, 0xe9, 0xd4, 0xd1, 0xb4, 0x67, 0x3c, + 0x5a, 0xd2, 0x26, 0x91, 0x95, 0x7d, 0x6a, 0xf5, + 0xc1, 0x1b, 0x64, 0x21, 0xe0, 0xea, 0x01, 0xd4, + 0x2c, 0xa4, 0x16, 0x9e, 0x79, 0x18, 0xba, 0x0d, ]); + let input_point: CompressedMontgomeryU = CompressedMontgomeryU([ + 0xe5, 0x21, 0x0f, 0x12, 0x78, 0x68, 0x11, 0xd3, + 0xf4, 0xb7, 0x95, 0x9d, 0x05, 0x38, 0xae, 0x2c, + 0x31, 0xdb, 0xe7, 0x10, 0x6f, 0xc0, 0x3c, 0x3e, + 0xfc, 0x4c, 0xd5, 0x49, 0xc7, 0x15, 0xa4, 0x93, ]); + let expected: [u8; 32] = [ + 0x95, 0xcb, 0xde, 0x94, 0x76, 0xe8, 0x90, 0x7d, + 0x7a, 0xad, 0xe4, 0x5c, 0xb4, 0xb8, 0x73, 0xf8, + 0x8b, 0x59, 0x5a, 0x68, 0x79, 0x9f, 0xa1, 0x52, + 0xe6, 0xf8, 0xf7, 0x64, 0x7a, 0xac, 0x79, 0x57, ]; + + do_rfc7748_ladder_test1(&input_scalar, &input_point, &expected); + } + + #[test] + #[ignore] // Run only if you want to burn a lot of CPU doing 1,000,000 DH operations + fn rfc7748_ladder_test2() { + let mut k: Scalar = Scalar(BASE_COMPRESSED_MONTGOMERY.0); + let mut u: CompressedMontgomeryU = BASE_COMPRESSED_MONTGOMERY; + let mut result: CompressedMontgomeryU; + + macro_rules! do_iterations { + ($n:expr) => ( + for _ in 0..$n { + result = x25519(&k, &u); + // OBVIOUS THING THAT I'M GOING TO NOTE ANYWAY BECAUSE I'VE + // SEEN PEOPLE DO THIS WITH GOLANG'S STDLIB AND YOU SURE AS + // HELL SHOULDN'T DO HORRIBLY STUPID THINGS LIKE THIS WITH + // MY LIBRARY: + // + // NEVER EVER TREAT SCALARS AS POINTS AND/OR VICE VERSA. + // + // ↓↓ DON'T DO THIS ↓↓ + u = CompressedMontgomeryU(k.as_bytes().clone()); + k = Scalar(result.to_bytes()); + } + ) + } + + // After one iteration: + // 422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854b783c60e80311ae3079 + // After 1,000 iterations: + // 684cf59ba83309552800ef566f2f4d3c1c3887c49360e3875f2eb94d99532c51 + // After 1,000,000 iterations: + // 7c3911e0ab2586fd864497297e575e6f3bc601c0883c30df5f4dd2d24f665424 + + do_iterations!(1); + assert_eq!(k.as_bytes(), &[ 0x42, 0x2c, 0x8e, 0x7a, 0x62, 0x27, 0xd7, 0xbc, + 0xa1, 0x35, 0x0b, 0x3e, 0x2b, 0xb7, 0x27, 0x9f, + 0x78, 0x97, 0xb8, 0x7b, 0xb6, 0x85, 0x4b, 0x78, + 0x3c, 0x60, 0xe8, 0x03, 0x11, 0xae, 0x30, 0x79, ]); + do_iterations!(999); + assert_eq!(k.as_bytes(), &[ 0x68, 0x4c, 0xf5, 0x9b, 0xa8, 0x33, 0x09, 0x55, + 0x28, 0x00, 0xef, 0x56, 0x6f, 0x2f, 0x4d, 0x3c, + 0x1c, 0x38, 0x87, 0xc4, 0x93, 0x60, 0xe3, 0x87, + 0x5f, 0x2e, 0xb9, 0x4d, 0x99, 0x53, 0x2c, 0x51, ]); + do_iterations!(999_000); + assert_eq!(k.as_bytes(), &[ 0x7c, 0x39, 0x11, 0xe0, 0xab, 0x25, 0x86, 0xfd, + 0x86, 0x44, 0x97, 0x29, 0x7e, 0x57, 0x5e, 0x6f, + 0x3b, 0xc6, 0x01, 0xc0, 0x88, 0x3c, 0x30, 0xdf, + 0x5f, 0x4d, 0xd2, 0xd2, 0x4f, 0x66, 0x54, 0x24, ]); + } +}