Compare commits

...

33 Commits

Author SHA1 Message Date
str4d 5afe70d831
Merge 76131db25a into 895afe51f7 2024-04-23 18:51:20 +01:00
Kris Nuttycombe 895afe51f7
Merge pull request #1359 from zcash/cargo-audits
Set up Cargo audit infrastructure
2024-04-23 11:51:16 -06:00
Jack Grigg 069109b691 Adjust versions of pinned dependencies to cover more audits 2024-04-23 00:57:08 +00:00
Jack Grigg 011909d609 CI: Add audit check for `cargo deny check licenses` 2024-04-23 00:34:03 +00:00
Jack Grigg 66f11ce29f Add config file for `cargo deny check licenses`
Most of the config is copied from `zcash/zcash`, but with a few extra
license exceptions due to the `download-params` feature of
`zcash_proofs` and the `lightwalletd-tonic-transport` feature of
`zcash_client_backend`.
2024-04-23 00:32:49 +00:00
Jack Grigg 08cd7e20bd CI: Add audit check for `cargo vet` 2024-04-23 00:31:02 +00:00
Jack Grigg e574c27755 Import Rust crate audits from Fermyon 2024-04-23 00:08:48 +00:00
Jack Grigg 846d9860f1 Import Rust crate audits from Embark Studios 2024-04-23 00:08:48 +00:00
Jack Grigg 03627b1de5 Import Rust crate audits from the Bytecode Alliance 2024-04-23 00:08:48 +00:00
Jack Grigg d99edccaa3 Import Rust crate audits from ISRG 2024-04-23 00:08:48 +00:00
Jack Grigg 12334b3a18 Import Rust crate audits from Google 2024-04-23 00:08:48 +00:00
Jack Grigg 6bbd002f59 Import Rust crate audits from Mozilla 2024-04-23 00:08:48 +00:00
Jack Grigg 4eb2df6714 Trust the Windows crates published by Microsoft
As with our `cargo-vet` usage in `zcash/zcash`, these are binary crates
for interacting with Windows APIs, so both sides are maintained by
Microsoft and are not something we can audit ourselves.
2024-04-23 00:08:48 +00:00
Jack Grigg 3f11ba5c74 Import our Rust crate audits from elsewhere 2024-04-23 00:08:48 +00:00
Jack Grigg f3717d9427 Trust the Zcash crates we maintain and publish
Trust set imported from `zcash/zcash` where there were common deps.
2024-04-23 00:08:48 +00:00
Jack Grigg afb8b55ed8 Import cargo-vet criteria from `zcash/zcash` 2024-04-22 23:37:02 +00:00
Jack Grigg 672cc9f080 cargo vet init 2024-04-22 23:31:40 +00:00
teor 76131db25a Add commented-out prints of solution candidates for debugging 2024-04-19 02:27:34 +00:00
teor 9391e65c21 equihash: Clear slots when setting the hash state
The equivalent change is made to the C worker, which is unused.
2024-04-19 02:27:34 +00:00
teor 2bd7bc8f8e equihash: Don't import a header that's missing in Windows CI 2024-04-19 02:27:34 +00:00
teor b737d0fe26 equihash: Remove unused thread support to enable Windows compilation 2024-04-19 02:27:34 +00:00
teor 989f40ee9b equihash: Add a portable endian.h for `htole32()` on macOS and Windows
Source: mikepb/endian.h@0f885cbba6
License: Public Domain (or "BSD OR MIT OR Apache-2.0")
2024-04-19 02:27:34 +00:00
teor d7ccd07d0b equihash: Ensure returned compressed solutions are unique 2024-04-19 02:27:34 +00:00
teor 5f77bd79db equihash: Place solver behind a feature flag 2024-04-19 02:27:34 +00:00
teor 3c78bf60a1 equihash: Set C pointers to NULL after freeing them to avoid double-frees
Also includes some redundant cleanup code for defense in depth.
2024-04-19 02:27:34 +00:00
teor 463e7d9958 equihash: Move allocation out of the loop 2024-04-19 02:27:34 +00:00
teor fe3b269f3a equihash: Verify compressed solutions in tests 2024-04-19 02:27:34 +00:00
teor 1b20c15053 equihash: Add Rust APIs for compressed solutions 2024-04-19 02:27:34 +00:00
Jack Grigg d07505de71 equihash: Add Rust API for Tromp solver
Co-authored-by: teor <teor@riseup.net>
2024-04-19 02:00:40 +00:00
Jack Grigg 45e7238b80 equihash: Pass `blake2b_simd` bindings to Tromp solver as callbacks
This avoids linker errors by removing cycles.
2024-04-19 02:00:40 +00:00
Jack Grigg 3aaeb8b719 equihash: Modify Tromp solver to compile as C
Co-authored-by: teor <teor@riseup.net>
2024-04-19 02:00:40 +00:00
Jack Grigg 7ab6c47d5b equihash: Import `blake2b_simd` C bindings from `zcashd`
Source: zcash/zcash@01d5576a97
License: MIT
2024-04-19 02:00:40 +00:00
Jack Grigg 45652a21a8 equihash: Import Tromp solver
Source: zcash/zcash@01d5576a97
License: MIT
2024-04-19 02:00:40 +00:00
17 changed files with 4047 additions and 17 deletions

30
.github/workflows/audits.yml vendored Normal file
View File

@ -0,0 +1,30 @@
name: Audits
on:
pull_request:
push:
branches: main
permissions:
contents: read
jobs:
cargo-vet:
name: Vet Rust dependencies
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
id: toolchain
- run: rustup override set ${{steps.toolchain.outputs.name}}
- run: cargo install cargo-vet --version ~0.9
- run: cargo vet --locked
cargo-deny:
name: Check licenses
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: EmbarkStudios/cargo-deny-action@v1
with:
command: check licenses

22
Cargo.lock generated
View File

@ -282,9 +282,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.4.1"
version = "2.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
[[package]]
name = "bitvec"
@ -659,6 +659,8 @@ version = "0.2.0"
dependencies = [
"blake2b_simd",
"byteorder",
"cc",
"hex",
]
[[package]]
@ -1751,7 +1753,7 @@ checksum = "7c003ac8c77cb07bb74f5f198bce836a689bcd5a42574612bf14d17bfd08c20e"
dependencies = [
"bit-set",
"bit-vec",
"bitflags 2.4.1",
"bitflags 2.4.2",
"lazy_static",
"num-traits",
"rand",
@ -2034,7 +2036,7 @@ version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "549b9d036d571d42e6e85d1c1425e2ac83491075078ca9a15be021c56b1641f2"
dependencies = [
"bitflags 2.4.1",
"bitflags 2.4.2",
"fallible-iterator",
"fallible-streaming-iterator",
"hashlink",
@ -2055,7 +2057,7 @@ version = "0.38.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3"
dependencies = [
"bitflags 2.4.1",
"bitflags 2.4.2",
"errno",
"libc",
"linux-raw-sys",
@ -2265,7 +2267,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d766257c56a1bdd75479c256b97c92e72788a9afb18b5199f58faf7188dc99d9"
dependencies = [
"assert_matches",
"bitflags 2.4.1",
"bitflags 2.4.2",
"either",
"incrementalmerkletree",
"proptest",
@ -2421,18 +2423,18 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
[[package]]
name = "thiserror"
version = "1.0.50"
version = "1.0.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2"
checksum = "f11c217e1416d6f036b870f14e0413d480dbf28edbee1f877abaf0206af43bb7"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.50"
version = "1.0.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df"
dependencies = [
"proc-macro2",
"quote",

View File

@ -9,9 +9,21 @@ license = "MIT OR Apache-2.0"
edition = "2021"
rust-version = "1.56.1"
[features]
default = []
## Builds the C++ tromp solver and Rust FFI layer.
solver = ["dep:cc"]
[dependencies]
blake2b_simd = "1"
byteorder = "1"
[build-dependencies]
cc = { version = "1", optional = true }
[dev-dependencies]
hex = "0.4"
[lib]
bench = false

View File

@ -0,0 +1,17 @@
//! Build script for the equihash tromp solver in C.
fn main() {
#[cfg(feature = "solver")]
build_tromp_solver();
}
#[cfg(feature = "solver")]
fn build_tromp_solver() {
cc::Build::new()
.include("tromp/")
.file("tromp/equi_miner.c")
.compile("equitromp");
// Tell Cargo to only rerun this build script if the tromp C files or headers change.
println!("cargo:rerun-if-changed=tromp");
}

View File

@ -0,0 +1,59 @@
// Copyright (c) 2020-2022 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
// This module uses unsafe code for FFI into blake2b.
#![allow(unsafe_code)]
use blake2b_simd::{State, PERSONALBYTES};
use std::ptr;
use std::slice;
#[no_mangle]
pub extern "C" fn blake2b_init(
output_len: usize,
personalization: *const [u8; PERSONALBYTES],
) -> *mut State {
let personalization = unsafe { personalization.as_ref().unwrap() };
Box::into_raw(Box::new(
blake2b_simd::Params::new()
.hash_length(output_len)
.personal(personalization)
.to_state(),
))
}
#[no_mangle]
pub extern "C" fn blake2b_clone(state: *const State) -> *mut State {
unsafe { state.as_ref() }
.map(|state| Box::into_raw(Box::new(state.clone())))
.unwrap_or(ptr::null_mut())
}
#[no_mangle]
pub extern "C" fn blake2b_free(state: *mut State) {
if !state.is_null() {
drop(unsafe { Box::from_raw(state) });
}
}
#[no_mangle]
pub extern "C" fn blake2b_update(state: *mut State, input: *const u8, input_len: usize) {
let state = unsafe { state.as_mut().unwrap() };
let input = unsafe { slice::from_raw_parts(input, input_len) };
state.update(input);
}
#[no_mangle]
pub extern "C" fn blake2b_finalize(state: *mut State, output: *mut u8, output_len: usize) {
let state = unsafe { state.as_mut().unwrap() };
let output = unsafe { slice::from_raw_parts_mut(output, output_len) };
// Allow consuming only part of the output.
let hash = state.finalize();
assert!(output_len <= hash.as_bytes().len());
output.copy_from_slice(&hash.as_bytes()[..output_len]);
}

View File

@ -28,3 +28,8 @@ mod verify;
mod test_vectors;
pub use verify::{is_valid_solution, Error};
#[cfg(feature = "solver")]
mod blake2b;
#[cfg(feature = "solver")]
pub mod tromp;

View File

@ -5,6 +5,49 @@ use byteorder::{BigEndian, ReadBytesExt};
use crate::params::Params;
// Rough translation of CompressArray() from:
// https://github.com/zcash/zcash/blob/6fdd9f1b81d3b228326c9826fa10696fc516444b/src/crypto/equihash.cpp#L39-L76
#[cfg(any(feature = "solver", test))]
fn compress_array(array: &[u8], bit_len: usize, byte_pad: usize) -> Vec<u8> {
let index_bytes = (u32::BITS / 8) as usize;
assert!(bit_len >= 8);
assert!(8 * index_bytes >= 7 + bit_len);
let in_width: usize = (bit_len + 7) / 8 + byte_pad;
let out_len = bit_len * array.len() / (8 * in_width);
let mut out = Vec::with_capacity(out_len);
let bit_len_mask: u32 = (1 << (bit_len as u32)) - 1;
// The acc_bits least-significant bits of acc_value represent a bit sequence
// in big-endian order.
let mut acc_bits: usize = 0;
let mut acc_value: u32 = 0;
let mut j: usize = 0;
for _i in 0..out_len {
// When we have fewer than 8 bits left in the accumulator, read the next
// input element.
if acc_bits < 8 {
acc_value <<= bit_len;
for x in byte_pad..in_width {
acc_value |= (
// Apply bit_len_mask across byte boundaries
(array[j + x] & ((bit_len_mask >> (8 * (in_width - x - 1))) as u8)) as u32
)
.wrapping_shl(8 * (in_width - x - 1) as u32); // Big-endian
}
j += in_width;
acc_bits += bit_len;
}
acc_bits -= 8;
out.push((acc_value >> acc_bits) as u8);
}
out
}
pub(crate) fn expand_array(vin: &[u8], bit_len: usize, byte_pad: usize) -> Vec<u8> {
assert!(bit_len >= 8);
assert!(u32::BITS as usize >= 7 + bit_len);
@ -50,6 +93,31 @@ pub(crate) fn expand_array(vin: &[u8], bit_len: usize, byte_pad: usize) -> Vec<u
vout
}
// Rough translation of GetMinimalFromIndices() from:
// https://github.com/zcash/zcash/blob/6fdd9f1b81d3b228326c9826fa10696fc516444b/src/crypto/equihash.cpp#L130-L145
#[cfg(any(feature = "solver", test))]
pub(crate) fn minimal_from_indices(p: Params, indices: &[u32]) -> Vec<u8> {
let c_bit_len = p.collision_bit_length();
let index_bytes = (u32::BITS / 8) as usize;
let digit_bytes = ((c_bit_len + 1) + 7) / 8;
assert!(digit_bytes <= index_bytes);
let len_indices = indices.len() * index_bytes;
let byte_pad = index_bytes - digit_bytes;
// Rough translation of EhIndexToArray(index, array_pointer) from:
// https://github.com/zcash/zcash/blob/6fdd9f1b81d3b228326c9826fa10696fc516444b/src/crypto/equihash.cpp#L123-L128
//
// Big-endian so that lexicographic array comparison is equivalent to integer comparison.
let array: Vec<u8> = indices
.iter()
.flat_map(|index| index.to_be_bytes())
.collect();
assert_eq!(array.len(), len_indices);
compress_array(&array, c_bit_len + 1, byte_pad)
}
/// Returns `None` if the parameters are invalid for this minimal encoding.
pub(crate) fn indices_from_minimal(p: Params, minimal: &[u8]) -> Option<Vec<u32>> {
let c_bit_len = p.collision_bit_length();
@ -76,11 +144,14 @@ pub(crate) fn indices_from_minimal(p: Params, minimal: &[u8]) -> Option<Vec<u32>
#[cfg(test)]
mod tests {
use super::{expand_array, indices_from_minimal, Params};
use crate::minimal::minimal_from_indices;
use super::{compress_array, expand_array, indices_from_minimal, Params};
#[test]
fn array_expansion() {
fn array_compression_and_expansion() {
let check_array = |(bit_len, byte_pad), compact, expanded| {
assert_eq!(compress_array(expanded, bit_len, byte_pad), compact);
assert_eq!(expand_array(compact, bit_len, byte_pad), expanded);
};
@ -149,10 +220,9 @@ mod tests {
#[test]
fn minimal_solution_repr() {
let check_repr = |minimal, indices| {
assert_eq!(
indices_from_minimal(Params { n: 80, k: 3 }, minimal).unwrap(),
indices,
);
let p = Params { n: 80, k: 3 };
assert_eq!(minimal_from_indices(p, indices), minimal);
assert_eq!(indices_from_minimal(p, minimal).unwrap(), indices);
};
// The solutions here are not intended to be valid.

View File

@ -0,0 +1,256 @@
//! Rust interface to the tromp equihash solver.
use std::marker::{PhantomData, PhantomPinned};
use std::slice;
use blake2b_simd::State;
use crate::{blake2b, minimal::minimal_from_indices, params::Params, verify};
#[repr(C)]
struct CEqui {
_f: [u8; 0],
_m: PhantomData<(*mut u8, PhantomPinned)>,
}
#[link(name = "equitromp")]
extern "C" {
#[allow(improper_ctypes)]
fn equi_new(
blake2b_clone: extern "C" fn(state: *const State) -> *mut State,
blake2b_free: extern "C" fn(state: *mut State),
blake2b_update: extern "C" fn(state: *mut State, input: *const u8, input_len: usize),
blake2b_finalize: extern "C" fn(state: *mut State, output: *mut u8, output_len: usize),
) -> *mut CEqui;
fn equi_free(eq: *mut CEqui);
#[allow(improper_ctypes)]
fn equi_setstate(eq: *mut CEqui, ctx: *const State);
fn equi_clearslots(eq: *mut CEqui);
fn equi_digit0(eq: *mut CEqui, id: u32);
fn equi_digitodd(eq: *mut CEqui, r: u32, id: u32);
fn equi_digiteven(eq: *mut CEqui, r: u32, id: u32);
fn equi_digitK(eq: *mut CEqui, id: u32);
fn equi_nsols(eq: *const CEqui) -> usize;
/// Returns `equi_nsols()` solutions of length `2^K`, in a single memory allocation.
fn equi_sols(eq: *const CEqui) -> *const u32;
}
/// Performs a single equihash solver run with equihash parameters `p` and hash state `curr_state`.
/// Returns zero or more unique solutions.
///
/// # SAFETY
///
/// The parameters to this function must match the hard-coded parameters in the C++ code.
///
/// This function uses unsafe code for FFI into the tromp solver.
#[allow(unsafe_code)]
#[allow(clippy::print_stdout)]
unsafe fn worker(eq: *mut CEqui, p: Params, curr_state: &State) -> Vec<Vec<u32>> {
// SAFETY: caller must supply a valid `eq` instance.
//
// Review Note: nsols is set to zero in C++ here
equi_setstate(eq, curr_state);
// Initialization done, start algo driver.
equi_digit0(eq, 0);
equi_clearslots(eq);
// SAFETY: caller must supply a `p` instance that matches the hard-coded values in the C code.
for r in 1..p.k {
if (r & 1) != 0 {
equi_digitodd(eq, r, 0)
} else {
equi_digiteven(eq, r, 0)
};
equi_clearslots(eq);
}
// Review Note: nsols is increased here, but only if the solution passes the strictly ordered check.
// With 256 nonces, we get to around 6/9 digits strictly ordered.
equi_digitK(eq, 0);
let solutions = {
let nsols = equi_nsols(eq);
let sols = equi_sols(eq);
let solution_len = 1 << p.k;
//println!("{nsols} solutions of length {solution_len} at {sols:?}");
// SAFETY:
// - caller must supply a `p` instance that matches the hard-coded values in the C code.
// - `sols` is a single allocation containing at least `nsols` solutions.
// - this slice is a shared ref to the memory in a valid `eq` instance supplied by the caller.
let solutions: &[u32] = slice::from_raw_parts(sols, nsols * solution_len);
/*
println!(
"{nsols} solutions of length {solution_len} as a slice of length {:?}",
solutions.len()
);
*/
let mut chunks = solutions.chunks_exact(solution_len);
// SAFETY:
// - caller must supply a `p` instance that matches the hard-coded values in the C code.
// - each solution contains `solution_len` u32 values.
// - the temporary slices are shared refs to a valid `eq` instance supplied by the caller.
// - the bytes in the shared ref are copied before they are returned.
// - dropping `solutions: &[u32]` does not drop the underlying memory owned by `eq`.
let mut solutions = (&mut chunks)
.map(|solution| solution.to_vec())
.collect::<Vec<_>>();
assert_eq!(chunks.remainder().len(), 0);
// Sometimes the solver returns identical solutions.
solutions.sort();
solutions.dedup();
solutions
};
/*
println!(
"{} solutions as cloned vectors of length {:?}",
solutions.len(),
solutions
.iter()
.map(|solution| solution.len())
.collect::<Vec<_>>()
);
*/
solutions
}
/// Performs multiple equihash solver runs with equihash parameters `200, 9`, initialising the hash with
/// the supplied partial `input`. Between each run, generates a new nonce of length `N` using the
/// `next_nonce` function.
///
/// Returns zero or more unique solutions.
pub fn solve_200_9<const N: usize>(
input: &[u8],
mut next_nonce: impl FnMut() -> Option<[u8; N]>,
) -> Vec<Vec<u32>> {
let p = Params::new(200, 9).expect("should be valid");
let mut state = verify::initialise_state(p.n, p.k, p.hash_output());
state.update(input);
// Create solver and initialize it.
//
// # SAFETY
// - the parameters 200,9 match the hard-coded parameters in the C++ code.
// - tromp is compiled without multi-threading support, so each instance can only support 1 thread.
// - the blake2b functions are in the correct order in Rust and C++ initializers.
#[allow(unsafe_code)]
let eq = unsafe {
equi_new(
blake2b::blake2b_clone,
blake2b::blake2b_free,
blake2b::blake2b_update,
blake2b::blake2b_finalize,
)
};
let solutions = loop {
let nonce = match next_nonce() {
Some(nonce) => nonce,
None => break vec![],
};
let mut curr_state = state.clone();
// Review Note: these hashes are changing when the nonce changes
curr_state.update(&nonce);
// SAFETY:
// - the parameters 200,9 match the hard-coded parameters in the C++ code.
// - the eq instance is initilized above.
#[allow(unsafe_code)]
let solutions = unsafe { worker(eq, p, &curr_state) };
if !solutions.is_empty() {
break solutions;
}
};
// SAFETY:
// - the eq instance is initilized above, and not used after this point.
#[allow(unsafe_code)]
unsafe {
equi_free(eq)
};
solutions
}
/// Performs multiple equihash solver runs with equihash parameters `200, 9`, initialising the hash with
/// the supplied partial `input`. Between each run, generates a new nonce of length `N` using the
/// `next_nonce` function.
///
/// Returns zero or more unique compressed solutions.
pub fn solve_200_9_compressed<const N: usize>(
input: &[u8],
next_nonce: impl FnMut() -> Option<[u8; N]>,
) -> Vec<Vec<u8>> {
let p = Params::new(200, 9).expect("should be valid");
let solutions = solve_200_9(input, next_nonce);
let mut solutions: Vec<Vec<u8>> = solutions
.iter()
.map(|solution| minimal_from_indices(p, solution))
.collect();
// Just in case the solver returns solutions that become the same when compressed.
solutions.sort();
solutions.dedup();
solutions
}
#[cfg(test)]
mod tests {
use super::solve_200_9_compressed;
#[test]
#[allow(clippy::print_stdout)]
fn run_solver() {
let input = b"Equihash is an asymmetric PoW based on the Generalised Birthday problem.";
let mut nonce: [u8; 32] = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0,
];
let mut nonces = 0..=32_u32;
let nonce_count = nonces.clone().count();
let solutions = solve_200_9_compressed(input, || {
let variable_nonce = nonces.next()?;
println!("Using variable nonce [0..4] of {}", variable_nonce);
let variable_nonce = variable_nonce.to_le_bytes();
nonce[0] = variable_nonce[0];
nonce[1] = variable_nonce[1];
nonce[2] = variable_nonce[2];
nonce[3] = variable_nonce[3];
Some(nonce)
});
if solutions.is_empty() {
// Expected solution rate is documented at:
// https://github.com/tromp/equihash/blob/master/README.md
panic!("Found no solutions after {nonce_count} runs, expected 1.88 solutions per run",);
} else {
println!("Found {} solutions:", solutions.len());
for (sol_num, solution) in solutions.iter().enumerate() {
println!("Validating solution {sol_num}:-\n{}", hex::encode(solution));
crate::is_valid_solution(200, 9, input, &nonce, solution).unwrap_or_else(|error| {
panic!(
"unexpected invalid equihash 200, 9 solution:\n\
error: {error:?}\n\
input: {input:?}\n\
nonce: {nonce:?}\n\
solution: {solution:?}"
)
});
println!("Solution {sol_num} is valid!\n");
}
}
}
}

View File

@ -114,7 +114,7 @@ impl fmt::Display for Kind {
}
}
fn initialise_state(n: u32, k: u32, digest_len: u8) -> Blake2bState {
pub(crate) fn initialise_state(n: u32, k: u32, digest_len: u8) -> Blake2bState {
let mut personalization: Vec<u8> = Vec::from("ZcashPoW");
personalization.write_u32::<LittleEndian>(n).unwrap();
personalization.write_u32::<LittleEndian>(k).unwrap();

View File

@ -0,0 +1,51 @@
// Copyright (c) 2020-2022 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
#ifndef ZCASH_RUST_INCLUDE_RUST_BLAKE2B_H
#define ZCASH_RUST_INCLUDE_RUST_BLAKE2B_H
#include <stddef.h>
struct BLAKE2bState;
typedef struct BLAKE2bState BLAKE2bState;
#define BLAKE2bPersonalBytes 16U
/// Initializes a BLAKE2b state with no key and no salt.
///
/// `personalization` MUST be a pointer to a 16-byte array.
///
/// Please free this with `blake2b_free` when you are done.
typedef BLAKE2bState* (*blake2b_init)(
size_t output_len,
const unsigned char* personalization);
/// Clones the given BLAKE2b state.
///
/// Both states need to be separately freed with `blake2b_free` when you are
/// done.
typedef BLAKE2bState* (*blake2b_clone)(const BLAKE2bState* state);
/// Frees a BLAKE2b state returned by `blake2b_init`.
typedef void (*blake2b_free)(BLAKE2bState* state);
/// Adds input to the hash. You can call this any number of times.
typedef void (*blake2b_update)(
BLAKE2bState* state,
const unsigned char* input,
size_t input_len);
/// Finalizes the `state` and stores the result in `output`.
///
/// `output_len` MUST be less than or equal to the value that was passed as the
/// first parameter to `blake2b_init`.
///
/// This method is idempotent, and calling it multiple times will give the same
/// result. It's also possible to call `blake2b_update` with more input in
/// between.
typedef void (*blake2b_finalize)(
BLAKE2bState* state,
unsigned char* output,
size_t output_len);
#endif // ZCASH_RUST_INCLUDE_RUST_BLAKE2B_H

View File

@ -0,0 +1,47 @@
// Equihash solver
// Copyright (c) 2016-2016 John Tromp, The Zcash developers
#ifndef ZCASH_POW_TROMP_EQUI_H
#define ZCASH_POW_TROMP_EQUI_H
#include <stdbool.h> // for type bool
#include <stdint.h> // for types uint32_t,uint64_t
#include <string.h> // for functions memset
#include <stdlib.h> // for function qsort
#include "blake2b.h"
typedef uint32_t u32;
typedef unsigned char uchar;
// algorithm parameters, prefixed with W to reduce include file conflicts
#ifndef WN
#define WN 200
#endif
#ifndef WK
#define WK 9
#endif
#define NDIGITS (WK+1)
#define DIGITBITS (WN/(NDIGITS))
#define PROOFSIZE (1<<WK)
#define BASE (1<<DIGITBITS)
#define NHASHES (2*BASE)
#define HASHESPERBLAKE (512/WN)
#define HASHOUT (HASHESPERBLAKE*WN/8)
typedef u32 proof[PROOFSIZE];
enum verify_code { POW_OK, POW_DUPLICATE, POW_OUT_OF_ORDER, POW_NONZERO_XOR };
const char *errstr[] = { "OK", "duplicate index", "indices out of order", "nonzero xor" };
int compu32(const void *pa, const void *pb) {
u32 a = *(u32 *)pa, b = *(u32 *)pb;
return a<b ? -1 : a==b ? 0 : +1;
}
#endif // ZCASH_POW_TROMP_EQUI_H

View File

@ -0,0 +1,737 @@
// Equihash solver
// Copyright (c) 2016 John Tromp, The Zcash developers
// Fix N, K, such that n = N/(k+1) is integer
// Fix M = 2^{n+1} hashes each of length N bits,
// H_0, ... , H_{M-1}, generated from (n+1)-bit indices.
// Problem: find binary tree on 2^K distinct indices,
// for which the exclusive-or of leaf hashes is all 0s.
// Additionally, it should satisfy the Wagner conditions:
// for each height i subtree, the exclusive-or
// of its 2^i corresponding hashes starts with i*n 0 bits,
// and for i>0 the leftmost leaf of its left subtree
// is less than the leftmost leaf of its right subtree
// The algorithm below solves this by maintaining the trees
// in a graph of K layers, each split into buckets
// with buckets indexed by the first n-RESTBITS bits following
// the i*n 0s, each bucket having 4 * 2^RESTBITS slots,
// twice the number of subtrees expected to land there.
#ifndef ZCASH_POW_TROMP_EQUI_MINER_H
#define ZCASH_POW_TROMP_EQUI_MINER_H
#include "equi.h"
// Provides htole32() on macOS and Windows
#include "portable_endian.h"
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef uint16_t u16;
typedef uint64_t u64;
#ifdef EQUIHASH_TROMP_ATOMIC
#include <stdatomic.h>
typedef atomic_uint au32;
#else
typedef u32 au32;
#endif
#ifndef RESTBITS
#define RESTBITS 8
#endif
// 2_log of number of buckets
#define BUCKBITS (DIGITBITS-RESTBITS)
#ifndef SAVEMEM
#if RESTBITS == 4
// can't save memory in such small buckets
#define SAVEMEM 1
#elif RESTBITS >= 8
// take advantage of law of large numbers (sum of 2^8 random numbers)
// this reduces (200,9) memory to under 144MB, with negligible discarding
#define SAVEMEM 9/14
#endif
#endif
// number of buckets
#define NBUCKETS (1<<BUCKBITS)
// 2_log of number of slots per bucket
#define SLOTBITS (RESTBITS+1+1)
#define SLOTRANGE (1<<SLOTBITS)
#ifdef SLOTDIFF
static const u32 SLOTMSB = 1<<(SLOTBITS-1);
#endif
// number of slots per bucket
#define NSLOTS (SLOTRANGE * SAVEMEM)
// number of per-xhash slots
#define XFULL 16
// SLOTBITS mask
static const u32 SLOTMASK = SLOTRANGE-1;
// number of possible values of xhash (rest of n) bits
#define NRESTS (1<<RESTBITS)
// number of blocks of hashes extracted from single 512 bit blake2b output
#define NBLOCKS ((NHASHES+HASHESPERBLAKE-1)/HASHESPERBLAKE)
// nothing larger found in 100000 runs
static const u32 MAXSOLS = 8;
// tree node identifying its children as two different slots in
// a bucket on previous layer with the same rest bits (x-tra hash)
struct tree {
u32 bid_s0_s1; // manual bitfields
};
typedef struct tree tree;
tree tree_from_idx(const u32 idx) {
tree t;
t.bid_s0_s1 = idx;
return t;
}
tree tree_from_bid(const u32 bid, const u32 s0, const u32 s1) {
tree t;
#ifdef SLOTDIFF
u32 ds10 = (s1 - s0) & SLOTMASK;
if (ds10 & SLOTMSB) {
bid_s0_s1 = (((bid << SLOTBITS) | s1) << (SLOTBITS-1)) | (SLOTMASK & ~ds10);
} else {
bid_s0_s1 = (((bid << SLOTBITS) | s0) << (SLOTBITS-1)) | (ds10 - 1);
}
#else
t.bid_s0_s1 = (((bid << SLOTBITS) | s0) << SLOTBITS) | s1;
#endif
return t;
}
u32 getindex(const tree *t) {
return t->bid_s0_s1;
}
u32 bucketid(const tree *t) {
#ifdef SLOTDIFF
return t->bid_s0_s1 >> (2 * SLOTBITS - 1);
#else
return t->bid_s0_s1 >> (2 * SLOTBITS);
#endif
}
u32 slotid0(const tree *t) {
#ifdef SLOTDIFF
return (t->bid_s0_s1 >> (SLOTBITS-1)) & SLOTMASK;
#else
return (t->bid_s0_s1 >> SLOTBITS) & SLOTMASK;
#endif
}
u32 slotid1(const tree *t) {
#ifdef SLOTDIFF
return (slotid0() + 1 + (t->bid_s0_s1 & (SLOTMASK>>1))) & SLOTMASK;
#else
return t->bid_s0_s1 & SLOTMASK;
#endif
}
union hashunit {
u32 word;
uchar bytes[sizeof(u32)];
};
typedef union hashunit hashunit;
#define WORDS(bits) ((bits + 31) / 32)
#define HASHWORDS0 WORDS(WN - DIGITBITS + RESTBITS)
#define HASHWORDS1 WORDS(WN - 2*DIGITBITS + RESTBITS)
struct slot0 {
tree attr;
hashunit hash[HASHWORDS0];
};
typedef struct slot0 slot0;
struct slot1 {
tree attr;
hashunit hash[HASHWORDS1];
};
typedef struct slot1 slot1;
// a bucket is NSLOTS treenodes
typedef slot0 bucket0[NSLOTS];
typedef slot1 bucket1[NSLOTS];
// the N-bit hash consists of K+1 n-bit "digits"
// each of which corresponds to a layer of NBUCKETS buckets
typedef bucket0 digit0[NBUCKETS];
typedef bucket1 digit1[NBUCKETS];
// size (in bytes) of hash in round 0 <= r < WK
u32 hashsize(const u32 r) {
const u32 hashbits = WN - (r+1) * DIGITBITS + RESTBITS;
return (hashbits + 7) / 8;
}
u32 hashwords(u32 bytes) {
return (bytes + 3) / 4;
}
// manages hash and tree data
struct htalloc {
u32 *heap0;
u32 *heap1;
bucket0 *trees0[(WK+1)/2];
bucket1 *trees1[WK/2];
u32 alloced;
};
typedef struct htalloc htalloc;
htalloc htalloc_new() {
htalloc hta;
hta.alloced = 0;
return hta;
}
void *htalloc_alloc(htalloc *hta, const u32 n, const u32 sz);
void alloctrees(htalloc *hta) {
// optimize xenoncat's fixed memory layout, avoiding any waste
// digit trees hashes trees hashes
// 0 0 A A A A A A . . . . . .
// 1 0 A A A A A A 1 B B B B B
// 2 0 2 C C C C C 1 B B B B B
// 3 0 2 C C C C C 1 3 D D D D
// 4 0 2 4 E E E E 1 3 D D D D
// 5 0 2 4 E E E E 1 3 5 F F F
// 6 0 2 4 6 . G G 1 3 5 F F F
// 7 0 2 4 6 . G G 1 3 5 7 H H
// 8 0 2 4 6 8 . I 1 3 5 7 H H
assert(DIGITBITS >= 16); // ensures hashes shorten by 1 unit every 2 digits
hta->heap0 = (u32 *)htalloc_alloc(hta, 1, sizeof(digit0));
hta->heap1 = (u32 *)htalloc_alloc(hta, 1, sizeof(digit1));
for (int r=0; r<WK; r++)
if ((r&1) == 0)
hta->trees0[r/2] = (bucket0 *)(hta->heap0 + r/2);
else
hta->trees1[r/2] = (bucket1 *)(hta->heap1 + r/2);
}
void dealloctrees(htalloc *hta) {
if (hta == NULL) {
return;
}
free(hta->heap0);
free(hta->heap1);
// Avoid use-after-free and double-free
hta->heap0 = NULL;
hta->heap1 = NULL;
for (int r=0; r<WK; r++)
if ((r&1) == 0)
hta->trees0[r/2] = NULL;
else
hta->trees1[r/2] = NULL;
hta->alloced = 0;
}
void *htalloc_alloc(htalloc *hta, const u32 n, const u32 sz) {
void *mem = calloc(n, sz);
assert(mem);
hta->alloced += n * sz;
return mem;
}
typedef au32 bsizes[NBUCKETS];
u32 minu32(const u32 a, const u32 b) {
return a < b ? a : b;
}
struct equi {
BLAKE2bState* blake_ctx;
blake2b_clone blake2b_clone;
blake2b_free blake2b_free;
blake2b_update blake2b_update;
blake2b_finalize blake2b_finalize;
htalloc hta;
bsizes *nslots; // PUT IN BUCKET STRUCT
proof *sols;
au32 nsols;
u32 xfull;
u32 hfull;
u32 bfull;
};
typedef struct equi equi;
void equi_clearslots(equi *eq);
equi *equi_new(
blake2b_clone blake2b_clone,
blake2b_free blake2b_free,
blake2b_update blake2b_update,
blake2b_finalize blake2b_finalize
) {
assert(sizeof(hashunit) == 4);
equi *eq = malloc(sizeof(equi));
eq->blake2b_clone = blake2b_clone;
eq->blake2b_free = blake2b_free;
eq->blake2b_update = blake2b_update;
eq->blake2b_finalize = blake2b_finalize;
alloctrees(&eq->hta);
eq->nslots = (bsizes *)htalloc_alloc(&eq->hta, 2 * NBUCKETS, sizeof(au32));
eq->sols = (proof *)htalloc_alloc(&eq->hta, MAXSOLS, sizeof(proof));
// C malloc() does not guarantee zero-initialized memory (but calloc() does)
eq->blake_ctx = NULL;
eq->nsols = 0;
equi_clearslots(eq);
return eq;
}
void equi_free(equi *eq) {
if (eq == NULL) {
return;
}
dealloctrees(&eq->hta);
free(eq->nslots);
free(eq->sols);
eq->blake2b_free(eq->blake_ctx);
// Avoid use-after-free and double-free
eq->nslots = NULL;
eq->sols = NULL;
eq->blake_ctx = NULL;
free(eq);
}
void equi_setstate(equi *eq, const BLAKE2bState *ctx) {
if (eq->blake_ctx) {
eq->blake2b_free(eq->blake_ctx);
}
eq->blake_ctx = eq->blake2b_clone(ctx);
memset(eq->nslots, 0, NBUCKETS * sizeof(au32)); // only nslots[0] needs zeroing
equi_clearslots(eq);
eq->nsols = 0;
}
void equi_clearslots(equi *eq) {
eq->xfull = eq->bfull = eq->hfull = 0;
}
u32 getslot(equi *eq, const u32 r, const u32 bucketi) {
#ifdef EQUIHASH_TROMP_ATOMIC
return std::atomic_fetch_add_explicit(&eq->nslots[r&1][bucketi], 1U, std::memory_order_relaxed);
#else
return eq->nslots[r&1][bucketi]++;
#endif
}
u32 getnslots(equi *eq, const u32 r, const u32 bid) { // SHOULD BE METHOD IN BUCKET STRUCT
au32 *nslot = &eq->nslots[r&1][bid];
const u32 n = minu32(*nslot, NSLOTS);
*nslot = 0;
return n;
}
void orderindices(u32 *indices, u32 size) {
if (indices[0] > indices[size]) {
for (u32 i=0; i < size; i++) {
const u32 tmp = indices[i];
indices[i] = indices[size+i];
indices[size+i] = tmp;
}
}
}
void listindices1(equi *eq, u32 r, const tree t, u32 *indices);
void listindices0(equi *eq, u32 r, const tree t, u32 *indices) {
if (r == 0) {
*indices = getindex(&t);
return;
}
const bucket1 *buck = &eq->hta.trees1[--r/2][bucketid(&t)];
const u32 size = 1 << r;
u32 *indices1 = indices + size;
listindices1(eq, r, (*buck)[slotid0(&t)].attr, indices);
listindices1(eq, r, (*buck)[slotid1(&t)].attr, indices1);
orderindices(indices, size);
}
void listindices1(equi *eq, u32 r, const tree t, u32 *indices) {
const bucket0 *buck = &eq->hta.trees0[--r/2][bucketid(&t)];
const u32 size = 1 << r;
u32 *indices1 = indices + size;
listindices0(eq, r, (*buck)[slotid0(&t)].attr, indices);
listindices0(eq, r, (*buck)[slotid1(&t)].attr, indices1);
orderindices(indices, size);
}
void candidate(equi *eq, const tree t) {
proof prf;
listindices1(eq, WK, t, prf); // assume WK odd
qsort(prf, PROOFSIZE, sizeof(u32), &compu32);
for (u32 i=1; i<PROOFSIZE; i++)
if (prf[i] <= prf[i-1]) {
/*
printf(
"failed dup indexes check: wanted: proof[%d] > proof[%d], actual: %d <= %d\n",
i, i-1, prf[i], prf[i-1]
);
*/
return;
}
#ifdef EQUIHASH_TROMP_ATOMIC
u32 soli = std::atomic_fetch_add_explicit(&eq->nsols, 1U, std::memory_order_relaxed);
#else
u32 soli = eq->nsols++;
#endif
if (soli < MAXSOLS)
listindices1(eq, WK, t, eq->sols[soli]); // assume WK odd
}
#ifdef EQUIHASH_SHOW_BUCKET_SIZES
void showbsizes(equi *eq, u32 r) {
#if defined(HIST) || defined(SPARK) || defined(LOGSPARK)
u32 binsizes[65];
memset(binsizes, 0, 65 * sizeof(u32));
for (u32 bucketid = 0; bucketid < NBUCKETS; bucketid++) {
u32 bsize = minu32(eq->nslots[r&1][bucketid], NSLOTS) >> (SLOTBITS-6);
binsizes[bsize]++;
}
for (u32 i=0; i < 65; i++) {
#ifdef HIST
// printf(" %d:%d", i, binsizes[i]);
#else
#ifdef SPARK
u32 sparks = binsizes[i] / SPARKSCALE;
#else
u32 sparks = 0;
for (u32 bs = binsizes[i]; bs; bs >>= 1) sparks++;
sparks = sparks * 7 / SPARKSCALE;
#endif
// printf("\342\226%c", '\201' + sparks);
#endif
}
// printf("\n");
#endif
}
#endif
struct htlayout {
htalloc hta;
u32 prevhashunits;
u32 nexthashunits;
u32 dunits;
u32 prevbo;
u32 nextbo;
};
typedef struct htlayout htlayout;
htlayout htlayout_new(equi *eq, u32 r) {
htlayout htl;
htl.hta = eq->hta;
htl.prevhashunits = 0;
htl.dunits = 0;
u32 nexthashbytes = hashsize(r);
htl.nexthashunits = hashwords(nexthashbytes);
htl.prevbo = 0;
htl.nextbo = htl.nexthashunits * sizeof(hashunit) - nexthashbytes; // 0-3
if (r) {
u32 prevhashbytes = hashsize(r-1);
htl.prevhashunits = hashwords(prevhashbytes);
htl.prevbo = htl.prevhashunits * sizeof(hashunit) - prevhashbytes; // 0-3
htl.dunits = htl.prevhashunits - htl.nexthashunits;
}
return htl;
}
u32 getxhash0(const htlayout *htl, const slot0* pslot) {
#if WN == 200 && RESTBITS == 4
return pslot->hash->bytes[htl->prevbo] >> 4;
#elif WN == 200 && RESTBITS == 8
return (pslot->hash->bytes[htl->prevbo] & 0xf) << 4 | pslot->hash->bytes[htl->prevbo+1] >> 4;
#elif WN == 200 && RESTBITS == 9
return (pslot->hash->bytes[htl->prevbo] & 0x1f) << 4 | pslot->hash->bytes[htl->prevbo+1] >> 4;
#elif WN == 144 && RESTBITS == 4
return pslot->hash->bytes[htl->prevbo] & 0xf;
#else
#error non implemented
#endif
}
u32 getxhash1(const htlayout *htl, const slot1* pslot) {
#if WN == 200 && RESTBITS == 4
return pslot->hash->bytes[htl->prevbo] & 0xf;
#elif WN == 200 && RESTBITS == 8
return pslot->hash->bytes[htl->prevbo];
#elif WN == 200 && RESTBITS == 9
return (pslot->hash->bytes[htl->prevbo]&1) << 8 | pslot->hash->bytes[htl->prevbo+1];
#elif WN == 144 && RESTBITS == 4
return pslot->hash->bytes[htl->prevbo] & 0xf;
#else
#error non implemented
#endif
}
bool htlayout_equal(const htlayout *htl, const hashunit *hash0, const hashunit *hash1) {
return hash0[htl->prevhashunits-1].word == hash1[htl->prevhashunits-1].word;
}
#if RESTBITS <= 6
typedef uchar xslot;
#else
typedef u16 xslot;
#endif
struct collisiondata {
#ifdef XBITMAP
#if NSLOTS > 64
#error cant use XBITMAP with more than 64 slots
#endif
u64 xhashmap[NRESTS];
u64 xmap;
#else
xslot nxhashslots[NRESTS];
xslot xhashslots[NRESTS][XFULL];
xslot *xx;
u32 n0;
u32 n1;
#endif
u32 s0;
};
typedef struct collisiondata collisiondata;
void collisiondata_clear(collisiondata *cd) {
#ifdef XBITMAP
memset(cd->xhashmap, 0, NRESTS * sizeof(u64));
#else
memset(cd->nxhashslots, 0, NRESTS * sizeof(xslot));
#endif
}
bool addslot(collisiondata *cd, u32 s1, u32 xh) {
#ifdef XBITMAP
xmap = xhashmap[xh];
xhashmap[xh] |= (u64)1 << s1;
s0 = -1;
return true;
#else
cd->n1 = (u32)cd->nxhashslots[xh]++;
if (cd->n1 >= XFULL)
return false;
cd->xx = cd->xhashslots[xh];
cd->xx[cd->n1] = s1;
cd->n0 = 0;
return true;
#endif
}
bool nextcollision(const collisiondata *cd) {
#ifdef XBITMAP
return cd->xmap != 0;
#else
return cd->n0 < cd->n1;
#endif
}
u32 slot(collisiondata *cd) {
#ifdef XBITMAP
const u32 ffs = __builtin_ffsll(cd->xmap);
s0 += ffs; cd->xmap >>= ffs;
return s0;
#else
return (u32)cd->xx[cd->n0++];
#endif
}
void equi_digit0(equi *eq, const u32 id) {
uchar hash[HASHOUT];
BLAKE2bState* state;
htlayout htl = htlayout_new(eq, 0);
const u32 hashbytes = hashsize(0);
for (u32 block = id; block < NBLOCKS; block++) {
state = eq->blake2b_clone(eq->blake_ctx);
u32 leb = htole32(block);
eq->blake2b_update(state, (uchar *)&leb, sizeof(u32));
eq->blake2b_finalize(state, hash, HASHOUT);
eq->blake2b_free(state);
// Avoid use-after-free and double-free
state = NULL;
for (u32 i = 0; i<HASHESPERBLAKE; i++) {
const uchar *ph = hash + i * WN/8;
#if BUCKBITS == 16 && RESTBITS == 4
const u32 bucketid = ((u32)ph[0] << 8) | ph[1];
#elif BUCKBITS == 12 && RESTBITS == 8
const u32 bucketid = ((u32)ph[0] << 4) | ph[1] >> 4;
#elif BUCKBITS == 11 && RESTBITS == 9
const u32 bucketid = ((u32)ph[0] << 3) | ph[1] >> 5;
#elif BUCKBITS == 20 && RESTBITS == 4
const u32 bucketid = ((((u32)ph[0] << 8) | ph[1]) << 4) | ph[2] >> 4;
#elif BUCKBITS == 12 && RESTBITS == 4
const u32 bucketid = ((u32)ph[0] << 4) | ph[1] >> 4;
const u32 xhash = ph[1] & 0xf;
#else
#error not implemented
#endif
const u32 slot = getslot(eq, 0, bucketid);
if (slot >= NSLOTS) {
eq->bfull++;
continue;
}
slot0 *s = &eq->hta.trees0[0][bucketid][slot];
s->attr = tree_from_idx(block * HASHESPERBLAKE + i);
memcpy(s->hash->bytes+htl.nextbo, ph+WN/8-hashbytes, hashbytes);
}
}
}
void equi_digitodd(equi *eq, const u32 r, const u32 id) {
htlayout htl = htlayout_new(eq, r);
collisiondata cd;
for (u32 bucketid=id; bucketid < NBUCKETS; bucketid++) {
collisiondata_clear(&cd);
slot0 *buck = htl.hta.trees0[(r-1)/2][bucketid]; // optimize by updating previous buck?!
u32 bsize = getnslots(eq, r-1, bucketid); // optimize by putting bucketsize with block?!
for (u32 s1 = 0; s1 < bsize; s1++) {
const slot0 *pslot1 = buck + s1; // optimize by updating previous pslot1?!
if (!addslot(&cd, s1, getxhash0(&htl, pslot1))) {
eq->xfull++;
continue;
}
for (; nextcollision(&cd); ) {
const u32 s0 = slot(&cd);
const slot0 *pslot0 = buck + s0;
if (htlayout_equal(&htl, pslot0->hash, pslot1->hash)) {
eq->hfull++;
continue;
}
u32 xorbucketid;
const uchar *bytes0 = pslot0->hash->bytes, *bytes1 = pslot1->hash->bytes;
#if WN == 200 && BUCKBITS == 12 && RESTBITS == 8
xorbucketid = (((u32)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) & 0xf) << 8)
| (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]);
#elif WN == 200 && BUCKBITS == 11 && RESTBITS == 9
xorbucketid = (((u32)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) & 0xf) << 7)
| (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 1;
#elif WN == 144 && BUCKBITS == 20 && RESTBITS == 4
xorbucketid = ((((u32)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) << 8)
| (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2])) << 4)
| (bytes0[htl.prevbo+3] ^ bytes1[htl.prevbo+3]) >> 4;
#elif WN == 96 && BUCKBITS == 12 && RESTBITS == 4
xorbucketid = ((u32)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) << 4)
| (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4;
#else
#error not implemented
#endif
const u32 xorslot = getslot(eq, r, xorbucketid);
if (xorslot >= NSLOTS) {
eq->bfull++;
continue;
}
slot1 *xs = &htl.hta.trees1[r/2][xorbucketid][xorslot];
xs->attr = tree_from_bid(bucketid, s0, s1);
for (u32 i=htl.dunits; i < htl.prevhashunits; i++)
xs->hash[i-htl.dunits].word = pslot0->hash[i].word ^ pslot1->hash[i].word;
}
}
}
}
void equi_digiteven(equi *eq, const u32 r, const u32 id) {
htlayout htl = htlayout_new(eq, r);
collisiondata cd;
for (u32 bucketid=id; bucketid < NBUCKETS; bucketid++) {
collisiondata_clear(&cd);
slot1 *buck = htl.hta.trees1[(r-1)/2][bucketid]; // OPTIMIZE BY UPDATING PREVIOUS
u32 bsize = getnslots(eq, r-1, bucketid);
for (u32 s1 = 0; s1 < bsize; s1++) {
const slot1 *pslot1 = buck + s1; // OPTIMIZE BY UPDATING PREVIOUS
if (!addslot(&cd, s1, getxhash1(&htl, pslot1))) {
eq->xfull++;
continue;
}
for (; nextcollision(&cd); ) {
const u32 s0 = slot(&cd);
const slot1 *pslot0 = buck + s0;
if (htlayout_equal(&htl, pslot0->hash, pslot1->hash)) {
eq->hfull++;
continue;
}
u32 xorbucketid;
const uchar *bytes0 = pslot0->hash->bytes, *bytes1 = pslot1->hash->bytes;
#if WN == 200 && BUCKBITS == 12 && RESTBITS == 8
xorbucketid = ((u32)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) << 4)
| (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4;
#elif WN == 200 && BUCKBITS == 11 && RESTBITS == 9
xorbucketid = ((u32)(bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) << 3)
| (bytes0[htl.prevbo+3] ^ bytes1[htl.prevbo+3]) >> 5;
#elif WN == 144 && BUCKBITS == 20 && RESTBITS == 4
xorbucketid = ((((u32)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) << 8)
| (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2])) << 4)
| (bytes0[htl.prevbo+3] ^ bytes1[htl.prevbo+3]) >> 4;
#elif WN == 96 && BUCKBITS == 12 && RESTBITS == 4
xorbucketid = ((u32)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) << 4)
| (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4;
#else
#error not implemented
#endif
const u32 xorslot = getslot(eq, r, xorbucketid);
if (xorslot >= NSLOTS) {
eq->bfull++;
continue;
}
slot0 *xs = &htl.hta.trees0[r/2][xorbucketid][xorslot];
xs->attr = tree_from_bid(bucketid, s0, s1);
for (u32 i=htl.dunits; i < htl.prevhashunits; i++)
xs->hash[i-htl.dunits].word = pslot0->hash[i].word ^ pslot1->hash[i].word;
}
}
}
}
void equi_digitK(equi *eq, const u32 id) {
collisiondata cd;
htlayout htl = htlayout_new(eq, WK);
u32 nc = 0;
for (u32 bucketid = id; bucketid < NBUCKETS; bucketid++) {
collisiondata_clear(&cd);
slot0 *buck = htl.hta.trees0[(WK-1)/2][bucketid];
u32 bsize = getnslots(eq, WK-1, bucketid);
for (u32 s1 = 0; s1 < bsize; s1++) {
const slot0 *pslot1 = buck + s1;
if (!addslot(&cd, s1, getxhash0(&htl, pslot1))) // assume WK odd
continue;
for (; nextcollision(&cd); ) {
const u32 s0 = slot(&cd);
if (htlayout_equal(&htl, buck[s0].hash, pslot1->hash))
nc++, candidate(eq, tree_from_bid(bucketid, s0, s1));
}
}
}
//printf(" %d candidates\n", nc);
}
size_t equi_nsols(const equi *eq) {
return eq->nsols;
}
proof *equi_sols(const equi *eq) {
return eq->sols;
}
typedef struct {
u32 id;
equi *eq;
} thread_ctx;
void *worker(void *vp) {
thread_ctx *tp = (thread_ctx *)vp;
equi *eq = tp->eq;
// if (tp->id == 0)
// printf("Digit 0\n");
if (tp->id == 0) {
equi_clearslots(eq);
}
equi_digit0(eq, tp->id);
if (tp->id == 0) {
equi_clearslots(eq);
#ifdef EQUIHASH_SHOW_BUCKET_SIZES
showbsizes(eq, 0);
#endif
}
for (u32 r = 1; r < WK; r++) {
// if (tp->id == 0)
// printf("Digit %d", r);
r&1 ? equi_digitodd(eq, r, tp->id) : equi_digiteven(eq, r, tp->id);
if (tp->id == 0) {
// printf(" x%d b%d h%d\n", eq->xfull, eq->bfull, eq->hfull);
equi_clearslots(eq);
#ifdef EQUIHASH_SHOW_BUCKET_SIZES
showbsizes(eq, r);
#endif
}
}
// if (tp->id == 0)
// printf("Digit %d\n", WK);
equi_digitK(eq, tp->id);
return 0;
}
#endif // ZCASH_POW_TROMP_EQUI_MINER_H

View File

@ -0,0 +1,130 @@
//
// endian.h
//
// https://gist.github.com/panzi/6856583
//
// I, Mathias Panzenböck, place this file hereby into the public domain. Use
// it at your own risk for whatever you like. In case there are
// jurisdictions that don't support putting things in the public domain you
// can also consider it to be "dual licensed" under the BSD, MIT and Apache
// licenses, if you want to. This code is trivial anyway. Consider it an
// example on how to get the endian conversion functions on different
// platforms.
// Downloaded from https://raw.githubusercontent.com/mikepb/endian.h/master/endian.h
// on 12 January 2024.
#ifndef PORTABLE_ENDIAN_H__
#define PORTABLE_ENDIAN_H__
#if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) && !defined(__WINDOWS__)
# define __WINDOWS__
#endif
#if defined(__linux__) || defined(__CYGWIN__)
# include <endian.h>
#elif defined(__APPLE__)
# include <libkern/OSByteOrder.h>
# define htobe16(x) OSSwapHostToBigInt16(x)
# define htole16(x) OSSwapHostToLittleInt16(x)
# define be16toh(x) OSSwapBigToHostInt16(x)
# define le16toh(x) OSSwapLittleToHostInt16(x)
# define htobe32(x) OSSwapHostToBigInt32(x)
# define htole32(x) OSSwapHostToLittleInt32(x)
# define be32toh(x) OSSwapBigToHostInt32(x)
# define le32toh(x) OSSwapLittleToHostInt32(x)
# define htobe64(x) OSSwapHostToBigInt64(x)
# define htole64(x) OSSwapHostToLittleInt64(x)
# define be64toh(x) OSSwapBigToHostInt64(x)
# define le64toh(x) OSSwapLittleToHostInt64(x)
# define __BYTE_ORDER BYTE_ORDER
# define __BIG_ENDIAN BIG_ENDIAN
# define __LITTLE_ENDIAN LITTLE_ENDIAN
# define __PDP_ENDIAN PDP_ENDIAN
#elif defined(__OpenBSD__)
# include <sys/endian.h>
#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
# include <sys/endian.h>
# define be16toh(x) betoh16(x)
# define le16toh(x) letoh16(x)
# define be32toh(x) betoh32(x)
# define le32toh(x) letoh32(x)
# define be64toh(x) betoh64(x)
# define le64toh(x) letoh64(x)
#elif defined(__WINDOWS__)
# include <winsock2.h>
// Not available in librustzcash CI
//# include <sys/param.h>
# if BYTE_ORDER == LITTLE_ENDIAN
# define htobe16(x) htons(x)
# define htole16(x) (x)
# define be16toh(x) ntohs(x)
# define le16toh(x) (x)
# define htobe32(x) htonl(x)
# define htole32(x) (x)
# define be32toh(x) ntohl(x)
# define le32toh(x) (x)
# define htobe64(x) htonll(x)
# define htole64(x) (x)
# define be64toh(x) ntohll(x)
# define le64toh(x) (x)
# elif BYTE_ORDER == BIG_ENDIAN
/* that would be xbox 360 */
# define htobe16(x) (x)
# define htole16(x) __builtin_bswap16(x)
# define be16toh(x) (x)
# define le16toh(x) __builtin_bswap16(x)
# define htobe32(x) (x)
# define htole32(x) __builtin_bswap32(x)
# define be32toh(x) (x)
# define le32toh(x) __builtin_bswap32(x)
# define htobe64(x) (x)
# define htole64(x) __builtin_bswap64(x)
# define be64toh(x) (x)
# define le64toh(x) __builtin_bswap64(x)
# else
# error byte order not supported
# endif
# define __BYTE_ORDER BYTE_ORDER
# define __BIG_ENDIAN BIG_ENDIAN
# define __LITTLE_ENDIAN LITTLE_ENDIAN
# define __PDP_ENDIAN PDP_ENDIAN
#else
# error platform not supported
#endif
#endif

51
deny.toml Normal file
View File

@ -0,0 +1,51 @@
# Configuration file for cargo-deny
[graph]
targets = [
# Targets used by zcashd
{ triple = "aarch64-unknown-linux-gnu" },
{ triple = "x86_64-apple-darwin" },
{ triple = "x86_64-pc-windows-gnu" },
{ triple = "x86_64-unknown-freebsd" },
{ triple = "x86_64-unknown-linux-gnu" },
# Targets used by zcash-android-wallet-sdk
{ triple = "aarch64-linux-android" },
{ triple = "armv7-linux-androideabi" },
{ triple = "i686-linux-android" },
{ triple = "x86_64-linux-android" },
# Targets used by zcash-swift-wallet-sdk
{ triple = "aarch64-apple-darwin" },
{ triple = "aarch64-apple-ios" },
{ triple = "aarch64-apple-ios-sim" },
{ triple = "x86_64-apple-darwin" },
{ triple = "x86_64-apple-ios" },
]
all-features = true
exclude-dev = true
[licenses]
version = 2
allow = [
"Apache-2.0",
"MIT",
]
exceptions = [
{ name = "arrayref", allow = ["BSD-2-Clause"] },
{ name = "matchit", allow = ["BSD-3-Clause"] },
{ name = "minreq", allow = ["ISC"] },
{ name = "ring", allow = ["LicenseRef-ring"] },
{ name = "rustls-webpki", allow = ["ISC"] },
{ name = "secp256k1", allow = ["CC0-1.0"] },
{ name = "secp256k1-sys", allow = ["CC0-1.0"] },
{ name = "subtle", allow = ["BSD-3-Clause"] },
{ name = "unicode-ident", allow = ["Unicode-DFS-2016"] },
{ name = "untrusted", allow = ["ISC"] },
{ name = "webpki-roots", allow = ["MPL-2.0"] },
]
[[licenses.clarify]]
name = "ring"
expression = "LicenseRef-ring"
license-files = [
{ path = "LICENSE", hash = 0xbd0eed23 },
]

238
supply-chain/audits.toml Normal file
View File

@ -0,0 +1,238 @@
# cargo-vet audits file
[criteria.crypto-reviewed]
description = "The cryptographic code in this crate has been reviewed for correctness by a member of a designated set of cryptography experts within the project."
[criteria.license-reviewed]
description = "The license of this crate has been reviewed for compatibility with its usage in this repository."
[audits]
[[trusted.equihash]]
criteria = "safe-to-deploy"
user-id = 6289 # str4d
start = "2020-06-26"
end = "2025-04-22"
[[trusted.f4jumble]]
criteria = ["safe-to-deploy", "crypto-reviewed"]
user-id = 6289 # str4d
start = "2021-09-22"
end = "2025-04-22"
[[trusted.halo2_gadgets]]
criteria = ["safe-to-deploy", "crypto-reviewed"]
user-id = 1244 # ebfull
start = "2022-05-10"
end = "2025-04-22"
[[trusted.halo2_legacy_pdqsort]]
criteria = ["safe-to-deploy", "crypto-reviewed"]
user-id = 199950 # Daira Emma Hopwood (daira)
start = "2023-02-24"
end = "2025-04-22"
[[trusted.halo2_proofs]]
criteria = ["safe-to-deploy", "crypto-reviewed"]
user-id = 1244 # ebfull
start = "2022-05-10"
end = "2025-04-22"
[[trusted.incrementalmerkletree]]
criteria = "safe-to-deploy"
user-id = 6289 # str4d
start = "2021-12-17"
end = "2025-04-22"
[[trusted.incrementalmerkletree]]
criteria = "safe-to-deploy"
user-id = 1244 # ebfull
start = "2021-06-24"
end = "2025-04-22"
[[trusted.incrementalmerkletree]]
criteria = "safe-to-deploy"
user-id = 169181 # Kris Nuttycombe (nuttycom)
start = "2023-02-28"
end = "2025-04-22"
[[trusted.orchard]]
criteria = ["safe-to-deploy", "crypto-reviewed", "license-reviewed"]
user-id = 6289 # str4d
start = "2021-01-07"
end = "2025-04-22"
[[trusted.orchard]]
criteria = ["safe-to-deploy", "crypto-reviewed", "license-reviewed"]
user-id = 1244 # ebfull
start = "2022-10-19"
end = "2025-04-22"
[[trusted.sapling-crypto]]
criteria = ["safe-to-deploy", "crypto-reviewed"]
user-id = 6289 # str4d
start = "2024-01-26"
end = "2025-04-22"
[[trusted.shardtree]]
criteria = "safe-to-deploy"
user-id = 169181 # Kris Nuttycombe (nuttycom)
start = "2022-12-15"
end = "2025-04-22"
[[trusted.windows-sys]]
criteria = "safe-to-deploy"
user-id = 64539 # Kenny Kerr (kennykerr)
start = "2021-11-15"
end = "2025-04-22"
[[trusted.windows-targets]]
criteria = "safe-to-deploy"
user-id = 64539 # Kenny Kerr (kennykerr)
start = "2022-09-09"
end = "2025-04-22"
[[trusted.windows_aarch64_gnullvm]]
criteria = "safe-to-deploy"
user-id = 64539 # Kenny Kerr (kennykerr)
start = "2022-09-01"
end = "2025-04-22"
[[trusted.windows_aarch64_msvc]]
criteria = "safe-to-deploy"
user-id = 64539 # Kenny Kerr (kennykerr)
start = "2021-11-05"
end = "2025-04-22"
[[trusted.windows_i686_gnu]]
criteria = "safe-to-deploy"
user-id = 64539 # Kenny Kerr (kennykerr)
start = "2021-10-28"
end = "2025-04-22"
[[trusted.windows_i686_msvc]]
criteria = "safe-to-deploy"
user-id = 64539 # Kenny Kerr (kennykerr)
start = "2021-10-27"
end = "2025-04-22"
[[trusted.windows_x86_64_gnu]]
criteria = "safe-to-deploy"
user-id = 64539 # Kenny Kerr (kennykerr)
start = "2021-10-28"
end = "2025-04-22"
[[trusted.windows_x86_64_gnullvm]]
criteria = "safe-to-deploy"
user-id = 64539 # Kenny Kerr (kennykerr)
start = "2022-09-01"
end = "2025-04-22"
[[trusted.windows_x86_64_msvc]]
criteria = "safe-to-deploy"
user-id = 64539 # Kenny Kerr (kennykerr)
start = "2021-10-27"
end = "2025-04-22"
[[trusted.zcash_address]]
criteria = "safe-to-deploy"
user-id = 1244 # ebfull
start = "2022-10-19"
end = "2025-04-22"
[[trusted.zcash_address]]
criteria = "safe-to-deploy"
user-id = 6289 # str4d
start = "2021-03-07"
end = "2025-04-22"
[[trusted.zcash_client_backend]]
criteria = "safe-to-deploy"
user-id = 169181 # Kris Nuttycombe (nuttycom)
start = "2024-03-25"
end = "2025-04-22"
[[trusted.zcash_client_sqlite]]
criteria = "safe-to-deploy"
user-id = 169181 # Kris Nuttycombe (nuttycom)
start = "2024-03-25"
end = "2025-04-22"
[[trusted.zcash_encoding]]
criteria = "safe-to-deploy"
user-id = 1244 # ebfull
start = "2022-10-19"
end = "2025-04-22"
[[trusted.zcash_extensions]]
criteria = "safe-to-deploy"
user-id = 6289 # str4d
start = "2020-04-24"
end = "2025-04-23"
[[trusted.zcash_history]]
criteria = "safe-to-deploy"
user-id = 1244 # ebfull
start = "2020-03-04"
end = "2025-04-22"
[[trusted.zcash_history]]
criteria = "safe-to-deploy"
user-id = 6289 # str4d
start = "2024-03-01"
end = "2025-04-22"
[[trusted.zcash_keys]]
criteria = "safe-to-deploy"
user-id = 169181 # Kris Nuttycombe (nuttycom)
start = "2024-01-15"
end = "2025-04-22"
[[trusted.zcash_note_encryption]]
criteria = ["safe-to-deploy", "crypto-reviewed"]
user-id = 169181 # Kris Nuttycombe (nuttycom)
start = "2023-03-22"
end = "2025-04-22"
[[trusted.zcash_primitives]]
criteria = ["safe-to-deploy", "crypto-reviewed", "license-reviewed"]
user-id = 6289 # str4d
start = "2021-03-26"
end = "2025-04-22"
[[trusted.zcash_primitives]]
criteria = ["safe-to-deploy", "crypto-reviewed", "license-reviewed"]
user-id = 1244 # ebfull
start = "2019-10-08"
end = "2025-04-22"
[[trusted.zcash_proofs]]
criteria = ["safe-to-deploy", "crypto-reviewed", "license-reviewed"]
user-id = 6289 # str4d
start = "2021-03-26"
end = "2025-04-22"
[[trusted.zcash_protocol]]
criteria = "safe-to-deploy"
user-id = 169181 # Kris Nuttycombe (nuttycom)
start = "2024-01-27"
end = "2025-04-22"
[[trusted.zcash_spec]]
criteria = ["safe-to-deploy", "crypto-reviewed", "license-reviewed"]
user-id = 6289 # str4d
start = "2023-12-07"
end = "2025-04-22"
[[trusted.zip32]]
criteria = "safe-to-deploy"
user-id = 6289 # str4d
start = "2023-12-06"
end = "2025-04-22"
[[trusted.zip321]]
criteria = "safe-to-deploy"
user-id = 169181 # Kris Nuttycombe (nuttycom)
start = "2024-01-15"
end = "2025-04-22"

881
supply-chain/config.toml Normal file
View File

@ -0,0 +1,881 @@
# cargo-vet config file
[cargo-vet]
version = "0.9"
[imports.bytecode-alliance]
url = "https://raw.githubusercontent.com/bytecodealliance/wasmtime/main/supply-chain/audits.toml"
[imports.embark-studios]
url = "https://raw.githubusercontent.com/EmbarkStudios/rust-ecosystem/main/audits.toml"
[imports.fermyon]
url = "https://raw.githubusercontent.com/fermyon/spin/main/supply-chain/audits.toml"
[imports.google]
url = "https://raw.githubusercontent.com/google/supply-chain/main/audits.toml"
[imports.isrg]
url = "https://raw.githubusercontent.com/divviup/libprio-rs/main/supply-chain/audits.toml"
[imports.mozilla]
url = "https://raw.githubusercontent.com/mozilla/supply-chain/main/audits.toml"
[imports.zcash]
url = "https://raw.githubusercontent.com/zcash/rust-ecosystem/main/supply-chain/audits.toml"
[policy.equihash]
audit-as-crates-io = true
[policy.f4jumble]
audit-as-crates-io = true
[policy.zcash_address]
audit-as-crates-io = true
[policy.zcash_client_backend]
audit-as-crates-io = true
[policy.zcash_client_sqlite]
audit-as-crates-io = true
[policy.zcash_encoding]
audit-as-crates-io = true
[policy.zcash_extensions]
audit-as-crates-io = true
[policy.zcash_history]
audit-as-crates-io = true
[policy.zcash_keys]
audit-as-crates-io = true
[policy.zcash_primitives]
audit-as-crates-io = true
[policy.zcash_proofs]
audit-as-crates-io = true
[policy.zcash_protocol]
audit-as-crates-io = true
[policy.zip321]
audit-as-crates-io = true
[[exemptions.addr2line]]
version = "0.21.0"
criteria = "safe-to-deploy"
[[exemptions.aead]]
version = "0.5.2"
criteria = "safe-to-deploy"
[[exemptions.aes]]
version = "0.8.3"
criteria = "safe-to-deploy"
[[exemptions.ahash]]
version = "0.8.6"
criteria = "safe-to-deploy"
[[exemptions.aho-corasick]]
version = "1.1.2"
criteria = "safe-to-deploy"
[[exemptions.allocator-api2]]
version = "0.2.16"
criteria = "safe-to-deploy"
[[exemptions.arrayvec]]
version = "0.7.4"
criteria = "safe-to-deploy"
[[exemptions.assert_matches]]
version = "1.5.0"
criteria = "safe-to-deploy"
[[exemptions.async-trait]]
version = "0.1.78"
criteria = "safe-to-deploy"
[[exemptions.axum]]
version = "0.6.20"
criteria = "safe-to-deploy"
[[exemptions.axum-core]]
version = "0.3.4"
criteria = "safe-to-deploy"
[[exemptions.backtrace]]
version = "0.3.69"
criteria = "safe-to-deploy"
[[exemptions.base64ct]]
version = "1.0.1"
criteria = "safe-to-deploy"
[[exemptions.bech32]]
version = "0.9.1"
criteria = "safe-to-deploy"
[[exemptions.bellman]]
version = "0.14.0"
criteria = "safe-to-deploy"
[[exemptions.bip0039]]
version = "0.10.1"
criteria = "safe-to-deploy"
[[exemptions.bitflags]]
version = "1.3.2"
criteria = "safe-to-deploy"
[[exemptions.bitvec]]
version = "1.0.1"
criteria = "safe-to-deploy"
[[exemptions.blake2b_simd]]
version = "1.0.1"
criteria = "safe-to-deploy"
[[exemptions.blake2s_simd]]
version = "1.0.1"
criteria = "safe-to-deploy"
[[exemptions.bls12_381]]
version = "0.8.0"
criteria = "safe-to-deploy"
[[exemptions.bs58]]
version = "0.5.0"
criteria = "safe-to-deploy"
[[exemptions.bytemuck]]
version = "1.14.0"
criteria = "safe-to-run"
[[exemptions.byteorder]]
version = "1.5.0"
criteria = "safe-to-deploy"
[[exemptions.bytes]]
version = "1.5.0"
criteria = "safe-to-deploy"
[[exemptions.cast]]
version = "0.3.0"
criteria = "safe-to-run"
[[exemptions.cbc]]
version = "0.1.2"
criteria = "safe-to-deploy"
[[exemptions.chacha20]]
version = "0.9.1"
criteria = "safe-to-deploy"
[[exemptions.chacha20poly1305]]
version = "0.10.1"
criteria = "safe-to-deploy"
[[exemptions.ciborium]]
version = "0.2.1"
criteria = "safe-to-run"
[[exemptions.ciborium-io]]
version = "0.2.1"
criteria = "safe-to-run"
[[exemptions.ciborium-ll]]
version = "0.2.1"
criteria = "safe-to-run"
[[exemptions.cipher]]
version = "0.4.4"
criteria = "safe-to-deploy"
[[exemptions.clap]]
version = "3.2.25"
criteria = "safe-to-run"
[[exemptions.cpp_demangle]]
version = "0.4.3"
criteria = "safe-to-run"
[[exemptions.cpufeatures]]
version = "0.2.11"
criteria = "safe-to-deploy"
[[exemptions.criterion]]
version = "0.4.0"
criteria = "safe-to-run"
[[exemptions.criterion-plot]]
version = "0.5.0"
criteria = "safe-to-run"
[[exemptions.crossbeam-channel]]
version = "0.5.8"
criteria = "safe-to-deploy"
[[exemptions.crossbeam-deque]]
version = "0.8.3"
criteria = "safe-to-deploy"
[[exemptions.crossbeam-epoch]]
version = "0.9.15"
criteria = "safe-to-deploy"
[[exemptions.crossbeam-utils]]
version = "0.8.16"
criteria = "safe-to-deploy"
[[exemptions.daggy]]
version = "0.8.0"
criteria = "safe-to-deploy"
[[exemptions.digest]]
version = "0.10.7"
criteria = "safe-to-deploy"
[[exemptions.errno]]
version = "0.3.6"
criteria = "safe-to-deploy"
[[exemptions.fallible-iterator]]
version = "0.2.0"
criteria = "safe-to-deploy"
[[exemptions.fallible-streaming-iterator]]
version = "0.1.9"
criteria = "safe-to-deploy"
[[exemptions.ff]]
version = "0.13.0"
criteria = "safe-to-deploy"
[[exemptions.findshlibs]]
version = "0.10.2"
criteria = "safe-to-run"
[[exemptions.fixed-hash]]
version = "0.8.0"
criteria = "safe-to-deploy"
[[exemptions.fixedbitset]]
version = "0.4.2"
criteria = "safe-to-deploy"
[[exemptions.fpe]]
version = "0.6.1"
criteria = "safe-to-deploy"
[[exemptions.funty]]
version = "2.0.0"
criteria = "safe-to-deploy"
[[exemptions.futures-macro]]
version = "0.3.29"
criteria = "safe-to-deploy"
[[exemptions.futures-sink]]
version = "0.3.29"
criteria = "safe-to-deploy"
[[exemptions.futures-task]]
version = "0.3.29"
criteria = "safe-to-deploy"
[[exemptions.futures-util]]
version = "0.3.29"
criteria = "safe-to-deploy"
[[exemptions.generic-array]]
version = "0.14.7"
criteria = "safe-to-deploy"
[[exemptions.getrandom]]
version = "0.2.11"
criteria = "safe-to-deploy"
[[exemptions.gimli]]
version = "0.28.0"
criteria = "safe-to-deploy"
[[exemptions.group]]
version = "0.13.0"
criteria = "safe-to-deploy"
[[exemptions.gumdrop]]
version = "0.8.1"
criteria = "safe-to-run"
[[exemptions.gumdrop_derive]]
version = "0.8.1"
criteria = "safe-to-run"
[[exemptions.h2]]
version = "0.3.21"
criteria = "safe-to-deploy"
[[exemptions.hashbrown]]
version = "0.14.2"
criteria = "safe-to-deploy"
[[exemptions.hashlink]]
version = "0.8.4"
criteria = "safe-to-deploy"
[[exemptions.hdwallet]]
version = "0.4.1"
criteria = "safe-to-deploy"
[[exemptions.hermit-abi]]
version = "0.1.19"
criteria = "safe-to-run"
[[exemptions.hermit-abi]]
version = "0.3.3"
criteria = "safe-to-deploy"
[[exemptions.home]]
version = "0.5.5"
criteria = "safe-to-deploy"
[[exemptions.http]]
version = "0.2.9"
criteria = "safe-to-deploy"
[[exemptions.http-body]]
version = "0.4.5"
criteria = "safe-to-deploy"
[[exemptions.httparse]]
version = "1.8.0"
criteria = "safe-to-deploy"
[[exemptions.hyper]]
version = "0.14.27"
criteria = "safe-to-deploy"
[[exemptions.hyper-timeout]]
version = "0.4.1"
criteria = "safe-to-deploy"
[[exemptions.indexmap]]
version = "1.9.3"
criteria = "safe-to-deploy"
[[exemptions.indexmap]]
version = "2.1.0"
criteria = "safe-to-deploy"
[[exemptions.inferno]]
version = "0.11.17"
criteria = "safe-to-run"
[[exemptions.itertools]]
version = "0.11.0"
criteria = "safe-to-deploy"
[[exemptions.itoa]]
version = "1.0.9"
criteria = "safe-to-deploy"
[[exemptions.js-sys]]
version = "0.3.65"
criteria = "safe-to-deploy"
[[exemptions.jubjub]]
version = "0.10.0"
criteria = "safe-to-deploy"
[[exemptions.libc]]
version = "0.2.150"
criteria = "safe-to-deploy"
[[exemptions.libm]]
version = "0.2.2"
criteria = "safe-to-deploy"
[[exemptions.libsqlite3-sys]]
version = "0.26.0"
criteria = "safe-to-deploy"
[[exemptions.linux-raw-sys]]
version = "0.4.11"
criteria = "safe-to-deploy"
[[exemptions.lock_api]]
version = "0.4.11"
criteria = "safe-to-run"
[[exemptions.matchit]]
version = "0.7.3"
criteria = "safe-to-deploy"
[[exemptions.memchr]]
version = "2.6.4"
criteria = "safe-to-deploy"
[[exemptions.memmap2]]
version = "0.5.10"
criteria = "safe-to-run"
[[exemptions.memoffset]]
version = "0.9.0"
criteria = "safe-to-deploy"
[[exemptions.memuse]]
version = "0.2.1"
criteria = "safe-to-deploy"
[[exemptions.mime]]
version = "0.3.17"
criteria = "safe-to-deploy"
[[exemptions.minimal-lexical]]
version = "0.2.1"
criteria = "safe-to-deploy"
[[exemptions.minreq]]
version = "2.11.0"
criteria = "safe-to-deploy"
[[exemptions.mio]]
version = "0.8.9"
criteria = "safe-to-deploy"
[[exemptions.multimap]]
version = "0.8.3"
criteria = "safe-to-deploy"
[[exemptions.nonempty]]
version = "0.7.0"
criteria = "safe-to-deploy"
[[exemptions.num-format]]
version = "0.4.4"
criteria = "safe-to-run"
[[exemptions.num_cpus]]
version = "1.16.0"
criteria = "safe-to-deploy"
[[exemptions.object]]
version = "0.32.1"
criteria = "safe-to-deploy"
[[exemptions.once_cell]]
version = "1.18.0"
criteria = "safe-to-deploy"
[[exemptions.os_str_bytes]]
version = "6.6.1"
criteria = "safe-to-run"
[[exemptions.pairing]]
version = "0.23.0"
criteria = "safe-to-deploy"
[[exemptions.parking_lot_core]]
version = "0.9.9"
criteria = "safe-to-run"
[[exemptions.password-hash]]
version = "0.3.2"
criteria = "safe-to-deploy"
[[exemptions.pasta_curves]]
version = "0.5.1"
criteria = "safe-to-deploy"
[[exemptions.pbkdf2]]
version = "0.10.1"
criteria = "safe-to-deploy"
[[exemptions.petgraph]]
version = "0.6.4"
criteria = "safe-to-deploy"
[[exemptions.pin-project]]
version = "1.1.3"
criteria = "safe-to-deploy"
[[exemptions.pin-project-internal]]
version = "1.1.3"
criteria = "safe-to-deploy"
[[exemptions.pkg-config]]
version = "0.3.27"
criteria = "safe-to-deploy"
[[exemptions.plotters]]
version = "0.3.5"
criteria = "safe-to-run"
[[exemptions.plotters-backend]]
version = "0.3.5"
criteria = "safe-to-run"
[[exemptions.plotters-svg]]
version = "0.3.5"
criteria = "safe-to-run"
[[exemptions.poly1305]]
version = "0.8.0"
criteria = "safe-to-deploy"
[[exemptions.pprof]]
version = "0.11.1"
criteria = "safe-to-run"
[[exemptions.ppv-lite86]]
version = "0.2.17"
criteria = "safe-to-deploy"
[[exemptions.prettyplease]]
version = "0.2.15"
criteria = "safe-to-deploy"
[[exemptions.primitive-types]]
version = "0.12.2"
criteria = "safe-to-deploy"
[[exemptions.proptest]]
version = "1.3.1"
criteria = "safe-to-deploy"
[[exemptions.prost]]
version = "0.12.1"
criteria = "safe-to-deploy"
[[exemptions.prost-build]]
version = "0.12.1"
criteria = "safe-to-deploy"
[[exemptions.prost-derive]]
version = "0.12.1"
criteria = "safe-to-deploy"
[[exemptions.prost-types]]
version = "0.12.1"
criteria = "safe-to-deploy"
[[exemptions.quick-error]]
version = "1.2.3"
criteria = "safe-to-deploy"
[[exemptions.quick-xml]]
version = "0.26.0"
criteria = "safe-to-run"
[[exemptions.radium]]
version = "0.7.0"
criteria = "safe-to-deploy"
[[exemptions.rand]]
version = "0.8.5"
criteria = "safe-to-deploy"
[[exemptions.reddsa]]
version = "0.5.1"
criteria = "safe-to-deploy"
[[exemptions.redox_syscall]]
version = "0.4.1"
criteria = "safe-to-deploy"
[[exemptions.regex]]
version = "1.10.2"
criteria = "safe-to-deploy"
[[exemptions.regex-automata]]
version = "0.4.3"
criteria = "safe-to-deploy"
[[exemptions.regex-syntax]]
version = "0.7.5"
criteria = "safe-to-deploy"
[[exemptions.rgb]]
version = "0.8.37"
criteria = "safe-to-run"
[[exemptions.ring]]
version = "0.16.20"
criteria = "safe-to-deploy"
[[exemptions.ring]]
version = "0.17.5"
criteria = "safe-to-deploy"
[[exemptions.ripemd]]
version = "0.1.3"
criteria = "safe-to-deploy"
[[exemptions.rusqlite]]
version = "0.29.0"
criteria = "safe-to-deploy"
[[exemptions.rustix]]
version = "0.38.21"
criteria = "safe-to-deploy"
[[exemptions.rustls]]
version = "0.21.8"
criteria = "safe-to-deploy"
[[exemptions.rustls-webpki]]
version = "0.101.7"
criteria = "safe-to-deploy"
[[exemptions.rusty-fork]]
version = "0.3.0"
criteria = "safe-to-deploy"
[[exemptions.ryu]]
version = "1.0.15"
criteria = "safe-to-run"
[[exemptions.schemer]]
version = "0.2.1"
criteria = "safe-to-deploy"
[[exemptions.schemer-rusqlite]]
version = "0.2.2"
criteria = "safe-to-deploy"
[[exemptions.scopeguard]]
version = "1.2.0"
criteria = "safe-to-deploy"
[[exemptions.sct]]
version = "0.7.1"
criteria = "safe-to-deploy"
[[exemptions.secp256k1]]
version = "0.26.0"
criteria = "safe-to-deploy"
[[exemptions.secp256k1-sys]]
version = "0.8.1"
criteria = "safe-to-deploy"
[[exemptions.secrecy]]
version = "0.8.0"
criteria = "safe-to-deploy"
[[exemptions.serde]]
version = "1.0.192"
criteria = "safe-to-deploy"
[[exemptions.serde_derive]]
version = "1.0.192"
criteria = "safe-to-deploy"
[[exemptions.sha2]]
version = "0.10.8"
criteria = "safe-to-deploy"
[[exemptions.slab]]
version = "0.4.9"
criteria = "safe-to-deploy"
[[exemptions.smallvec]]
version = "1.11.1"
criteria = "safe-to-deploy"
[[exemptions.socket2]]
version = "0.4.10"
criteria = "safe-to-deploy"
[[exemptions.socket2]]
version = "0.5.5"
criteria = "safe-to-deploy"
[[exemptions.spin]]
version = "0.5.2"
criteria = "safe-to-deploy"
[[exemptions.spin]]
version = "0.9.8"
criteria = "safe-to-deploy"
[[exemptions.str_stack]]
version = "0.1.0"
criteria = "safe-to-run"
[[exemptions.subtle]]
version = "2.4.1"
criteria = "safe-to-deploy"
[[exemptions.symbolic-common]]
version = "10.2.1"
criteria = "safe-to-run"
[[exemptions.symbolic-demangle]]
version = "10.2.1"
criteria = "safe-to-run"
[[exemptions.syn]]
version = "2.0.53"
criteria = "safe-to-deploy"
[[exemptions.sync_wrapper]]
version = "0.1.2"
criteria = "safe-to-deploy"
[[exemptions.tempfile]]
version = "3.8.1"
criteria = "safe-to-deploy"
[[exemptions.time]]
version = "0.3.23"
criteria = "safe-to-deploy"
[[exemptions.tinytemplate]]
version = "1.2.1"
criteria = "safe-to-run"
[[exemptions.tokio]]
version = "1.35.1"
criteria = "safe-to-deploy"
[[exemptions.tokio-io-timeout]]
version = "1.2.0"
criteria = "safe-to-deploy"
[[exemptions.tokio-util]]
version = "0.7.10"
criteria = "safe-to-deploy"
[[exemptions.tonic]]
version = "0.10.2"
criteria = "safe-to-deploy"
[[exemptions.tonic-build]]
version = "0.10.2"
criteria = "safe-to-deploy"
[[exemptions.tower]]
version = "0.4.13"
criteria = "safe-to-deploy"
[[exemptions.tower-layer]]
version = "0.3.2"
criteria = "safe-to-deploy"
[[exemptions.tower-service]]
version = "0.3.2"
criteria = "safe-to-deploy"
[[exemptions.tracing]]
version = "0.1.40"
criteria = "safe-to-deploy"
[[exemptions.tracing-attributes]]
version = "0.1.27"
criteria = "safe-to-deploy"
[[exemptions.tracing-core]]
version = "0.1.32"
criteria = "safe-to-deploy"
[[exemptions.typenum]]
version = "1.17.0"
criteria = "safe-to-deploy"
[[exemptions.uint]]
version = "0.9.5"
criteria = "safe-to-deploy"
[[exemptions.unarray]]
version = "0.1.4"
criteria = "safe-to-deploy"
[[exemptions.untrusted]]
version = "0.9.0"
criteria = "safe-to-deploy"
[[exemptions.uuid]]
version = "1.5.0"
criteria = "safe-to-deploy"
[[exemptions.wait-timeout]]
version = "0.2.0"
criteria = "safe-to-deploy"
[[exemptions.walkdir]]
version = "2.4.0"
criteria = "safe-to-run"
[[exemptions.wasi]]
version = "0.11.0+wasi-snapshot-preview1"
criteria = "safe-to-deploy"
[[exemptions.wasm-bindgen]]
version = "0.2.88"
criteria = "safe-to-deploy"
[[exemptions.wasm-bindgen-backend]]
version = "0.2.88"
criteria = "safe-to-deploy"
[[exemptions.wasm-bindgen-macro]]
version = "0.2.88"
criteria = "safe-to-deploy"
[[exemptions.wasm-bindgen-macro-support]]
version = "0.2.88"
criteria = "safe-to-deploy"
[[exemptions.wasm-bindgen-shared]]
version = "0.2.88"
criteria = "safe-to-deploy"
[[exemptions.web-sys]]
version = "0.3.65"
criteria = "safe-to-deploy"
[[exemptions.which]]
version = "4.4.2"
criteria = "safe-to-deploy"
[[exemptions.winapi]]
version = "0.3.9"
criteria = "safe-to-deploy"
[[exemptions.winapi-i686-pc-windows-gnu]]
version = "0.4.0"
criteria = "safe-to-deploy"
[[exemptions.winapi-x86_64-pc-windows-gnu]]
version = "0.4.0"
criteria = "safe-to-deploy"
[[exemptions.wyz]]
version = "0.5.1"
criteria = "safe-to-deploy"
[[exemptions.xdg]]
version = "2.5.2"
criteria = "safe-to-deploy"
[[exemptions.zerocopy]]
version = "0.7.25"
criteria = "safe-to-deploy"
[[exemptions.zerocopy-derive]]
version = "0.7.25"
criteria = "safe-to-deploy"
[[exemptions.zeroize]]
version = "1.6.0"
criteria = "safe-to-deploy"
[[exemptions.zeroize_derive]]
version = "1.4.2"
criteria = "safe-to-deploy"

1444
supply-chain/imports.lock Normal file

File diff suppressed because it is too large Load Diff