├── .gitignore ├── .github ├── example.png └── workflows │ └── tests.yml ├── src ├── krist │ ├── mod.rs │ ├── block.rs │ └── address.rs ├── miner │ ├── cpu │ │ ├── kernels │ │ │ ├── unoptimized.rs │ │ │ ├── mod.rs │ │ │ └── sha.rs │ │ ├── thread_priority.rs │ │ ├── framework.rs │ │ └── mod.rs │ ├── mod.rs │ ├── gpu │ │ ├── kristforge.cl │ │ └── mod.rs │ └── interface.rs ├── network │ ├── http.rs │ ├── ws.rs │ └── mod.rs ├── ext.rs └── main.rs ├── .editorconfig ├── release.sh ├── Cargo.toml ├── CHANGELOG.md ├── README.md ├── LICENSE.txt └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | .idea 4 | -------------------------------------------------------------------------------- /.github/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tmpim/kristforge/HEAD/.github/example.png -------------------------------------------------------------------------------- /src/krist/mod.rs: -------------------------------------------------------------------------------- 1 | //! Krist-related types 2 | 3 | pub mod address; 4 | pub mod block; 5 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | insert_final_newline = true 6 | charset = utf-8 7 | -------------------------------------------------------------------------------- /release.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | cross build --target x86_64-pc-windows-gnu --release 3 | cross build --target x86_64-unknown-linux-gnu --release 4 | rm target/kristforge_{windows,linux}.zip 5 | zip -j target/kristforge_windows.zip target/x86_64-pc-windows-gnu/release/kristforge.exe 6 | zip -j target/kristforge_linux.zip target/x86_64-unknown-linux-gnu/release/kristforge 7 | -------------------------------------------------------------------------------- /src/miner/cpu/kernels/unoptimized.rs: -------------------------------------------------------------------------------- 1 | use super::{score_output, Kernel, ScalarKernelInput}; 2 | use ring::digest::{digest, SHA256}; 3 | 4 | pub struct Unoptimized; 5 | impl Kernel for Unoptimized { 6 | type Input = ScalarKernelInput; 7 | 8 | #[inline(always)] 9 | fn score(&self, input: &ScalarKernelInput) -> u64 { 10 | score_output(digest(&SHA256, input.data()).as_ref()) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/miner/cpu/thread_priority.rs: -------------------------------------------------------------------------------- 1 | #[cfg(windows)] 2 | pub fn set_low_priority() { 3 | use winapi::um::processthreadsapi::*; 4 | 5 | unsafe { 6 | let thread = GetCurrentThread(); 7 | SetThreadPriority(thread, -1); 8 | } 9 | } 10 | 11 | #[cfg(unix)] 12 | pub fn set_low_priority() { 13 | use libc::*; 14 | 15 | unsafe { 16 | assert_eq!(setpriority(PRIO_PROCESS as u32, 0, 5), 0); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Rust tests 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v1 12 | - name: Update rust stable 13 | run: | 14 | rustup set profile minimal 15 | rustup update stable 16 | - name: Build 17 | run: cargo build --verbose 18 | - name: Run tests 19 | run: cargo test --verbose -- --nocapture 20 | -------------------------------------------------------------------------------- /src/network/http.rs: -------------------------------------------------------------------------------- 1 | use super::NetworkError; 2 | use isahc::http::Uri; 3 | use isahc::ResponseExt; 4 | use serde::Deserialize; 5 | use url::Url; 6 | 7 | #[derive(Debug, Deserialize)] 8 | pub struct WsStartResponse { 9 | pub url: Url, 10 | } 11 | 12 | /// Request to start a websocket connection 13 | pub async fn ws_start(uri: Uri) -> Result { 14 | let json = isahc::post_async(uri, ()).await?.text_async().await?; 15 | serde_json::from_str(&json).map_err(|e| e.into()) 16 | } 17 | -------------------------------------------------------------------------------- /src/ext.rs: -------------------------------------------------------------------------------- 1 | use ocl::error::Result as OclResult; 2 | use ocl::Device; 3 | use ocl_extras::full_device_info::FullDeviceInfo; 4 | 5 | pub trait DeviceExt { 6 | fn human_name(&self) -> OclResult; 7 | 8 | fn preferred_vecsize(&self) -> OclResult; 9 | } 10 | 11 | impl DeviceExt for Device { 12 | fn human_name(&self) -> OclResult { 13 | const CL_DEVICE_BOARD_NAME_AMD: u32 = 0x4038; 14 | 15 | if self.extensions()?.contains("cl_amd_device_attribute_query") { 16 | // read raw name 17 | let mut raw = self.info_raw(CL_DEVICE_BOARD_NAME_AMD)?; 18 | 19 | // remove null byte(s) 20 | raw.retain(|&b| b != 0); 21 | 22 | // parse as UTF-8 23 | Ok(String::from_utf8_lossy(&raw).into_owned()) 24 | } else { 25 | self.name() 26 | } 27 | } 28 | 29 | fn preferred_vecsize(&self) -> OclResult { 30 | Ok(1) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/network/ws.rs: -------------------------------------------------------------------------------- 1 | use super::{NetworkError, ServerMessage}; 2 | use crate::network::ClientMessage; 3 | use futures::{future, Sink, SinkExt, StreamExt, TryFutureExt, TryStream, TryStreamExt}; 4 | use tokio_tungstenite::connect_async; 5 | use url::Url; 6 | 7 | pub async fn ws_connect( 8 | url: Url, 9 | ) -> Result< 10 | ( 11 | impl Sink, 12 | impl TryStream, 13 | ), 14 | NetworkError, 15 | > { 16 | // open a connection and split into sending/receiving halves 17 | let (ws, _response) = connect_async(url).await?; 18 | let (sink, stream) = ws.split(); 19 | 20 | // map the sending half 21 | let sink = sink 22 | .sink_err_into::() 23 | .with(|m| future::ready(serde_json::to_string(&m).map(|j| j.into())).err_into()); 24 | 25 | // map the receiving half 26 | let stream = stream 27 | .err_into() 28 | .try_filter(|m| future::ready(!(m.is_ping() || m.is_pong()))) 29 | .and_then(|m| future::ready(m.into_text()).err_into()) 30 | .inspect_ok(|json| log::info!("Server message: {}", json)) 31 | .and_then(|json| future::ready(serde_json::from_str(&json)).err_into()); 32 | 33 | Ok((sink, stream)) 34 | } 35 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "kristforge" 3 | version = "3.1.6" 4 | description = "Hardware accelerated CPU and GPU Krist miner" 5 | authors = ["Dana Marcuse "] 6 | edition = "2018" 7 | license = "Apache-2.0" 8 | 9 | [dependencies] 10 | serde = { version = "1.0.115", features = [ "derive" ] } 11 | serde_json = "1.0.57" 12 | hex = "0.4.2" 13 | thiserror = "1.0.20" 14 | futures = "0.3.5" 15 | tokio = { version = "0.2.22", features = [ "macros" ] } 16 | tokio-tungstenite = { version = "0.11.0", features = [ "tls" ] } 17 | isahc = { version = "0.9.8", features = [ "static-ssl" ] } 18 | lazy_static = "1.4.0" 19 | structopt = "0.3.16" 20 | url = { version = "2.1.1", features = [ "serde" ] } 21 | indicatif = "0.15.0" 22 | log = "0.4.11" 23 | simplelog = "0.8.0" 24 | dirs = "3.0.1" 25 | rand = "0.7.3" 26 | dynamic_ocl = "0.1.0-alpha.1" 27 | enumset = "1.0.1" 28 | itertools = "0.9.0" 29 | num_cpus = "1.13.0" 30 | crossbeam = "0.7.3" 31 | ring = "0.16.15" 32 | 33 | [target.'cfg(windows)'.dependencies] 34 | winapi = "0.3.9" 35 | 36 | [target.'cfg(unix)'.dependencies] 37 | libc = "0.2.74" 38 | 39 | [profile.release] 40 | lto = true 41 | codegen-units = 1 42 | debug = true 43 | 44 | [profile.release.package."*"] 45 | codegen-units = 1 46 | debug = false 47 | 48 | [profile.dev.package."*"] 49 | opt-level = 1 50 | codegen-units = 1 51 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 3.1.6 4 | 5 | - Fix panic with intel iGPU OpenCL runtime due to flaky kernel argument type checks (https://github.com/tmpim/kristforge/issues/18) 6 | - Updated dependencies 7 | 8 | ## 3.1.5 9 | 10 | - Fix mined krist being double-counted (https://github.com/tmpim/kristforge/issues/16) 11 | - Updated dependencies 12 | 13 | ## 3.1.4 14 | 15 | - Fix crash on systems where OpenCL isn't available (will now degrade gracefully to CPU-only mining as intended) 16 | 17 | ## 3.1.3 18 | 19 | - Allow specifying krist address via `KRISTFORGE_ADDRESS` environment variable 20 | - Fix crash related to OpenCL compiler unloading 21 | 22 | ## 3.1.2 23 | 24 | - Revert Intel default thread count change from version 3.1.1 25 | - Set CPU mining threads to lower priority to avoid crippling system performance 26 | 27 | ## 3.1.1 28 | 29 | - On Intel systems, uses fewer threads by default to avoid crippling system performance 30 | - Improved UI a bit 31 | 32 | ## 3.1.0 33 | 34 | - Added CPU support including two mining kernels: 35 | - `unoptimized` which makes no assumptions about instruction sets and should work everywhere 36 | - `SHA` which takes advantage of the SHA instruction set on recent processors to offer dramatically better speeds 37 | - Updated dependencies 38 | 39 | ## 3.0.0-alpha 40 | 41 | - Initial release with only GPU support via OpenCL 42 | -------------------------------------------------------------------------------- /src/miner/cpu/kernels/mod.rs: -------------------------------------------------------------------------------- 1 | mod sha; 2 | mod unoptimized; 3 | 4 | use super::framework::{Kernel, ScalarKernelInput}; 5 | pub use sha::SHA; 6 | pub use unoptimized::Unoptimized; 7 | 8 | /// Calculate the score from the raw a/b variables of the hash state 9 | #[inline(always)] 10 | fn score_ab(a: u32, b: u32) -> u64 { 11 | (a.to_le() as u64) << 16 | (b as u64) >> 16 12 | } 13 | 14 | /// Calculate the score from the hash output (len must be >= 6) 15 | #[inline(always)] 16 | fn score_output(h: &[u8]) -> u64 { 17 | h[..6] 18 | .iter() 19 | .enumerate() 20 | .map(|(i, &v)| (v as u64) << (40 - (8 * i))) 21 | .sum() 22 | } 23 | 24 | #[cfg(test)] 25 | mod tests { 26 | use super::super::framework::KernelInput; 27 | use super::*; 28 | use crate::krist::address::Address; 29 | use ring::digest::{digest, SHA256}; 30 | use std::str::FromStr; 31 | 32 | fn test_scalar_kernel(kernel: impl Kernel) { 33 | let mut input = ScalarKernelInput::new(Address::from_str("k5ztameslf").unwrap(), 0); 34 | input.set_block(&*b"abce8f03b1d2"); 35 | 36 | let expected_hex = hex::encode(digest(&SHA256, input.data()).as_ref()); 37 | let expected = u64::from_str_radix(&expected_hex[..12], 16).unwrap(); 38 | 39 | let actual = kernel.score(&input); 40 | 41 | assert_eq!( 42 | expected, 43 | actual, 44 | "hash score mismatch for input '{}'", 45 | String::from_utf8_lossy(input.data()) 46 | ) 47 | } 48 | 49 | #[test] 50 | fn test_unoptimized_kernel() { 51 | test_scalar_kernel(Unoptimized); 52 | } 53 | 54 | #[test] 55 | fn test_sha_kernel() { 56 | if is_x86_feature_detected!("sha") { 57 | test_scalar_kernel(SHA); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # kristforge ![Rust tests](https://github.com/tmpim/kristforge/workflows/Rust%20tests/badge.svg) 2 | 3 | Kristforge is a cross-platform hardware accelerated GPU and CPU [krist](https://krist.ceriat.net) miner. Kristforge uses 4 | OpenCL and accelerated CPU instruction sets to maximize performance, making it the fastest krist miner in existence. 5 | 6 | ![Screenshot](.github/example.png) 7 | 8 | ## Download 9 | 10 | Pre-built 64-bit binaries for Linux and Windows can be found on the 11 | [release page](https://github.com/tmpim/kristforge/releases). 12 | 13 | ## Usage 14 | 15 | Kristforge supports both CPU and GPU mining. GPU mining is usually faster and more efficient, but modern CPUs can also 16 | provide decent speeds. 17 | 18 | OpenCL drivers are required for GPU support to work - these are usually included with your 19 | graphics drivers, but you may need to manually install them. See your manufacturer's driver/support page for 20 | instructions for your specific setup. On Linux systems in particular, these are often packaged separately from graphics 21 | drivers, and should be installed through your distribution's package manager. 22 | 23 | Kristforge provides many command-line options to configure it to suit your needs, but also intelligently selects 24 | defaults that provide near-optimal performance for most users. The default behavior of kristforge is to use all GPU 25 | devices and automatically scale up batch sizes, and use as many CPU miner threads as your system has logical cores. 26 | 27 | ## Examples 28 | 29 | - Mine with default settings using both CPU and GPU 30 | - `kristforge mine
` 31 | - Mine with default settings using only GPU 32 | - `kristforge mine
--no-cpu` 33 | - Mine with only CPU with a specific number of threads 34 | - `kristforge mine
--no-gpu --cpu-threads 8` 35 | - Get mining hardware information 36 | - `kristforge info` 37 | 38 | Complete usage information for more advanced configuration can be viewed with `kristforge help [subcommand]`. 39 | -------------------------------------------------------------------------------- /src/miner/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod cpu; 2 | pub mod gpu; 3 | pub mod interface; 4 | 5 | use crate::krist::address::Address; 6 | use crate::krist::block::ShortHash; 7 | use crate::miner::cpu::{CpuMiner, KernelType}; 8 | use crate::miner::gpu::OclMiner; 9 | use crate::miner::interface::MinerInterface; 10 | use structopt::StructOpt; 11 | 12 | #[derive(Debug, Clone, StructOpt)] 13 | pub struct MinerConfig { 14 | /// Don't use OpenCL for mining. 15 | #[structopt(long)] 16 | no_gpu: bool, 17 | // TODO: allow selecting individual devices 18 | /// OpenCL miner target kernel execution time, in seconds. 19 | #[structopt(long, default_value = "0.1")] 20 | gpu_rate: f32, 21 | 22 | /// OpenCL miner max work size (default 2^31). 23 | #[structopt(long, default_value = "2147483648")] 24 | gpu_max_worksize: usize, 25 | 26 | /// Don't use the CPU for mining. 27 | #[structopt(long)] 28 | no_cpu: bool, 29 | 30 | /// CPU miner threads, defaulting to the processor's thread count. 31 | #[structopt(long)] 32 | cpu_threads: Option, 33 | 34 | /// Select a specific CPU mining kernel. 35 | #[structopt(long)] 36 | cpu_kernel: Option, 37 | } 38 | 39 | #[derive(Debug, thiserror::Error)] 40 | pub enum MinerError { 41 | #[error("OpenCL error: {0}")] 42 | OclError(#[from] dynamic_ocl::Error), 43 | } 44 | 45 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 46 | pub struct Target { 47 | pub work: u64, 48 | pub block: ShortHash, 49 | } 50 | 51 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 52 | pub struct Solution { 53 | pub address: Address, 54 | pub nonce: [u8; 12], 55 | } 56 | 57 | pub trait Miner { 58 | /// Get a human-readable description of this miner 59 | fn describe(&self) -> String; 60 | 61 | /// Start a long-lived mining operation, blocking the thread and using the 62 | /// given interface for state operations. 63 | fn mine(self: Box, interface: MinerInterface) -> Result<(), MinerError>; 64 | } 65 | 66 | pub fn create_miners(opts: MinerConfig) -> Result>, MinerError> { 67 | let mut miners = Vec::>::new(); 68 | 69 | if !opts.no_gpu { 70 | for device in gpu::get_opencl_devices()? { 71 | miners.push(Box::new(OclMiner::new(device, &opts)?)); 72 | } 73 | } 74 | 75 | if !opts.no_cpu { 76 | miners.push(Box::new(CpuMiner::new(&opts))); 77 | } 78 | 79 | Ok(miners) 80 | } 81 | -------------------------------------------------------------------------------- /src/krist/block.rs: -------------------------------------------------------------------------------- 1 | use super::address::Address; 2 | use hex::FromHexError; 3 | use serde::{Deserialize, Serialize}; 4 | use std::convert::TryFrom; 5 | use std::fmt::{self, Debug, Display, Formatter}; 6 | use std::str::FromStr; 7 | 8 | #[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] 9 | #[serde(try_from = "&str", into = "String")] 10 | pub struct ShortHash([u8; ShortHash::LENGTH]); 11 | 12 | impl ShortHash { 13 | pub const LENGTH: usize = 6; 14 | 15 | pub fn bytes(self) -> [u8; ShortHash::LENGTH] { 16 | self.0 17 | } 18 | 19 | pub fn into_hex(self) -> String { 20 | hex::encode(self.0) 21 | } 22 | } 23 | 24 | impl FromStr for ShortHash { 25 | type Err = FromHexError; 26 | 27 | fn from_str(s: &str) -> Result { 28 | let mut hash = [0u8; Self::LENGTH]; 29 | hex::decode_to_slice(s, &mut hash)?; 30 | Ok(Self(hash)) 31 | } 32 | } 33 | 34 | impl TryFrom<&str> for ShortHash { 35 | type Error = FromHexError; 36 | 37 | fn try_from(value: &str) -> Result { 38 | Self::from_str(value) 39 | } 40 | } 41 | 42 | impl Display for ShortHash { 43 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { 44 | f.write_str(&self.into_hex()) 45 | } 46 | } 47 | 48 | impl From for String { 49 | fn from(hash: ShortHash) -> Self { 50 | hash.into_hex() 51 | } 52 | } 53 | 54 | impl Debug for ShortHash { 55 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { 56 | write!(f, "ShortHash({})", self) 57 | } 58 | } 59 | 60 | #[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] 61 | #[serde(try_from = "&str", into = "String")] 62 | pub struct Hash([u8; Hash::LENGTH]); 63 | 64 | impl Hash { 65 | pub const LENGTH: usize = 32; 66 | 67 | pub fn bytes(self) -> [u8; Hash::LENGTH] { 68 | self.0 69 | } 70 | 71 | pub fn into_hex(self) -> String { 72 | hex::encode(self.0) 73 | } 74 | } 75 | 76 | impl FromStr for Hash { 77 | type Err = FromHexError; 78 | 79 | fn from_str(s: &str) -> Result { 80 | let mut hash = [0u8; Self::LENGTH]; 81 | hex::decode_to_slice(s, &mut hash)?; 82 | Ok(Self(hash)) 83 | } 84 | } 85 | 86 | impl TryFrom<&str> for Hash { 87 | type Error = FromHexError; 88 | 89 | fn try_from(value: &str) -> Result { 90 | Self::from_str(value) 91 | } 92 | } 93 | 94 | impl Display for Hash { 95 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { 96 | f.write_str(&self.into_hex()) 97 | } 98 | } 99 | 100 | impl From for String { 101 | fn from(hash: Hash) -> Self { 102 | hash.into_hex() 103 | } 104 | } 105 | 106 | impl Debug for Hash { 107 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { 108 | write!(f, "Hash({})", self) 109 | } 110 | } 111 | 112 | /// A mined block 113 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] 114 | pub struct Block { 115 | pub height: u64, 116 | pub value: u32, 117 | pub hash: Hash, 118 | pub short_hash: ShortHash, 119 | pub address: Address, 120 | } 121 | -------------------------------------------------------------------------------- /src/miner/gpu/kristforge.cl: -------------------------------------------------------------------------------- 1 | // right rotate macro 2 | #define RR(x, y) rotate((uint)(x), -(uint)(y)) 3 | 4 | // sha256 macros 5 | #define CH(x, y, z) bitselect((z),(y),(x)) 6 | #define MAJ(x, y, z) bitselect((x),(y),(z)^(x)) 7 | #define EP0(x) (RR((x),2) ^ RR((x),13) ^ RR((x),22)) 8 | #define EP1(x) (RR((x),6) ^ RR((x),11) ^ RR((x),25)) 9 | #define SIG0(x) (RR((x),7) ^ RR((x),18) ^ ((x) >> 3)) 10 | #define SIG1(x) (RR((x),17) ^ RR((x),19) ^ ((x) >> 10)) 11 | 12 | // sha256 initial hash values 13 | #define H0 0x6a09e667 14 | #define H1 0xbb67ae85 15 | #define H2 0x3c6ef372 16 | #define H3 0xa54ff53a 17 | #define H4 0x510e527f 18 | #define H5 0x9b05688c 19 | #define H6 0x1f83d9ab 20 | #define H7 0x5be0cd19 21 | 22 | // sha256 round constants 23 | constant uint K[64] = { 24 | 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 25 | 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 26 | 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 27 | 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 28 | 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 29 | 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 30 | 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 31 | 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 32 | }; 33 | 34 | kernel void mine( 35 | constant const uchar *input, // address + prev block - 22 bytes 36 | const ulong work, // target work 37 | const ulong offset, // id offset 38 | global uchar *solution // solution nonce - 11 bytes 39 | ) { 40 | // initialize hash input array 41 | uchar text[64] = { 0 }; 42 | 43 | // fill first 22 bytes of hash input 44 | #pragma unroll 45 | for (int i = 0; i < 22; i++) text[i] = input[i]; 46 | 47 | // expand id into next 11 bytes 48 | ulong id = get_global_id(0) + offset; 49 | 50 | #pragma unroll 51 | for (int i = 0; i < 11; i++) { text[i + 22] = ((id >> (i * 6)) & 0x3f) + 32; } 52 | 53 | // padding - digest input is 33 bytes 54 | text[33] = 0x80; 55 | text[62] = ((33 * 8) >> 8) & 0xff; 56 | text[63] = (33 * 8) & 0xff; 57 | 58 | uint a, b, c, d, e, f, g, h, t1, t2, m[64]; 59 | 60 | // message extension 61 | #pragma unroll 62 | for (int i = 0; i < 16; i++) { 63 | m[i] = text[i * 4 ] << 24 | 64 | text[i * 4 + 1] << 16 | 65 | text[i * 4 + 2] << 8 | 66 | text[i * 4 + 3]; 67 | } 68 | 69 | #pragma unroll 70 | for (int i = 16; i < 64; i++) { 71 | m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16]; 72 | } 73 | 74 | // transformation 75 | a = H0; 76 | b = H1; 77 | c = H2; 78 | d = H3; 79 | e = H4; 80 | f = H5; 81 | g = H6; 82 | h = H7; 83 | 84 | #pragma unroll 85 | for (int i = 0; i < 64; i++) { 86 | t1 = h + EP1(e) + CH(e, f, g) + K[i] + m[i]; 87 | t2 = EP0(a) + MAJ(a, b, c); 88 | h = g; 89 | g = f; 90 | f = e; 91 | e = d + t1; 92 | d = c; 93 | c = b; 94 | b = a; 95 | a = t1 + t2; 96 | } 97 | 98 | // only need the first 6 bytes of the hash output 99 | a += H0; 100 | b += H1; 101 | 102 | ulong score = (((ulong)(a >> 24)) & 0xff) << 40 | 103 | (((ulong)(a >> 16)) & 0xff) << 32 | 104 | (((ulong)(a >> 8)) & 0xff) << 24 | 105 | (((ulong)(a )) & 0xff) << 16 | 106 | (((ulong)(b >> 24)) & 0xff) << 8 | 107 | (((ulong)(b >> 16)) & 0xff); 108 | 109 | if (score <= work) { 110 | // solution found! 111 | // copy nonce to solution buffer 112 | #pragma unroll 113 | for (int i = 0; i < 11; i++) { 114 | solution[i] = text[i + 22]; 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/miner/interface.rs: -------------------------------------------------------------------------------- 1 | use super::Target; 2 | use crate::krist::address::Address; 3 | use crossbeam::channel::{Receiver, TryRecvError}; 4 | use futures::channel::mpsc::UnboundedSender; 5 | use indicatif::ProgressBar; 6 | use std::cmp::min; 7 | use std::convert::TryInto; 8 | use std::time::Duration; 9 | 10 | pub struct MinerInterface { 11 | address: Address, 12 | pb: ProgressBar, 13 | target_rx: Receiver, 14 | target: Option, 15 | solution_tx: UnboundedSender, 16 | } 17 | 18 | pub struct StopMining; 19 | 20 | #[derive(Debug, Clone, Copy)] 21 | pub enum CurrentTarget { 22 | New(Target), 23 | Unchanged(Target), 24 | StopMining, 25 | } 26 | 27 | impl CurrentTarget { 28 | pub fn into_raw(self) -> Option<([u8; 12], u64)> { 29 | match self { 30 | CurrentTarget::New(t) | CurrentTarget::Unchanged(t) => { 31 | Some((t.block.into_hex().as_bytes().try_into().unwrap(), t.work)) 32 | } 33 | CurrentTarget::StopMining => None, 34 | } 35 | } 36 | } 37 | 38 | impl MinerInterface { 39 | pub fn new( 40 | address: Address, 41 | pb: ProgressBar, 42 | target_rx: Receiver, 43 | solution_tx: UnboundedSender, 44 | ) -> Self { 45 | Self { 46 | address, 47 | pb, 48 | target_rx, 49 | target: None, 50 | solution_tx, 51 | } 52 | } 53 | 54 | pub fn address(&self) -> Address { 55 | self.address 56 | } 57 | 58 | /// Get the current target, blocking the thread if necessary 59 | pub fn current_target(&mut self) -> CurrentTarget { 60 | if let Some(old) = self.target { 61 | match self.target_rx.try_recv() { 62 | Ok(target) => { 63 | self.target = Some(target); 64 | CurrentTarget::New(target) 65 | } 66 | Err(TryRecvError::Empty) => CurrentTarget::Unchanged(old), 67 | Err(TryRecvError::Disconnected) => CurrentTarget::StopMining, 68 | } 69 | } else { 70 | match self.target_rx.recv() { 71 | Ok(target) => { 72 | self.target = Some(target); 73 | CurrentTarget::New(target) 74 | } 75 | Err(_) => CurrentTarget::StopMining, 76 | } 77 | } 78 | } 79 | 80 | pub fn report_speed(&mut self, hashes: u64, time: Duration) { 81 | let per_second = hashes as f64 / time.as_secs_f64(); 82 | 83 | const PREFIXES: [&str; 5] = ["", "k", "M", "G", "T"]; 84 | let magnitude = min(PREFIXES.len() - 1, per_second.log(1000.).floor() as usize); 85 | let value = per_second / 1000f64.powf(magnitude as f64); 86 | 87 | self.pb.set_message(&format!( 88 | "Mining at {:.1} {}h/s", 89 | value, PREFIXES[magnitude] 90 | )); 91 | } 92 | 93 | pub fn report_solution(&self, solution: String) -> Result<(), StopMining> { 94 | log::info!( 95 | "Solution reported for address {} and target {:?}: nonce {} (hex: {:x?})", 96 | self.address, 97 | self.target, 98 | solution, 99 | solution, 100 | ); 101 | 102 | self.pb.println(format!( 103 | "Submitting solution for block {} (nonce {})", 104 | self.target.unwrap().block.into_hex(), 105 | solution 106 | )); 107 | 108 | // TODO: validate solution 109 | 110 | self.solution_tx 111 | .unbounded_send(solution) 112 | .map_err(|_| StopMining) 113 | } 114 | } 115 | 116 | impl Drop for MinerInterface { 117 | fn drop(&mut self) { 118 | self.pb.finish(); 119 | } 120 | } 121 | 122 | #[cfg(test)] 123 | mod tests {} 124 | -------------------------------------------------------------------------------- /src/network/mod.rs: -------------------------------------------------------------------------------- 1 | //! Networking code for interacting with a krist node 2 | 3 | mod http; 4 | mod ws; 5 | 6 | use crate::krist::address::Address; 7 | use crate::krist::block::Block; 8 | use futures::{Sink, TryStream}; 9 | use isahc::http::Uri; 10 | use serde::de::Error as _; 11 | use serde::{Deserialize, Deserializer, Serialize, Serializer}; 12 | use std::collections::HashMap; 13 | use std::num::NonZeroU64; 14 | use structopt::StructOpt; 15 | 16 | #[derive(Debug, StructOpt)] 17 | pub struct NetConfig { 18 | /// The krist node to connect to 19 | #[structopt(short, long, default_value = "https://krist.ceriat.net/ws/start")] 20 | pub node: Uri, 21 | } 22 | 23 | #[derive(Debug, thiserror::Error)] 24 | pub enum NetworkError { 25 | #[error("HTTP error: {0}")] 26 | HttpError(#[from] isahc::Error), 27 | 28 | #[error("IO error: {0}")] 29 | IoError(#[from] std::io::Error), 30 | 31 | #[error("JSON error: {0}")] 32 | JsonError(#[from] serde_json::Error), 33 | 34 | #[error("Websocket error: {0}")] 35 | WsError(#[from] tokio_tungstenite::tungstenite::Error), 36 | } 37 | 38 | #[derive(Debug, Clone, Copy)] 39 | pub struct KeepAliveType; 40 | 41 | impl<'de> Deserialize<'de> for KeepAliveType { 42 | fn deserialize>(deserializer: D) -> Result { 43 | match <&str>::deserialize(deserializer)? { 44 | "keepalive" => Ok(KeepAliveType), 45 | _ => Err(D::Error::custom("Message type is not keepalive")), 46 | } 47 | } 48 | } 49 | 50 | #[derive(Debug, Clone, Copy, Default)] 51 | pub struct SubmitBlockType; 52 | 53 | impl Serialize for SubmitBlockType { 54 | fn serialize(&self, serializer: S) -> Result { 55 | serializer.serialize_str("submit_block") 56 | } 57 | } 58 | 59 | #[derive(Debug, Clone, Deserialize)] 60 | #[serde(untagged)] 61 | pub enum ServerMessage { 62 | Target { 63 | #[serde(alias = "type")] 64 | msg_type: String, 65 | 66 | #[serde(alias = "last_block")] 67 | block: Block, 68 | 69 | #[serde(alias = "new_work")] 70 | work: u64, 71 | }, 72 | 73 | KeepAlive { 74 | #[serde(alias = "type")] 75 | msg_type: KeepAliveType, 76 | }, 77 | 78 | Unknown { 79 | #[serde(alias = "type")] 80 | msg_type: Option, 81 | 82 | #[serde(flatten)] 83 | fields: HashMap, 84 | }, 85 | } 86 | 87 | #[derive(Debug, Clone, Serialize)] 88 | #[serde(untagged)] 89 | pub enum ClientMessage { 90 | SubmitBlock { 91 | #[serde(rename = "type")] 92 | msg_type: SubmitBlockType, 93 | id: NonZeroU64, 94 | address: Address, 95 | nonce: String, 96 | }, 97 | } 98 | 99 | impl ClientMessage { 100 | pub fn new_solution(address: Address, nonce: String) -> Self { 101 | ClientMessage::SubmitBlock { 102 | msg_type: SubmitBlockType, 103 | id: rand::random(), 104 | address, 105 | nonce, 106 | } 107 | } 108 | } 109 | 110 | pub async fn connect( 111 | cfg: NetConfig, 112 | ) -> Result< 113 | ( 114 | impl Sink, 115 | impl TryStream, 116 | ), 117 | NetworkError, 118 | > { 119 | ws::ws_connect(http::ws_start(cfg.node).await?.url).await 120 | } 121 | 122 | #[cfg(test)] 123 | mod tests { 124 | use super::*; 125 | use serde_json::{json, to_value}; 126 | use std::str::FromStr; 127 | 128 | #[test] 129 | fn test_client_message() { 130 | let json = json!({ 131 | "id": 5, 132 | "type": "submit_block", 133 | "address": "k5ztameslf", 134 | "nonce": "aaaaaaaaaaaaaaa" 135 | }); 136 | 137 | let msg = ClientMessage::SubmitBlock { 138 | id: NonZeroU64::new(5).unwrap(), 139 | msg_type: SubmitBlockType, 140 | address: Address::from_str("k5ztameslf").unwrap(), 141 | nonce: "aaaaaaaaaaaaaaa".to_string(), 142 | }; 143 | 144 | assert_eq!(json, to_value(&msg).unwrap()); 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/krist/address.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | use std::convert::{TryFrom, TryInto}; 3 | use std::fmt::{self, Debug, Display, Formatter}; 4 | use std::str::FromStr; 5 | 6 | /// A krist address - v1 and v2 compatible 7 | #[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] 8 | #[serde(try_from = "&str", into = "String")] 9 | pub struct Address([u8; Address::LENGTH]); 10 | 11 | impl Address { 12 | /// The required length of krist addresses, in bytes 13 | pub const LENGTH: usize = 10; 14 | 15 | /// The set of allowed characters for v1 addresses 16 | pub const V1_CHARS: &'static str = "1234567890abcdef"; 17 | 18 | /// The set of allowed characters for v2 addresses 19 | pub const V2_CHARS: &'static str = "1234567890abcdefghijklmnopqrstuvwxyz"; 20 | 21 | /// Get this krist address as a string slice 22 | pub fn as_str(&self) -> &str { 23 | // the contents were originally from a utf-8 string, so this should 24 | // never panic 25 | std::str::from_utf8(&self.0).unwrap() 26 | } 27 | 28 | pub fn as_bytes(&self) -> &[u8; Address::LENGTH] { 29 | &self.0 30 | } 31 | } 32 | 33 | /// An error caused by an invalid address 34 | #[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)] 35 | pub enum InvalidAddress { 36 | #[error("invalid address length: {0}")] 37 | InvalidLength(usize), 38 | 39 | #[error("illegal character: {0} at index {1}")] 40 | IllegalCharacter(char, usize), 41 | } 42 | 43 | impl FromStr for Address { 44 | type Err = InvalidAddress; 45 | 46 | fn from_str(s: &str) -> Result { 47 | // v1 and v2 addresses allow a different set of characters 48 | let allowed = if s.starts_with('k') { 49 | Self::V2_CHARS 50 | } else { 51 | Self::V1_CHARS 52 | }; 53 | 54 | // search for illegal characters 55 | if let Some((i, c)) = s.chars().enumerate().find(|&(_, c)| !allowed.contains(c)) { 56 | return Err(InvalidAddress::IllegalCharacter(c, i)); 57 | } 58 | 59 | // convert to bytes 60 | let bytes: [u8; Self::LENGTH] = s 61 | .as_bytes() 62 | .try_into() 63 | .map_err(|_| InvalidAddress::InvalidLength(s.len()))?; 64 | 65 | Ok(Self(bytes)) 66 | } 67 | } 68 | 69 | impl TryFrom<&str> for Address { 70 | type Error = InvalidAddress; 71 | 72 | fn try_from(value: &str) -> Result { 73 | Self::from_str(value) 74 | } 75 | } 76 | 77 | impl Display for Address { 78 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { 79 | f.write_str(self.as_str()) 80 | } 81 | } 82 | 83 | impl From
for String { 84 | fn from(address: Address) -> Self { 85 | address.to_string() 86 | } 87 | } 88 | 89 | impl Debug for Address { 90 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { 91 | write!(f, "Address({})", self.as_str()) 92 | } 93 | } 94 | 95 | impl PartialEq for Address { 96 | fn eq(&self, other: &str) -> bool { 97 | self.0 == other.as_bytes() 98 | } 99 | } 100 | 101 | impl PartialEq<&str> for Address { 102 | fn eq(&self, other: &&str) -> bool { 103 | self.0 == other.as_bytes() 104 | } 105 | } 106 | 107 | impl PartialEq for Address { 108 | fn eq(&self, other: &String) -> bool { 109 | self.0 == other.as_bytes() 110 | } 111 | } 112 | 113 | #[cfg(test)] 114 | mod tests { 115 | use super::*; 116 | 117 | #[test] 118 | fn check_valid_addresses() { 119 | assert_eq!(Address::from_str("abcdef1234").unwrap(), "abcdef1234",); 120 | assert_eq!(Address::from_str("kabcdefghi").unwrap(), "kabcdefghi",); 121 | } 122 | 123 | #[test] 124 | fn check_invalid_addresses() { 125 | assert_eq!( 126 | Address::from_str("abc").unwrap_err(), 127 | InvalidAddress::InvalidLength(3) 128 | ); 129 | assert_eq!( 130 | Address::from_str("abcdefghij").unwrap_err(), 131 | InvalidAddress::IllegalCharacter('g', 6) 132 | ); 133 | } 134 | 135 | #[test] 136 | fn test_serialize_deserialize() { 137 | let address = Address::from_str("kabcdefghi").unwrap(); 138 | 139 | assert_eq!( 140 | address, 141 | serde_json::from_str::
(&serde_json::to_string(&address).unwrap()).unwrap() 142 | ); 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /src/miner/cpu/framework.rs: -------------------------------------------------------------------------------- 1 | //! CPU miner core framework 2 | 3 | use crate::krist::address::Address; 4 | use crate::krist::block::ShortHash; 5 | use crossbeam::atomic::AtomicCell; 6 | use crossbeam::channel::Sender; 7 | use std::str; 8 | use std::sync::atomic::{AtomicU64, Ordering}; 9 | 10 | /// A type that can be used to efficiently feed input to a CPU miner kernel 11 | pub trait KernelInput: Sized { 12 | /// Create a new instance with the given address and nonce 13 | fn new(address: Address, nonce: u64) -> Self; 14 | 15 | /// Set the block 16 | fn set_block(&mut self, block: &[u8; 12]); 17 | 18 | /// Increment the nonce for the next cycle 19 | fn increment_nonce(&mut self); 20 | 21 | type Score; 22 | fn get_solution(&mut self, work: u64, score: Self::Score) -> Option; 23 | } 24 | 25 | /// A type to manage miner digest input for scalar kernels 26 | #[derive(Clone)] 27 | pub struct ScalarKernelInput { 28 | data: [u8; 64], 29 | nonce: u64, 30 | } 31 | 32 | impl KernelInput for ScalarKernelInput { 33 | fn new(address: Address, nonce: u64) -> Self { 34 | let mut data = [0u8; 64]; 35 | 36 | data[..Address::LENGTH].copy_from_slice(address.as_bytes()); 37 | 38 | // padding 39 | data[Self::LENGTH] = 0x80; 40 | data[62] = (((Self::LENGTH * 8) >> 8) & 0xFF) as u8; 41 | data[63] = ((Self::LENGTH * 8) & 0xFF) as u8; 42 | 43 | let mut input = Self { data, nonce }; 44 | input.increment_nonce(); 45 | input 46 | } 47 | 48 | fn set_block(&mut self, block: &[u8; 12]) { 49 | self.data[Address::LENGTH..Self::LENGTH - Self::NONCE_LENGTH].copy_from_slice(block); 50 | } 51 | 52 | fn increment_nonce(&mut self) { 53 | self.nonce = self.nonce.wrapping_add(1); 54 | let n = self.nonce; 55 | 56 | for (i, v) in self.nonce_mut().iter_mut().enumerate() { 57 | *v = (((n >> (i * 6)) & 0x3f) + 32) as u8; 58 | } 59 | } 60 | 61 | type Score = u64; 62 | 63 | #[inline(always)] 64 | fn get_solution(&mut self, work: u64, score: u64) -> Option { 65 | if score <= work { 66 | Some(self.nonce_str().to_string()) 67 | } else { 68 | None 69 | } 70 | } 71 | } 72 | 73 | impl ScalarKernelInput { 74 | const NONCE_LENGTH: usize = 11; 75 | pub const LENGTH: usize = Address::LENGTH + (ShortHash::LENGTH * 2) + Self::NONCE_LENGTH; 76 | 77 | fn nonce_mut(&mut self) -> &mut [u8] { 78 | &mut self.data[Self::LENGTH - Self::NONCE_LENGTH..Self::LENGTH] 79 | } 80 | 81 | /// Get an immutable reference to the expanded nonce (e.g. for submission) 82 | pub fn nonce(&mut self) -> &[u8] { 83 | self.nonce_mut() as &_ 84 | } 85 | 86 | pub fn nonce_str(&mut self) -> &str { 87 | str::from_utf8(self.nonce()).unwrap() 88 | } 89 | 90 | /// Get the data for this input 91 | pub fn data(&self) -> &[u8] { 92 | &self.data[..Self::LENGTH] 93 | } 94 | 95 | /// Get the full padded data block for this input 96 | pub fn data_block(&self) -> &[u8; 64] { 97 | &self.data 98 | } 99 | } 100 | 101 | /// A CPU mining kernel. 102 | pub trait Kernel { 103 | /// The input type for this kernel 104 | type Input: KernelInput; 105 | 106 | /// Get the score for a hash with the given input. 107 | fn score(&self, input: &Self::Input) -> ::Score; 108 | } 109 | 110 | pub struct Context<'a> { 111 | address: Address, 112 | hashes: &'a AtomicU64, 113 | target: &'a AtomicCell>, 114 | nonce: u64, 115 | sol_tx: &'a Sender, 116 | } 117 | 118 | impl<'a> Context<'a> { 119 | /// Create a new `Context`. 120 | pub fn new( 121 | address: Address, 122 | hashes: &'a AtomicU64, 123 | target: &'a AtomicCell>, 124 | nonce: u64, 125 | sol_tx: &'a Sender, 126 | ) -> Self { 127 | Self { 128 | address, 129 | hashes, 130 | target, 131 | nonce, 132 | sol_tx, 133 | } 134 | } 135 | 136 | /// Mine synchronously using this context and the given kernel. 137 | pub fn mine(self, kernel: K) { 138 | const BATCH_SIZE: u64 = 10_000; 139 | let mut input = K::Input::new(self.address, self.nonce); 140 | 141 | while let Some((block, work)) = self.target.load() { 142 | input.set_block(&block); 143 | 144 | for _ in 0..BATCH_SIZE { 145 | let score = kernel.score(&input); 146 | if let Some(solution) = input.get_solution(work, score) { 147 | // solution found! 148 | if self.sol_tx.send(solution).is_err() { 149 | return; 150 | } 151 | } 152 | input.increment_nonce(); 153 | } 154 | 155 | self.hashes.fetch_add(BATCH_SIZE, Ordering::Relaxed); 156 | } 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /src/miner/cpu/mod.rs: -------------------------------------------------------------------------------- 1 | mod framework; 2 | mod kernels; 3 | mod thread_priority; 4 | 5 | use crate::miner::cpu::framework::Context; 6 | use crate::miner::interface::{CurrentTarget, MinerInterface}; 7 | use crate::miner::{Miner, MinerConfig, MinerError}; 8 | use crossbeam::atomic::AtomicCell; 9 | use crossbeam::channel::RecvTimeoutError; 10 | use enumset::{EnumSet, EnumSetType}; 11 | use itertools::Itertools; 12 | use std::fmt::{self, Display, Formatter}; 13 | use std::num::Wrapping; 14 | use std::str::FromStr; 15 | use std::sync::atomic::{AtomicU64, Ordering}; 16 | use std::time::{Duration, Instant}; 17 | 18 | /// Select a CPU mining kernel to use 19 | #[derive(Debug, EnumSetType, PartialOrd, Ord)] 20 | pub enum KernelType { 21 | /// CPU mining kernel with no hardware-specific optimizations. 22 | Unoptimized, 23 | 24 | /// CPU mining kernel using x86/x86_64 SHA instructions 25 | SHA, 26 | } 27 | 28 | #[derive(Debug, thiserror::Error)] 29 | #[error("Invalid kernel type: {0}")] 30 | pub struct InvalidKernelType(String); 31 | 32 | impl FromStr for KernelType { 33 | type Err = InvalidKernelType; 34 | 35 | fn from_str(s: &str) -> Result { 36 | Ok(match s.to_lowercase().as_ref() { 37 | "unoptimized" => Self::Unoptimized, 38 | "sha" => Self::SHA, 39 | s => return Err(InvalidKernelType(s.to_string())), 40 | }) 41 | } 42 | } 43 | 44 | impl KernelType { 45 | pub fn mine_with(self, context: Context) { 46 | match self { 47 | Self::Unoptimized => context.mine(kernels::Unoptimized), 48 | Self::SHA => context.mine(kernels::SHA), 49 | } 50 | } 51 | } 52 | 53 | impl Default for KernelType { 54 | fn default() -> Self { 55 | KernelType::Unoptimized 56 | } 57 | } 58 | 59 | impl Display for KernelType { 60 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { 61 | let name = match self { 62 | Self::Unoptimized => "unoptimized", 63 | Self::SHA => "SHA", 64 | }; 65 | 66 | write!(f, "{}", name) 67 | } 68 | } 69 | 70 | #[derive(Debug)] 71 | pub struct CpuInfo { 72 | threads: usize, 73 | supported: EnumSet, 74 | } 75 | 76 | impl Display for CpuInfo { 77 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { 78 | write!( 79 | f, 80 | "CPU:\n\ 81 | \tThreads: {threads}\n\ 82 | \tSupported kernels: {supported}\n\ 83 | \tUnsupported kernels: {available}", 84 | threads = self.threads, 85 | supported = self.supported.iter().join(", "), 86 | available = (!self.supported).iter().join(", "), 87 | ) 88 | } 89 | } 90 | 91 | fn get_supported_kernels() -> EnumSet { 92 | let mut supported = EnumSet::only(KernelType::Unoptimized); 93 | 94 | if is_x86_feature_detected!("sha") { 95 | supported |= KernelType::SHA; 96 | } 97 | 98 | supported 99 | } 100 | 101 | fn get_best_kernel() -> KernelType { 102 | Iterator::max(get_supported_kernels().iter()).unwrap_or_default() 103 | } 104 | 105 | pub fn get_cpu_info() -> CpuInfo { 106 | let threads = num_cpus::get(); 107 | let supported = get_supported_kernels(); 108 | 109 | CpuInfo { threads, supported } 110 | } 111 | 112 | pub struct CpuMiner { 113 | kernel_type: KernelType, 114 | threads: usize, 115 | } 116 | 117 | impl CpuMiner { 118 | pub fn new( 119 | &MinerConfig { 120 | cpu_threads, 121 | cpu_kernel, 122 | .. 123 | }: &MinerConfig, 124 | ) -> CpuMiner { 125 | CpuMiner { 126 | threads: cpu_threads.unwrap_or_else(num_cpus::get), 127 | kernel_type: cpu_kernel.unwrap_or_else(get_best_kernel), 128 | } 129 | } 130 | } 131 | 132 | impl Miner for CpuMiner { 133 | fn describe(&self) -> String { 134 | format!("CPU [{}x {}]", self.threads, self.kernel_type) 135 | } 136 | 137 | fn mine(self: Box, mut interface: MinerInterface) -> Result<(), MinerError> { 138 | let Self { 139 | threads, 140 | kernel_type, 141 | } = *self; 142 | // todo: investigate using evc to avoid locks, or parking_lot for better locks? 143 | let hashes = AtomicU64::new(0); 144 | let target = AtomicCell::new(interface.current_target().into_raw()); 145 | let (sol_tx, sol_rx) = crossbeam::channel::bounded(1); 146 | 147 | // convert bindings to references to avoid lifetime/ownership complications 148 | let hashes = &hashes; 149 | let target = ⌖ 150 | let sol_tx = &sol_tx; 151 | 152 | crossbeam::scope(|s| { 153 | let address = interface.address(); 154 | let mut offset = Wrapping(rand::random()); 155 | 156 | for i in 0..threads { 157 | log::debug!("Spawning CPU miner thread {} using {:?}", i, kernel_type); 158 | offset += Wrapping(std::u64::MAX / (threads as u64)); 159 | let ctx = Context::new(address, hashes, target, offset.0, sol_tx); 160 | s.builder() 161 | .name(format!("CPU miner {}", i)) 162 | .spawn(move |_| { 163 | thread_priority::set_low_priority(); 164 | kernel_type.mine_with(ctx); 165 | }) 166 | .unwrap(); 167 | } 168 | 169 | // management thread 170 | s.builder() 171 | .name("CPU miner dispatch".to_string()) 172 | .spawn(|_| { 173 | let mut cycle_start = Instant::now(); 174 | 175 | loop { 176 | match sol_rx.recv_timeout(Duration::from_millis(1000)) { 177 | Ok(s) => { 178 | if interface.report_solution(s).is_err() { 179 | target.store(None); 180 | break; 181 | } 182 | } 183 | Err(RecvTimeoutError::Disconnected) => break, 184 | Err(RecvTimeoutError::Timeout) => {} 185 | } 186 | 187 | match interface.current_target() { 188 | CurrentTarget::Unchanged(_) => {} 189 | t => target.store(t.into_raw()), 190 | } 191 | 192 | let cycle_time = 193 | std::mem::replace(&mut cycle_start, Instant::now()).elapsed(); 194 | let cycle_hashes = hashes.swap(0, Ordering::Relaxed); 195 | interface.report_speed(cycle_hashes, cycle_time); 196 | } 197 | }) 198 | .unwrap(); 199 | }) 200 | .unwrap(); 201 | 202 | Ok(()) 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | mod krist; 2 | mod miner; 3 | mod network; 4 | 5 | use crate::krist::address::Address; 6 | use crate::miner::interface::MinerInterface; 7 | use crate::miner::Target; 8 | use crate::network::{ClientMessage, ServerMessage}; 9 | use futures::{future, StreamExt, TryFutureExt, TryStreamExt}; 10 | use indicatif::{MultiProgress, ProgressBar, ProgressStyle}; 11 | use log::LevelFilter; 12 | use miner::MinerConfig; 13 | use network::{NetConfig, NetworkError}; 14 | use std::error::Error; 15 | use std::fs::{create_dir_all, File}; 16 | use structopt::StructOpt; 17 | 18 | #[derive(Debug, StructOpt)] 19 | #[structopt(about, author)] 20 | pub enum Opts { 21 | /// Connect to the krist node and log incoming messages for troubleshooting 22 | NetLog { 23 | #[structopt(flatten)] 24 | net_cfg: NetConfig, 25 | }, 26 | 27 | /// Get information about mining hardware 28 | Info {}, 29 | 30 | /// Mine krist 31 | Mine { 32 | #[structopt(flatten)] 33 | net_cfg: NetConfig, 34 | 35 | #[structopt(flatten)] 36 | miner_cfg: MinerConfig, 37 | 38 | /// The address to mine krist for 39 | #[structopt(env = "KRISTFORGE_ADDRESS")] 40 | address: Address, 41 | }, 42 | } 43 | 44 | async fn net_log(net_cfg: NetConfig) -> Result<(), NetworkError> { 45 | let (_sink, stream) = network::connect(net_cfg).await?; 46 | 47 | println!("Connected!"); 48 | 49 | stream 50 | .try_for_each(|m| { 51 | println!("{:?}", m); 52 | future::ok(()) 53 | }) 54 | .await?; 55 | 56 | Ok(()) 57 | } 58 | 59 | fn system_info() { 60 | match miner::gpu::get_opencl_devices() { 61 | Ok(devices) => { 62 | for d in devices { 63 | println!("{}", d) 64 | } 65 | } 66 | Err(e) => { 67 | eprintln!("Error enumerating OpenCL devices: {:?}", e); 68 | } 69 | } 70 | 71 | println!("{}", miner::cpu::get_cpu_info()); 72 | } 73 | 74 | async fn mine( 75 | net_cfg: NetConfig, 76 | address: Address, 77 | miner_cfg: MinerConfig, 78 | ) -> Result<(), Box> { 79 | let miners = miner::create_miners(miner_cfg)?; 80 | 81 | if miners.is_empty() { 82 | eprintln!("No miners available!"); 83 | return Ok(()); 84 | } 85 | 86 | let mut target_channels = vec![]; 87 | let (sol_tx, sol_rx) = futures::channel::mpsc::unbounded(); 88 | 89 | let multi_pb = MultiProgress::new(); 90 | 91 | let wallet_pb = multi_pb.add(ProgressBar::new_spinner()); 92 | wallet_pb.set_style(ProgressStyle::default_bar().template("{wide_msg}")); 93 | wallet_pb.set_message(&format!("Mining for {}", address)); 94 | let mut mined_kst = 0; 95 | 96 | let target_pb = multi_pb.add(ProgressBar::new_spinner()); 97 | target_pb.set_style(ProgressStyle::default_spinner().template("Current target: {wide_msg}")); 98 | 99 | let miner_style = ProgressStyle::default_spinner().template("{spinner} {prefix}: {wide_msg}"); 100 | 101 | for miner in miners { 102 | let (target_tx, target_rx) = crossbeam::channel::bounded(1); 103 | target_channels.push(target_tx); 104 | 105 | let name = miner.describe(); 106 | let pb = multi_pb.add(ProgressBar::new_spinner()); 107 | pb.set_prefix(&name); 108 | pb.set_style(miner_style.clone()); 109 | pb.set_message("Initializing..."); 110 | 111 | let interface = MinerInterface::new(address, pb, target_rx, sol_tx.clone()); 112 | 113 | std::thread::spawn(move || { 114 | miner.mine(interface).unwrap(); 115 | }); 116 | } 117 | 118 | std::thread::spawn(move || multi_pb.join().unwrap()); 119 | 120 | // set up network connection 121 | let (sink, stream) = network::connect(net_cfg).await?; 122 | 123 | // set up futures to pipe messages 124 | let solution_sender = sol_rx 125 | .map(|n| Ok(ClientMessage::new_solution(address, n))) 126 | .forward(sink) 127 | .err_into::>(); 128 | 129 | let target_receiver = stream.err_into().try_for_each(|message| match message { 130 | ServerMessage::KeepAlive { .. } => future::ok(()), 131 | ServerMessage::Unknown { msg_type, fields } => { 132 | log::warn!("Got unknown message type {:?}: {:?}", msg_type, fields); 133 | future::ok(()) 134 | } 135 | ServerMessage::Target { 136 | block, 137 | work, 138 | msg_type, 139 | } => { 140 | log::info!( 141 | "Got new mining target - msg_type {} work {} block {:?}", 142 | msg_type, 143 | work, 144 | block 145 | ); 146 | 147 | if address == block.address && msg_type == "response" { 148 | mined_kst += block.value; 149 | wallet_pb.set_message(&format!("Mined {} KST for {}", mined_kst, address)); 150 | } 151 | 152 | target_pb.set_message(&format!( 153 | "Block #{} (shorthash {}, work {})", 154 | block.height, block.short_hash, work 155 | )); 156 | 157 | for tx in &target_channels { 158 | if let Err(e) = tx.send(Target { 159 | block: block.short_hash, 160 | work, 161 | }) { 162 | return future::err(e.into()); 163 | } 164 | } 165 | 166 | future::ok(()) 167 | } 168 | }); 169 | 170 | future::try_join(solution_sender, target_receiver).await?; 171 | 172 | Ok(()) 173 | } 174 | 175 | fn init_logging() { 176 | let log_file = dirs::data_dir() 177 | .map(|d| d.join(env!("CARGO_PKG_NAME"))) 178 | .unwrap_or_default() 179 | .join(concat!(env!("CARGO_PKG_NAME"), ".log")); 180 | 181 | if let Some(parent) = log_file.parent() { 182 | create_dir_all(parent).expect("creating data dirs"); 183 | } 184 | 185 | simplelog::WriteLogger::init( 186 | LevelFilter::Debug, 187 | Default::default(), 188 | File::create(log_file).expect("creating log file"), 189 | ) 190 | .expect("initializing logger"); 191 | } 192 | 193 | #[tokio::main] 194 | async fn main() { 195 | let opts: Opts = Opts::from_args(); 196 | 197 | init_logging(); 198 | log::info!("Arguments: {:?}", opts); 199 | 200 | match opts { 201 | Opts::NetLog { net_cfg } => { 202 | if let Err(e) = net_log(net_cfg).await { 203 | eprintln!("Network error: {:?}", e); 204 | } 205 | } 206 | Opts::Info {} => system_info(), 207 | Opts::Mine { 208 | net_cfg, 209 | address, 210 | miner_cfg, 211 | } => { 212 | if let Err(e) = mine(net_cfg, address, miner_cfg).await { 213 | eprintln!("Mining error: {:?}", e); 214 | } 215 | } 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /src/miner/gpu/mod.rs: -------------------------------------------------------------------------------- 1 | use super::MinerError; 2 | use crate::miner::interface::{CurrentTarget, MinerInterface}; 3 | use crate::miner::{Miner, MinerConfig}; 4 | use dynamic_ocl::buffer::flags::{DeviceReadOnly, DeviceWriteOnly, HostReadWrite, HostWriteOnly}; 5 | use dynamic_ocl::buffer::Buffer; 6 | use dynamic_ocl::device::{Device, DeviceType}; 7 | use dynamic_ocl::kernel::Kernel; 8 | use dynamic_ocl::platform::Platform; 9 | use dynamic_ocl::program::ProgramBuilder; 10 | use dynamic_ocl::queue::Queue; 11 | use dynamic_ocl::raw::{cl_device_info, cl_uchar, cl_uint, cl_ulong, CL_DEVICE_NOT_FOUND}; 12 | use dynamic_ocl::util::OclInfo; 13 | use dynamic_ocl::{load_opencl, Error as OclError}; 14 | use std::cmp::{max, min}; 15 | use std::collections::HashSet; 16 | use std::ffi::CString; 17 | use std::fmt::{self, Display, Formatter}; 18 | use std::time::Instant; 19 | 20 | /// OpenCL kernel source 21 | const OCL_SRC: &str = include_str!("kristforge.cl"); 22 | 23 | /// An OpenCL device that can be used for mining 24 | #[derive(Debug)] 25 | pub struct MiningDevice { 26 | device: Device, 27 | name: String, 28 | compute_units: cl_uint, 29 | clock_freq: cl_uint, 30 | } 31 | 32 | impl Display for MiningDevice { 33 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { 34 | write!( 35 | f, 36 | "OpenCL device \"{name}\":\n\ 37 | \tCompute units: {compute_units}\n\ 38 | \tClock frequency: {clock_freq}", 39 | name = self.name, 40 | compute_units = self.compute_units, 41 | clock_freq = self.clock_freq 42 | ) 43 | } 44 | } 45 | 46 | fn device_human_name(device: Device) -> Result { 47 | const CL_DEVICE_BOARD_NAME_AMD: cl_device_info = 0x4038; 48 | if device 49 | .extensions()? 50 | .to_string_lossy() 51 | .contains("cl_amd_device_attribute_query") 52 | { 53 | device.get_info(CL_DEVICE_BOARD_NAME_AMD) 54 | } else { 55 | device.name() 56 | } 57 | } 58 | 59 | /// Get compatible OpenCL devices 60 | pub fn get_opencl_devices() -> Result, MinerError> { 61 | match load_opencl() { 62 | Err(e) => { 63 | eprintln!( 64 | "Failed to load OpenCL library; GPU support disabled. Check logs for details.", 65 | ); 66 | log::error!("OpenCL load error: {:?}", e); 67 | Ok(vec![]) 68 | } 69 | Ok(_) => { 70 | let mut devices = HashSet::new(); 71 | 72 | let platforms = match Platform::get_platforms() { 73 | Err(e) => { 74 | eprintln!("Failed to enumerate OpenCL platforms; GPU support disabled. Check logs for details."); 75 | log::error!("Error getting platform IDs: {:?}", e); 76 | return Ok(vec![]); 77 | } 78 | Ok(p) => p, 79 | }; 80 | 81 | for platform in platforms { 82 | let platform_devices = match platform.get_devices(DeviceType::GPU) { 83 | Err(OclError::ApiError(e)) if e.code() == CL_DEVICE_NOT_FOUND => vec![], 84 | e => e?, 85 | }; 86 | devices.extend(platform_devices.into_iter()); 87 | } 88 | 89 | let mut wrapped = vec![]; 90 | 91 | for device in devices { 92 | let name = device_human_name(device)?.to_string_lossy().into_owned(); 93 | let compute_units = device.max_compute_units()?; 94 | let clock_freq = device.max_clock_frequency()?; 95 | 96 | let device = MiningDevice { 97 | device, 98 | name, 99 | compute_units, 100 | clock_freq, 101 | }; 102 | 103 | log::debug!("Found compatible OpenCL device: {:#?}", device); 104 | 105 | wrapped.push(device); 106 | } 107 | 108 | Ok(wrapped) 109 | } 110 | } 111 | } 112 | 113 | type MinerKernel = Kernel<( 114 | Buffer<'static, HostWriteOnly, cl_uchar>, 115 | cl_ulong, 116 | cl_ulong, 117 | Buffer<'static, HostReadWrite, cl_uchar>, 118 | )>; 119 | 120 | pub struct OclMiner { 121 | name: String, 122 | queue: Queue, 123 | kernel: MinerKernel, 124 | max_work_size: usize, 125 | target_rate: f32, 126 | } 127 | 128 | impl OclMiner { 129 | pub fn new( 130 | MiningDevice { device, name, .. }: MiningDevice, 131 | &MinerConfig { 132 | gpu_rate: target_rate, 133 | gpu_max_worksize: max_work_size, 134 | .. 135 | }: &MinerConfig, 136 | ) -> Result { 137 | log::info!("Initializing OpenCL miner on {}", name); 138 | 139 | let ctx = device.create_context()?; 140 | let queue = ctx.create_queue(device)?; 141 | let program = ProgramBuilder::with_source(&ctx, &OCL_SRC).build()?; 142 | 143 | let build_log = program.build_info(device)?.log()?; 144 | let build_log = build_log.to_string_lossy(); 145 | log::info!("Program build log:\n{}", build_log.trim()); 146 | 147 | let kernel = program.create_kernel(&CString::new("mine").unwrap())?; 148 | 149 | let input_buf = ctx 150 | .buffer_builder() 151 | .host_access::() 152 | .device_access::() 153 | .build_with_size(22)?; 154 | 155 | let output_buf = ctx 156 | .buffer_builder() 157 | .device_access::() 158 | .alloc_host_ptr() 159 | .build_copying_slice(&[0u8; 11])?; 160 | 161 | // kernel arg type checks can cause issues with some OpenCL drivers, so 162 | // we disable them in release mode 163 | let kernel = if cfg!(debug_assertions) { 164 | kernel.bind_arguments((input_buf, 0, 0, output_buf))? 165 | } else { 166 | kernel.bind_arguments_unchecked((input_buf, 0, 0, output_buf))? 167 | }; 168 | 169 | Ok(Self { 170 | name, 171 | queue, 172 | kernel, 173 | max_work_size, 174 | target_rate, 175 | }) 176 | } 177 | } 178 | 179 | impl Miner for OclMiner { 180 | fn describe(&self) -> String { 181 | format!("GPU [{}]", self.name) 182 | } 183 | 184 | fn mine(mut self: Box, mut interface: MinerInterface) -> Result<(), MinerError> { 185 | // write the address into first part of input buffer 186 | self.queue 187 | .buffer_cmd(&mut self.kernel.arguments().0) 188 | .write(&interface.address().as_bytes()[..])?; 189 | 190 | let mut work_size = 1usize; 191 | let mut offset = rand::random(); 192 | 193 | let mut cycle_start = Instant::now(); 194 | 195 | loop { 196 | // update miner target 197 | match interface.current_target() { 198 | CurrentTarget::StopMining => break, 199 | CurrentTarget::New(t) => { 200 | let (mut input, work, _, _) = self.kernel.arguments(); 201 | work.set(t.work)?; 202 | self.queue 203 | .buffer_cmd(&mut input) 204 | .offset(10) 205 | .write(t.block.into_hex().as_bytes())?; 206 | } 207 | CurrentTarget::Unchanged(_) => {} 208 | }; 209 | 210 | // execute kernel 211 | self.queue 212 | .kernel_cmd(&mut self.kernel) 213 | .exec_ndrange(work_size)?; 214 | 215 | // read output and check for solution 216 | let mut solution = [0u8; 11]; 217 | self.queue 218 | .buffer_cmd(&mut self.kernel.arguments().3) 219 | .read(&mut solution)?; 220 | 221 | if solution != [0u8; 11] { 222 | // solution found! 223 | let solution = String::from_utf8(Vec::from(&solution[..])).expect("invalid nonce"); 224 | 225 | if interface.report_solution(solution).is_err() { 226 | break; 227 | } 228 | 229 | // zero out solution buffer 230 | self.queue 231 | .buffer_cmd(&mut self.kernel.arguments().3) 232 | .write(&[0; 11])?; 233 | } 234 | 235 | let cycle_time = std::mem::replace(&mut cycle_start, Instant::now()).elapsed(); 236 | 237 | offset += work_size as u64; 238 | self.kernel.arguments().2.set(offset)?; 239 | interface.report_speed(work_size as u64, cycle_time); 240 | 241 | // adjust work size for next execution 242 | if cycle_time.as_secs_f32() < self.target_rate / 2.0 { 243 | work_size = min(self.max_work_size, work_size * 2); 244 | } else if cycle_time.as_secs_f32() > self.target_rate * 2.0 { 245 | work_size = max(1, work_size / 2); 246 | } 247 | } 248 | 249 | Ok(()) 250 | } 251 | } 252 | -------------------------------------------------------------------------------- /src/miner/cpu/kernels/sha.rs: -------------------------------------------------------------------------------- 1 | #![allow( 2 | clippy::unreadable_literal, 3 | clippy::cast_ptr_alignment, 4 | overflowing_literals 5 | )] 6 | 7 | use super::{score_ab, Kernel, ScalarKernelInput}; 8 | use std::arch::x86_64::*; 9 | 10 | pub struct SHA; 11 | impl Kernel for SHA { 12 | type Input = ScalarKernelInput; 13 | 14 | #[inline(always)] 15 | fn score(&self, input: &ScalarKernelInput) -> u64 { 16 | let [a, b, _, _, _, _, _, _] = digest(input.data_block()); 17 | score_ab(a, b) 18 | } 19 | } 20 | 21 | /// SHA256 digest of a single padded block of data. 22 | #[inline(always)] 23 | fn digest(data: &[u8; 64]) -> [u32; 8] { 24 | // initial state 25 | let mut state = [ 26 | 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 27 | 0x5be0cd19, 28 | ]; 29 | 30 | unsafe { process(&mut state, &data) }; 31 | 32 | state 33 | } 34 | 35 | /// Process multiple blocks. The caller is responsible for setting the initial 36 | /// state, and the caller is responsible for padding the final block. 37 | #[target_feature(enable = "sha")] 38 | #[target_feature(enable = "sse4.1")] 39 | unsafe fn process(state: &mut [u32; 8], data: &[u8; 64]) { 40 | let mask = _mm_set_epi64x(0x0c0d0e0f08090a0b, 0x0405060700010203); 41 | 42 | let mut state0: __m128i; 43 | let mut state1: __m128i; 44 | let mut msg: __m128i; 45 | let mut tmp: __m128i; 46 | let mut msg0: __m128i; 47 | let mut msg1: __m128i; 48 | let mut msg2: __m128i; 49 | let mut msg3: __m128i; 50 | let abef_save: __m128i; 51 | let cdgh_save: __m128i; 52 | 53 | /* Load initial values */ 54 | tmp = _mm_loadu_si128(state.as_ptr() as _); 55 | state1 = _mm_loadu_si128(state.as_ptr().add(4) as _); 56 | 57 | tmp = _mm_shuffle_epi32(tmp, 0xb1); /* CDAB */ 58 | state1 = _mm_shuffle_epi32(state1, 0x1b); /* EFGH */ 59 | state0 = _mm_alignr_epi8(tmp, state1, 8); /* ABEF */ 60 | state1 = _mm_blend_epi16(state1, tmp, 0xf0); /* CDGH */ 61 | 62 | /* Save current state */ 63 | abef_save = state0; 64 | cdgh_save = state1; 65 | 66 | /* Rounds 0-3 */ 67 | msg = _mm_loadu_si128(data.as_ptr().add(0) as _); 68 | msg0 = _mm_shuffle_epi8(msg, mask); 69 | msg = _mm_add_epi32(msg0, _mm_set_epi64x(0xE9B5DBA5B5C0FBCF, 0x71374491428A2F98)); 70 | state1 = _mm_sha256rnds2_epu32(state1, state0, msg); 71 | msg = _mm_shuffle_epi32(msg, 0x0E); 72 | state0 = _mm_sha256rnds2_epu32(state0, state1, msg); 73 | 74 | /* Rounds 4-7 */ 75 | msg1 = _mm_loadu_si128(data.as_ptr().add(16) as _); 76 | msg1 = _mm_shuffle_epi8(msg1, mask); 77 | msg = _mm_add_epi32(msg1, _mm_set_epi64x(0xAB1C5ED5923F82A4, 0x59F111F13956C25B)); 78 | state1 = _mm_sha256rnds2_epu32(state1, state0, msg); 79 | msg = _mm_shuffle_epi32(msg, 0x0E); 80 | state0 = _mm_sha256rnds2_epu32(state0, state1, msg); 81 | msg0 = _mm_sha256msg1_epu32(msg0, msg1); 82 | 83 | /* Rounds 8-11 */ 84 | msg2 = _mm_loadu_si128(data.as_ptr().add(32) as _); 85 | msg2 = _mm_shuffle_epi8(msg2, mask); 86 | msg = _mm_add_epi32(msg2, _mm_set_epi64x(0x550C7DC3243185BE, 0x12835B01D807AA98)); 87 | state1 = _mm_sha256rnds2_epu32(state1, state0, msg); 88 | msg = _mm_shuffle_epi32(msg, 0x0E); 89 | state0 = _mm_sha256rnds2_epu32(state0, state1, msg); 90 | msg1 = _mm_sha256msg1_epu32(msg1, msg2); 91 | 92 | /* Rounds 12-15 */ 93 | msg3 = _mm_loadu_si128(data.as_ptr().add(48) as _); 94 | msg3 = _mm_shuffle_epi8(msg3, mask); 95 | msg = _mm_add_epi32(msg3, _mm_set_epi64x(0xC19BF1749BDC06A7, 0x80DEB1FE72BE5D74)); 96 | state1 = _mm_sha256rnds2_epu32(state1, state0, msg); 97 | tmp = _mm_alignr_epi8(msg3, msg2, 4); 98 | msg0 = _mm_add_epi32(msg0, tmp); 99 | msg0 = _mm_sha256msg2_epu32(msg0, msg3); 100 | msg = _mm_shuffle_epi32(msg, 0x0E); 101 | state0 = _mm_sha256rnds2_epu32(state0, state1, msg); 102 | msg2 = _mm_sha256msg1_epu32(msg2, msg3); 103 | 104 | /* Rounds 16-19 */ 105 | msg = _mm_add_epi32(msg0, _mm_set_epi64x(0x240CA1CC0FC19DC6, 0xEFBE4786E49B69C1)); 106 | state1 = _mm_sha256rnds2_epu32(state1, state0, msg); 107 | tmp = _mm_alignr_epi8(msg0, msg3, 4); 108 | msg1 = _mm_add_epi32(msg1, tmp); 109 | msg1 = _mm_sha256msg2_epu32(msg1, msg0); 110 | msg = _mm_shuffle_epi32(msg, 0x0E); 111 | state0 = _mm_sha256rnds2_epu32(state0, state1, msg); 112 | msg3 = _mm_sha256msg1_epu32(msg3, msg0); 113 | 114 | /* Rounds 20-23 */ 115 | msg = _mm_add_epi32(msg1, _mm_set_epi64x(0x76F988DA5CB0A9DC, 0x4A7484AA2DE92C6F)); 116 | state1 = _mm_sha256rnds2_epu32(state1, state0, msg); 117 | tmp = _mm_alignr_epi8(msg1, msg0, 4); 118 | msg2 = _mm_add_epi32(msg2, tmp); 119 | msg2 = _mm_sha256msg2_epu32(msg2, msg1); 120 | msg = _mm_shuffle_epi32(msg, 0x0E); 121 | state0 = _mm_sha256rnds2_epu32(state0, state1, msg); 122 | msg0 = _mm_sha256msg1_epu32(msg0, msg1); 123 | 124 | /* Rounds 24-27 */ 125 | msg = _mm_add_epi32(msg2, _mm_set_epi64x(0xBF597FC7B00327C8, 0xA831C66D983E5152)); 126 | state1 = _mm_sha256rnds2_epu32(state1, state0, msg); 127 | tmp = _mm_alignr_epi8(msg2, msg1, 4); 128 | msg3 = _mm_add_epi32(msg3, tmp); 129 | msg3 = _mm_sha256msg2_epu32(msg3, msg2); 130 | msg = _mm_shuffle_epi32(msg, 0x0E); 131 | state0 = _mm_sha256rnds2_epu32(state0, state1, msg); 132 | msg1 = _mm_sha256msg1_epu32(msg1, msg2); 133 | 134 | /* Rounds 28-31 */ 135 | msg = _mm_add_epi32(msg3, _mm_set_epi64x(0x1429296706CA6351, 0xD5A79147C6E00BF3)); 136 | state1 = _mm_sha256rnds2_epu32(state1, state0, msg); 137 | tmp = _mm_alignr_epi8(msg3, msg2, 4); 138 | msg0 = _mm_add_epi32(msg0, tmp); 139 | msg0 = _mm_sha256msg2_epu32(msg0, msg3); 140 | msg = _mm_shuffle_epi32(msg, 0x0E); 141 | state0 = _mm_sha256rnds2_epu32(state0, state1, msg); 142 | msg2 = _mm_sha256msg1_epu32(msg2, msg3); 143 | 144 | /* Rounds 32-35 */ 145 | msg = _mm_add_epi32(msg0, _mm_set_epi64x(0x53380D134D2C6DFC, 0x2E1B213827B70A85)); 146 | state1 = _mm_sha256rnds2_epu32(state1, state0, msg); 147 | tmp = _mm_alignr_epi8(msg0, msg3, 4); 148 | msg1 = _mm_add_epi32(msg1, tmp); 149 | msg1 = _mm_sha256msg2_epu32(msg1, msg0); 150 | msg = _mm_shuffle_epi32(msg, 0x0E); 151 | state0 = _mm_sha256rnds2_epu32(state0, state1, msg); 152 | msg3 = _mm_sha256msg1_epu32(msg3, msg0); 153 | 154 | /* Rounds 36-39 */ 155 | msg = _mm_add_epi32(msg1, _mm_set_epi64x(0x92722C8581C2C92E, 0x766A0ABB650A7354)); 156 | state1 = _mm_sha256rnds2_epu32(state1, state0, msg); 157 | tmp = _mm_alignr_epi8(msg1, msg0, 4); 158 | msg2 = _mm_add_epi32(msg2, tmp); 159 | msg2 = _mm_sha256msg2_epu32(msg2, msg1); 160 | msg = _mm_shuffle_epi32(msg, 0x0E); 161 | state0 = _mm_sha256rnds2_epu32(state0, state1, msg); 162 | msg0 = _mm_sha256msg1_epu32(msg0, msg1); 163 | 164 | /* Rounds 40-43 */ 165 | msg = _mm_add_epi32(msg2, _mm_set_epi64x(0xC76C51A3C24B8B70, 0xA81A664BA2BFE8A1)); 166 | state1 = _mm_sha256rnds2_epu32(state1, state0, msg); 167 | tmp = _mm_alignr_epi8(msg2, msg1, 4); 168 | msg3 = _mm_add_epi32(msg3, tmp); 169 | msg3 = _mm_sha256msg2_epu32(msg3, msg2); 170 | msg = _mm_shuffle_epi32(msg, 0x0E); 171 | state0 = _mm_sha256rnds2_epu32(state0, state1, msg); 172 | msg1 = _mm_sha256msg1_epu32(msg1, msg2); 173 | 174 | /* Rounds 44-47 */ 175 | msg = _mm_add_epi32(msg3, _mm_set_epi64x(0x106AA070F40E3585, 0xD6990624D192E819)); 176 | state1 = _mm_sha256rnds2_epu32(state1, state0, msg); 177 | tmp = _mm_alignr_epi8(msg3, msg2, 4); 178 | msg0 = _mm_add_epi32(msg0, tmp); 179 | msg0 = _mm_sha256msg2_epu32(msg0, msg3); 180 | msg = _mm_shuffle_epi32(msg, 0x0E); 181 | state0 = _mm_sha256rnds2_epu32(state0, state1, msg); 182 | msg2 = _mm_sha256msg1_epu32(msg2, msg3); 183 | 184 | /* Rounds 48-51 */ 185 | msg = _mm_add_epi32(msg0, _mm_set_epi64x(0x34B0BCB52748774C, 0x1E376C0819A4C116)); 186 | state1 = _mm_sha256rnds2_epu32(state1, state0, msg); 187 | tmp = _mm_alignr_epi8(msg0, msg3, 4); 188 | msg1 = _mm_add_epi32(msg1, tmp); 189 | msg1 = _mm_sha256msg2_epu32(msg1, msg0); 190 | msg = _mm_shuffle_epi32(msg, 0x0E); 191 | state0 = _mm_sha256rnds2_epu32(state0, state1, msg); 192 | msg3 = _mm_sha256msg1_epu32(msg3, msg0); 193 | 194 | /* Rounds 52-55 */ 195 | msg = _mm_add_epi32(msg1, _mm_set_epi64x(0x682E6FF35B9CCA4F, 0x4ED8AA4A391C0CB3)); 196 | state1 = _mm_sha256rnds2_epu32(state1, state0, msg); 197 | tmp = _mm_alignr_epi8(msg1, msg0, 4); 198 | msg2 = _mm_add_epi32(msg2, tmp); 199 | msg2 = _mm_sha256msg2_epu32(msg2, msg1); 200 | msg = _mm_shuffle_epi32(msg, 0x0E); 201 | state0 = _mm_sha256rnds2_epu32(state0, state1, msg); 202 | 203 | /* Rounds 56-59 */ 204 | msg = _mm_add_epi32(msg2, _mm_set_epi64x(0x8CC7020884C87814, 0x78A5636F748F82EE)); 205 | state1 = _mm_sha256rnds2_epu32(state1, state0, msg); 206 | tmp = _mm_alignr_epi8(msg2, msg1, 4); 207 | msg3 = _mm_add_epi32(msg3, tmp); 208 | msg3 = _mm_sha256msg2_epu32(msg3, msg2); 209 | msg = _mm_shuffle_epi32(msg, 0x0E); 210 | state0 = _mm_sha256rnds2_epu32(state0, state1, msg); 211 | 212 | /* Rounds 60-63 */ 213 | msg = _mm_add_epi32(msg3, _mm_set_epi64x(0xC67178F2BEF9A3F7, 0xA4506CEB90BEFFFA)); 214 | state1 = _mm_sha256rnds2_epu32(state1, state0, msg); 215 | msg = _mm_shuffle_epi32(msg, 0x0E); 216 | state0 = _mm_sha256rnds2_epu32(state0, state1, msg); 217 | 218 | /* Combine state */ 219 | state0 = _mm_add_epi32(state0, abef_save); 220 | state1 = _mm_add_epi32(state1, cdgh_save); 221 | 222 | tmp = _mm_shuffle_epi32(state0, 0x1B); /* FEBA */ 223 | state1 = _mm_shuffle_epi32(state1, 0xB1); /* DCHG */ 224 | state0 = _mm_blend_epi16(tmp, state1, 0xF0); /* DCBA */ 225 | state1 = _mm_alignr_epi8(state1, tmp, 8); /* ABEF */ 226 | 227 | /* Save state */ 228 | _mm_storeu_si128(state.as_ptr() as _, state0); 229 | _mm_storeu_si128(state.as_ptr().add(4) as _, state1); 230 | } 231 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2020 Dana Marcuse 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /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 = "ansi_term" 7 | version = "0.12.1" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" 10 | dependencies = [ 11 | "winapi 0.3.9", 12 | ] 13 | 14 | [[package]] 15 | name = "async-channel" 16 | version = "1.6.1" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319" 19 | dependencies = [ 20 | "concurrent-queue", 21 | "event-listener", 22 | "futures-core", 23 | ] 24 | 25 | [[package]] 26 | name = "atty" 27 | version = "0.2.14" 28 | source = "registry+https://github.com/rust-lang/crates.io-index" 29 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 30 | dependencies = [ 31 | "hermit-abi", 32 | "libc", 33 | "winapi 0.3.9", 34 | ] 35 | 36 | [[package]] 37 | name = "autocfg" 38 | version = "1.1.0" 39 | source = "registry+https://github.com/rust-lang/crates.io-index" 40 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 41 | 42 | [[package]] 43 | name = "base64" 44 | version = "0.12.3" 45 | source = "registry+https://github.com/rust-lang/crates.io-index" 46 | checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" 47 | 48 | [[package]] 49 | name = "bitflags" 50 | version = "1.3.2" 51 | source = "registry+https://github.com/rust-lang/crates.io-index" 52 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 53 | 54 | [[package]] 55 | name = "block-buffer" 56 | version = "0.9.0" 57 | source = "registry+https://github.com/rust-lang/crates.io-index" 58 | checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" 59 | dependencies = [ 60 | "generic-array 0.14.5", 61 | ] 62 | 63 | [[package]] 64 | name = "bumpalo" 65 | version = "3.9.1" 66 | source = "registry+https://github.com/rust-lang/crates.io-index" 67 | checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" 68 | 69 | [[package]] 70 | name = "byteorder" 71 | version = "1.4.3" 72 | source = "registry+https://github.com/rust-lang/crates.io-index" 73 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 74 | 75 | [[package]] 76 | name = "bytes" 77 | version = "0.5.6" 78 | source = "registry+https://github.com/rust-lang/crates.io-index" 79 | checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" 80 | 81 | [[package]] 82 | name = "bytes" 83 | version = "1.1.0" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" 86 | 87 | [[package]] 88 | name = "cache-padded" 89 | version = "1.2.0" 90 | source = "registry+https://github.com/rust-lang/crates.io-index" 91 | checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c" 92 | 93 | [[package]] 94 | name = "cc" 95 | version = "1.0.73" 96 | source = "registry+https://github.com/rust-lang/crates.io-index" 97 | checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" 98 | 99 | [[package]] 100 | name = "cfg-if" 101 | version = "0.1.10" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 104 | 105 | [[package]] 106 | name = "cfg-if" 107 | version = "1.0.0" 108 | source = "registry+https://github.com/rust-lang/crates.io-index" 109 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 110 | 111 | [[package]] 112 | name = "chrono" 113 | version = "0.4.19" 114 | source = "registry+https://github.com/rust-lang/crates.io-index" 115 | checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" 116 | dependencies = [ 117 | "libc", 118 | "num-integer", 119 | "num-traits", 120 | "time", 121 | "winapi 0.3.9", 122 | ] 123 | 124 | [[package]] 125 | name = "clap" 126 | version = "2.34.0" 127 | source = "registry+https://github.com/rust-lang/crates.io-index" 128 | checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" 129 | dependencies = [ 130 | "ansi_term", 131 | "atty", 132 | "bitflags", 133 | "strsim 0.8.0", 134 | "textwrap", 135 | "unicode-width", 136 | "vec_map", 137 | ] 138 | 139 | [[package]] 140 | name = "concurrent-queue" 141 | version = "1.2.2" 142 | source = "registry+https://github.com/rust-lang/crates.io-index" 143 | checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" 144 | dependencies = [ 145 | "cache-padded", 146 | ] 147 | 148 | [[package]] 149 | name = "console" 150 | version = "0.15.0" 151 | source = "registry+https://github.com/rust-lang/crates.io-index" 152 | checksum = "a28b32d32ca44b70c3e4acd7db1babf555fa026e385fb95f18028f88848b3c31" 153 | dependencies = [ 154 | "encode_unicode", 155 | "libc", 156 | "once_cell", 157 | "regex", 158 | "terminal_size", 159 | "unicode-width", 160 | "winapi 0.3.9", 161 | ] 162 | 163 | [[package]] 164 | name = "const-cstr" 165 | version = "0.3.0" 166 | source = "registry+https://github.com/rust-lang/crates.io-index" 167 | checksum = "ed3d0b5ff30645a68f35ece8cea4556ca14ef8a1651455f789a099a0513532a6" 168 | 169 | [[package]] 170 | name = "core-foundation" 171 | version = "0.9.3" 172 | source = "registry+https://github.com/rust-lang/crates.io-index" 173 | checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" 174 | dependencies = [ 175 | "core-foundation-sys", 176 | "libc", 177 | ] 178 | 179 | [[package]] 180 | name = "core-foundation-sys" 181 | version = "0.8.3" 182 | source = "registry+https://github.com/rust-lang/crates.io-index" 183 | checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" 184 | 185 | [[package]] 186 | name = "cpufeatures" 187 | version = "0.2.1" 188 | source = "registry+https://github.com/rust-lang/crates.io-index" 189 | checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" 190 | dependencies = [ 191 | "libc", 192 | ] 193 | 194 | [[package]] 195 | name = "crossbeam" 196 | version = "0.7.3" 197 | source = "registry+https://github.com/rust-lang/crates.io-index" 198 | checksum = "69323bff1fb41c635347b8ead484a5ca6c3f11914d784170b158d8449ab07f8e" 199 | dependencies = [ 200 | "cfg-if 0.1.10", 201 | "crossbeam-channel", 202 | "crossbeam-deque", 203 | "crossbeam-epoch", 204 | "crossbeam-queue", 205 | "crossbeam-utils 0.7.2", 206 | ] 207 | 208 | [[package]] 209 | name = "crossbeam-channel" 210 | version = "0.4.4" 211 | source = "registry+https://github.com/rust-lang/crates.io-index" 212 | checksum = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87" 213 | dependencies = [ 214 | "crossbeam-utils 0.7.2", 215 | "maybe-uninit", 216 | ] 217 | 218 | [[package]] 219 | name = "crossbeam-deque" 220 | version = "0.7.4" 221 | source = "registry+https://github.com/rust-lang/crates.io-index" 222 | checksum = "c20ff29ded3204c5106278a81a38f4b482636ed4fa1e6cfbeef193291beb29ed" 223 | dependencies = [ 224 | "crossbeam-epoch", 225 | "crossbeam-utils 0.7.2", 226 | "maybe-uninit", 227 | ] 228 | 229 | [[package]] 230 | name = "crossbeam-epoch" 231 | version = "0.8.2" 232 | source = "registry+https://github.com/rust-lang/crates.io-index" 233 | checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" 234 | dependencies = [ 235 | "autocfg", 236 | "cfg-if 0.1.10", 237 | "crossbeam-utils 0.7.2", 238 | "lazy_static", 239 | "maybe-uninit", 240 | "memoffset", 241 | "scopeguard", 242 | ] 243 | 244 | [[package]] 245 | name = "crossbeam-queue" 246 | version = "0.2.3" 247 | source = "registry+https://github.com/rust-lang/crates.io-index" 248 | checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" 249 | dependencies = [ 250 | "cfg-if 0.1.10", 251 | "crossbeam-utils 0.7.2", 252 | "maybe-uninit", 253 | ] 254 | 255 | [[package]] 256 | name = "crossbeam-utils" 257 | version = "0.7.2" 258 | source = "registry+https://github.com/rust-lang/crates.io-index" 259 | checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" 260 | dependencies = [ 261 | "autocfg", 262 | "cfg-if 0.1.10", 263 | "lazy_static", 264 | ] 265 | 266 | [[package]] 267 | name = "crossbeam-utils" 268 | version = "0.8.7" 269 | source = "registry+https://github.com/rust-lang/crates.io-index" 270 | checksum = "b5e5bed1f1c269533fa816a0a5492b3545209a205ca1a54842be180eb63a16a6" 271 | dependencies = [ 272 | "cfg-if 1.0.0", 273 | "lazy_static", 274 | ] 275 | 276 | [[package]] 277 | name = "curl" 278 | version = "0.4.42" 279 | source = "registry+https://github.com/rust-lang/crates.io-index" 280 | checksum = "7de97b894edd5b5bcceef8b78d7da9b75b1d2f2f9a910569d0bde3dd31d84939" 281 | dependencies = [ 282 | "curl-sys", 283 | "libc", 284 | "openssl-probe", 285 | "openssl-sys", 286 | "schannel", 287 | "socket2", 288 | "winapi 0.3.9", 289 | ] 290 | 291 | [[package]] 292 | name = "curl-sys" 293 | version = "0.4.52+curl-7.81.0" 294 | source = "registry+https://github.com/rust-lang/crates.io-index" 295 | checksum = "14b8c2d1023ea5fded5b7b892e4b8e95f70038a421126a056761a84246a28971" 296 | dependencies = [ 297 | "cc", 298 | "libc", 299 | "libnghttp2-sys", 300 | "libz-sys", 301 | "openssl-sys", 302 | "pkg-config", 303 | "vcpkg", 304 | "winapi 0.3.9", 305 | ] 306 | 307 | [[package]] 308 | name = "darling" 309 | version = "0.13.1" 310 | source = "registry+https://github.com/rust-lang/crates.io-index" 311 | checksum = "d0d720b8683f8dd83c65155f0530560cba68cd2bf395f6513a483caee57ff7f4" 312 | dependencies = [ 313 | "darling_core", 314 | "darling_macro", 315 | ] 316 | 317 | [[package]] 318 | name = "darling_core" 319 | version = "0.13.1" 320 | source = "registry+https://github.com/rust-lang/crates.io-index" 321 | checksum = "7a340f241d2ceed1deb47ae36c4144b2707ec7dd0b649f894cb39bb595986324" 322 | dependencies = [ 323 | "fnv", 324 | "ident_case", 325 | "proc-macro2 1.0.36", 326 | "quote 1.0.15", 327 | "strsim 0.10.0", 328 | "syn 1.0.86", 329 | ] 330 | 331 | [[package]] 332 | name = "darling_macro" 333 | version = "0.13.1" 334 | source = "registry+https://github.com/rust-lang/crates.io-index" 335 | checksum = "72c41b3b7352feb3211a0d743dc5700a4e3b60f51bd2b368892d1e0f9a95f44b" 336 | dependencies = [ 337 | "darling_core", 338 | "quote 1.0.15", 339 | "syn 1.0.86", 340 | ] 341 | 342 | [[package]] 343 | name = "digest" 344 | version = "0.9.0" 345 | source = "registry+https://github.com/rust-lang/crates.io-index" 346 | checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" 347 | dependencies = [ 348 | "generic-array 0.14.5", 349 | ] 350 | 351 | [[package]] 352 | name = "dirs" 353 | version = "3.0.2" 354 | source = "registry+https://github.com/rust-lang/crates.io-index" 355 | checksum = "30baa043103c9d0c2a57cf537cc2f35623889dc0d405e6c3cccfadbc81c71309" 356 | dependencies = [ 357 | "dirs-sys", 358 | ] 359 | 360 | [[package]] 361 | name = "dirs-sys" 362 | version = "0.3.6" 363 | source = "registry+https://github.com/rust-lang/crates.io-index" 364 | checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" 365 | dependencies = [ 366 | "libc", 367 | "redox_users", 368 | "winapi 0.3.9", 369 | ] 370 | 371 | [[package]] 372 | name = "dlopen" 373 | version = "0.1.8" 374 | source = "registry+https://github.com/rust-lang/crates.io-index" 375 | checksum = "71e80ad39f814a9abe68583cd50a2d45c8a67561c3361ab8da240587dda80937" 376 | dependencies = [ 377 | "dlopen_derive", 378 | "lazy_static", 379 | "libc", 380 | "winapi 0.3.9", 381 | ] 382 | 383 | [[package]] 384 | name = "dlopen_derive" 385 | version = "0.1.4" 386 | source = "registry+https://github.com/rust-lang/crates.io-index" 387 | checksum = "f236d9e1b1fbd81cea0f9cbdc8dcc7e8ebcd80e6659cd7cb2ad5f6c05946c581" 388 | dependencies = [ 389 | "libc", 390 | "quote 0.6.13", 391 | "syn 0.15.44", 392 | ] 393 | 394 | [[package]] 395 | name = "dynamic_ocl" 396 | version = "0.1.0-alpha.1" 397 | source = "registry+https://github.com/rust-lang/crates.io-index" 398 | checksum = "df6150f15e388359ad9d1f2037c6b13c219c3381050fbb6e0c70b65f64330d6a" 399 | dependencies = [ 400 | "const-cstr", 401 | "dlopen", 402 | "generic-array 0.13.3", 403 | "lazy_static", 404 | "libc", 405 | "log", 406 | "thiserror", 407 | "tynm", 408 | ] 409 | 410 | [[package]] 411 | name = "either" 412 | version = "1.6.1" 413 | source = "registry+https://github.com/rust-lang/crates.io-index" 414 | checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" 415 | 416 | [[package]] 417 | name = "encode_unicode" 418 | version = "0.3.6" 419 | source = "registry+https://github.com/rust-lang/crates.io-index" 420 | checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" 421 | 422 | [[package]] 423 | name = "encoding_rs" 424 | version = "0.8.30" 425 | source = "registry+https://github.com/rust-lang/crates.io-index" 426 | checksum = "7896dc8abb250ffdda33912550faa54c88ec8b998dec0b2c55ab224921ce11df" 427 | dependencies = [ 428 | "cfg-if 1.0.0", 429 | ] 430 | 431 | [[package]] 432 | name = "enumset" 433 | version = "1.0.8" 434 | source = "registry+https://github.com/rust-lang/crates.io-index" 435 | checksum = "6216d2c19a6fb5f29d1ada1dc7bc4367a8cbf0fa4af5cf12e07b5bbdde6b5b2c" 436 | dependencies = [ 437 | "enumset_derive", 438 | ] 439 | 440 | [[package]] 441 | name = "enumset_derive" 442 | version = "0.5.5" 443 | source = "registry+https://github.com/rust-lang/crates.io-index" 444 | checksum = "6451128aa6655d880755345d085494cf7561a6bee7c8dc821e5d77e6d267ecd4" 445 | dependencies = [ 446 | "darling", 447 | "proc-macro2 1.0.36", 448 | "quote 1.0.15", 449 | "syn 1.0.86", 450 | ] 451 | 452 | [[package]] 453 | name = "event-listener" 454 | version = "2.5.2" 455 | source = "registry+https://github.com/rust-lang/crates.io-index" 456 | checksum = "77f3309417938f28bf8228fcff79a4a37103981e3e186d2ccd19c74b38f4eb71" 457 | 458 | [[package]] 459 | name = "fastrand" 460 | version = "1.7.0" 461 | source = "registry+https://github.com/rust-lang/crates.io-index" 462 | checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" 463 | dependencies = [ 464 | "instant", 465 | ] 466 | 467 | [[package]] 468 | name = "flume" 469 | version = "0.9.2" 470 | source = "registry+https://github.com/rust-lang/crates.io-index" 471 | checksum = "1bebadab126f8120d410b677ed95eee4ba6eb7c6dd8e34a5ec88a08050e26132" 472 | dependencies = [ 473 | "futures-core", 474 | "futures-sink", 475 | "spinning_top", 476 | ] 477 | 478 | [[package]] 479 | name = "fnv" 480 | version = "1.0.7" 481 | source = "registry+https://github.com/rust-lang/crates.io-index" 482 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 483 | 484 | [[package]] 485 | name = "foreign-types" 486 | version = "0.3.2" 487 | source = "registry+https://github.com/rust-lang/crates.io-index" 488 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 489 | dependencies = [ 490 | "foreign-types-shared", 491 | ] 492 | 493 | [[package]] 494 | name = "foreign-types-shared" 495 | version = "0.1.1" 496 | source = "registry+https://github.com/rust-lang/crates.io-index" 497 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 498 | 499 | [[package]] 500 | name = "form_urlencoded" 501 | version = "1.0.1" 502 | source = "registry+https://github.com/rust-lang/crates.io-index" 503 | checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" 504 | dependencies = [ 505 | "matches", 506 | "percent-encoding", 507 | ] 508 | 509 | [[package]] 510 | name = "fuchsia-zircon" 511 | version = "0.3.3" 512 | source = "registry+https://github.com/rust-lang/crates.io-index" 513 | checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" 514 | dependencies = [ 515 | "bitflags", 516 | "fuchsia-zircon-sys", 517 | ] 518 | 519 | [[package]] 520 | name = "fuchsia-zircon-sys" 521 | version = "0.3.3" 522 | source = "registry+https://github.com/rust-lang/crates.io-index" 523 | checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" 524 | 525 | [[package]] 526 | name = "futures" 527 | version = "0.3.21" 528 | source = "registry+https://github.com/rust-lang/crates.io-index" 529 | checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" 530 | dependencies = [ 531 | "futures-channel", 532 | "futures-core", 533 | "futures-executor", 534 | "futures-io", 535 | "futures-sink", 536 | "futures-task", 537 | "futures-util", 538 | ] 539 | 540 | [[package]] 541 | name = "futures-channel" 542 | version = "0.3.21" 543 | source = "registry+https://github.com/rust-lang/crates.io-index" 544 | checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" 545 | dependencies = [ 546 | "futures-core", 547 | "futures-sink", 548 | ] 549 | 550 | [[package]] 551 | name = "futures-core" 552 | version = "0.3.21" 553 | source = "registry+https://github.com/rust-lang/crates.io-index" 554 | checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" 555 | 556 | [[package]] 557 | name = "futures-executor" 558 | version = "0.3.21" 559 | source = "registry+https://github.com/rust-lang/crates.io-index" 560 | checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" 561 | dependencies = [ 562 | "futures-core", 563 | "futures-task", 564 | "futures-util", 565 | ] 566 | 567 | [[package]] 568 | name = "futures-io" 569 | version = "0.3.21" 570 | source = "registry+https://github.com/rust-lang/crates.io-index" 571 | checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" 572 | 573 | [[package]] 574 | name = "futures-lite" 575 | version = "1.12.0" 576 | source = "registry+https://github.com/rust-lang/crates.io-index" 577 | checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48" 578 | dependencies = [ 579 | "fastrand", 580 | "futures-core", 581 | "futures-io", 582 | "memchr", 583 | "parking", 584 | "pin-project-lite 0.2.8", 585 | "waker-fn", 586 | ] 587 | 588 | [[package]] 589 | name = "futures-macro" 590 | version = "0.3.21" 591 | source = "registry+https://github.com/rust-lang/crates.io-index" 592 | checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" 593 | dependencies = [ 594 | "proc-macro2 1.0.36", 595 | "quote 1.0.15", 596 | "syn 1.0.86", 597 | ] 598 | 599 | [[package]] 600 | name = "futures-sink" 601 | version = "0.3.21" 602 | source = "registry+https://github.com/rust-lang/crates.io-index" 603 | checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" 604 | 605 | [[package]] 606 | name = "futures-task" 607 | version = "0.3.21" 608 | source = "registry+https://github.com/rust-lang/crates.io-index" 609 | checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" 610 | 611 | [[package]] 612 | name = "futures-util" 613 | version = "0.3.21" 614 | source = "registry+https://github.com/rust-lang/crates.io-index" 615 | checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" 616 | dependencies = [ 617 | "futures-channel", 618 | "futures-core", 619 | "futures-io", 620 | "futures-macro", 621 | "futures-sink", 622 | "futures-task", 623 | "memchr", 624 | "pin-project-lite 0.2.8", 625 | "pin-utils", 626 | "slab", 627 | ] 628 | 629 | [[package]] 630 | name = "generic-array" 631 | version = "0.13.3" 632 | source = "registry+https://github.com/rust-lang/crates.io-index" 633 | checksum = "f797e67af32588215eaaab8327027ee8e71b9dd0b2b26996aedf20c030fce309" 634 | dependencies = [ 635 | "typenum", 636 | ] 637 | 638 | [[package]] 639 | name = "generic-array" 640 | version = "0.14.5" 641 | source = "registry+https://github.com/rust-lang/crates.io-index" 642 | checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" 643 | dependencies = [ 644 | "typenum", 645 | "version_check", 646 | ] 647 | 648 | [[package]] 649 | name = "getrandom" 650 | version = "0.1.16" 651 | source = "registry+https://github.com/rust-lang/crates.io-index" 652 | checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" 653 | dependencies = [ 654 | "cfg-if 1.0.0", 655 | "libc", 656 | "wasi 0.9.0+wasi-snapshot-preview1", 657 | ] 658 | 659 | [[package]] 660 | name = "getrandom" 661 | version = "0.2.4" 662 | source = "registry+https://github.com/rust-lang/crates.io-index" 663 | checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c" 664 | dependencies = [ 665 | "cfg-if 1.0.0", 666 | "libc", 667 | "wasi 0.10.2+wasi-snapshot-preview1", 668 | ] 669 | 670 | [[package]] 671 | name = "heck" 672 | version = "0.3.3" 673 | source = "registry+https://github.com/rust-lang/crates.io-index" 674 | checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" 675 | dependencies = [ 676 | "unicode-segmentation", 677 | ] 678 | 679 | [[package]] 680 | name = "hermit-abi" 681 | version = "0.1.19" 682 | source = "registry+https://github.com/rust-lang/crates.io-index" 683 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 684 | dependencies = [ 685 | "libc", 686 | ] 687 | 688 | [[package]] 689 | name = "hex" 690 | version = "0.4.3" 691 | source = "registry+https://github.com/rust-lang/crates.io-index" 692 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 693 | 694 | [[package]] 695 | name = "http" 696 | version = "0.2.6" 697 | source = "registry+https://github.com/rust-lang/crates.io-index" 698 | checksum = "31f4c6746584866f0feabcc69893c5b51beef3831656a968ed7ae254cdc4fd03" 699 | dependencies = [ 700 | "bytes 1.1.0", 701 | "fnv", 702 | "itoa", 703 | ] 704 | 705 | [[package]] 706 | name = "httparse" 707 | version = "1.6.0" 708 | source = "registry+https://github.com/rust-lang/crates.io-index" 709 | checksum = "9100414882e15fb7feccb4897e5f0ff0ff1ca7d1a86a23208ada4d7a18e6c6c4" 710 | 711 | [[package]] 712 | name = "ident_case" 713 | version = "1.0.1" 714 | source = "registry+https://github.com/rust-lang/crates.io-index" 715 | checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" 716 | 717 | [[package]] 718 | name = "idna" 719 | version = "0.2.3" 720 | source = "registry+https://github.com/rust-lang/crates.io-index" 721 | checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" 722 | dependencies = [ 723 | "matches", 724 | "unicode-bidi", 725 | "unicode-normalization", 726 | ] 727 | 728 | [[package]] 729 | name = "indicatif" 730 | version = "0.15.0" 731 | source = "registry+https://github.com/rust-lang/crates.io-index" 732 | checksum = "7baab56125e25686df467fe470785512329883aab42696d661247aca2a2896e4" 733 | dependencies = [ 734 | "console", 735 | "lazy_static", 736 | "number_prefix", 737 | "regex", 738 | ] 739 | 740 | [[package]] 741 | name = "input_buffer" 742 | version = "0.3.1" 743 | source = "registry+https://github.com/rust-lang/crates.io-index" 744 | checksum = "19a8a95243d5a0398cae618ec29477c6e3cb631152be5c19481f80bc71559754" 745 | dependencies = [ 746 | "bytes 0.5.6", 747 | ] 748 | 749 | [[package]] 750 | name = "instant" 751 | version = "0.1.12" 752 | source = "registry+https://github.com/rust-lang/crates.io-index" 753 | checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" 754 | dependencies = [ 755 | "cfg-if 1.0.0", 756 | ] 757 | 758 | [[package]] 759 | name = "iovec" 760 | version = "0.1.4" 761 | source = "registry+https://github.com/rust-lang/crates.io-index" 762 | checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" 763 | dependencies = [ 764 | "libc", 765 | ] 766 | 767 | [[package]] 768 | name = "isahc" 769 | version = "0.9.14" 770 | source = "registry+https://github.com/rust-lang/crates.io-index" 771 | checksum = "e2948a0ce43e2c2ef11d7edf6816508998d99e13badd1150be0914205df9388a" 772 | dependencies = [ 773 | "bytes 0.5.6", 774 | "crossbeam-utils 0.8.7", 775 | "curl", 776 | "curl-sys", 777 | "encoding_rs", 778 | "flume", 779 | "futures-lite", 780 | "http", 781 | "log", 782 | "mime", 783 | "once_cell", 784 | "slab", 785 | "sluice", 786 | "tracing", 787 | "tracing-futures", 788 | "url", 789 | "waker-fn", 790 | ] 791 | 792 | [[package]] 793 | name = "itertools" 794 | version = "0.9.0" 795 | source = "registry+https://github.com/rust-lang/crates.io-index" 796 | checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" 797 | dependencies = [ 798 | "either", 799 | ] 800 | 801 | [[package]] 802 | name = "itoa" 803 | version = "1.0.1" 804 | source = "registry+https://github.com/rust-lang/crates.io-index" 805 | checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" 806 | 807 | [[package]] 808 | name = "js-sys" 809 | version = "0.3.56" 810 | source = "registry+https://github.com/rust-lang/crates.io-index" 811 | checksum = "a38fc24e30fd564ce974c02bf1d337caddff65be6cc4735a1f7eab22a7440f04" 812 | dependencies = [ 813 | "wasm-bindgen", 814 | ] 815 | 816 | [[package]] 817 | name = "kernel32-sys" 818 | version = "0.2.2" 819 | source = "registry+https://github.com/rust-lang/crates.io-index" 820 | checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" 821 | dependencies = [ 822 | "winapi 0.2.8", 823 | "winapi-build", 824 | ] 825 | 826 | [[package]] 827 | name = "kristforge" 828 | version = "3.1.6" 829 | dependencies = [ 830 | "crossbeam", 831 | "dirs", 832 | "dynamic_ocl", 833 | "enumset", 834 | "futures", 835 | "hex", 836 | "indicatif", 837 | "isahc", 838 | "itertools", 839 | "lazy_static", 840 | "libc", 841 | "log", 842 | "num_cpus", 843 | "rand", 844 | "ring", 845 | "serde", 846 | "serde_json", 847 | "simplelog", 848 | "structopt", 849 | "thiserror", 850 | "tokio", 851 | "tokio-tungstenite", 852 | "url", 853 | "winapi 0.3.9", 854 | ] 855 | 856 | [[package]] 857 | name = "lazy_static" 858 | version = "1.4.0" 859 | source = "registry+https://github.com/rust-lang/crates.io-index" 860 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 861 | 862 | [[package]] 863 | name = "libc" 864 | version = "0.2.119" 865 | source = "registry+https://github.com/rust-lang/crates.io-index" 866 | checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4" 867 | 868 | [[package]] 869 | name = "libnghttp2-sys" 870 | version = "0.1.7+1.45.0" 871 | source = "registry+https://github.com/rust-lang/crates.io-index" 872 | checksum = "57ed28aba195b38d5ff02b9170cbff627e336a20925e43b4945390401c5dc93f" 873 | dependencies = [ 874 | "cc", 875 | "libc", 876 | ] 877 | 878 | [[package]] 879 | name = "libz-sys" 880 | version = "1.1.3" 881 | source = "registry+https://github.com/rust-lang/crates.io-index" 882 | checksum = "de5435b8549c16d423ed0c03dbaafe57cf6c3344744f1242520d59c9d8ecec66" 883 | dependencies = [ 884 | "cc", 885 | "libc", 886 | "pkg-config", 887 | "vcpkg", 888 | ] 889 | 890 | [[package]] 891 | name = "lock_api" 892 | version = "0.4.6" 893 | source = "registry+https://github.com/rust-lang/crates.io-index" 894 | checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" 895 | dependencies = [ 896 | "scopeguard", 897 | ] 898 | 899 | [[package]] 900 | name = "log" 901 | version = "0.4.14" 902 | source = "registry+https://github.com/rust-lang/crates.io-index" 903 | checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" 904 | dependencies = [ 905 | "cfg-if 1.0.0", 906 | ] 907 | 908 | [[package]] 909 | name = "matches" 910 | version = "0.1.9" 911 | source = "registry+https://github.com/rust-lang/crates.io-index" 912 | checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" 913 | 914 | [[package]] 915 | name = "maybe-uninit" 916 | version = "2.0.0" 917 | source = "registry+https://github.com/rust-lang/crates.io-index" 918 | checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" 919 | 920 | [[package]] 921 | name = "memchr" 922 | version = "2.4.1" 923 | source = "registry+https://github.com/rust-lang/crates.io-index" 924 | checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" 925 | 926 | [[package]] 927 | name = "memoffset" 928 | version = "0.5.6" 929 | source = "registry+https://github.com/rust-lang/crates.io-index" 930 | checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa" 931 | dependencies = [ 932 | "autocfg", 933 | ] 934 | 935 | [[package]] 936 | name = "mime" 937 | version = "0.3.16" 938 | source = "registry+https://github.com/rust-lang/crates.io-index" 939 | checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" 940 | 941 | [[package]] 942 | name = "mio" 943 | version = "0.6.23" 944 | source = "registry+https://github.com/rust-lang/crates.io-index" 945 | checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" 946 | dependencies = [ 947 | "cfg-if 0.1.10", 948 | "fuchsia-zircon", 949 | "fuchsia-zircon-sys", 950 | "iovec", 951 | "kernel32-sys", 952 | "libc", 953 | "log", 954 | "miow", 955 | "net2", 956 | "slab", 957 | "winapi 0.2.8", 958 | ] 959 | 960 | [[package]] 961 | name = "mio-uds" 962 | version = "0.6.8" 963 | source = "registry+https://github.com/rust-lang/crates.io-index" 964 | checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0" 965 | dependencies = [ 966 | "iovec", 967 | "libc", 968 | "mio", 969 | ] 970 | 971 | [[package]] 972 | name = "miow" 973 | version = "0.2.2" 974 | source = "registry+https://github.com/rust-lang/crates.io-index" 975 | checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" 976 | dependencies = [ 977 | "kernel32-sys", 978 | "net2", 979 | "winapi 0.2.8", 980 | "ws2_32-sys", 981 | ] 982 | 983 | [[package]] 984 | name = "native-tls" 985 | version = "0.2.8" 986 | source = "registry+https://github.com/rust-lang/crates.io-index" 987 | checksum = "48ba9f7719b5a0f42f338907614285fb5fd70e53858141f69898a1fb7203b24d" 988 | dependencies = [ 989 | "lazy_static", 990 | "libc", 991 | "log", 992 | "openssl", 993 | "openssl-probe", 994 | "openssl-sys", 995 | "schannel", 996 | "security-framework", 997 | "security-framework-sys", 998 | "tempfile", 999 | ] 1000 | 1001 | [[package]] 1002 | name = "net2" 1003 | version = "0.2.37" 1004 | source = "registry+https://github.com/rust-lang/crates.io-index" 1005 | checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae" 1006 | dependencies = [ 1007 | "cfg-if 0.1.10", 1008 | "libc", 1009 | "winapi 0.3.9", 1010 | ] 1011 | 1012 | [[package]] 1013 | name = "nom" 1014 | version = "5.1.2" 1015 | source = "registry+https://github.com/rust-lang/crates.io-index" 1016 | checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" 1017 | dependencies = [ 1018 | "memchr", 1019 | "version_check", 1020 | ] 1021 | 1022 | [[package]] 1023 | name = "num-integer" 1024 | version = "0.1.44" 1025 | source = "registry+https://github.com/rust-lang/crates.io-index" 1026 | checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" 1027 | dependencies = [ 1028 | "autocfg", 1029 | "num-traits", 1030 | ] 1031 | 1032 | [[package]] 1033 | name = "num-traits" 1034 | version = "0.2.14" 1035 | source = "registry+https://github.com/rust-lang/crates.io-index" 1036 | checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" 1037 | dependencies = [ 1038 | "autocfg", 1039 | ] 1040 | 1041 | [[package]] 1042 | name = "num_cpus" 1043 | version = "1.13.1" 1044 | source = "registry+https://github.com/rust-lang/crates.io-index" 1045 | checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" 1046 | dependencies = [ 1047 | "hermit-abi", 1048 | "libc", 1049 | ] 1050 | 1051 | [[package]] 1052 | name = "number_prefix" 1053 | version = "0.3.0" 1054 | source = "registry+https://github.com/rust-lang/crates.io-index" 1055 | checksum = "17b02fc0ff9a9e4b35b3342880f48e896ebf69f2967921fe8646bf5b7125956a" 1056 | 1057 | [[package]] 1058 | name = "once_cell" 1059 | version = "1.9.0" 1060 | source = "registry+https://github.com/rust-lang/crates.io-index" 1061 | checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" 1062 | 1063 | [[package]] 1064 | name = "opaque-debug" 1065 | version = "0.3.0" 1066 | source = "registry+https://github.com/rust-lang/crates.io-index" 1067 | checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" 1068 | 1069 | [[package]] 1070 | name = "openssl" 1071 | version = "0.10.38" 1072 | source = "registry+https://github.com/rust-lang/crates.io-index" 1073 | checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95" 1074 | dependencies = [ 1075 | "bitflags", 1076 | "cfg-if 1.0.0", 1077 | "foreign-types", 1078 | "libc", 1079 | "once_cell", 1080 | "openssl-sys", 1081 | ] 1082 | 1083 | [[package]] 1084 | name = "openssl-probe" 1085 | version = "0.1.5" 1086 | source = "registry+https://github.com/rust-lang/crates.io-index" 1087 | checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" 1088 | 1089 | [[package]] 1090 | name = "openssl-src" 1091 | version = "111.17.0+1.1.1m" 1092 | source = "registry+https://github.com/rust-lang/crates.io-index" 1093 | checksum = "05d6a336abd10814198f66e2a91ccd7336611f30334119ca8ce300536666fcf4" 1094 | dependencies = [ 1095 | "cc", 1096 | ] 1097 | 1098 | [[package]] 1099 | name = "openssl-sys" 1100 | version = "0.9.72" 1101 | source = "registry+https://github.com/rust-lang/crates.io-index" 1102 | checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb" 1103 | dependencies = [ 1104 | "autocfg", 1105 | "cc", 1106 | "libc", 1107 | "openssl-src", 1108 | "pkg-config", 1109 | "vcpkg", 1110 | ] 1111 | 1112 | [[package]] 1113 | name = "parking" 1114 | version = "2.0.0" 1115 | source = "registry+https://github.com/rust-lang/crates.io-index" 1116 | checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" 1117 | 1118 | [[package]] 1119 | name = "percent-encoding" 1120 | version = "2.1.0" 1121 | source = "registry+https://github.com/rust-lang/crates.io-index" 1122 | checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" 1123 | 1124 | [[package]] 1125 | name = "pin-project" 1126 | version = "0.4.29" 1127 | source = "registry+https://github.com/rust-lang/crates.io-index" 1128 | checksum = "9615c18d31137579e9ff063499264ddc1278e7b1982757ebc111028c4d1dc909" 1129 | dependencies = [ 1130 | "pin-project-internal 0.4.29", 1131 | ] 1132 | 1133 | [[package]] 1134 | name = "pin-project" 1135 | version = "1.0.10" 1136 | source = "registry+https://github.com/rust-lang/crates.io-index" 1137 | checksum = "58ad3879ad3baf4e44784bc6a718a8698867bb991f8ce24d1bcbe2cfb4c3a75e" 1138 | dependencies = [ 1139 | "pin-project-internal 1.0.10", 1140 | ] 1141 | 1142 | [[package]] 1143 | name = "pin-project-internal" 1144 | version = "0.4.29" 1145 | source = "registry+https://github.com/rust-lang/crates.io-index" 1146 | checksum = "044964427019eed9d49d9d5bbce6047ef18f37100ea400912a9fa4a3523ab12a" 1147 | dependencies = [ 1148 | "proc-macro2 1.0.36", 1149 | "quote 1.0.15", 1150 | "syn 1.0.86", 1151 | ] 1152 | 1153 | [[package]] 1154 | name = "pin-project-internal" 1155 | version = "1.0.10" 1156 | source = "registry+https://github.com/rust-lang/crates.io-index" 1157 | checksum = "744b6f092ba29c3650faf274db506afd39944f48420f6c86b17cfe0ee1cb36bb" 1158 | dependencies = [ 1159 | "proc-macro2 1.0.36", 1160 | "quote 1.0.15", 1161 | "syn 1.0.86", 1162 | ] 1163 | 1164 | [[package]] 1165 | name = "pin-project-lite" 1166 | version = "0.1.12" 1167 | source = "registry+https://github.com/rust-lang/crates.io-index" 1168 | checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" 1169 | 1170 | [[package]] 1171 | name = "pin-project-lite" 1172 | version = "0.2.8" 1173 | source = "registry+https://github.com/rust-lang/crates.io-index" 1174 | checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" 1175 | 1176 | [[package]] 1177 | name = "pin-utils" 1178 | version = "0.1.0" 1179 | source = "registry+https://github.com/rust-lang/crates.io-index" 1180 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1181 | 1182 | [[package]] 1183 | name = "pkg-config" 1184 | version = "0.3.24" 1185 | source = "registry+https://github.com/rust-lang/crates.io-index" 1186 | checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" 1187 | 1188 | [[package]] 1189 | name = "ppv-lite86" 1190 | version = "0.2.16" 1191 | source = "registry+https://github.com/rust-lang/crates.io-index" 1192 | checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" 1193 | 1194 | [[package]] 1195 | name = "proc-macro-error" 1196 | version = "1.0.4" 1197 | source = "registry+https://github.com/rust-lang/crates.io-index" 1198 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 1199 | dependencies = [ 1200 | "proc-macro-error-attr", 1201 | "proc-macro2 1.0.36", 1202 | "quote 1.0.15", 1203 | "syn 1.0.86", 1204 | "version_check", 1205 | ] 1206 | 1207 | [[package]] 1208 | name = "proc-macro-error-attr" 1209 | version = "1.0.4" 1210 | source = "registry+https://github.com/rust-lang/crates.io-index" 1211 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 1212 | dependencies = [ 1213 | "proc-macro2 1.0.36", 1214 | "quote 1.0.15", 1215 | "version_check", 1216 | ] 1217 | 1218 | [[package]] 1219 | name = "proc-macro2" 1220 | version = "0.4.30" 1221 | source = "registry+https://github.com/rust-lang/crates.io-index" 1222 | checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" 1223 | dependencies = [ 1224 | "unicode-xid 0.1.0", 1225 | ] 1226 | 1227 | [[package]] 1228 | name = "proc-macro2" 1229 | version = "1.0.36" 1230 | source = "registry+https://github.com/rust-lang/crates.io-index" 1231 | checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" 1232 | dependencies = [ 1233 | "unicode-xid 0.2.2", 1234 | ] 1235 | 1236 | [[package]] 1237 | name = "quote" 1238 | version = "0.6.13" 1239 | source = "registry+https://github.com/rust-lang/crates.io-index" 1240 | checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" 1241 | dependencies = [ 1242 | "proc-macro2 0.4.30", 1243 | ] 1244 | 1245 | [[package]] 1246 | name = "quote" 1247 | version = "1.0.15" 1248 | source = "registry+https://github.com/rust-lang/crates.io-index" 1249 | checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145" 1250 | dependencies = [ 1251 | "proc-macro2 1.0.36", 1252 | ] 1253 | 1254 | [[package]] 1255 | name = "rand" 1256 | version = "0.7.3" 1257 | source = "registry+https://github.com/rust-lang/crates.io-index" 1258 | checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" 1259 | dependencies = [ 1260 | "getrandom 0.1.16", 1261 | "libc", 1262 | "rand_chacha", 1263 | "rand_core", 1264 | "rand_hc", 1265 | ] 1266 | 1267 | [[package]] 1268 | name = "rand_chacha" 1269 | version = "0.2.2" 1270 | source = "registry+https://github.com/rust-lang/crates.io-index" 1271 | checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" 1272 | dependencies = [ 1273 | "ppv-lite86", 1274 | "rand_core", 1275 | ] 1276 | 1277 | [[package]] 1278 | name = "rand_core" 1279 | version = "0.5.1" 1280 | source = "registry+https://github.com/rust-lang/crates.io-index" 1281 | checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" 1282 | dependencies = [ 1283 | "getrandom 0.1.16", 1284 | ] 1285 | 1286 | [[package]] 1287 | name = "rand_hc" 1288 | version = "0.2.0" 1289 | source = "registry+https://github.com/rust-lang/crates.io-index" 1290 | checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" 1291 | dependencies = [ 1292 | "rand_core", 1293 | ] 1294 | 1295 | [[package]] 1296 | name = "redox_syscall" 1297 | version = "0.2.10" 1298 | source = "registry+https://github.com/rust-lang/crates.io-index" 1299 | checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" 1300 | dependencies = [ 1301 | "bitflags", 1302 | ] 1303 | 1304 | [[package]] 1305 | name = "redox_users" 1306 | version = "0.4.0" 1307 | source = "registry+https://github.com/rust-lang/crates.io-index" 1308 | checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" 1309 | dependencies = [ 1310 | "getrandom 0.2.4", 1311 | "redox_syscall", 1312 | ] 1313 | 1314 | [[package]] 1315 | name = "regex" 1316 | version = "1.5.4" 1317 | source = "registry+https://github.com/rust-lang/crates.io-index" 1318 | checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" 1319 | dependencies = [ 1320 | "regex-syntax", 1321 | ] 1322 | 1323 | [[package]] 1324 | name = "regex-syntax" 1325 | version = "0.6.25" 1326 | source = "registry+https://github.com/rust-lang/crates.io-index" 1327 | checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" 1328 | 1329 | [[package]] 1330 | name = "remove_dir_all" 1331 | version = "0.5.3" 1332 | source = "registry+https://github.com/rust-lang/crates.io-index" 1333 | checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" 1334 | dependencies = [ 1335 | "winapi 0.3.9", 1336 | ] 1337 | 1338 | [[package]] 1339 | name = "ring" 1340 | version = "0.16.20" 1341 | source = "registry+https://github.com/rust-lang/crates.io-index" 1342 | checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" 1343 | dependencies = [ 1344 | "cc", 1345 | "libc", 1346 | "once_cell", 1347 | "spin", 1348 | "untrusted", 1349 | "web-sys", 1350 | "winapi 0.3.9", 1351 | ] 1352 | 1353 | [[package]] 1354 | name = "ryu" 1355 | version = "1.0.9" 1356 | source = "registry+https://github.com/rust-lang/crates.io-index" 1357 | checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" 1358 | 1359 | [[package]] 1360 | name = "schannel" 1361 | version = "0.1.19" 1362 | source = "registry+https://github.com/rust-lang/crates.io-index" 1363 | checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" 1364 | dependencies = [ 1365 | "lazy_static", 1366 | "winapi 0.3.9", 1367 | ] 1368 | 1369 | [[package]] 1370 | name = "scopeguard" 1371 | version = "1.1.0" 1372 | source = "registry+https://github.com/rust-lang/crates.io-index" 1373 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 1374 | 1375 | [[package]] 1376 | name = "security-framework" 1377 | version = "2.6.1" 1378 | source = "registry+https://github.com/rust-lang/crates.io-index" 1379 | checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc" 1380 | dependencies = [ 1381 | "bitflags", 1382 | "core-foundation", 1383 | "core-foundation-sys", 1384 | "libc", 1385 | "security-framework-sys", 1386 | ] 1387 | 1388 | [[package]] 1389 | name = "security-framework-sys" 1390 | version = "2.6.1" 1391 | source = "registry+https://github.com/rust-lang/crates.io-index" 1392 | checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" 1393 | dependencies = [ 1394 | "core-foundation-sys", 1395 | "libc", 1396 | ] 1397 | 1398 | [[package]] 1399 | name = "serde" 1400 | version = "1.0.136" 1401 | source = "registry+https://github.com/rust-lang/crates.io-index" 1402 | checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" 1403 | dependencies = [ 1404 | "serde_derive", 1405 | ] 1406 | 1407 | [[package]] 1408 | name = "serde_derive" 1409 | version = "1.0.136" 1410 | source = "registry+https://github.com/rust-lang/crates.io-index" 1411 | checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" 1412 | dependencies = [ 1413 | "proc-macro2 1.0.36", 1414 | "quote 1.0.15", 1415 | "syn 1.0.86", 1416 | ] 1417 | 1418 | [[package]] 1419 | name = "serde_json" 1420 | version = "1.0.79" 1421 | source = "registry+https://github.com/rust-lang/crates.io-index" 1422 | checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" 1423 | dependencies = [ 1424 | "itoa", 1425 | "ryu", 1426 | "serde", 1427 | ] 1428 | 1429 | [[package]] 1430 | name = "sha-1" 1431 | version = "0.9.8" 1432 | source = "registry+https://github.com/rust-lang/crates.io-index" 1433 | checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" 1434 | dependencies = [ 1435 | "block-buffer", 1436 | "cfg-if 1.0.0", 1437 | "cpufeatures", 1438 | "digest", 1439 | "opaque-debug", 1440 | ] 1441 | 1442 | [[package]] 1443 | name = "simplelog" 1444 | version = "0.8.0" 1445 | source = "registry+https://github.com/rust-lang/crates.io-index" 1446 | checksum = "2b2736f58087298a448859961d3f4a0850b832e72619d75adc69da7993c2cd3c" 1447 | dependencies = [ 1448 | "chrono", 1449 | "log", 1450 | "termcolor", 1451 | ] 1452 | 1453 | [[package]] 1454 | name = "slab" 1455 | version = "0.4.5" 1456 | source = "registry+https://github.com/rust-lang/crates.io-index" 1457 | checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" 1458 | 1459 | [[package]] 1460 | name = "sluice" 1461 | version = "0.5.5" 1462 | source = "registry+https://github.com/rust-lang/crates.io-index" 1463 | checksum = "6d7400c0eff44aa2fcb5e31a5f24ba9716ed90138769e4977a2ba6014ae63eb5" 1464 | dependencies = [ 1465 | "async-channel", 1466 | "futures-core", 1467 | "futures-io", 1468 | ] 1469 | 1470 | [[package]] 1471 | name = "socket2" 1472 | version = "0.4.4" 1473 | source = "registry+https://github.com/rust-lang/crates.io-index" 1474 | checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" 1475 | dependencies = [ 1476 | "libc", 1477 | "winapi 0.3.9", 1478 | ] 1479 | 1480 | [[package]] 1481 | name = "spin" 1482 | version = "0.5.2" 1483 | source = "registry+https://github.com/rust-lang/crates.io-index" 1484 | checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" 1485 | 1486 | [[package]] 1487 | name = "spinning_top" 1488 | version = "0.2.4" 1489 | source = "registry+https://github.com/rust-lang/crates.io-index" 1490 | checksum = "75adad84ee84b521fb2cca2d4fd0f1dab1d8d026bda3c5bea4ca63b5f9f9293c" 1491 | dependencies = [ 1492 | "lock_api", 1493 | ] 1494 | 1495 | [[package]] 1496 | name = "strsim" 1497 | version = "0.8.0" 1498 | source = "registry+https://github.com/rust-lang/crates.io-index" 1499 | checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" 1500 | 1501 | [[package]] 1502 | name = "strsim" 1503 | version = "0.10.0" 1504 | source = "registry+https://github.com/rust-lang/crates.io-index" 1505 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 1506 | 1507 | [[package]] 1508 | name = "structopt" 1509 | version = "0.3.26" 1510 | source = "registry+https://github.com/rust-lang/crates.io-index" 1511 | checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10" 1512 | dependencies = [ 1513 | "clap", 1514 | "lazy_static", 1515 | "structopt-derive", 1516 | ] 1517 | 1518 | [[package]] 1519 | name = "structopt-derive" 1520 | version = "0.4.18" 1521 | source = "registry+https://github.com/rust-lang/crates.io-index" 1522 | checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" 1523 | dependencies = [ 1524 | "heck", 1525 | "proc-macro-error", 1526 | "proc-macro2 1.0.36", 1527 | "quote 1.0.15", 1528 | "syn 1.0.86", 1529 | ] 1530 | 1531 | [[package]] 1532 | name = "syn" 1533 | version = "0.15.44" 1534 | source = "registry+https://github.com/rust-lang/crates.io-index" 1535 | checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" 1536 | dependencies = [ 1537 | "proc-macro2 0.4.30", 1538 | "quote 0.6.13", 1539 | "unicode-xid 0.1.0", 1540 | ] 1541 | 1542 | [[package]] 1543 | name = "syn" 1544 | version = "1.0.86" 1545 | source = "registry+https://github.com/rust-lang/crates.io-index" 1546 | checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b" 1547 | dependencies = [ 1548 | "proc-macro2 1.0.36", 1549 | "quote 1.0.15", 1550 | "unicode-xid 0.2.2", 1551 | ] 1552 | 1553 | [[package]] 1554 | name = "tempfile" 1555 | version = "3.3.0" 1556 | source = "registry+https://github.com/rust-lang/crates.io-index" 1557 | checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" 1558 | dependencies = [ 1559 | "cfg-if 1.0.0", 1560 | "fastrand", 1561 | "libc", 1562 | "redox_syscall", 1563 | "remove_dir_all", 1564 | "winapi 0.3.9", 1565 | ] 1566 | 1567 | [[package]] 1568 | name = "termcolor" 1569 | version = "1.1.2" 1570 | source = "registry+https://github.com/rust-lang/crates.io-index" 1571 | checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" 1572 | dependencies = [ 1573 | "winapi-util", 1574 | ] 1575 | 1576 | [[package]] 1577 | name = "terminal_size" 1578 | version = "0.1.17" 1579 | source = "registry+https://github.com/rust-lang/crates.io-index" 1580 | checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" 1581 | dependencies = [ 1582 | "libc", 1583 | "winapi 0.3.9", 1584 | ] 1585 | 1586 | [[package]] 1587 | name = "textwrap" 1588 | version = "0.11.0" 1589 | source = "registry+https://github.com/rust-lang/crates.io-index" 1590 | checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" 1591 | dependencies = [ 1592 | "unicode-width", 1593 | ] 1594 | 1595 | [[package]] 1596 | name = "thiserror" 1597 | version = "1.0.30" 1598 | source = "registry+https://github.com/rust-lang/crates.io-index" 1599 | checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" 1600 | dependencies = [ 1601 | "thiserror-impl", 1602 | ] 1603 | 1604 | [[package]] 1605 | name = "thiserror-impl" 1606 | version = "1.0.30" 1607 | source = "registry+https://github.com/rust-lang/crates.io-index" 1608 | checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" 1609 | dependencies = [ 1610 | "proc-macro2 1.0.36", 1611 | "quote 1.0.15", 1612 | "syn 1.0.86", 1613 | ] 1614 | 1615 | [[package]] 1616 | name = "time" 1617 | version = "0.1.43" 1618 | source = "registry+https://github.com/rust-lang/crates.io-index" 1619 | checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" 1620 | dependencies = [ 1621 | "libc", 1622 | "winapi 0.3.9", 1623 | ] 1624 | 1625 | [[package]] 1626 | name = "tinyvec" 1627 | version = "1.5.1" 1628 | source = "registry+https://github.com/rust-lang/crates.io-index" 1629 | checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" 1630 | dependencies = [ 1631 | "tinyvec_macros", 1632 | ] 1633 | 1634 | [[package]] 1635 | name = "tinyvec_macros" 1636 | version = "0.1.0" 1637 | source = "registry+https://github.com/rust-lang/crates.io-index" 1638 | checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" 1639 | 1640 | [[package]] 1641 | name = "tokio" 1642 | version = "0.2.25" 1643 | source = "registry+https://github.com/rust-lang/crates.io-index" 1644 | checksum = "6703a273949a90131b290be1fe7b039d0fc884aa1935860dfcbe056f28cd8092" 1645 | dependencies = [ 1646 | "bytes 0.5.6", 1647 | "iovec", 1648 | "lazy_static", 1649 | "libc", 1650 | "memchr", 1651 | "mio", 1652 | "mio-uds", 1653 | "pin-project-lite 0.1.12", 1654 | "slab", 1655 | "tokio-macros", 1656 | ] 1657 | 1658 | [[package]] 1659 | name = "tokio-macros" 1660 | version = "0.2.6" 1661 | source = "registry+https://github.com/rust-lang/crates.io-index" 1662 | checksum = "e44da00bfc73a25f814cd8d7e57a68a5c31b74b3152a0a1d1f590c97ed06265a" 1663 | dependencies = [ 1664 | "proc-macro2 1.0.36", 1665 | "quote 1.0.15", 1666 | "syn 1.0.86", 1667 | ] 1668 | 1669 | [[package]] 1670 | name = "tokio-native-tls" 1671 | version = "0.1.0" 1672 | source = "registry+https://github.com/rust-lang/crates.io-index" 1673 | checksum = "cd608593a919a8e05a7d1fc6df885e40f6a88d3a70a3a7eff23ff27964eda069" 1674 | dependencies = [ 1675 | "native-tls", 1676 | "tokio", 1677 | ] 1678 | 1679 | [[package]] 1680 | name = "tokio-tungstenite" 1681 | version = "0.11.0" 1682 | source = "registry+https://github.com/rust-lang/crates.io-index" 1683 | checksum = "6d9e878ad426ca286e4dcae09cbd4e1973a7f8987d97570e2469703dd7f5720c" 1684 | dependencies = [ 1685 | "futures-util", 1686 | "log", 1687 | "native-tls", 1688 | "pin-project 0.4.29", 1689 | "tokio", 1690 | "tokio-native-tls", 1691 | "tungstenite", 1692 | ] 1693 | 1694 | [[package]] 1695 | name = "tracing" 1696 | version = "0.1.31" 1697 | source = "registry+https://github.com/rust-lang/crates.io-index" 1698 | checksum = "f6c650a8ef0cd2dd93736f033d21cbd1224c5a967aa0c258d00fcf7dafef9b9f" 1699 | dependencies = [ 1700 | "cfg-if 1.0.0", 1701 | "log", 1702 | "pin-project-lite 0.2.8", 1703 | "tracing-attributes", 1704 | "tracing-core", 1705 | ] 1706 | 1707 | [[package]] 1708 | name = "tracing-attributes" 1709 | version = "0.1.19" 1710 | source = "registry+https://github.com/rust-lang/crates.io-index" 1711 | checksum = "8276d9a4a3a558d7b7ad5303ad50b53d58264641b82914b7ada36bd762e7a716" 1712 | dependencies = [ 1713 | "proc-macro2 1.0.36", 1714 | "quote 1.0.15", 1715 | "syn 1.0.86", 1716 | ] 1717 | 1718 | [[package]] 1719 | name = "tracing-core" 1720 | version = "0.1.22" 1721 | source = "registry+https://github.com/rust-lang/crates.io-index" 1722 | checksum = "03cfcb51380632a72d3111cb8d3447a8d908e577d31beeac006f836383d29a23" 1723 | dependencies = [ 1724 | "lazy_static", 1725 | ] 1726 | 1727 | [[package]] 1728 | name = "tracing-futures" 1729 | version = "0.2.5" 1730 | source = "registry+https://github.com/rust-lang/crates.io-index" 1731 | checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" 1732 | dependencies = [ 1733 | "pin-project 1.0.10", 1734 | "tracing", 1735 | ] 1736 | 1737 | [[package]] 1738 | name = "tungstenite" 1739 | version = "0.11.1" 1740 | source = "registry+https://github.com/rust-lang/crates.io-index" 1741 | checksum = "f0308d80d86700c5878b9ef6321f020f29b1bb9d5ff3cab25e75e23f3a492a23" 1742 | dependencies = [ 1743 | "base64", 1744 | "byteorder", 1745 | "bytes 0.5.6", 1746 | "http", 1747 | "httparse", 1748 | "input_buffer", 1749 | "log", 1750 | "native-tls", 1751 | "rand", 1752 | "sha-1", 1753 | "url", 1754 | "utf-8", 1755 | ] 1756 | 1757 | [[package]] 1758 | name = "tynm" 1759 | version = "0.1.6" 1760 | source = "registry+https://github.com/rust-lang/crates.io-index" 1761 | checksum = "a4df2caa2dc9c3d1f7641ba981f4cd40ab229775aa7aeb834c9ab2850d50623d" 1762 | dependencies = [ 1763 | "nom", 1764 | ] 1765 | 1766 | [[package]] 1767 | name = "typenum" 1768 | version = "1.15.0" 1769 | source = "registry+https://github.com/rust-lang/crates.io-index" 1770 | checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" 1771 | 1772 | [[package]] 1773 | name = "unicode-bidi" 1774 | version = "0.3.7" 1775 | source = "registry+https://github.com/rust-lang/crates.io-index" 1776 | checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" 1777 | 1778 | [[package]] 1779 | name = "unicode-normalization" 1780 | version = "0.1.19" 1781 | source = "registry+https://github.com/rust-lang/crates.io-index" 1782 | checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" 1783 | dependencies = [ 1784 | "tinyvec", 1785 | ] 1786 | 1787 | [[package]] 1788 | name = "unicode-segmentation" 1789 | version = "1.9.0" 1790 | source = "registry+https://github.com/rust-lang/crates.io-index" 1791 | checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" 1792 | 1793 | [[package]] 1794 | name = "unicode-width" 1795 | version = "0.1.9" 1796 | source = "registry+https://github.com/rust-lang/crates.io-index" 1797 | checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" 1798 | 1799 | [[package]] 1800 | name = "unicode-xid" 1801 | version = "0.1.0" 1802 | source = "registry+https://github.com/rust-lang/crates.io-index" 1803 | checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" 1804 | 1805 | [[package]] 1806 | name = "unicode-xid" 1807 | version = "0.2.2" 1808 | source = "registry+https://github.com/rust-lang/crates.io-index" 1809 | checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" 1810 | 1811 | [[package]] 1812 | name = "untrusted" 1813 | version = "0.7.1" 1814 | source = "registry+https://github.com/rust-lang/crates.io-index" 1815 | checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" 1816 | 1817 | [[package]] 1818 | name = "url" 1819 | version = "2.2.2" 1820 | source = "registry+https://github.com/rust-lang/crates.io-index" 1821 | checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" 1822 | dependencies = [ 1823 | "form_urlencoded", 1824 | "idna", 1825 | "matches", 1826 | "percent-encoding", 1827 | "serde", 1828 | ] 1829 | 1830 | [[package]] 1831 | name = "utf-8" 1832 | version = "0.7.6" 1833 | source = "registry+https://github.com/rust-lang/crates.io-index" 1834 | checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" 1835 | 1836 | [[package]] 1837 | name = "vcpkg" 1838 | version = "0.2.15" 1839 | source = "registry+https://github.com/rust-lang/crates.io-index" 1840 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 1841 | 1842 | [[package]] 1843 | name = "vec_map" 1844 | version = "0.8.2" 1845 | source = "registry+https://github.com/rust-lang/crates.io-index" 1846 | checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" 1847 | 1848 | [[package]] 1849 | name = "version_check" 1850 | version = "0.9.4" 1851 | source = "registry+https://github.com/rust-lang/crates.io-index" 1852 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 1853 | 1854 | [[package]] 1855 | name = "waker-fn" 1856 | version = "1.1.0" 1857 | source = "registry+https://github.com/rust-lang/crates.io-index" 1858 | checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" 1859 | 1860 | [[package]] 1861 | name = "wasi" 1862 | version = "0.9.0+wasi-snapshot-preview1" 1863 | source = "registry+https://github.com/rust-lang/crates.io-index" 1864 | checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" 1865 | 1866 | [[package]] 1867 | name = "wasi" 1868 | version = "0.10.2+wasi-snapshot-preview1" 1869 | source = "registry+https://github.com/rust-lang/crates.io-index" 1870 | checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" 1871 | 1872 | [[package]] 1873 | name = "wasm-bindgen" 1874 | version = "0.2.79" 1875 | source = "registry+https://github.com/rust-lang/crates.io-index" 1876 | checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06" 1877 | dependencies = [ 1878 | "cfg-if 1.0.0", 1879 | "wasm-bindgen-macro", 1880 | ] 1881 | 1882 | [[package]] 1883 | name = "wasm-bindgen-backend" 1884 | version = "0.2.79" 1885 | source = "registry+https://github.com/rust-lang/crates.io-index" 1886 | checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca" 1887 | dependencies = [ 1888 | "bumpalo", 1889 | "lazy_static", 1890 | "log", 1891 | "proc-macro2 1.0.36", 1892 | "quote 1.0.15", 1893 | "syn 1.0.86", 1894 | "wasm-bindgen-shared", 1895 | ] 1896 | 1897 | [[package]] 1898 | name = "wasm-bindgen-macro" 1899 | version = "0.2.79" 1900 | source = "registry+https://github.com/rust-lang/crates.io-index" 1901 | checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01" 1902 | dependencies = [ 1903 | "quote 1.0.15", 1904 | "wasm-bindgen-macro-support", 1905 | ] 1906 | 1907 | [[package]] 1908 | name = "wasm-bindgen-macro-support" 1909 | version = "0.2.79" 1910 | source = "registry+https://github.com/rust-lang/crates.io-index" 1911 | checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc" 1912 | dependencies = [ 1913 | "proc-macro2 1.0.36", 1914 | "quote 1.0.15", 1915 | "syn 1.0.86", 1916 | "wasm-bindgen-backend", 1917 | "wasm-bindgen-shared", 1918 | ] 1919 | 1920 | [[package]] 1921 | name = "wasm-bindgen-shared" 1922 | version = "0.2.79" 1923 | source = "registry+https://github.com/rust-lang/crates.io-index" 1924 | checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2" 1925 | 1926 | [[package]] 1927 | name = "web-sys" 1928 | version = "0.3.56" 1929 | source = "registry+https://github.com/rust-lang/crates.io-index" 1930 | checksum = "c060b319f29dd25724f09a2ba1418f142f539b2be99fbf4d2d5a8f7330afb8eb" 1931 | dependencies = [ 1932 | "js-sys", 1933 | "wasm-bindgen", 1934 | ] 1935 | 1936 | [[package]] 1937 | name = "winapi" 1938 | version = "0.2.8" 1939 | source = "registry+https://github.com/rust-lang/crates.io-index" 1940 | checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" 1941 | 1942 | [[package]] 1943 | name = "winapi" 1944 | version = "0.3.9" 1945 | source = "registry+https://github.com/rust-lang/crates.io-index" 1946 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1947 | dependencies = [ 1948 | "winapi-i686-pc-windows-gnu", 1949 | "winapi-x86_64-pc-windows-gnu", 1950 | ] 1951 | 1952 | [[package]] 1953 | name = "winapi-build" 1954 | version = "0.1.1" 1955 | source = "registry+https://github.com/rust-lang/crates.io-index" 1956 | checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" 1957 | 1958 | [[package]] 1959 | name = "winapi-i686-pc-windows-gnu" 1960 | version = "0.4.0" 1961 | source = "registry+https://github.com/rust-lang/crates.io-index" 1962 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1963 | 1964 | [[package]] 1965 | name = "winapi-util" 1966 | version = "0.1.5" 1967 | source = "registry+https://github.com/rust-lang/crates.io-index" 1968 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 1969 | dependencies = [ 1970 | "winapi 0.3.9", 1971 | ] 1972 | 1973 | [[package]] 1974 | name = "winapi-x86_64-pc-windows-gnu" 1975 | version = "0.4.0" 1976 | source = "registry+https://github.com/rust-lang/crates.io-index" 1977 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1978 | 1979 | [[package]] 1980 | name = "ws2_32-sys" 1981 | version = "0.2.1" 1982 | source = "registry+https://github.com/rust-lang/crates.io-index" 1983 | checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" 1984 | dependencies = [ 1985 | "winapi 0.2.8", 1986 | "winapi-build", 1987 | ] 1988 | --------------------------------------------------------------------------------