From afd0e90a7482f50dcdf0f85378b87109097d0607 Mon Sep 17 00:00:00 2001 From: Jane Lusby Date: Fri, 26 Jun 2020 11:21:02 -0700 Subject: [PATCH] Implement equihash verification (#549) This change brings in the `equihash` crate from librustzcash and uses it to add a basic `is_valid` test for `EquihashSolutions`. Co-authored-by: Jane Lusby --- Cargo.lock | 11 ++++++++++ zebra-chain/Cargo.toml | 1 + zebra-chain/src/equihash_solution.rs | 33 +++++++++++++++++++++++++++- 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 6277a9e3..100a5317 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -428,6 +428,16 @@ dependencies = [ "thiserror", ] +[[package]] +name = "equihash" +version = "0.0.0" +source = "git+https://github.com/ZcashFoundation/librustzcash.git?branch=equihash-crate#5b2c71e112ade5488ba49bb16f50897d513702f8" +dependencies = [ + "blake2b_simd", + "byteorder", + "log", +] + [[package]] name = "eyre" version = "0.6.0" @@ -2300,6 +2310,7 @@ dependencies = [ "byteorder", "chrono", "ed25519-zebra", + "equihash", "futures", "hex", "jubjub", diff --git a/zebra-chain/Cargo.toml b/zebra-chain/Cargo.toml index ad7226d1..209fb551 100644 --- a/zebra-chain/Cargo.toml +++ b/zebra-chain/Cargo.toml @@ -29,6 +29,7 @@ serde-big-array = "0.3.0" # ZF deps ed25519-zebra = "0.4" redjubjub = "0.1" +equihash = { git = "https://github.com/ZcashFoundation/librustzcash.git", branch = "equihash-crate" } [dev-dependencies] proptest = "0.10" diff --git a/zebra-chain/src/equihash_solution.rs b/zebra-chain/src/equihash_solution.rs index 5e58b4fa..6c3b5d7f 100644 --- a/zebra-chain/src/equihash_solution.rs +++ b/zebra-chain/src/equihash_solution.rs @@ -28,6 +28,15 @@ pub struct EquihashSolution( #[serde(with = "serde_helpers::BigArray")] pub [u8; EQUIHASH_SOLUTION_SIZE], ); +impl EquihashSolution { + /// Validate an equihash solution + pub fn is_valid(&self, input: &[u8], nonce: &[u8]) -> bool { + let n = 200; + let k = 9; + equihash::is_valid_solution(n, k, input, nonce, &self.0) + } +} + impl PartialEq for EquihashSolution { fn eq(&self, other: &EquihashSolution) -> bool { self.0.as_ref() == other.0.as_ref() @@ -117,7 +126,8 @@ mod tests { } - const EQUIHASH_SOLUTION_BLOCK_OFFSET: usize = 4 + 32 * 3 + 4 * 2 + 32; + const EQUIHASH_NONCE_BLOCK_OFFSET: usize = 4 + 32 * 3 + 4 * 2; + const EQUIHASH_SOLUTION_BLOCK_OFFSET: usize = EQUIHASH_NONCE_BLOCK_OFFSET + 32; #[test] fn equihash_solution_test_vector() { @@ -134,6 +144,27 @@ mod tests { assert_eq!(solution_bytes, data.as_slice()); } + #[test] + fn equihash_solution_test_vector_is_valid() { + let block = crate::block::Block::zcash_deserialize( + &zebra_test::vectors::BLOCK_MAINNET_415000_BYTES[..], + ) + .expect("block test vector should deserialize"); + + let solution = block.header.solution; + let header_bytes = + &zebra_test::vectors::HEADER_MAINNET_415000_BYTES[..EQUIHASH_NONCE_BLOCK_OFFSET]; + + assert!(solution.is_valid(header_bytes, &block.header.nonce)); + + let heade_bytes = + &zebra_test::vectors::HEADER_MAINNET_415000_BYTES[..EQUIHASH_NONCE_BLOCK_OFFSET - 1]; + let headerr_bytes = + &zebra_test::vectors::HEADER_MAINNET_415000_BYTES[..EQUIHASH_NONCE_BLOCK_OFFSET + 1]; + assert!(!solution.is_valid(heade_bytes, &block.header.nonce)); + assert!(!solution.is_valid(headerr_bytes, &block.header.nonce)); + } + static EQUIHASH_SIZE_TESTS: &[u64] = &[ 0, 1,