diff --git a/wasm/anubis/src/lib.rs b/wasm/anubis/src/lib.rs index 710492fb..23ab1b5e 100644 --- a/wasm/anubis/src/lib.rs +++ b/wasm/anubis/src/lib.rs @@ -38,9 +38,21 @@ mod hostimport { #[cfg(not(target_arch = "wasm32"))] mod hostimport { + use crate::{DATA_BUFFER, DATA_LENGTH}; + pub fn update_nonce(_nonce: u32) { // This is intentionally blank } + + pub fn data_ptr() -> *const u8 { + let challenge = &DATA_BUFFER; + challenge.as_ptr() + } + + pub fn set_data_length(len: u32) { + let mut data_length = DATA_LENGTH.lock().unwrap(); + *data_length = len as usize; + } } /// The data buffer is a bit weird in that it doesn't have an explicit length as it can @@ -57,4 +69,4 @@ mod hostimport { pub static DATA_BUFFER: LazyLock<[u8; 4096]> = LazyLock::new(|| [0; 4096]); pub static DATA_LENGTH: LazyLock> = LazyLock::new(|| Mutex::new(0)); -pub use hostimport::update_nonce; +pub use hostimport::{data_ptr, set_data_length, update_nonce}; diff --git a/wasm/pow/hashx/src/lib.rs b/wasm/pow/hashx/src/lib.rs index 1a340ca4..c7f1cf6f 100644 --- a/wasm/pow/hashx/src/lib.rs +++ b/wasm/pow/hashx/src/lib.rs @@ -55,10 +55,12 @@ fn anubis_work_inner( let data = &DATA_BUFFER; let data_len = *DATA_LENGTH.lock().unwrap(); let data_slice = &data[..data_len]; + let mut i = 0; let h = HashX::new(data_slice)?; loop { + i += 1; let hash = h.hash_to_bytes(nonce as u64); if validate(&hash, difficulty) { @@ -69,24 +71,18 @@ fn anubis_work_inner( return Ok(nonce); } - let old_nonce = nonce; nonce = nonce.wrapping_add(iterand); - // send a progress update every 1024 iterations. since each thread checks - // separate values, one simple way to do this is by bit masking the - // nonce for multiples of 1024. unfortunately, if the number of threads - // is not prime, only some of the threads will be sending the status - // update and they will get behind the others. this is slightly more - // complicated but ensures an even distribution between threads. - if nonce > old_nonce | 1023 && (nonce >> 10) % iterand == initial_nonce { + if i == 1024 { update_nonce(nonce); + i = 0; } } } /// This function is the main entrypoint for the Anubis proof of work implementation. /// -/// This expects `DATA_BUFFER` to be pre-populated with the challenge value as "raw bytes". +/// This expects `DATA_BUFFER` to be prepopulated with the challenge value as "raw bytes". /// The definition of what goes in the data buffer is an exercise for the implementor, but /// for SHA-256 we store the hash as "raw bytes". The data buffer is intentionally oversized /// so that the challenge value can be expanded in the future. diff --git a/wasm/pow/sha256/src/lib.rs b/wasm/pow/sha256/src/lib.rs index 81eeb527..8eb7babe 100644 --- a/wasm/pow/sha256/src/lib.rs +++ b/wasm/pow/sha256/src/lib.rs @@ -62,7 +62,6 @@ fn compute_hash(nonce: u32) -> [u8; 32] { let data = &DATA_BUFFER; let data_len = *DATA_LENGTH.lock().unwrap(); let use_le = data[data_len - 1] >= 128; - let data_slice = &data[..data_len]; let mut hasher = Sha256::new(); @@ -77,7 +76,7 @@ fn compute_hash(nonce: u32) -> [u8; 32] { /// This function is the main entrypoint for the Anubis proof of work implementation. /// -/// This expects `DATA_BUFFER` to be pre-populated with the challenge value as "raw bytes". +/// This expects `DATA_BUFFER` to be prepopulated with the challenge value as "raw bytes". /// The definition of what goes in the data buffer is an exercise for the implementor, but /// for SHA-256 we store the hash as "raw bytes". The data buffer is intentionally oversized /// so that the challenge value can be expanded in the future. @@ -96,8 +95,10 @@ fn compute_hash(nonce: u32) -> [u8; 32] { #[unsafe(no_mangle)] pub extern "C" fn anubis_work(difficulty: u32, initial_nonce: u32, iterand: u32) -> u32 { let mut nonce = initial_nonce; + let mut i = 0; loop { + i += 1; let hash = compute_hash(nonce); if validate(&hash, difficulty) { @@ -108,17 +109,11 @@ pub extern "C" fn anubis_work(difficulty: u32, initial_nonce: u32, iterand: u32) return nonce; } - let old_nonce = nonce; nonce = nonce.wrapping_add(iterand); - // send a progress update every 1024 iterations. since each thread checks - // separate values, one simple way to do this is by bit masking the - // nonce for multiples of 1024. unfortunately, if the number of threads - // is not prime, only some of the threads will be sending the status - // update and they will get behind the others. this is slightly more - // complicated but ensures an even distribution between threads. - if nonce > old_nonce | 1023 && (nonce >> 10) % iterand == initial_nonce { + if i == 1024 { update_nonce(nonce); + i = 0; } } }