Compare commits

...

4 commits

Author SHA1 Message Date
8be369846e
cuprated: Blockchain Manager (#274)
Some checks failed
CI / fmt (push) Waiting to run
CI / typo (push) Waiting to run
CI / ci (macos-latest, stable, bash) (push) Waiting to run
CI / ci (ubuntu-latest, stable, bash) (push) Waiting to run
CI / ci (windows-latest, stable-x86_64-pc-windows-gnu, msys2 {0}) (push) Waiting to run
Doc / build (push) Waiting to run
Doc / deploy (push) Blocked by required conditions
Audit / audit (push) Has been cancelled
Deny / audit (push) Has been cancelled
* add cuprated skeleton

* fmt and add deny exception

* add main chain batch handler

* add blockchain init

* very rough block manager

* misc changes

* move more config values

* add new tables & types

* add function to fully add an alt block

* resolve current todo!s

* add new requests

* WIP: starting re-orgs

* add last service request

* commit Cargo.lock

* add test

* more docs + cleanup + alt blocks request

* clippy + fmt

* document types

* move tx_fee to helper

* more doc updates

* fmt

* fix imports

* remove config files

* fix merge errors

* fix generated coins

* handle more p2p requests + alt blocks

* clean up handler code

* add function for incoming blocks

* add docs to handler functions

* broadcast new blocks + add commands

* add fluffy block handler

* fix new block handling

* small cleanup

* increase outbound peer count

* fix merge

* clean up the blockchain manger

* add more docs + cleanup imports

* fix typo

* fix doc

* remove unrelated changes

* improve interface globals

* manger -> manager

* enums instead of bools

* move chain service to separate file

* more review fixes

* add link to issue

* fix syncer + update comment

* fmt
2024-10-08 18:26:07 +01:00
Dmitry Holodov
00bdd6ffaa
cryptonight in pure Rust (#271)
* removed FORCE_USE_HEAP to from c code

* removed unused headers

* simplifying C code to better understand it

* more c code simplifications

* removed conditional code for the v4 register size

* got one version of keccak working

* not so important hash_process unwound

* got keccak working using the sha3 lib

* hash state unions created

* slow hash through VARIANT1_PORTABLE_INIT is working

* variant 2 init working

* ported version of random_math_init compiling, but not yet passing tests

* fixed hash algorithm, tests working

* formatting

* more macro reduction

* monero AES working in Rust

* fixed AES key expansion expected key size

* first 75% of slow hash converted and working correctly

* adjusted key format for aesb_single_round

* converted some macros to functions

* variant2_integer_math working with test cases

* broke sqrt out of variant2_integer_math for code coverage

* variant2_portable_shuffle_add working with unit tests

* added skein and jh hashes

* 524287 iteration loop producing correct results

* all tests working in Rust

* subarray macros added

* aes simplifications

* code cleanups

* code cleanups part 2

* removed unused blake C code as prep for port to rust

* original blake algorithm in pure rust is working

* converted macro in compress to a lamda

* added module documentation for blake256

* Gave Blake256 a Digest trait

* adding more documentation

* more documentation and cleanup

* more slow hash tests

* removed C code

* misc refactoring

* fix

* lint fix

* additional linting

* downgraded deps to latest stable versions

* made thiserror a workspace dep

* removed commented dead code

* lint fixes

* fixed lint issues in test code

* limited util macro scopes to the crate

* Reformatted dependencies using:
group_imports = "StdExternalCrate"
reorder_modules = true
reorder_impl_items = true
imports_granularity = "crate"

* converted util macros to inline functions

* hex dep comes from workspace

Co-authored-by: hinto-janai <hinto.janai@protonmail.com>

* panic subarray tests

Co-authored-by: hinto-janai <hinto.janai@protonmail.com>

* updates to doc comments

* removes extra parens in hash_v4.rs

Co-authored-by: hinto-janai <hinto.janai@protonmail.com>

* early return to remove indentation in hash_v2.rs

Co-authored-by: hinto-janai <hinto.janai@protonmail.com>

* gropuing expect annotations in hash_v2.rs

Co-authored-by: hinto-janai <hinto.janai@protonmail.com>

* use matches macro to simplify code hash_v4.rs

Co-authored-by: hinto-janai <hinto.janai@protonmail.com>

* remove extra paren in hash_v4.rs

Co-authored-by: hinto-janai <hinto.janai@protonmail.com>

* eary return to remove indentation in hash_v2.rs

Co-authored-by: hinto-janai <hinto.janai@protonmail.com>

* minor comment fixes

* early loop continue to remove indentation in hash_v4.rs

Co-authored-by: hinto-janai <hinto.janai@protonmail.com>

* convert non-capturing llamda to fn in hash_v2.rs

Co-authored-by: hinto-janai <hinto.janai@protonmail.com>

* another lamda to fn conversion in hash_v2.rs

Co-authored-by: hinto-janai <hinto.janai@protonmail.com>

* llamda to fn conversion in cnaes.rs

Co-authored-by: hinto-janai <hinto.janai@protonmail.com>

* 2nd llamda to fn conversion in cnaes.rs

Co-authored-by: hinto-janai <hinto.janai@protonmail.com>

* test lamdas in lib.rs are now functions

* round_fwd optimized

* added myself as an author

* fixed place that needed wrapping_add

* clippy allow->expect change needed after merging master

* moving state to u128

* round_fwd changes sped up fuzzer by 10%

* 1st working version using u128 for long state

* text converted to u128 array

* removed LongState union

* simplified long_state's initialization

* aes round keys now use u128

* CRYPTONIGHT_SBOX is now u32 instead of u8

* cleaner hash_v4 loop unrolling semantics (same peformance)

* switched to a better maintained loop unrolling macro
2024-10-08 16:03:56 +01:00
ca882512fc
P2P: move seed nodes to config (#306)
* move seed nodes to config

* fix tests
2024-10-07 23:36:46 +01:00
hinto-janai
80bfe0a34c
types: JSON representation types (#300)
* add `cuprate_types::json`

* docs

* `Option` -> flattened enums + prefix structs

* output enum

* docs

* todo!() epee impl

* cuprate-rpc-types: add comments

* cuprate-rpc-types: common `TxEntry` fields into prefix struct

* remove epee

* docs

* add `hex` module

* `From` serai types

* cleanup

* proofs

* tx from impls

* fix tx timelock

* add block value tests

* add ringct types

* add tx_v1, tx_rct_3 test

* clsag bulletproofs tx test

* clsag bulletproofs plus tx test

* docs

* fix hex bytes

* typo

* docs
2024-10-05 01:47:44 +01:00
88 changed files with 6206 additions and 13244 deletions

106
Cargo.lock generated
View file

@ -629,8 +629,14 @@ version = "0.1.0"
name = "cuprate-cryptonight"
version = "0.1.0"
dependencies = [
"cc",
"digest",
"groestl",
"hex",
"jh",
"keccak",
"seq-macro",
"sha3",
"skein",
"thiserror",
]
@ -917,11 +923,16 @@ dependencies = [
"bytes",
"cuprate-epee-encoding",
"cuprate-fixed-bytes",
"cuprate-helper",
"curve25519-dalek",
"hex",
"hex-literal",
"monero-serai",
"pretty_assertions",
"proptest",
"proptest-derive",
"serde",
"serde_json",
"thiserror",
]
@ -1318,6 +1329,15 @@ version = "0.31.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64"
[[package]]
name = "groestl"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "343cfc165f92a988fd60292f7a0bfde4352a5a0beff9fbec29251ca4e9676e4d"
dependencies = [
"digest",
]
[[package]]
name = "group"
version = "0.13.0"
@ -1412,6 +1432,9 @@ name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
dependencies = [
"serde",
]
[[package]]
name = "hex-literal"
@ -1573,6 +1596,17 @@ version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]]
name = "jh"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f65735f9e73adc203417d2e05352aef71d7e832ec090f65de26c96c9ec563aa5"
dependencies = [
"digest",
"hex-literal",
"ppv-lite86",
]
[[package]]
name = "js-sys"
version = "0.3.70"
@ -1872,6 +1906,16 @@ dependencies = [
"tokio",
]
[[package]]
name = "nu-ansi-term"
version = "0.46.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
dependencies = [
"overload",
"winapi",
]
[[package]]
name = "num-traits"
version = "0.2.19"
@ -1909,6 +1953,12 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]]
name = "overload"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
[[package]]
name = "page_size"
version = "0.6.0"
@ -2440,6 +2490,12 @@ version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
[[package]]
name = "seq-macro"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3f0bf26fd526d2a95683cd0f87bf103b8539e2ca1ef48ce002d67aad59aa0b4"
[[package]]
name = "serde"
version = "1.0.210"
@ -2524,6 +2580,15 @@ dependencies = [
"keccak",
]
[[package]]
name = "sharded-slab"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
dependencies = [
"lazy_static",
]
[[package]]
name = "shlex"
version = "1.3.0"
@ -2558,6 +2623,16 @@ version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
[[package]]
name = "skein"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f412279217fa74b69094bf6b5cde63dd0ece9b85d94fedda9bbfdfb2666125cf"
dependencies = [
"digest",
"threefish",
]
[[package]]
name = "slab"
version = "0.4.9"
@ -2708,6 +2783,12 @@ dependencies = [
"once_cell",
]
[[package]]
name = "threefish"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a693d0c8cf16973fac5a93fbe47b8c6452e7097d4fcac49f3d7a18e39c76e62e"
[[package]]
name = "tinyvec"
version = "1.8.0"
@ -2904,6 +2985,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
dependencies = [
"once_cell",
"valuable",
]
[[package]]
name = "tracing-log"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
dependencies = [
"log",
"once_cell",
"tracing-core",
]
[[package]]
@ -2912,7 +3005,12 @@ version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b"
dependencies = [
"nu-ansi-term",
"sharded-slab",
"smallvec",
"thread_local",
"tracing-core",
"tracing-log",
]
[[package]]
@ -2995,6 +3093,12 @@ dependencies = [
"percent-encoding",
]
[[package]]
name = "valuable"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
[[package]]
name = "version_check"
version = "0.9.5"

View file

@ -23,7 +23,7 @@ cuprate-p2p-core = { path = "../../p2p/p2p-core" }
cuprate-dandelion-tower = { path = "../../p2p/dandelion-tower" }
cuprate-async-buffer = { path = "../../p2p/async-buffer" }
cuprate-address-book = { path = "../../p2p/address-book" }
cuprate-blockchain = { path = "../../storage/blockchain" }
cuprate-blockchain = { path = "../../storage/blockchain", features = ["service"] }
cuprate-database-service = { path = "../../storage/service" }
cuprate-txpool = { path = "../../storage/txpool" }
cuprate-database = { path = "../../storage/database" }
@ -70,8 +70,14 @@ tokio-util = { workspace = true }
tokio-stream = { workspace = true }
tokio = { workspace = true }
tower = { workspace = true }
tracing-subscriber = { workspace = true }
tracing-subscriber = { workspace = true, features = ["std", "fmt", "default"] }
tracing = { workspace = true }
[lints]
workspace = true
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"

View file

@ -1,6 +1,101 @@
//! Blockchain
//!
//! Will contain the chain manager and syncer.
//! Contains the blockchain manager, syncer and an interface to mutate the blockchain.
use std::sync::Arc;
use futures::FutureExt;
use tokio::sync::{mpsc, Notify};
use tower::{BoxError, Service, ServiceExt};
use cuprate_blockchain::service::{BlockchainReadHandle, BlockchainWriteHandle};
use cuprate_consensus::{generate_genesis_block, BlockChainContextService, ContextConfig};
use cuprate_cryptonight::cryptonight_hash_v0;
use cuprate_p2p::{block_downloader::BlockDownloaderConfig, NetworkInterface};
use cuprate_p2p_core::{ClearNet, Network};
use cuprate_types::{
blockchain::{BlockchainReadRequest, BlockchainWriteRequest},
VerifiedBlockInformation,
};
use crate::constants::PANIC_CRITICAL_SERVICE_ERROR;
mod chain_service;
pub mod interface;
mod manager;
mod syncer;
mod types;
use types::{
ConcreteBlockVerifierService, ConcreteTxVerifierService, ConsensusBlockchainReadHandle,
};
/// Checks if the genesis block is in the blockchain and adds it if not.
pub async fn check_add_genesis(
blockchain_read_handle: &mut BlockchainReadHandle,
blockchain_write_handle: &mut BlockchainWriteHandle,
network: Network,
) {
// Try to get the chain height, will fail if the genesis block is not in the DB.
if blockchain_read_handle
.ready()
.await
.expect(PANIC_CRITICAL_SERVICE_ERROR)
.call(BlockchainReadRequest::ChainHeight)
.await
.is_ok()
{
return;
}
let genesis = generate_genesis_block(network);
assert_eq!(genesis.miner_transaction.prefix().outputs.len(), 1);
assert!(genesis.transactions.is_empty());
blockchain_write_handle
.ready()
.await
.expect(PANIC_CRITICAL_SERVICE_ERROR)
.call(BlockchainWriteRequest::WriteBlock(
VerifiedBlockInformation {
block_blob: genesis.serialize(),
txs: vec![],
block_hash: genesis.hash(),
pow_hash: cryptonight_hash_v0(&genesis.serialize_pow_hash()),
height: 0,
generated_coins: genesis.miner_transaction.prefix().outputs[0]
.amount
.unwrap(),
weight: genesis.miner_transaction.weight(),
long_term_weight: genesis.miner_transaction.weight(),
cumulative_difficulty: 1,
block: genesis,
},
))
.await
.expect(PANIC_CRITICAL_SERVICE_ERROR);
}
/// Initializes the consensus services.
pub async fn init_consensus(
blockchain_read_handle: BlockchainReadHandle,
context_config: ContextConfig,
) -> Result<
(
ConcreteBlockVerifierService,
ConcreteTxVerifierService,
BlockChainContextService,
),
BoxError,
> {
let read_handle = ConsensusBlockchainReadHandle::new(blockchain_read_handle, BoxError::from);
let ctx_service =
cuprate_consensus::initialize_blockchain_context(context_config, read_handle.clone())
.await?;
let (block_verifier_svc, tx_verifier_svc) =
cuprate_consensus::initialize_verifier(read_handle, ctx_service.clone());
Ok((block_verifier_svc, tx_verifier_svc, ctx_service))
}

View file

@ -0,0 +1,72 @@
use std::task::{Context, Poll};
use futures::{future::BoxFuture, FutureExt, TryFutureExt};
use tower::Service;
use cuprate_blockchain::service::BlockchainReadHandle;
use cuprate_p2p::block_downloader::{ChainSvcRequest, ChainSvcResponse};
use cuprate_types::blockchain::{BlockchainReadRequest, BlockchainResponse};
/// That service that allows retrieving the chain state to give to the P2P crates, so we can figure out
/// what blocks we need.
///
/// This has a more minimal interface than [`BlockchainReadRequest`] to make using the p2p crates easier.
#[derive(Clone)]
pub struct ChainService(pub BlockchainReadHandle);
impl Service<ChainSvcRequest> for ChainService {
type Response = ChainSvcResponse;
type Error = tower::BoxError;
type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.0.poll_ready(cx).map_err(Into::into)
}
fn call(&mut self, req: ChainSvcRequest) -> Self::Future {
let map_res = |res: BlockchainResponse| match res {
BlockchainResponse::CompactChainHistory {
block_ids,
cumulative_difficulty,
} => ChainSvcResponse::CompactHistory {
block_ids,
cumulative_difficulty,
},
BlockchainResponse::FindFirstUnknown(res) => ChainSvcResponse::FindFirstUnknown(res),
_ => unreachable!(),
};
match req {
ChainSvcRequest::CompactHistory => self
.0
.call(BlockchainReadRequest::CompactChainHistory)
.map_ok(map_res)
.map_err(Into::into)
.boxed(),
ChainSvcRequest::FindFirstUnknown(req) => self
.0
.call(BlockchainReadRequest::FindFirstUnknown(req))
.map_ok(map_res)
.map_err(Into::into)
.boxed(),
ChainSvcRequest::CumulativeDifficulty => self
.0
.call(BlockchainReadRequest::CompactChainHistory)
.map_ok(|res| {
// TODO create a custom request instead of hijacking this one.
// TODO: use the context cache.
let BlockchainResponse::CompactChainHistory {
cumulative_difficulty,
..
} = res
else {
unreachable!()
};
ChainSvcResponse::CumulativeDifficulty(cumulative_difficulty)
})
.map_err(Into::into)
.boxed(),
}
}
}

View file

@ -0,0 +1,161 @@
//! The blockchain manager interface.
//!
//! This module contains all the functions to mutate the blockchain's state in any way, through the
//! blockchain manager.
use std::{
collections::{HashMap, HashSet},
sync::{LazyLock, Mutex, OnceLock},
};
use monero_serai::{block::Block, transaction::Transaction};
use rayon::prelude::*;
use tokio::sync::{mpsc, oneshot};
use tower::{Service, ServiceExt};
use cuprate_blockchain::service::BlockchainReadHandle;
use cuprate_consensus::transactions::new_tx_verification_data;
use cuprate_helper::cast::usize_to_u64;
use cuprate_types::{
blockchain::{BlockchainReadRequest, BlockchainResponse},
Chain,
};
use crate::{
blockchain::manager::{BlockchainManagerCommand, IncomingBlockOk},
constants::PANIC_CRITICAL_SERVICE_ERROR,
};
/// The channel used to send [`BlockchainManagerCommand`]s to the blockchain manager.
///
/// This channel is initialized in [`init_blockchain_manager`](super::manager::init_blockchain_manager), the functions
/// in this file document what happens if this is not initialized when they are called.
pub(super) static COMMAND_TX: OnceLock<mpsc::Sender<BlockchainManagerCommand>> = OnceLock::new();
/// An error that can be returned from [`handle_incoming_block`].
#[derive(Debug, thiserror::Error)]
pub enum IncomingBlockError {
/// Some transactions in the block were unknown.
///
/// The inner values are the block hash and the indexes of the missing txs in the block.
#[error("Unknown transactions in block.")]
UnknownTransactions([u8; 32], Vec<u64>),
/// We are missing the block's parent.
#[error("The block has an unknown parent.")]
Orphan,
/// The block was invalid.
#[error(transparent)]
InvalidBlock(anyhow::Error),
}
/// Try to add a new block to the blockchain.
///
/// On success returns [`IncomingBlockOk`].
///
/// # Errors
///
/// This function will return an error if:
/// - the block was invalid
/// - we are missing transactions
/// - the block's parent is unknown
pub async fn handle_incoming_block(
block: Block,
given_txs: Vec<Transaction>,
blockchain_read_handle: &mut BlockchainReadHandle,
) -> Result<IncomingBlockOk, IncomingBlockError> {
/// A [`HashSet`] of block hashes that the blockchain manager is currently handling.
///
/// This lock prevents sending the same block to the blockchain manager from multiple connections
/// before one of them actually gets added to the chain, allowing peers to do other things.
///
/// This is used over something like a dashmap as we expect a lot of collisions in a short amount of
/// time for new blocks, so we would lose the benefit of sharded locks. A dashmap is made up of `RwLocks`
/// which are also more expensive than `Mutex`s.
static BLOCKS_BEING_HANDLED: LazyLock<Mutex<HashSet<[u8; 32]>>> =
LazyLock::new(|| Mutex::new(HashSet::new()));
// FIXME: we should look in the tx-pool for txs when that is ready.
if !block_exists(block.header.previous, blockchain_read_handle)
.await
.expect(PANIC_CRITICAL_SERVICE_ERROR)
{
return Err(IncomingBlockError::Orphan);
}
let block_hash = block.hash();
if block_exists(block_hash, blockchain_read_handle)
.await
.expect(PANIC_CRITICAL_SERVICE_ERROR)
{
return Ok(IncomingBlockOk::AlreadyHave);
}
// TODO: remove this when we have a working tx-pool.
if given_txs.len() != block.transactions.len() {
return Err(IncomingBlockError::UnknownTransactions(
block_hash,
(0..usize_to_u64(block.transactions.len())).collect(),
));
}
// TODO: check we actually got given the right txs.
let prepped_txs = given_txs
.into_par_iter()
.map(|tx| {
let tx = new_tx_verification_data(tx)?;
Ok((tx.tx_hash, tx))
})
.collect::<Result<_, anyhow::Error>>()
.map_err(IncomingBlockError::InvalidBlock)?;
let Some(incoming_block_tx) = COMMAND_TX.get() else {
// We could still be starting up the blockchain manager.
return Ok(IncomingBlockOk::NotReady);
};
// Add the blocks hash to the blocks being handled.
if !BLOCKS_BEING_HANDLED.lock().unwrap().insert(block_hash) {
// If another place is already adding this block then we can stop.
return Ok(IncomingBlockOk::AlreadyHave);
}
// From this point on we MUST not early return without removing the block hash from `BLOCKS_BEING_HANDLED`.
let (response_tx, response_rx) = oneshot::channel();
incoming_block_tx
.send(BlockchainManagerCommand::AddBlock {
block,
prepped_txs,
response_tx,
})
.await
.expect("TODO: don't actually panic here, an err means we are shutting down");
let res = response_rx
.await
.expect("The blockchain manager will always respond")
.map_err(IncomingBlockError::InvalidBlock);
// Remove the block hash from the blocks being handled.
BLOCKS_BEING_HANDLED.lock().unwrap().remove(&block_hash);
res
}
/// Check if we have a block with the given hash.
async fn block_exists(
block_hash: [u8; 32],
blockchain_read_handle: &mut BlockchainReadHandle,
) -> Result<bool, anyhow::Error> {
let BlockchainResponse::FindBlock(chain) = blockchain_read_handle
.ready()
.await?
.call(BlockchainReadRequest::FindBlock(block_hash))
.await?
else {
unreachable!();
};
Ok(chain.is_some())
}

View file

@ -1 +1,143 @@
use std::{collections::HashMap, sync::Arc};
use futures::StreamExt;
use monero_serai::block::Block;
use tokio::sync::{mpsc, oneshot, Notify};
use tower::{Service, ServiceExt};
use tracing::error;
use cuprate_blockchain::service::{BlockchainReadHandle, BlockchainWriteHandle};
use cuprate_consensus::{
context::RawBlockChainContext, BlockChainContextRequest, BlockChainContextResponse,
BlockChainContextService, BlockVerifierService, ExtendedConsensusError, TxVerifierService,
VerifyBlockRequest, VerifyBlockResponse, VerifyTxRequest, VerifyTxResponse,
};
use cuprate_p2p::{
block_downloader::{BlockBatch, BlockDownloaderConfig},
BroadcastSvc, NetworkInterface,
};
use cuprate_p2p_core::ClearNet;
use cuprate_types::{
blockchain::{BlockchainReadRequest, BlockchainResponse},
Chain, TransactionVerificationData,
};
use crate::{
blockchain::{
chain_service::ChainService,
interface::COMMAND_TX,
syncer,
types::{ConcreteBlockVerifierService, ConsensusBlockchainReadHandle},
},
constants::PANIC_CRITICAL_SERVICE_ERROR,
};
mod commands;
mod handler;
pub use commands::{BlockchainManagerCommand, IncomingBlockOk};
/// Initialize the blockchain manager.
///
/// This function sets up the [`BlockchainManager`] and the [`syncer`] so that the functions in [`interface`](super::interface)
/// can be called.
pub async fn init_blockchain_manager(
clearnet_interface: NetworkInterface<ClearNet>,
blockchain_write_handle: BlockchainWriteHandle,
blockchain_read_handle: BlockchainReadHandle,
mut blockchain_context_service: BlockChainContextService,
block_verifier_service: ConcreteBlockVerifierService,
block_downloader_config: BlockDownloaderConfig,
) {
// TODO: find good values for these size limits
let (batch_tx, batch_rx) = mpsc::channel(1);
let stop_current_block_downloader = Arc::new(Notify::new());
let (command_tx, command_rx) = mpsc::channel(3);
COMMAND_TX.set(command_tx).unwrap();
tokio::spawn(syncer::syncer(
blockchain_context_service.clone(),
ChainService(blockchain_read_handle.clone()),
clearnet_interface.clone(),
batch_tx,
Arc::clone(&stop_current_block_downloader),
block_downloader_config,
));
let BlockChainContextResponse::Context(blockchain_context) = blockchain_context_service
.ready()
.await
.expect(PANIC_CRITICAL_SERVICE_ERROR)
.call(BlockChainContextRequest::GetContext)
.await
.expect(PANIC_CRITICAL_SERVICE_ERROR)
else {
unreachable!()
};
let manager = BlockchainManager {
blockchain_write_handle,
blockchain_read_handle,
blockchain_context_service,
cached_blockchain_context: blockchain_context.unchecked_blockchain_context().clone(),
block_verifier_service,
stop_current_block_downloader,
broadcast_svc: clearnet_interface.broadcast_svc(),
};
tokio::spawn(manager.run(batch_rx, command_rx));
}
/// The blockchain manager.
///
/// This handles all mutation of the blockchain, anything that changes the state of the blockchain must
/// go through this.
///
/// Other parts of Cuprate can interface with this by using the functions in [`interface`](super::interface).
pub struct BlockchainManager {
/// The [`BlockchainWriteHandle`], this is the _only_ part of Cuprate where a [`BlockchainWriteHandle`]
/// is held.
blockchain_write_handle: BlockchainWriteHandle,
/// A [`BlockchainReadHandle`].
blockchain_read_handle: BlockchainReadHandle,
// TODO: Improve the API of the cache service.
// TODO: rename the cache service -> `BlockchainContextService`.
/// The blockchain context cache, this caches the current state of the blockchain to quickly calculate/retrieve
/// values without needing to go to a [`BlockchainReadHandle`].
blockchain_context_service: BlockChainContextService,
/// A cached context representing the current state.
cached_blockchain_context: RawBlockChainContext,
/// The block verifier service, to verify incoming blocks.
block_verifier_service: ConcreteBlockVerifierService,
/// A [`Notify`] to tell the [syncer](syncer::syncer) that we want to cancel this current download
/// attempt.
stop_current_block_downloader: Arc<Notify>,
/// The broadcast service, to broadcast new blocks.
broadcast_svc: BroadcastSvc<ClearNet>,
}
impl BlockchainManager {
/// The [`BlockchainManager`] task.
pub async fn run(
mut self,
mut block_batch_rx: mpsc::Receiver<BlockBatch>,
mut command_rx: mpsc::Receiver<BlockchainManagerCommand>,
) {
loop {
tokio::select! {
Some(batch) = block_batch_rx.recv() => {
self.handle_incoming_block_batch(
batch,
).await;
}
Some(incoming_command) = command_rx.recv() => {
self.handle_command(incoming_command).await;
}
else => {
todo!("TODO: exit the BC manager")
}
}
}
}
}

View file

@ -0,0 +1,32 @@
//! This module contains the commands for the blockchain manager.
use std::collections::HashMap;
use monero_serai::block::Block;
use tokio::sync::oneshot;
use cuprate_types::TransactionVerificationData;
/// The blockchain manager commands.
pub enum BlockchainManagerCommand {
/// Attempt to add a new block to the blockchain.
AddBlock {
/// The [`Block`] to add.
block: Block,
/// All the transactions defined in [`Block::transactions`].
prepped_txs: HashMap<[u8; 32], TransactionVerificationData>,
/// The channel to send the response down.
response_tx: oneshot::Sender<Result<IncomingBlockOk, anyhow::Error>>,
},
}
/// The [`Ok`] response for an incoming block.
pub enum IncomingBlockOk {
/// The block was added to the main-chain.
AddedToMainChain,
/// The blockchain manager is not ready yet.
NotReady,
/// The block was added to an alt-chain.
AddedToAltChain,
/// We already have the block.
AlreadyHave,
}

View file

@ -0,0 +1,484 @@
//! The blockchain manager handler functions.
use bytes::Bytes;
use futures::{TryFutureExt, TryStreamExt};
use monero_serai::{block::Block, transaction::Transaction};
use rayon::prelude::*;
use std::ops::ControlFlow;
use std::{collections::HashMap, sync::Arc};
use tower::{Service, ServiceExt};
use tracing::info;
use cuprate_blockchain::service::{BlockchainReadHandle, BlockchainWriteHandle};
use cuprate_consensus::{
block::PreparedBlock, context::NewBlockData, transactions::new_tx_verification_data,
BlockChainContextRequest, BlockChainContextResponse, BlockVerifierService,
ExtendedConsensusError, VerifyBlockRequest, VerifyBlockResponse, VerifyTxRequest,
VerifyTxResponse,
};
use cuprate_helper::cast::usize_to_u64;
use cuprate_p2p::{block_downloader::BlockBatch, constants::LONG_BAN, BroadcastRequest};
use cuprate_types::{
blockchain::{BlockchainReadRequest, BlockchainResponse, BlockchainWriteRequest},
AltBlockInformation, HardFork, TransactionVerificationData, VerifiedBlockInformation,
};
use crate::blockchain::manager::commands::IncomingBlockOk;
use crate::{
blockchain::{
manager::commands::BlockchainManagerCommand, types::ConsensusBlockchainReadHandle,
},
constants::PANIC_CRITICAL_SERVICE_ERROR,
signals::REORG_LOCK,
};
impl super::BlockchainManager {
/// Handle an incoming command from another part of Cuprate.
///
/// # Panics
///
/// This function will panic if any internal service returns an unexpected error that we cannot
/// recover from.
pub async fn handle_command(&mut self, command: BlockchainManagerCommand) {
match command {
BlockchainManagerCommand::AddBlock {
block,
prepped_txs,
response_tx,
} => {
let res = self.handle_incoming_block(block, prepped_txs).await;
drop(response_tx.send(res));
}
}
}
/// Broadcast a valid block to the network.
async fn broadcast_block(&mut self, block_bytes: Bytes, blockchain_height: usize) {
self.broadcast_svc
.ready()
.await
.expect("Broadcast service is Infallible.")
.call(BroadcastRequest::Block {
block_bytes,
current_blockchain_height: usize_to_u64(blockchain_height),
})
.await
.expect("Broadcast service is Infallible.");
}
/// Handle an incoming [`Block`].
///
/// This function will route to [`Self::handle_incoming_alt_block`] if the block does not follow
/// the top of the main chain.
///
/// Otherwise, this function will validate and add the block to the main chain.
///
/// # Panics
///
/// This function will panic if any internal service returns an unexpected error that we cannot
/// recover from.
pub async fn handle_incoming_block(
&mut self,
block: Block,
prepared_txs: HashMap<[u8; 32], TransactionVerificationData>,
) -> Result<IncomingBlockOk, anyhow::Error> {
if block.header.previous != self.cached_blockchain_context.top_hash {
self.handle_incoming_alt_block(block, prepared_txs).await?;
return Ok(IncomingBlockOk::AddedToAltChain);
}
let VerifyBlockResponse::MainChain(verified_block) = self
.block_verifier_service
.ready()
.await
.expect(PANIC_CRITICAL_SERVICE_ERROR)
.call(VerifyBlockRequest::MainChain {
block,
prepared_txs,
})
.await?
else {
unreachable!();
};
let block_blob = Bytes::copy_from_slice(&verified_block.block_blob);
self.add_valid_block_to_main_chain(verified_block).await;
self.broadcast_block(block_blob, self.cached_blockchain_context.chain_height)
.await;
Ok(IncomingBlockOk::AddedToMainChain)
}
/// Handle an incoming [`BlockBatch`].
///
/// This function will route to [`Self::handle_incoming_block_batch_main_chain`] or [`Self::handle_incoming_block_batch_alt_chain`]
/// depending on if the first block in the batch follows from the top of our chain.
///
/// # Panics
///
/// This function will panic if the batch is empty or if any internal service returns an unexpected
/// error that we cannot recover from or if the incoming batch contains no blocks.
pub async fn handle_incoming_block_batch(&mut self, batch: BlockBatch) {
let (first_block, _) = batch
.blocks
.first()
.expect("Block batch should not be empty");
if first_block.header.previous == self.cached_blockchain_context.top_hash {
self.handle_incoming_block_batch_main_chain(batch).await;
} else {
self.handle_incoming_block_batch_alt_chain(batch).await;
}
}
/// Handles an incoming [`BlockBatch`] that follows the main chain.
///
/// This function will handle validating the blocks in the batch and adding them to the blockchain
/// database and context cache.
///
/// This function will also handle banning the peer and canceling the block downloader if the
/// block is invalid.
///
/// # Panics
///
/// This function will panic if any internal service returns an unexpected error that we cannot
/// recover from or if the incoming batch contains no blocks.
async fn handle_incoming_block_batch_main_chain(&mut self, batch: BlockBatch) {
info!(
"Handling batch to main chain height: {}",
batch.blocks.first().unwrap().0.number().unwrap()
);
let batch_prep_res = self
.block_verifier_service
.ready()
.await
.expect(PANIC_CRITICAL_SERVICE_ERROR)
.call(VerifyBlockRequest::MainChainBatchPrepareBlocks {
blocks: batch.blocks,
})
.await;
let prepped_blocks = match batch_prep_res {
Ok(VerifyBlockResponse::MainChainBatchPrepped(prepped_blocks)) => prepped_blocks,
Err(_) => {
batch.peer_handle.ban_peer(LONG_BAN);
self.stop_current_block_downloader.notify_one();
return;
}
_ => unreachable!(),
};
for (block, txs) in prepped_blocks {
let verify_res = self
.block_verifier_service
.ready()
.await
.expect(PANIC_CRITICAL_SERVICE_ERROR)
.call(VerifyBlockRequest::MainChainPrepped { block, txs })
.await;
let verified_block = match verify_res {
Ok(VerifyBlockResponse::MainChain(verified_block)) => verified_block,
Err(_) => {
batch.peer_handle.ban_peer(LONG_BAN);
self.stop_current_block_downloader.notify_one();
return;
}
_ => unreachable!(),
};
self.add_valid_block_to_main_chain(verified_block).await;
}
}
/// Handles an incoming [`BlockBatch`] that does not follow the main-chain.
///
/// This function will handle validating the alt-blocks to add them to our cache and reorging the
/// chain if the alt-chain has a higher cumulative difficulty.
///
/// This function will also handle banning the peer and canceling the block downloader if the
/// alt block is invalid or if a reorg fails.
///
/// # Panics
///
/// This function will panic if any internal service returns an unexpected error that we cannot
/// recover from.
async fn handle_incoming_block_batch_alt_chain(&mut self, mut batch: BlockBatch) {
// TODO: this needs testing (this whole section does but alt-blocks specifically).
let mut blocks = batch.blocks.into_iter();
while let Some((block, txs)) = blocks.next() {
// async blocks work as try blocks.
let res = async {
let txs = txs
.into_par_iter()
.map(|tx| {
let tx = new_tx_verification_data(tx)?;
Ok((tx.tx_hash, tx))
})
.collect::<Result<_, anyhow::Error>>()?;
let reorged = self.handle_incoming_alt_block(block, txs).await?;
Ok::<_, anyhow::Error>(reorged)
}
.await;
match res {
Err(e) => {
batch.peer_handle.ban_peer(LONG_BAN);
self.stop_current_block_downloader.notify_one();
return;
}
Ok(AddAltBlock::Reorged) => {
// Collect the remaining blocks and add them to the main chain instead.
batch.blocks = blocks.collect();
self.handle_incoming_block_batch_main_chain(batch).await;
return;
}
// continue adding alt blocks.
Ok(AddAltBlock::Cached) => (),
}
}
}
/// Handles an incoming alt [`Block`].
///
/// This function will do some pre-validation of the alt block, then if the cumulative difficulty
/// of the alt chain is higher than the main chain it will attempt a reorg otherwise it will add
/// the alt block to the alt block cache.
///
/// # Errors
///
/// This will return an [`Err`] if:
/// - The alt block was invalid.
/// - An attempt to reorg the chain failed.
///
/// # Panics
///
/// This function will panic if any internal service returns an unexpected error that we cannot
/// recover from.
async fn handle_incoming_alt_block(
&mut self,
block: Block,
prepared_txs: HashMap<[u8; 32], TransactionVerificationData>,
) -> Result<AddAltBlock, anyhow::Error> {
let VerifyBlockResponse::AltChain(alt_block_info) = self
.block_verifier_service
.ready()
.await
.expect(PANIC_CRITICAL_SERVICE_ERROR)
.call(VerifyBlockRequest::AltChain {
block,
prepared_txs,
})
.await?
else {
unreachable!();
};
// TODO: check in consensus crate if alt block with this hash already exists.
// If this alt chain
if alt_block_info.cumulative_difficulty
> self.cached_blockchain_context.cumulative_difficulty
{
self.try_do_reorg(alt_block_info).await?;
return Ok(AddAltBlock::Reorged);
}
self.blockchain_write_handle
.ready()
.await
.expect(PANIC_CRITICAL_SERVICE_ERROR)
.call(BlockchainWriteRequest::WriteAltBlock(alt_block_info))
.await?;
Ok(AddAltBlock::Cached)
}
/// Attempt a re-org with the given top block of the alt-chain.
///
/// This function will take a write lock on [`REORG_LOCK`] and then set up the blockchain database
/// and context cache to verify the alt-chain. It will then attempt to verify and add each block
/// in the alt-chain to the main-chain. Releasing the lock on [`REORG_LOCK`] when finished.
///
/// # Errors
///
/// This function will return an [`Err`] if the re-org was unsuccessful, if this happens the chain
/// will be returned back into its state it was at when then function was called.
///
/// # Panics
///
/// This function will panic if any internal service returns an unexpected error that we cannot
/// recover from.
async fn try_do_reorg(
&mut self,
top_alt_block: AltBlockInformation,
) -> Result<(), anyhow::Error> {
let _guard = REORG_LOCK.write().await;
let BlockchainResponse::AltBlocksInChain(mut alt_blocks) = self
.blockchain_read_handle
.ready()
.await
.expect(PANIC_CRITICAL_SERVICE_ERROR)
.call(BlockchainReadRequest::AltBlocksInChain(
top_alt_block.chain_id,
))
.await?
else {
unreachable!();
};
alt_blocks.push(top_alt_block);
let split_height = alt_blocks[0].height;
let current_main_chain_height = self.cached_blockchain_context.chain_height;
let BlockchainResponse::PopBlocks(old_main_chain_id) = self
.blockchain_write_handle
.ready()
.await
.expect(PANIC_CRITICAL_SERVICE_ERROR)
.call(BlockchainWriteRequest::PopBlocks(
current_main_chain_height - split_height + 1,
))
.await
.expect(PANIC_CRITICAL_SERVICE_ERROR)
else {
unreachable!();
};
self.blockchain_context_service
.ready()
.await
.expect(PANIC_CRITICAL_SERVICE_ERROR)
.call(BlockChainContextRequest::PopBlocks {
numb_blocks: current_main_chain_height - split_height + 1,
})
.await
.expect(PANIC_CRITICAL_SERVICE_ERROR);
let reorg_res = self.verify_add_alt_blocks_to_main_chain(alt_blocks).await;
match reorg_res {
Ok(()) => Ok(()),
Err(e) => {
todo!("Reverse reorg")
}
}
}
/// Verify and add a list of [`AltBlockInformation`]s to the main-chain.
///
/// This function assumes the first [`AltBlockInformation`] is the next block in the blockchain
/// for the blockchain database and the context cache, or in other words that the blockchain database
/// and context cache have already had the top blocks popped to where the alt-chain meets the main-chain.
///
/// # Errors
///
/// This function will return an [`Err`] if the alt-blocks were invalid, in this case the re-org should
/// be aborted and the chain should be returned to its previous state.
///
/// # Panics
///
/// This function will panic if any internal service returns an unexpected error that we cannot
/// recover from.
async fn verify_add_alt_blocks_to_main_chain(
&mut self,
alt_blocks: Vec<AltBlockInformation>,
) -> Result<(), anyhow::Error> {
for mut alt_block in alt_blocks {
let prepped_txs = alt_block
.txs
.drain(..)
.map(|tx| Ok(Arc::new(tx.try_into()?)))
.collect::<Result<_, anyhow::Error>>()?;
let prepped_block = PreparedBlock::new_alt_block(alt_block)?;
let VerifyBlockResponse::MainChain(verified_block) = self
.block_verifier_service
.ready()
.await
.expect(PANIC_CRITICAL_SERVICE_ERROR)
.call(VerifyBlockRequest::MainChainPrepped {
block: prepped_block,
txs: prepped_txs,
})
.await?
else {
unreachable!();
};
self.add_valid_block_to_main_chain(verified_block).await;
}
Ok(())
}
/// Adds a [`VerifiedBlockInformation`] to the main-chain.
///
/// This function will update the blockchain database and the context cache, it will also
/// update [`Self::cached_blockchain_context`].
///
/// # Panics
///
/// This function will panic if any internal service returns an unexpected error that we cannot
/// recover from.
pub async fn add_valid_block_to_main_chain(
&mut self,
verified_block: VerifiedBlockInformation,
) {
self.blockchain_context_service
.ready()
.await
.expect(PANIC_CRITICAL_SERVICE_ERROR)
.call(BlockChainContextRequest::Update(NewBlockData {
block_hash: verified_block.block_hash,
height: verified_block.height,
timestamp: verified_block.block.header.timestamp,
weight: verified_block.weight,
long_term_weight: verified_block.long_term_weight,
generated_coins: verified_block.generated_coins,
vote: HardFork::from_vote(verified_block.block.header.hardfork_signal),
cumulative_difficulty: verified_block.cumulative_difficulty,
}))
.await
.expect(PANIC_CRITICAL_SERVICE_ERROR);
self.blockchain_write_handle
.ready()
.await
.expect(PANIC_CRITICAL_SERVICE_ERROR)
.call(BlockchainWriteRequest::WriteBlock(verified_block))
.await
.expect(PANIC_CRITICAL_SERVICE_ERROR);
let BlockChainContextResponse::Context(blockchain_context) = self
.blockchain_context_service
.ready()
.await
.expect(PANIC_CRITICAL_SERVICE_ERROR)
.call(BlockChainContextRequest::GetContext)
.await
.expect(PANIC_CRITICAL_SERVICE_ERROR)
else {
unreachable!();
};
self.cached_blockchain_context = blockchain_context.unchecked_blockchain_context().clone();
}
}
/// The result from successfully adding an alt-block.
enum AddAltBlock {
/// The alt-block was cached.
Cached,
/// The chain was reorged.
Reorged,
}

View file

@ -1 +1,143 @@
// FIXME: This whole module is not great and should be rewritten when the PeerSet is made.
use std::{pin::pin, sync::Arc, time::Duration};
use futures::StreamExt;
use tokio::time::interval;
use tokio::{
sync::{mpsc, Notify},
time::sleep,
};
use tower::{Service, ServiceExt};
use tracing::instrument;
use cuprate_consensus::{BlockChainContext, BlockChainContextRequest, BlockChainContextResponse};
use cuprate_p2p::{
block_downloader::{BlockBatch, BlockDownloaderConfig, ChainSvcRequest, ChainSvcResponse},
NetworkInterface,
};
use cuprate_p2p_core::ClearNet;
const CHECK_SYNC_FREQUENCY: Duration = Duration::from_secs(30);
/// An error returned from the [`syncer`].
#[derive(Debug, thiserror::Error)]
pub enum SyncerError {
#[error("Incoming block channel closed.")]
IncomingBlockChannelClosed,
#[error("One of our services returned an error: {0}.")]
ServiceError(#[from] tower::BoxError),
}
/// The syncer tasks that makes sure we are fully synchronised with our connected peers.
#[expect(
clippy::significant_drop_tightening,
reason = "Client pool which will be removed"
)]
#[instrument(level = "debug", skip_all)]
pub async fn syncer<C, CN>(
mut context_svc: C,
our_chain: CN,
clearnet_interface: NetworkInterface<ClearNet>,
incoming_block_batch_tx: mpsc::Sender<BlockBatch>,
stop_current_block_downloader: Arc<Notify>,
block_downloader_config: BlockDownloaderConfig,
) -> Result<(), SyncerError>
where
C: Service<
BlockChainContextRequest,
Response = BlockChainContextResponse,
Error = tower::BoxError,
>,
C::Future: Send + 'static,
CN: Service<ChainSvcRequest, Response = ChainSvcResponse, Error = tower::BoxError>
+ Clone
+ Send
+ 'static,
CN::Future: Send + 'static,
{
tracing::info!("Starting blockchain syncer");
let mut check_sync_interval = interval(CHECK_SYNC_FREQUENCY);
let BlockChainContextResponse::Context(mut blockchain_ctx) = context_svc
.ready()
.await?
.call(BlockChainContextRequest::GetContext)
.await?
else {
unreachable!();
};
let client_pool = clearnet_interface.client_pool();
tracing::debug!("Waiting for new sync info in top sync channel");
loop {
check_sync_interval.tick().await;
tracing::trace!("Checking connected peers to see if we are behind",);
check_update_blockchain_context(&mut context_svc, &mut blockchain_ctx).await?;
let raw_blockchain_context = blockchain_ctx.unchecked_blockchain_context();
if !client_pool.contains_client_with_more_cumulative_difficulty(
raw_blockchain_context.cumulative_difficulty,
) {
continue;
}
tracing::debug!(
"We are behind peers claimed cumulative difficulty, starting block downloader"
);
let mut block_batch_stream =
clearnet_interface.block_downloader(our_chain.clone(), block_downloader_config);
loop {
tokio::select! {
() = stop_current_block_downloader.notified() => {
tracing::info!("Stopping block downloader");
break;
}
batch = block_batch_stream.next() => {
let Some(batch) = batch else {
break;
};
tracing::debug!("Got batch, len: {}", batch.blocks.len());
if incoming_block_batch_tx.send(batch).await.is_err() {
return Err(SyncerError::IncomingBlockChannelClosed);
}
}
}
}
}
}
/// Checks if we should update the given [`BlockChainContext`] and updates it if needed.
async fn check_update_blockchain_context<C>(
context_svc: C,
old_context: &mut BlockChainContext,
) -> Result<(), tower::BoxError>
where
C: Service<
BlockChainContextRequest,
Response = BlockChainContextResponse,
Error = tower::BoxError,
>,
C::Future: Send + 'static,
{
if old_context.blockchain_context().is_ok() {
return Ok(());
}
let BlockChainContextResponse::Context(ctx) = context_svc
.oneshot(BlockChainContextRequest::GetContext)
.await?
else {
unreachable!();
};
*old_context = ctx;
Ok(())
}

View file

@ -0,0 +1,24 @@
use std::task::{Context, Poll};
use futures::future::BoxFuture;
use futures::{FutureExt, TryFutureExt};
use tower::{util::MapErr, Service};
use cuprate_blockchain::{cuprate_database::RuntimeError, service::BlockchainReadHandle};
use cuprate_consensus::{BlockChainContextService, BlockVerifierService, TxVerifierService};
use cuprate_p2p::block_downloader::{ChainSvcRequest, ChainSvcResponse};
use cuprate_types::blockchain::{BlockchainReadRequest, BlockchainResponse};
/// The [`BlockVerifierService`] with all generic types defined.
pub type ConcreteBlockVerifierService = BlockVerifierService<
BlockChainContextService,
ConcreteTxVerifierService,
ConsensusBlockchainReadHandle,
>;
/// The [`TxVerifierService`] with all generic types defined.
pub type ConcreteTxVerifierService = TxVerifierService<ConsensusBlockchainReadHandle>;
/// The [`BlockchainReadHandle`] with the [`tower::Service::Error`] mapped to conform to what the consensus crate requires.
pub type ConsensusBlockchainReadHandle =
MapErr<BlockchainReadHandle, fn(RuntimeError) -> tower::BoxError>;

View file

@ -14,6 +14,10 @@ pub const VERSION_BUILD: &str = if cfg!(debug_assertions) {
formatcp!("{VERSION}-release")
};
/// The panic message used when cuprated encounters a critical service error.
pub const PANIC_CRITICAL_SERVICE_ERROR: &str =
"A service critical to Cuprate's function returned an unexpected error.";
#[cfg(test)]
mod test {
use super::*;

View file

@ -16,6 +16,7 @@ mod config;
mod constants;
mod p2p;
mod rpc;
mod signals;
mod statics;
mod txpool;

View file

@ -2,4 +2,4 @@
//!
//! Will handle initiating the P2P and contains a protocol request handler.
mod request_handler;
pub mod request_handler;

View file

@ -0,0 +1,12 @@
//! Signals for Cuprate state used throughout the binary.
use tokio::sync::RwLock;
/// Reorg lock.
///
/// A [`RwLock`] where a write lock is taken during a reorg and a read lock can be taken
/// for any operation which must complete without a reorg happening.
///
/// Currently, the only operation that needs to take a read lock is adding txs to the tx-pool,
/// this can potentially be removed in the future, see: <https://github.com/Cuprate/cuprate/issues/305>
pub static REORG_LOCK: RwLock<()> = RwLock::const_new(());

View file

@ -123,7 +123,7 @@ impl PreparedBlock {
///
/// The randomX VM must be Some if RX is needed or this will panic.
/// The randomX VM must also be initialised with the correct seed.
fn new<R: RandomX>(block: Block, randomx_vm: Option<&R>) -> Result<Self, ConsensusError> {
pub fn new<R: RandomX>(block: Block, randomx_vm: Option<&R>) -> Result<Self, ConsensusError> {
let (hf_version, hf_vote) = HardFork::from_block_header(&block.header)
.map_err(|_| BlockError::HardForkError(HardForkError::HardForkUnknown))?;
@ -180,6 +180,20 @@ impl PreparedBlock {
block: block.block,
})
}
/// Creates a new [`PreparedBlock`] from an [`AltBlockInformation`].
pub fn new_alt_block(block: AltBlockInformation) -> Result<Self, ConsensusError> {
Ok(Self {
block_blob: block.block_blob,
hf_vote: HardFork::from_version(block.block.header.hardfork_version)
.map_err(|_| BlockError::HardForkError(HardForkError::HardForkUnknown))?,
hf_version: HardFork::from_vote(block.block.header.hardfork_signal),
block_hash: block.block_hash,
pow_hash: block.pow_hash,
miner_tx_weight: block.block.miner_transaction.weight(),
block: block.block,
})
}
}
/// A request to verify a block.
@ -246,7 +260,7 @@ where
+ Clone
+ Send
+ 'static,
D: Database + Clone + Send + Sync + 'static,
D: Database + Clone + Send + 'static,
D::Future: Send + 'static,
{
/// Creates a new block verifier.
@ -276,7 +290,7 @@ where
+ 'static,
TxV::Future: Send + 'static,
D: Database + Clone + Send + Sync + 'static,
D: Database + Clone + Send + 'static,
D::Future: Send + 'static,
{
type Response = VerifyBlockResponse;

View file

@ -37,6 +37,7 @@ pub use context::{
pub use transactions::{TxVerifierService, VerifyTxRequest, VerifyTxResponse};
// re-export.
pub use cuprate_consensus_rules::genesis::generate_genesis_block;
pub use cuprate_types::{
blockchain::{BlockchainReadRequest, BlockchainResponse},
HardFork,
@ -64,17 +65,13 @@ pub enum ExtendedConsensusError {
}
/// Initialize the 2 verifier [`tower::Service`]s (block and transaction).
#[expect(clippy::type_complexity)]
pub fn initialize_verifier<D, Ctx>(
database: D,
ctx_svc: Ctx,
) -> Result<
(
BlockVerifierService<Ctx, TxVerifierService<D>, D>,
TxVerifierService<D>,
),
ConsensusError,
>
) -> (
BlockVerifierService<Ctx, TxVerifierService<D>, D>,
TxVerifierService<D>,
)
where
D: Database + Clone + Send + Sync + 'static,
D::Future: Send + 'static,
@ -90,7 +87,7 @@ where
{
let tx_svc = TxVerifierService::new(database.clone());
let block_svc = BlockVerifierService::new(ctx_svc, tx_svc.clone(), database);
Ok((block_svc, tx_svc))
(block_svc, tx_svc)
}
use __private::Database;

View file

@ -4,14 +4,21 @@ version = "0.1.0"
edition = "2021"
description = "A wrapper around Monero's CryptoNight hash function."
license = "MIT"
authors = ["Boog900", "The Monero Project"]
authors = ["dimalinux", "Boog900", "The Monero Project"]
repository = "https://github.com/Cuprate/cuprate/tree/main/cryptonight"
[dependencies]
thiserror = "1"
[build-dependencies]
cc = "1"
thiserror = { workspace = true }
sha3 = "0.10.8"
groestl = "0.10.1"
skein = "0.1.0"
jh = "0.1.0"
keccak = "0.1.5"
digest = "0.10.7"
seq-macro = "0.3.5"
[dev-dependencies]
hex = "0.4"
hex = { workspace = true, features = ["std"] }
[lints]
workspace = true

View file

@ -1,52 +0,0 @@
extern crate cc;
use std::env;
use cc::Build;
fn main() {
let mut cfg = Build::new();
cfg.include("c")
.file("c/aesb.c")
.file("c/blake256.c")
.file("c/groestl.c")
.file("c/hash-extra-blake.c")
.file("c/hash-extra-groestl.c")
.file("c/hash-extra-jh.c")
.file("c/hash-extra-skein.c")
.file("c/hash.c")
.file("c/jh.c")
.file("c/keccak.c")
.file("c/oaes_lib.c")
.file("c/skein.c")
.file("c/memwipe.c")
.file("c/slow-hash.c")
.file("c/CryptonightR_JIT.c")
.flag_if_supported("-fexceptions")
// c/oaes_lib.c: In function oaes_get_seed:
// c/oaes_lib.c:515:9: warning: ftime is deprecated: Use gettimeofday or clock_gettime instead [-Wdeprecated-declarations]
// 515 | ftime (&timer);
// | ^~~~~
// In file included from c/oaes_lib.c:45:
// /usr/include/sys/timeb.h:29:12: note: declared here
// 29 | extern int ftime (struct timeb *__timebuf)
// | ^~~~~
// This flag doesn't work on MSVC and breaks CI.
.flag_if_supported("-Wno-deprecated-declarations")
// `#include <boost>` isn't found without this in macOS CI.
// <https://github.com/Cuprate/cuprate/pull/116>
.flag_if_supported("-I/opt/homebrew/include");
// Optimization flags are automatically added.
// https://docs.rs/cc/latest/cc/struct.Build.html#method.opt_level
let target = env::var("TARGET").unwrap();
if target.contains("x86_64") {
// FIXME: what are the equivalent flags for MSVC?
cfg.file("c/CryptonightR_template.S")
.flag_if_supported("-maes")
.flag_if_supported("-msse2");
}
cfg.compile("cryptonight")
}

View file

@ -1,123 +0,0 @@
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#if !(defined(_MSC_VER) || defined(__MINGW32__))
#include <sys/mman.h>
#endif
#include "int-util.h"
#include "hash-ops.h"
#include "variant4_random_math.h"
#include "CryptonightR_JIT.h"
#include "CryptonightR_template.h"
static const uint8_t prologue[] = {
#if defined __i386 || defined __x86_64__
0x4C, 0x8B, 0xD7, // mov r10, rdi
0x53, // push rbx
0x55, // push rbp
0x41, 0x57, // push r15
0x4C, 0x8B, 0xDC, // mov r11, rsp
0x41, 0x8B, 0x1A, // mov ebx, DWORD PTR [r10]
0x41, 0x8B, 0x72, 0x04, // mov esi, DWORD PTR [r10+4]
0x41, 0x8B, 0x7A, 0x08, // mov edi, DWORD PTR [r10+8]
0x41, 0x8B, 0x6A, 0x0C, // mov ebp, DWORD PTR [r10+12]
0x41, 0x8B, 0x62, 0x10, // mov esp, DWORD PTR [r10+16]
0x45, 0x8B, 0x7A, 0x14, // mov r15d, DWORD PTR [r10+20]
0x41, 0x8B, 0x42, 0x18, // mov eax, DWORD PTR [r10+24]
0x41, 0x8B, 0x52, 0x1C, // mov edx, DWORD PTR [r10+28]
0x45, 0x8B, 0x4A, 0x20, // mov r9d, DWORD PTR [r10+32]
#endif
};
static const uint8_t epilogue[] = {
#if defined __i386 || defined __x86_64__
0x49, 0x8B, 0xE3, // mov rsp, r11
0x41, 0x89, 0x1A, // mov DWORD PTR [r10], ebx
0x41, 0x89, 0x72, 0x04, // mov DWORD PTR [r10+4], esi
0x41, 0x89, 0x7A, 0x08, // mov DWORD PTR [r10+8], edi
0x41, 0x89, 0x6A, 0x0C, // mov DWORD PTR [r10+12], ebp
0x41, 0x5F, // pop r15
0x5D, // pop rbp
0x5B, // pop rbx
0xC3, // ret
#endif
};
#define APPEND_CODE(src, size) \
do { \
if (JIT_code + (size) > JIT_code_end) \
return -1; \
memcpy(JIT_code, (src), (size)); \
JIT_code += (size); \
} while (0)
int v4_generate_JIT_code(const struct V4_Instruction* code, v4_random_math_JIT_func buf, const size_t buf_size)
{
#if defined __i386 || defined __x86_64__
uint8_t* JIT_code = (uint8_t*) buf;
const uint8_t* JIT_code_end = JIT_code + buf_size;
#if !(defined(_MSC_VER) || defined(__MINGW32__))
if (mprotect((void*)buf, buf_size, PROT_READ | PROT_WRITE))
return -1;
#endif
APPEND_CODE(prologue, sizeof(prologue));
uint32_t prev_rot_src = 0xFFFFFFFFU;
for (int i = 0;; ++i)
{
const struct V4_Instruction inst = code[i];
if (inst.opcode == RET)
break;
const uint8_t opcode = (inst.opcode == MUL) ? inst.opcode : (inst.opcode + 2);
const uint32_t a = inst.dst_index;
const uint32_t b = inst.src_index;
const uint8_t c = opcode | (inst.dst_index << V4_OPCODE_BITS) | (((inst.src_index == 8) ? inst.dst_index : inst.src_index) << (V4_OPCODE_BITS + V4_DST_INDEX_BITS));
switch (inst.opcode)
{
case ROR:
case ROL:
if (b != prev_rot_src)
{
prev_rot_src = b;
const uint8_t* p1 = (const uint8_t*) instructions_mov[c];
const uint8_t* p2 = (const uint8_t*) instructions_mov[c + 1];
APPEND_CODE(p1, p2 - p1);
}
break;
}
if (a == prev_rot_src)
prev_rot_src = 0xFFFFFFFFU;
const uint8_t* p1 = (const uint8_t*) instructions[c];
const uint8_t* p2 = (const uint8_t*) instructions[c + 1];
APPEND_CODE(p1, p2 - p1);
if (inst.opcode == ADD)
*(uint32_t*)(JIT_code - 4) = inst.C;
}
APPEND_CODE(epilogue, sizeof(epilogue));
#if !(defined(_MSC_VER) || defined(__MINGW32__))
if (mprotect((void*)buf, buf_size, PROT_READ | PROT_EXEC))
return -1;
#endif
__builtin___clear_cache((char*)buf, (char*)JIT_code);
return 0;
#else
return -1;
#endif
}

View file

@ -1,22 +0,0 @@
#ifndef CRYPTONIGHTR_JIT_H
#define CRYPTONIGHTR_JIT_H
// Minimalistic JIT code generator for random math sequence in CryptonightR
//
// Usage:
// - Allocate writable and executable memory
// - Call v4_generate_JIT_code with "buf" pointed to memory allocated on previous step
// - Call the generated code instead of "v4_random_math(code, r)", omit the "code" parameter
typedef void (*v4_random_math_JIT_func)(uint32_t* r)
#if defined __i386 || defined __x86_64__
__attribute__((sysv_abi))
#endif
;
// Given the random math sequence, generates machine code (x86-64) for it
// Returns 0 if code was generated successfully
// Returns -1 if provided buffer was too small
int v4_generate_JIT_code(const struct V4_Instruction* code, v4_random_math_JIT_func buf, const size_t buf_size);
#endif // CRYPTONIGHTR_JIT_H

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,186 +0,0 @@
/*
---------------------------------------------------------------------------
Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved.
The redistribution and use of this software (with or without changes)
is allowed without the payment of fees or royalties provided that:
source code distributions include the above copyright notice, this
list of conditions and the following disclaimer;
binary distributions include the above copyright notice, this list
of conditions and the following disclaimer in their documentation.
This software is provided 'as is' with no explicit or implied warranties
in respect of its operation, including, but not limited to, correctness
and fitness for purpose.
---------------------------------------------------------------------------
Issue Date: 20/12/2007
*/
#include <stdint.h>
#include "int-util.h"
#if defined(__cplusplus)
extern "C"
{
#endif
#define TABLE_ALIGN 32
#define WPOLY 0x011b
#define N_COLS 4
#define AES_BLOCK_SIZE 16
#define RC_LENGTH (5 * (AES_BLOCK_SIZE / 4 - 2))
#if defined(_MSC_VER)
#define LOCAL_ALIGN __declspec(align(TABLE_ALIGN))
#elif defined(__GNUC__)
#define LOCAL_ALIGN __attribute__ ((aligned(16)))
#else
#define LOCAL_ALIGN
#endif
#define rf1(r,c) (r)
#define word_in(x,c) (*((uint32_t*)(x)+(c)))
#define word_out(x,c,v) (*((uint32_t*)(x)+(c)) = (v))
#define s(x,c) x[c]
#define si(y,x,c) (s(y,c) = word_in(x, c))
#define so(y,x,c) word_out(y, c, s(x,c))
#define state_in(y,x) si(y,x,0); si(y,x,1); si(y,x,2); si(y,x,3)
#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3)
#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3)
#define to_byte(x) ((x) & 0xff)
#define bval(x,n) to_byte(SWAP32LE(x) >> (8 * (n)))
#define fwd_var(x,r,c)\
( r == 0 ? ( c == 0 ? s(x,0) : c == 1 ? s(x,1) : c == 2 ? s(x,2) : s(x,3))\
: r == 1 ? ( c == 0 ? s(x,1) : c == 1 ? s(x,2) : c == 2 ? s(x,3) : s(x,0))\
: r == 2 ? ( c == 0 ? s(x,2) : c == 1 ? s(x,3) : c == 2 ? s(x,0) : s(x,1))\
: ( c == 0 ? s(x,3) : c == 1 ? s(x,0) : c == 2 ? s(x,1) : s(x,2)))
#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ SWAP32LE(four_tables(x,t_use(f,n),fwd_var,rf1,c)))
#define sb_data(w) {\
w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5),\
w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), w(0x76),\
w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), w(0x59), w(0x47), w(0xf0),\
w(0xad), w(0xd4), w(0xa2), w(0xaf), w(0x9c), w(0xa4), w(0x72), w(0xc0),\
w(0xb7), w(0xfd), w(0x93), w(0x26), w(0x36), w(0x3f), w(0xf7), w(0xcc),\
w(0x34), w(0xa5), w(0xe5), w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15),\
w(0x04), w(0xc7), w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a),\
w(0x07), w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75),\
w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), w(0xa0),\
w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), w(0x2f), w(0x84),\
w(0x53), w(0xd1), w(0x00), w(0xed), w(0x20), w(0xfc), w(0xb1), w(0x5b),\
w(0x6a), w(0xcb), w(0xbe), w(0x39), w(0x4a), w(0x4c), w(0x58), w(0xcf),\
w(0xd0), w(0xef), w(0xaa), w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85),\
w(0x45), w(0xf9), w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8),\
w(0x51), w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), w(0xf5),\
w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), w(0xd2),\
w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), w(0x44), w(0x17),\
w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), w(0x5d), w(0x19), w(0x73),\
w(0x60), w(0x81), w(0x4f), w(0xdc), w(0x22), w(0x2a), w(0x90), w(0x88),\
w(0x46), w(0xee), w(0xb8), w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb),\
w(0xe0), w(0x32), w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c),\
w(0xc2), w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), w(0x79),\
w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), w(0x4e), w(0xa9),\
w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), w(0xae), w(0x08),\
w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), w(0xa6), w(0xb4), w(0xc6),\
w(0xe8), w(0xdd), w(0x74), w(0x1f), w(0x4b), w(0xbd), w(0x8b), w(0x8a),\
w(0x70), w(0x3e), w(0xb5), w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e),\
w(0x61), w(0x35), w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e),\
w(0xe1), w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94),\
w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), w(0x28), w(0xdf),\
w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), w(0xe6), w(0x42), w(0x68),\
w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), w(0x54), w(0xbb), w(0x16) }
#define rc_data(w) {\
w(0x01), w(0x02), w(0x04), w(0x08), w(0x10),w(0x20), w(0x40), w(0x80),\
w(0x1b), w(0x36) }
#define bytes2word(b0, b1, b2, b3) (((uint32_t)(b3) << 24) | \
((uint32_t)(b2) << 16) | ((uint32_t)(b1) << 8) | (b0))
#define h0(x) (x)
#define w0(p) bytes2word(p, 0, 0, 0)
#define w1(p) bytes2word(0, p, 0, 0)
#define w2(p) bytes2word(0, 0, p, 0)
#define w3(p) bytes2word(0, 0, 0, p)
#define u0(p) bytes2word(f2(p), p, p, f3(p))
#define u1(p) bytes2word(f3(p), f2(p), p, p)
#define u2(p) bytes2word(p, f3(p), f2(p), p)
#define u3(p) bytes2word(p, p, f3(p), f2(p))
#define v0(p) bytes2word(fe(p), f9(p), fd(p), fb(p))
#define v1(p) bytes2word(fb(p), fe(p), f9(p), fd(p))
#define v2(p) bytes2word(fd(p), fb(p), fe(p), f9(p))
#define v3(p) bytes2word(f9(p), fd(p), fb(p), fe(p))
#define f2(x) ((x<<1) ^ (((x>>7) & 1) * WPOLY))
#define f4(x) ((x<<2) ^ (((x>>6) & 1) * WPOLY) ^ (((x>>6) & 2) * WPOLY))
#define f8(x) ((x<<3) ^ (((x>>5) & 1) * WPOLY) ^ (((x>>5) & 2) * WPOLY) ^ (((x>>5) & 4) * WPOLY))
#define f3(x) (f2(x) ^ x)
#define f9(x) (f8(x) ^ x)
#define fb(x) (f8(x) ^ f2(x) ^ x)
#define fd(x) (f8(x) ^ f4(x) ^ x)
#define fe(x) (f8(x) ^ f4(x) ^ f2(x))
#define t_dec(m,n) t_##m##n
#define t_set(m,n) t_##m##n
#define t_use(m,n) t_##m##n
#define d_4(t,n,b,e,f,g,h) LOCAL_ALIGN const t n[4][256] = { b(e), b(f), b(g), b(h) }
#define four_tables(x,tab,vf,rf,c) \
(tab[0][bval(vf(x,0,c),rf(0,c))] \
^ tab[1][bval(vf(x,1,c),rf(1,c))] \
^ tab[2][bval(vf(x,2,c),rf(2,c))] \
^ tab[3][bval(vf(x,3,c),rf(3,c))])
d_4(uint32_t, t_dec(f,n), sb_data, u0, u1, u2, u3);
#if !defined(STATIC)
#define STATIC
#endif
#if !defined(INLINE)
#define INLINE
#endif
STATIC INLINE void aesb_single_round(const uint8_t *in, uint8_t *out, uint8_t *expandedKey)
{
uint32_t b0[4], b1[4];
const uint32_t *kp = (uint32_t *) expandedKey;
state_in(b0, in);
round(fwd_rnd, b1, b0, kp);
state_out(out, b1);
}
STATIC INLINE void aesb_pseudo_round(const uint8_t *in, uint8_t *out, uint8_t *expandedKey)
{
uint32_t b0[4], b1[4];
const uint32_t *kp = (uint32_t *) expandedKey;
state_in(b0, in);
round(fwd_rnd, b1, b0, kp);
round(fwd_rnd, b0, b1, kp + 1 * N_COLS);
round(fwd_rnd, b1, b0, kp + 2 * N_COLS);
round(fwd_rnd, b0, b1, kp + 3 * N_COLS);
round(fwd_rnd, b1, b0, kp + 4 * N_COLS);
round(fwd_rnd, b0, b1, kp + 5 * N_COLS);
round(fwd_rnd, b1, b0, kp + 6 * N_COLS);
round(fwd_rnd, b0, b1, kp + 7 * N_COLS);
round(fwd_rnd, b1, b0, kp + 8 * N_COLS);
round(fwd_rnd, b0, b1, kp + 9 * N_COLS);
state_out(out, b0);
}
#if defined(__cplusplus)
}
#endif

View file

@ -1,356 +0,0 @@
// Copyright (c) 2014-2023, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
/*
* The blake256_* and blake224_* functions are largely copied from
* blake256_light.c and blake224_light.c from the BLAKE website:
*
* https://131002.net/blake/
*
* The hmac_* functions implement HMAC-BLAKE-256 and HMAC-BLAKE-224.
* HMAC is specified by RFC 2104.
*/
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include "memwipe.h"
#include "blake256.h"
#define U8TO32(p) \
(((uint32_t)((p)[0]) << 24) | ((uint32_t)((p)[1]) << 16) | \
((uint32_t)((p)[2]) << 8) | ((uint32_t)((p)[3]) ))
#define U32TO8(p, v) \
(p)[0] = (uint8_t)((v) >> 24); (p)[1] = (uint8_t)((v) >> 16); \
(p)[2] = (uint8_t)((v) >> 8); (p)[3] = (uint8_t)((v) );
const uint8_t sigma[][16] = {
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15},
{14,10, 4, 8, 9,15,13, 6, 1,12, 0, 2,11, 7, 5, 3},
{11, 8,12, 0, 5, 2,15,13,10,14, 3, 6, 7, 1, 9, 4},
{ 7, 9, 3, 1,13,12,11,14, 2, 6, 5,10, 4, 0,15, 8},
{ 9, 0, 5, 7, 2, 4,10,15,14, 1,11,12, 6, 8, 3,13},
{ 2,12, 6,10, 0,11, 8, 3, 4,13, 7, 5,15,14, 1, 9},
{12, 5, 1,15,14,13, 4,10, 0, 7, 6, 3, 9, 2, 8,11},
{13,11, 7,14,12, 1, 3, 9, 5, 0,15, 4, 8, 6, 2,10},
{ 6,15,14, 9,11, 3, 0, 8,12, 2,13, 7, 1, 4,10, 5},
{10, 2, 8, 4, 7, 6, 1, 5,15,11, 9,14, 3,12,13, 0},
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15},
{14,10, 4, 8, 9,15,13, 6, 1,12, 0, 2,11, 7, 5, 3},
{11, 8,12, 0, 5, 2,15,13,10,14, 3, 6, 7, 1, 9, 4},
{ 7, 9, 3, 1,13,12,11,14, 2, 6, 5,10, 4, 0,15, 8}
};
const uint32_t cst[16] = {
0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344,
0xA4093822, 0x299F31D0, 0x082EFA98, 0xEC4E6C89,
0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C,
0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917
};
static const uint8_t padding[] = {
0x80,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,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
};
void blake256_compress(state *S, const uint8_t *block) {
uint32_t v[16], m[16], i;
#define ROT(x,n) (((x)<<(32-n))|((x)>>(n)))
#define G(a,b,c,d,e) \
v[a] += (m[sigma[i][e]] ^ cst[sigma[i][e+1]]) + v[b]; \
v[d] = ROT(v[d] ^ v[a],16); \
v[c] += v[d]; \
v[b] = ROT(v[b] ^ v[c],12); \
v[a] += (m[sigma[i][e+1]] ^ cst[sigma[i][e]])+v[b]; \
v[d] = ROT(v[d] ^ v[a], 8); \
v[c] += v[d]; \
v[b] = ROT(v[b] ^ v[c], 7);
for (i = 0; i < 16; ++i) m[i] = U8TO32(block + i * 4);
for (i = 0; i < 8; ++i) v[i] = S->h[i];
v[ 8] = S->s[0] ^ 0x243F6A88;
v[ 9] = S->s[1] ^ 0x85A308D3;
v[10] = S->s[2] ^ 0x13198A2E;
v[11] = S->s[3] ^ 0x03707344;
v[12] = 0xA4093822;
v[13] = 0x299F31D0;
v[14] = 0x082EFA98;
v[15] = 0xEC4E6C89;
if (S->nullt == 0) {
v[12] ^= S->t[0];
v[13] ^= S->t[0];
v[14] ^= S->t[1];
v[15] ^= S->t[1];
}
for (i = 0; i < 14; ++i) {
G(0, 4, 8, 12, 0);
G(1, 5, 9, 13, 2);
G(2, 6, 10, 14, 4);
G(3, 7, 11, 15, 6);
G(3, 4, 9, 14, 14);
G(2, 7, 8, 13, 12);
G(0, 5, 10, 15, 8);
G(1, 6, 11, 12, 10);
}
for (i = 0; i < 16; ++i) S->h[i % 8] ^= v[i];
for (i = 0; i < 8; ++i) S->h[i] ^= S->s[i % 4];
}
void blake256_init(state *S) {
S->h[0] = 0x6A09E667;
S->h[1] = 0xBB67AE85;
S->h[2] = 0x3C6EF372;
S->h[3] = 0xA54FF53A;
S->h[4] = 0x510E527F;
S->h[5] = 0x9B05688C;
S->h[6] = 0x1F83D9AB;
S->h[7] = 0x5BE0CD19;
S->t[0] = S->t[1] = S->buflen = S->nullt = 0;
S->s[0] = S->s[1] = S->s[2] = S->s[3] = 0;
}
void blake224_init(state *S) {
S->h[0] = 0xC1059ED8;
S->h[1] = 0x367CD507;
S->h[2] = 0x3070DD17;
S->h[3] = 0xF70E5939;
S->h[4] = 0xFFC00B31;
S->h[5] = 0x68581511;
S->h[6] = 0x64F98FA7;
S->h[7] = 0xBEFA4FA4;
S->t[0] = S->t[1] = S->buflen = S->nullt = 0;
S->s[0] = S->s[1] = S->s[2] = S->s[3] = 0;
}
// datalen = number of bits
void blake256_update(state *S, const uint8_t *data, uint64_t datalen) {
int left = S->buflen >> 3;
int fill = 64 - left;
if (left && (((datalen >> 3)) >= (unsigned) fill)) {
memcpy((void *) (S->buf + left), (void *) data, fill);
S->t[0] += 512;
if (S->t[0] == 0) S->t[1]++;
blake256_compress(S, S->buf);
data += fill;
datalen -= (fill << 3);
left = 0;
}
while (datalen >= 512) {
S->t[0] += 512;
if (S->t[0] == 0) S->t[1]++;
blake256_compress(S, data);
data += 64;
datalen -= 512;
}
if (datalen > 0) {
memcpy((void *) (S->buf + left), (void *) data, datalen >> 3);
S->buflen = (left << 3) + datalen;
} else {
S->buflen = 0;
}
}
// datalen = number of bits
void blake224_update(state *S, const uint8_t *data, uint64_t datalen) {
blake256_update(S, data, datalen);
}
void blake256_final_h(state *S, uint8_t *digest, uint8_t pa, uint8_t pb) {
uint8_t msglen[8];
uint32_t lo = S->t[0] + S->buflen, hi = S->t[1];
if (lo < (unsigned) S->buflen) hi++;
U32TO8(msglen + 0, hi);
U32TO8(msglen + 4, lo);
if (S->buflen == 440) { /* one padding byte */
S->t[0] -= 8;
blake256_update(S, &pa, 8);
} else {
if (S->buflen < 440) { /* enough space to fill the block */
if (S->buflen == 0) S->nullt = 1;
S->t[0] -= 440 - S->buflen;
blake256_update(S, padding, 440 - S->buflen);
} else { /* need 2 compressions */
S->t[0] -= 512 - S->buflen;
blake256_update(S, padding, 512 - S->buflen);
S->t[0] -= 440;
blake256_update(S, padding + 1, 440);
S->nullt = 1;
}
blake256_update(S, &pb, 8);
S->t[0] -= 8;
}
S->t[0] -= 64;
blake256_update(S, msglen, 64);
U32TO8(digest + 0, S->h[0]);
U32TO8(digest + 4, S->h[1]);
U32TO8(digest + 8, S->h[2]);
U32TO8(digest + 12, S->h[3]);
U32TO8(digest + 16, S->h[4]);
U32TO8(digest + 20, S->h[5]);
U32TO8(digest + 24, S->h[6]);
U32TO8(digest + 28, S->h[7]);
}
void blake256_final(state *S, uint8_t *digest) {
blake256_final_h(S, digest, 0x81, 0x01);
}
void blake224_final(state *S, uint8_t *digest) {
blake256_final_h(S, digest, 0x80, 0x00);
}
// inlen = number of bytes
void blake256_hash(uint8_t *out, const uint8_t *in, uint64_t inlen) {
state S;
blake256_init(&S);
blake256_update(&S, in, inlen * 8);
blake256_final(&S, out);
}
// inlen = number of bytes
void blake224_hash(uint8_t *out, const uint8_t *in, uint64_t inlen) {
state S;
blake224_init(&S);
blake224_update(&S, in, inlen * 8);
blake224_final(&S, out);
}
// keylen = number of bytes
void hmac_blake256_init(hmac_state *S, const uint8_t *_key, uint64_t keylen) {
const uint8_t *key = _key;
uint8_t keyhash[32];
uint8_t pad[64];
uint64_t i;
if (keylen > 64) {
blake256_hash(keyhash, key, keylen);
key = keyhash;
keylen = 32;
}
blake256_init(&S->inner);
memset(pad, 0x36, 64);
for (i = 0; i < keylen; ++i) {
pad[i] ^= key[i];
}
blake256_update(&S->inner, pad, 512);
blake256_init(&S->outer);
memset(pad, 0x5c, 64);
for (i = 0; i < keylen; ++i) {
pad[i] ^= key[i];
}
blake256_update(&S->outer, pad, 512);
memwipe(keyhash, sizeof(keyhash));
}
// keylen = number of bytes
void hmac_blake224_init(hmac_state *S, const uint8_t *_key, uint64_t keylen) {
const uint8_t *key = _key;
uint8_t keyhash[32];
uint8_t pad[64];
uint64_t i;
if (keylen > 64) {
blake256_hash(keyhash, key, keylen);
key = keyhash;
keylen = 28;
}
blake224_init(&S->inner);
memset(pad, 0x36, 64);
for (i = 0; i < keylen; ++i) {
pad[i] ^= key[i];
}
blake224_update(&S->inner, pad, 512);
blake224_init(&S->outer);
memset(pad, 0x5c, 64);
for (i = 0; i < keylen; ++i) {
pad[i] ^= key[i];
}
blake224_update(&S->outer, pad, 512);
memwipe(keyhash, sizeof(keyhash));
}
// datalen = number of bits
void hmac_blake256_update(hmac_state *S, const uint8_t *data, uint64_t datalen) {
// update the inner state
blake256_update(&S->inner, data, datalen);
}
// datalen = number of bits
void hmac_blake224_update(hmac_state *S, const uint8_t *data, uint64_t datalen) {
// update the inner state
blake224_update(&S->inner, data, datalen);
}
void hmac_blake256_final(hmac_state *S, uint8_t *digest) {
uint8_t ihash[32];
blake256_final(&S->inner, ihash);
blake256_update(&S->outer, ihash, 256);
blake256_final(&S->outer, digest);
memwipe(ihash, sizeof(ihash));
}
void hmac_blake224_final(hmac_state *S, uint8_t *digest) {
uint8_t ihash[32];
blake224_final(&S->inner, ihash);
blake224_update(&S->outer, ihash, 224);
blake224_final(&S->outer, digest);
memwipe(ihash, sizeof(ihash));
}
// keylen = number of bytes; inlen = number of bytes
void hmac_blake256_hash(uint8_t *out, const uint8_t *key, uint64_t keylen, const uint8_t *in, uint64_t inlen) {
hmac_state S;
hmac_blake256_init(&S, key, keylen);
hmac_blake256_update(&S, in, inlen * 8);
hmac_blake256_final(&S, out);
}
// keylen = number of bytes; inlen = number of bytes
void hmac_blake224_hash(uint8_t *out, const uint8_t *key, uint64_t keylen, const uint8_t *in, uint64_t inlen) {
hmac_state S;
hmac_blake224_init(&S, key, keylen);
hmac_blake224_update(&S, in, inlen * 8);
hmac_blake224_final(&S, out);
}

View file

@ -1,73 +0,0 @@
// Copyright (c) 2014-2023, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#ifndef _BLAKE256_H_
#define _BLAKE256_H_
#include <stdint.h>
typedef struct {
uint32_t h[8], s[4], t[2];
int buflen, nullt;
uint8_t buf[64];
} state;
typedef struct {
state inner;
state outer;
} hmac_state;
void blake256_init(state *);
void blake224_init(state *);
void blake256_update(state *, const uint8_t *, uint64_t);
void blake224_update(state *, const uint8_t *, uint64_t);
void blake256_final(state *, uint8_t *);
void blake224_final(state *, uint8_t *);
void blake256_hash(uint8_t *, const uint8_t *, uint64_t);
void blake224_hash(uint8_t *, const uint8_t *, uint64_t);
/* HMAC functions: */
void hmac_blake256_init(hmac_state *, const uint8_t *, uint64_t);
void hmac_blake224_init(hmac_state *, const uint8_t *, uint64_t);
void hmac_blake256_update(hmac_state *, const uint8_t *, uint64_t);
void hmac_blake224_update(hmac_state *, const uint8_t *, uint64_t);
void hmac_blake256_final(hmac_state *, uint8_t *);
void hmac_blake224_final(hmac_state *, uint8_t *);
void hmac_blake256_hash(uint8_t *, const uint8_t *, uint64_t, const uint8_t *, uint64_t);
void hmac_blake224_hash(uint8_t *, const uint8_t *, uint64_t, const uint8_t *, uint64_t);
#endif /* _BLAKE256_H_ */

View file

@ -1,879 +0,0 @@
// Copyright (c) 2014-2023, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#include <stdint.h>
#include "crypto-ops.h"
/* sqrt(x) is such an integer y that 0 <= y <= p - 1, y % 2 = 0, and y^2 = x (mod p). */
/* d = -121665 / 121666 */
const fe fe_d = {-10913610, 13857413, -15372611, 6949391, 114729, -8787816, -6275908, -3247719, -18696448, -12055116}; /* d */
const fe fe_sqrtm1 = {-32595792, -7943725, 9377950, 3500415, 12389472, -272473, -25146209, -2005654, 326686, 11406482}; /* sqrt(-1) */
const fe fe_d2 = {-21827239, -5839606, -30745221, 13898782, 229458, 15978800, -12551817, -6495438, 29715968, 9444199}; /* 2 * d */
/* base[i][j] = (j+1)*256^i*B */
const ge_precomp ge_base[32][8] = {
{
{{25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605},
{-12545711, 934262, -2722910, 3049990, -727428, 9406986, 12720692, 5043384, 19500929, -15469378},
{-8738181, 4489570, 9688441, -14785194, 10184609, -12363380, 29287919, 11864899, -24514362, -4438546}},
{{-12815894, -12976347, -21581243, 11784320, -25355658, -2750717, -11717903, -3814571, -358445, -10211303},
{-21703237, 6903825, 27185491, 6451973, -29577724, -9554005, -15616551, 11189268, -26829678, -5319081},
{26966642, 11152617, 32442495, 15396054, 14353839, -12752335, -3128826, -9541118, -15472047, -4166697}},
{{15636291, -9688557, 24204773, -7912398, 616977, -16685262, 27787600, -14772189, 28944400, -1550024},
{16568933, 4717097, -11556148, -1102322, 15682896, -11807043, 16354577, -11775962, 7689662, 11199574},
{30464156, -5976125, -11779434, -15670865, 23220365, 15915852, 7512774, 10017326, -17749093, -9920357}},
{{-17036878, 13921892, 10945806, -6033431, 27105052, -16084379, -28926210, 15006023, 3284568, -6276540},
{23599295, -8306047, -11193664, -7687416, 13236774, 10506355, 7464579, 9656445, 13059162, 10374397},
{7798556, 16710257, 3033922, 2874086, 28997861, 2835604, 32406664, -3839045, -641708, -101325}},
{{10861363, 11473154, 27284546, 1981175, -30064349, 12577861, 32867885, 14515107, -15438304, 10819380},
{4708026, 6336745, 20377586, 9066809, -11272109, 6594696, -25653668, 12483688, -12668491, 5581306},
{19563160, 16186464, -29386857, 4097519, 10237984, -4348115, 28542350, 13850243, -23678021, -15815942}},
{{-15371964, -12862754, 32573250, 4720197, -26436522, 5875511, -19188627, -15224819, -9818940, -12085777},
{-8549212, 109983, 15149363, 2178705, 22900618, 4543417, 3044240, -15689887, 1762328, 14866737},
{-18199695, -15951423, -10473290, 1707278, -17185920, 3916101, -28236412, 3959421, 27914454, 4383652}},
{{5153746, 9909285, 1723747, -2777874, 30523605, 5516873, 19480852, 5230134, -23952439, -15175766},
{-30269007, -3463509, 7665486, 10083793, 28475525, 1649722, 20654025, 16520125, 30598449, 7715701},
{28881845, 14381568, 9657904, 3680757, -20181635, 7843316, -31400660, 1370708, 29794553, -1409300}},
{{14499471, -2729599, -33191113, -4254652, 28494862, 14271267, 30290735, 10876454, -33154098, 2381726},
{-7195431, -2655363, -14730155, 462251, -27724326, 3941372, -6236617, 3696005, -32300832, 15351955},
{27431194, 8222322, 16448760, -3907995, -18707002, 11938355, -32961401, -2970515, 29551813, 10109425}}
}, {
{{-13657040, -13155431, -31283750, 11777098, 21447386, 6519384, -2378284, -1627556, 10092783, -4764171},
{27939166, 14210322, 4677035, 16277044, -22964462, -12398139, -32508754, 12005538, -17810127, 12803510},
{17228999, -15661624, -1233527, 300140, -1224870, -11714777, 30364213, -9038194, 18016357, 4397660}},
{{-10958843, -7690207, 4776341, -14954238, 27850028, -15602212, -26619106, 14544525, -17477504, 982639},
{29253598, 15796703, -2863982, -9908884, 10057023, 3163536, 7332899, -4120128, -21047696, 9934963},
{5793303, 16271923, -24131614, -10116404, 29188560, 1206517, -14747930, 4559895, -30123922, -10897950}},
{{-27643952, -11493006, 16282657, -11036493, 28414021, -15012264, 24191034, 4541697, -13338309, 5500568},
{12650548, -1497113, 9052871, 11355358, -17680037, -8400164, -17430592, 12264343, 10874051, 13524335},
{25556948, -3045990, 714651, 2510400, 23394682, -10415330, 33119038, 5080568, -22528059, 5376628}},
{{-26088264, -4011052, -17013699, -3537628, -6726793, 1920897, -22321305, -9447443, 4535768, 1569007},
{-2255422, 14606630, -21692440, -8039818, 28430649, 8775819, -30494562, 3044290, 31848280, 12543772},
{-22028579, 2943893, -31857513, 6777306, 13784462, -4292203, -27377195, -2062731, 7718482, 14474653}},
{{2385315, 2454213, -22631320, 46603, -4437935, -15680415, 656965, -7236665, 24316168, -5253567},
{13741529, 10911568, -33233417, -8603737, -20177830, -1033297, 33040651, -13424532, -20729456, 8321686},
{21060490, -2212744, 15712757, -4336099, 1639040, 10656336, 23845965, -11874838, -9984458, 608372}},
{{-13672732, -15087586, -10889693, -7557059, -6036909, 11305547, 1123968, -6780577, 27229399, 23887},
{-23244140, -294205, -11744728, 14712571, -29465699, -2029617, 12797024, -6440308, -1633405, 16678954},
{-29500620, 4770662, -16054387, 14001338, 7830047, 9564805, -1508144, -4795045, -17169265, 4904953}},
{{24059557, 14617003, 19037157, -15039908, 19766093, -14906429, 5169211, 16191880, 2128236, -4326833},
{-16981152, 4124966, -8540610, -10653797, 30336522, -14105247, -29806336, 916033, -6882542, -2986532},
{-22630907, 12419372, -7134229, -7473371, -16478904, 16739175, 285431, 2763829, 15736322, 4143876}},
{{2379352, 11839345, -4110402, -5988665, 11274298, 794957, 212801, -14594663, 23527084, -16458268},
{33431127, -11130478, -17838966, -15626900, 8909499, 8376530, -32625340, 4087881, -15188911, -14416214},
{1767683, 7197987, -13205226, -2022635, -13091350, 448826, 5799055, 4357868, -4774191, -16323038}}
}, {
{{6721966, 13833823, -23523388, -1551314, 26354293, -11863321, 23365147, -3949732, 7390890, 2759800},
{4409041, 2052381, 23373853, 10530217, 7676779, -12885954, 21302353, -4264057, 1244380, -12919645},
{-4421239, 7169619, 4982368, -2957590, 30256825, -2777540, 14086413, 9208236, 15886429, 16489664}},
{{1996075, 10375649, 14346367, 13311202, -6874135, -16438411, -13693198, 398369, -30606455, -712933},
{-25307465, 9795880, -2777414, 14878809, -33531835, 14780363, 13348553, 12076947, -30836462, 5113182},
{-17770784, 11797796, 31950843, 13929123, -25888302, 12288344, -30341101, -7336386, 13847711, 5387222}},
{{-18582163, -3416217, 17824843, -2340966, 22744343, -10442611, 8763061, 3617786, -19600662, 10370991},
{20246567, -14369378, 22358229, -543712, 18507283, -10413996, 14554437, -8746092, 32232924, 16763880},
{9648505, 10094563, 26416693, 14745928, -30374318, -6472621, 11094161, 15689506, 3140038, -16510092}},
{{-16160072, 5472695, 31895588, 4744994, 8823515, 10365685, -27224800, 9448613, -28774454, 366295},
{19153450, 11523972, -11096490, -6503142, -24647631, 5420647, 28344573, 8041113, 719605, 11671788},
{8678025, 2694440, -6808014, 2517372, 4964326, 11152271, -15432916, -15266516, 27000813, -10195553}},
{{-15157904, 7134312, 8639287, -2814877, -7235688, 10421742, 564065, 5336097, 6750977, -14521026},
{11836410, -3979488, 26297894, 16080799, 23455045, 15735944, 1695823, -8819122, 8169720, 16220347},
{-18115838, 8653647, 17578566, -6092619, -8025777, -16012763, -11144307, -2627664, -5990708, -14166033}},
{{-23308498, -10968312, 15213228, -10081214, -30853605, -11050004, 27884329, 2847284, 2655861, 1738395},
{-27537433, -14253021, -25336301, -8002780, -9370762, 8129821, 21651608, -3239336, -19087449, -11005278},
{1533110, 3437855, 23735889, 459276, 29970501, 11335377, 26030092, 5821408, 10478196, 8544890}},
{{32173121, -16129311, 24896207, 3921497, 22579056, -3410854, 19270449, 12217473, 17789017, -3395995},
{-30552961, -2228401, -15578829, -10147201, 13243889, 517024, 15479401, -3853233, 30460520, 1052596},
{-11614875, 13323618, 32618793, 8175907, -15230173, 12596687, 27491595, -4612359, 3179268, -9478891}},
{{31947069, -14366651, -4640583, -15339921, -15125977, -6039709, -14756777, -16411740, 19072640, -9511060},
{11685058, 11822410, 3158003, -13952594, 33402194, -4165066, 5977896, -5215017, 473099, 5040608},
{-20290863, 8198642, -27410132, 11602123, 1290375, -2799760, 28326862, 1721092, -19558642, -3131606}}
}, {
{{7881532, 10687937, 7578723, 7738378, -18951012, -2553952, 21820786, 8076149, -27868496, 11538389},
{-19935666, 3899861, 18283497, -6801568, -15728660, -11249211, 8754525, 7446702, -5676054, 5797016},
{-11295600, -3793569, -15782110, -7964573, 12708869, -8456199, 2014099, -9050574, -2369172, -5877341}},
{{-22472376, -11568741, -27682020, 1146375, 18956691, 16640559, 1192730, -3714199, 15123619, 10811505},
{14352098, -3419715, -18942044, 10822655, 32750596, 4699007, -70363, 15776356, -28886779, -11974553},
{-28241164, -8072475, -4978962, -5315317, 29416931, 1847569, -20654173, -16484855, 4714547, -9600655}},
{{15200332, 8368572, 19679101, 15970074, -31872674, 1959451, 24611599, -4543832, -11745876, 12340220},
{12876937, -10480056, 33134381, 6590940, -6307776, 14872440, 9613953, 8241152, 15370987, 9608631},
{-4143277, -12014408, 8446281, -391603, 4407738, 13629032, -7724868, 15866074, -28210621, -8814099}},
{{26660628, -15677655, 8393734, 358047, -7401291, 992988, -23904233, 858697, 20571223, 8420556},
{14620715, 13067227, -15447274, 8264467, 14106269, 15080814, 33531827, 12516406, -21574435, -12476749},
{236881, 10476226, 57258, -14677024, 6472998, 2466984, 17258519, 7256740, 8791136, 15069930}},
{{1276410, -9371918, 22949635, -16322807, -23493039, -5702186, 14711875, 4874229, -30663140, -2331391},
{5855666, 4990204, -13711848, 7294284, -7804282, 1924647, -1423175, -7912378, -33069337, 9234253},
{20590503, -9018988, 31529744, -7352666, -2706834, 10650548, 31559055, -11609587, 18979186, 13396066}},
{{24474287, 4968103, 22267082, 4407354, 24063882, -8325180, -18816887, 13594782, 33514650, 7021958},
{-11566906, -6565505, -21365085, 15928892, -26158305, 4315421, -25948728, -3916677, -21480480, 12868082},
{-28635013, 13504661, 19988037, -2132761, 21078225, 6443208, -21446107, 2244500, -12455797, -8089383}},
{{-30595528, 13793479, -5852820, 319136, -25723172, -6263899, 33086546, 8957937, -15233648, 5540521},
{-11630176, -11503902, -8119500, -7643073, 2620056, 1022908, -23710744, -1568984, -16128528, -14962807},
{23152971, 775386, 27395463, 14006635, -9701118, 4649512, 1689819, 892185, -11513277, -15205948}},
{{9770129, 9586738, 26496094, 4324120, 1556511, -3550024, 27453819, 4763127, -19179614, 5867134},
{-32765025, 1927590, 31726409, -4753295, 23962434, -16019500, 27846559, 5931263, -29749703, -16108455},
{27461885, -2977536, 22380810, 1815854, -23033753, -3031938, 7283490, -15148073, -19526700, 7734629}}
}, {
{{-8010264, -9590817, -11120403, 6196038, 29344158, -13430885, 7585295, -3176626, 18549497, 15302069},
{-32658337, -6171222, -7672793, -11051681, 6258878, 13504381, 10458790, -6418461, -8872242, 8424746},
{24687205, 8613276, -30667046, -3233545, 1863892, -1830544, 19206234, 7134917, -11284482, -828919}},
{{11334899, -9218022, 8025293, 12707519, 17523892, -10476071, 10243738, -14685461, -5066034, 16498837},
{8911542, 6887158, -9584260, -6958590, 11145641, -9543680, 17303925, -14124238, 6536641, 10543906},
{-28946384, 15479763, -17466835, 568876, -1497683, 11223454, -2669190, -16625574, -27235709, 8876771}},
{{-25742899, -12566864, -15649966, -846607, -33026686, -796288, -33481822, 15824474, -604426, -9039817},
{10330056, 70051, 7957388, -9002667, 9764902, 15609756, 27698697, -4890037, 1657394, 3084098},
{10477963, -7470260, 12119566, -13250805, 29016247, -5365589, 31280319, 14396151, -30233575, 15272409}},
{{-12288309, 3169463, 28813183, 16658753, 25116432, -5630466, -25173957, -12636138, -25014757, 1950504},
{-26180358, 9489187, 11053416, -14746161, -31053720, 5825630, -8384306, -8767532, 15341279, 8373727},
{28685821, 7759505, -14378516, -12002860, -31971820, 4079242, 298136, -10232602, -2878207, 15190420}},
{{-32932876, 13806336, -14337485, -15794431, -24004620, 10940928, 8669718, 2742393, -26033313, -6875003},
{-1580388, -11729417, -25979658, -11445023, -17411874, -10912854, 9291594, -16247779, -12154742, 6048605},
{-30305315, 14843444, 1539301, 11864366, 20201677, 1900163, 13934231, 5128323, 11213262, 9168384}},
{{-26280513, 11007847, 19408960, -940758, -18592965, -4328580, -5088060, -11105150, 20470157, -16398701},
{-23136053, 9282192, 14855179, -15390078, -7362815, -14408560, -22783952, 14461608, 14042978, 5230683},
{29969567, -2741594, -16711867, -8552442, 9175486, -2468974, 21556951, 3506042, -5933891, -12449708}},
{{-3144746, 8744661, 19704003, 4581278, -20430686, 6830683, -21284170, 8971513, -28539189, 15326563},
{-19464629, 10110288, -17262528, -3503892, -23500387, 1355669, -15523050, 15300988, -20514118, 9168260},
{-5353335, 4488613, -23803248, 16314347, 7780487, -15638939, -28948358, 9601605, 33087103, -9011387}},
{{-19443170, -15512900, -20797467, -12445323, -29824447, 10229461, -27444329, -15000531, -5996870, 15664672},
{23294591, -16632613, -22650781, -8470978, 27844204, 11461195, 13099750, -2460356, 18151676, 13417686},
{-24722913, -4176517, -31150679, 5988919, -26858785, 6685065, 1661597, -12551441, 15271676, -15452665}}
}, {
{{11433042, -13228665, 8239631, -5279517, -1985436, -725718, -18698764, 2167544, -6921301, -13440182},
{-31436171, 15575146, 30436815, 12192228, -22463353, 9395379, -9917708, -8638997, 12215110, 12028277},
{14098400, 6555944, 23007258, 5757252, -15427832, -12950502, 30123440, 4617780, -16900089, -655628}},
{{-4026201, -15240835, 11893168, 13718664, -14809462, 1847385, -15819999, 10154009, 23973261, -12684474},
{-26531820, -3695990, -1908898, 2534301, -31870557, -16550355, 18341390, -11419951, 32013174, -10103539},
{-25479301, 10876443, -11771086, -14625140, -12369567, 1838104, 21911214, 6354752, 4425632, -837822}},
{{-10433389, -14612966, 22229858, -3091047, -13191166, 776729, -17415375, -12020462, 4725005, 14044970},
{19268650, -7304421, 1555349, 8692754, -21474059, -9910664, 6347390, -1411784, -19522291, -16109756},
{-24864089, 12986008, -10898878, -5558584, -11312371, -148526, 19541418, 8180106, 9282262, 10282508}},
{{-26205082, 4428547, -8661196, -13194263, 4098402, -14165257, 15522535, 8372215, 5542595, -10702683},
{-10562541, 14895633, 26814552, -16673850, -17480754, -2489360, -2781891, 6993761, -18093885, 10114655},
{-20107055, -929418, 31422704, 10427861, -7110749, 6150669, -29091755, -11529146, 25953725, -106158}},
{{-4234397, -8039292, -9119125, 3046000, 2101609, -12607294, 19390020, 6094296, -3315279, 12831125},
{-15998678, 7578152, 5310217, 14408357, -33548620, -224739, 31575954, 6326196, 7381791, -2421839},
{-20902779, 3296811, 24736065, -16328389, 18374254, 7318640, 6295303, 8082724, -15362489, 12339664}},
{{27724736, 2291157, 6088201, -14184798, 1792727, 5857634, 13848414, 15768922, 25091167, 14856294},
{-18866652, 8331043, 24373479, 8541013, -701998, -9269457, 12927300, -12695493, -22182473, -9012899},
{-11423429, -5421590, 11632845, 3405020, 30536730, -11674039, -27260765, 13866390, 30146206, 9142070}},
{{3924129, -15307516, -13817122, -10054960, 12291820, -668366, -27702774, 9326384, -8237858, 4171294},
{-15921940, 16037937, 6713787, 16606682, -21612135, 2790944, 26396185, 3731949, 345228, -5462949},
{-21327538, 13448259, 25284571, 1143661, 20614966, -8849387, 2031539, -12391231, -16253183, -13582083}},
{{31016211, -16722429, 26371392, -14451233, -5027349, 14854137, 17477601, 3842657, 28012650, -16405420},
{-5075835, 9368966, -8562079, -4600902, -15249953, 6970560, -9189873, 16292057, -8867157, 3507940},
{29439664, 3537914, 23333589, 6997794, -17555561, -11018068, -15209202, -15051267, -9164929, 6580396}}
}, {
{{-12185861, -7679788, 16438269, 10826160, -8696817, -6235611, 17860444, -9273846, -2095802, 9304567},
{20714564, -4336911, 29088195, 7406487, 11426967, -5095705, 14792667, -14608617, 5289421, -477127},
{-16665533, -10650790, -6160345, -13305760, 9192020, -1802462, 17271490, 12349094, 26939669, -3752294}},
{{-12889898, 9373458, 31595848, 16374215, 21471720, 13221525, -27283495, -12348559, -3698806, 117887},
{22263325, -6560050, 3984570, -11174646, -15114008, -566785, 28311253, 5358056, -23319780, 541964},
{16259219, 3261970, 2309254, -15534474, -16885711, -4581916, 24134070, -16705829, -13337066, -13552195}},
{{9378160, -13140186, -22845982, -12745264, 28198281, -7244098, -2399684, -717351, 690426, 14876244},
{24977353, -314384, -8223969, -13465086, 28432343, -1176353, -13068804, -12297348, -22380984, 6618999},
{-1538174, 11685646, 12944378, 13682314, -24389511, -14413193, 8044829, -13817328, 32239829, -5652762}},
{{-18603066, 4762990, -926250, 8885304, -28412480, -3187315, 9781647, -10350059, 32779359, 5095274},
{-33008130, -5214506, -32264887, -3685216, 9460461, -9327423, -24601656, 14506724, 21639561, -2630236},
{-16400943, -13112215, 25239338, 15531969, 3987758, -4499318, -1289502, -6863535, 17874574, 558605}},
{{-13600129, 10240081, 9171883, 16131053, -20869254, 9599700, 33499487, 5080151, 2085892, 5119761},
{-22205145, -2519528, -16381601, 414691, -25019550, 2170430, 30634760, -8363614, -31999993, -5759884},
{-6845704, 15791202, 8550074, -1312654, 29928809, -12092256, 27534430, -7192145, -22351378, 12961482}},
{{-24492060, -9570771, 10368194, 11582341, -23397293, -2245287, 16533930, 8206996, -30194652, -5159638},
{-11121496, -3382234, 2307366, 6362031, -135455, 8868177, -16835630, 7031275, 7589640, 8945490},
{-32152748, 8917967, 6661220, -11677616, -1192060, -15793393, 7251489, -11182180, 24099109, -14456170}},
{{5019558, -7907470, 4244127, -14714356, -26933272, 6453165, -19118182, -13289025, -6231896, -10280736},
{10853594, 10721687, 26480089, 5861829, -22995819, 1972175, -1866647, -10557898, -3363451, -6441124},
{-17002408, 5906790, 221599, -6563147, 7828208, -13248918, 24362661, -2008168, -13866408, 7421392}},
{{8139927, -6546497, 32257646, -5890546, 30375719, 1886181, -21175108, 15441252, 28826358, -4123029},
{6267086, 9695052, 7709135, -16603597, -32869068, -1886135, 14795160, -7840124, 13746021, -1742048},
{28584902, 7787108, -6732942, -15050729, 22846041, -7571236, -3181936, -363524, 4771362, -8419958}}
}, {
{{24949256, 6376279, -27466481, -8174608, -18646154, -9930606, 33543569, -12141695, 3569627, 11342593},
{26514989, 4740088, 27912651, 3697550, 19331575, -11472339, 6809886, 4608608, 7325975, -14801071},
{-11618399, -14554430, -24321212, 7655128, -1369274, 5214312, -27400540, 10258390, -17646694, -8186692}},
{{11431204, 15823007, 26570245, 14329124, 18029990, 4796082, -31446179, 15580664, 9280358, -3973687},
{-160783, -10326257, -22855316, -4304997, -20861367, -13621002, -32810901, -11181622, -15545091, 4387441},
{-20799378, 12194512, 3937617, -5805892, -27154820, 9340370, -24513992, 8548137, 20617071, -7482001}},
{{-938825, -3930586, -8714311, 16124718, 24603125, -6225393, -13775352, -11875822, 24345683, 10325460},
{-19855277, -1568885, -22202708, 8714034, 14007766, 6928528, 16318175, -1010689, 4766743, 3552007},
{-21751364, -16730916, 1351763, -803421, -4009670, 3950935, 3217514, 14481909, 10988822, -3994762}},
{{15564307, -14311570, 3101243, 5684148, 30446780, -8051356, 12677127, -6505343, -8295852, 13296005},
{-9442290, 6624296, -30298964, -11913677, -4670981, -2057379, 31521204, 9614054, -30000824, 12074674},
{4771191, -135239, 14290749, -13089852, 27992298, 14998318, -1413936, -1556716, 29832613, -16391035}},
{{7064884, -7541174, -19161962, -5067537, -18891269, -2912736, 25825242, 5293297, -27122660, 13101590},
{-2298563, 2439670, -7466610, 1719965, -27267541, -16328445, 32512469, -5317593, -30356070, -4190957},
{-30006540, 10162316, -33180176, 3981723, -16482138, -13070044, 14413974, 9515896, 19568978, 9628812}},
{{33053803, 199357, 15894591, 1583059, 27380243, -4580435, -17838894, -6106839, -6291786, 3437740},
{-18978877, 3884493, 19469877, 12726490, 15913552, 13614290, -22961733, 70104, 7463304, 4176122},
{-27124001, 10659917, 11482427, -16070381, 12771467, -6635117, -32719404, -5322751, 24216882, 5944158}},
{{8894125, 7450974, -2664149, -9765752, -28080517, -12389115, 19345746, 14680796, 11632993, 5847885},
{26942781, -2315317, 9129564, -4906607, 26024105, 11769399, -11518837, 6367194, -9727230, 4782140},
{19916461, -4828410, -22910704, -11414391, 25606324, -5972441, 33253853, 8220911, 6358847, -1873857}},
{{801428, -2081702, 16569428, 11065167, 29875704, 96627, 7908388, -4480480, -13538503, 1387155},
{19646058, 5720633, -11416706, 12814209, 11607948, 12749789, 14147075, 15156355, -21866831, 11835260},
{19299512, 1155910, 28703737, 14890794, 2925026, 7269399, 26121523, 15467869, -26560550, 5052483}}
}, {
{{-3017432, 10058206, 1980837, 3964243, 22160966, 12322533, -6431123, -12618185, 12228557, -7003677},
{32944382, 14922211, -22844894, 5188528, 21913450, -8719943, 4001465, 13238564, -6114803, 8653815},
{22865569, -4652735, 27603668, -12545395, 14348958, 8234005, 24808405, 5719875, 28483275, 2841751}},
{{-16420968, -1113305, -327719, -12107856, 21886282, -15552774, -1887966, -315658, 19932058, -12739203},
{-11656086, 10087521, -8864888, -5536143, -19278573, -3055912, 3999228, 13239134, -4777469, -13910208},
{1382174, -11694719, 17266790, 9194690, -13324356, 9720081, 20403944, 11284705, -14013818, 3093230}},
{{16650921, -11037932, -1064178, 1570629, -8329746, 7352753, -302424, 16271225, -24049421, -6691850},
{-21911077, -5927941, -4611316, -5560156, -31744103, -10785293, 24123614, 15193618, -21652117, -16739389},
{-9935934, -4289447, -25279823, 4372842, 2087473, 10399484, 31870908, 14690798, 17361620, 11864968}},
{{-11307610, 6210372, 13206574, 5806320, -29017692, -13967200, -12331205, -7486601, -25578460, -16240689},
{14668462, -12270235, 26039039, 15305210, 25515617, 4542480, 10453892, 6577524, 9145645, -6443880},
{5974874, 3053895, -9433049, -10385191, -31865124, 3225009, -7972642, 3936128, -5652273, -3050304}},
{{30625386, -4729400, -25555961, -12792866, -20484575, 7695099, 17097188, -16303496, -27999779, 1803632},
{-3553091, 9865099, -5228566, 4272701, -5673832, -16689700, 14911344, 12196514, -21405489, 7047412},
{20093277, 9920966, -11138194, -5343857, 13161587, 12044805, -32856851, 4124601, -32343828, -10257566}},
{{-20788824, 14084654, -13531713, 7842147, 19119038, -13822605, 4752377, -8714640, -21679658, 2288038},
{-26819236, -3283715, 29965059, 3039786, -14473765, 2540457, 29457502, 14625692, -24819617, 12570232},
{-1063558, -11551823, 16920318, 12494842, 1278292, -5869109, -21159943, -3498680, -11974704, 4724943}},
{{17960970, -11775534, -4140968, -9702530, -8876562, -1410617, -12907383, -8659932, -29576300, 1903856},
{23134274, -14279132, -10681997, -1611936, 20684485, 15770816, -12989750, 3190296, 26955097, 14109738},
{15308788, 5320727, -30113809, -14318877, 22902008, 7767164, 29425325, -11277562, 31960942, 11934971}},
{{-27395711, 8435796, 4109644, 12222639, -24627868, 14818669, 20638173, 4875028, 10491392, 1379718},
{-13159415, 9197841, 3875503, -8936108, -1383712, -5879801, 33518459, 16176658, 21432314, 12180697},
{-11787308, 11500838, 13787581, -13832590, -22430679, 10140205, 1465425, 12689540, -10301319, -13872883}}
}, {
{{5414091, -15386041, -21007664, 9643570, 12834970, 1186149, -2622916, -1342231, 26128231, 6032912},
{-26337395, -13766162, 32496025, -13653919, 17847801, -12669156, 3604025, 8316894, -25875034, -10437358},
{3296484, 6223048, 24680646, -12246460, -23052020, 5903205, -8862297, -4639164, 12376617, 3188849}},
{{29190488, -14659046, 27549113, -1183516, 3520066, -10697301, 32049515, -7309113, -16109234, -9852307},
{-14744486, -9309156, 735818, -598978, -20407687, -5057904, 25246078, -15795669, 18640741, -960977},
{-6928835, -16430795, 10361374, 5642961, 4910474, 12345252, -31638386, -494430, 10530747, 1053335}},
{{-29265967, -14186805, -13538216, -12117373, -19457059, -10655384, -31462369, -2948985, 24018831, 15026644},
{-22592535, -3145277, -2289276, 5953843, -13440189, 9425631, 25310643, 13003497, -2314791, -15145616},
{-27419985, -603321, -8043984, -1669117, -26092265, 13987819, -27297622, 187899, -23166419, -2531735}},
{{-21744398, -13810475, 1844840, 5021428, -10434399, -15911473, 9716667, 16266922, -5070217, 726099},
{29370922, -6053998, 7334071, -15342259, 9385287, 2247707, -13661962, -4839461, 30007388, -15823341},
{-936379, 16086691, 23751945, -543318, -1167538, -5189036, 9137109, 730663, 9835848, 4555336}},
{{-23376435, 1410446, -22253753, -12899614, 30867635, 15826977, 17693930, 544696, -11985298, 12422646},
{31117226, -12215734, -13502838, 6561947, -9876867, -12757670, -5118685, -4096706, 29120153, 13924425},
{-17400879, -14233209, 19675799, -2734756, -11006962, -5858820, -9383939, -11317700, 7240931, -237388}},
{{-31361739, -11346780, -15007447, -5856218, -22453340, -12152771, 1222336, 4389483, 3293637, -15551743},
{-16684801, -14444245, 11038544, 11054958, -13801175, -3338533, -24319580, 7733547, 12796905, -6335822},
{-8759414, -10817836, -25418864, 10783769, -30615557, -9746811, -28253339, 3647836, 3222231, -11160462}},
{{18606113, 1693100, -25448386, -15170272, 4112353, 10045021, 23603893, -2048234, -7550776, 2484985},
{9255317, -3131197, -12156162, -1004256, 13098013, -9214866, 16377220, -2102812, -19802075, -3034702},
{-22729289, 7496160, -5742199, 11329249, 19991973, -3347502, -31718148, 9936966, -30097688, -10618797}},
{{21878590, -5001297, 4338336, 13643897, -3036865, 13160960, 19708896, 5415497, -7360503, -4109293},
{27736861, 10103576, 12500508, 8502413, -3413016, -9633558, 10436918, -1550276, -23659143, -8132100},
{19492550, -12104365, -29681976, -852630, -3208171, 12403437, 30066266, 8367329, 13243957, 8709688}}
}, {
{{12015105, 2801261, 28198131, 10151021, 24818120, -4743133, -11194191, -5645734, 5150968, 7274186},
{2831366, -12492146, 1478975, 6122054, 23825128, -12733586, 31097299, 6083058, 31021603, -9793610},
{-2529932, -2229646, 445613, 10720828, -13849527, -11505937, -23507731, 16354465, 15067285, -14147707}},
{{7840942, 14037873, -33364863, 15934016, -728213, -3642706, 21403988, 1057586, -19379462, -12403220},
{915865, -16469274, 15608285, -8789130, -24357026, 6060030, -17371319, 8410997, -7220461, 16527025},
{32922597, -556987, 20336074, -16184568, 10903705, -5384487, 16957574, 52992, 23834301, 6588044}},
{{32752030, 11232950, 3381995, -8714866, 22652988, -10744103, 17159699, 16689107, -20314580, -1305992},
{-4689649, 9166776, -25710296, -10847306, 11576752, 12733943, 7924251, -2752281, 1976123, -7249027},
{21251222, 16309901, -2983015, -6783122, 30810597, 12967303, 156041, -3371252, 12331345, -8237197}},
{{8651614, -4477032, -16085636, -4996994, 13002507, 2950805, 29054427, -5106970, 10008136, -4667901},
{31486080, 15114593, -14261250, 12951354, 14369431, -7387845, 16347321, -13662089, 8684155, -10532952},
{19443825, 11385320, 24468943, -9659068, -23919258, 2187569, -26263207, -6086921, 31316348, 14219878}},
{{-28594490, 1193785, 32245219, 11392485, 31092169, 15722801, 27146014, 6992409, 29126555, 9207390},
{32382935, 1110093, 18477781, 11028262, -27411763, -7548111, -4980517, 10843782, -7957600, -14435730},
{2814918, 7836403, 27519878, -7868156, -20894015, -11553689, -21494559, 8550130, 28346258, 1994730}},
{{-19578299, 8085545, -14000519, -3948622, 2785838, -16231307, -19516951, 7174894, 22628102, 8115180},
{-30405132, 955511, -11133838, -15078069, -32447087, -13278079, -25651578, 3317160, -9943017, 930272},
{-15303681, -6833769, 28856490, 1357446, 23421993, 1057177, 24091212, -1388970, -22765376, -10650715}},
{{-22751231, -5303997, -12907607, -12768866, -15811511, -7797053, -14839018, -16554220, -1867018, 8398970},
{-31969310, 2106403, -4736360, 1362501, 12813763, 16200670, 22981545, -6291273, 18009408, -15772772},
{-17220923, -9545221, -27784654, 14166835, 29815394, 7444469, 29551787, -3727419, 19288549, 1325865}},
{{15100157, -15835752, -23923978, -1005098, -26450192, 15509408, 12376730, -3479146, 33166107, -8042750},
{20909231, 13023121, -9209752, 16251778, -5778415, -8094914, 12412151, 10018715, 2213263, -13878373},
{32529814, -11074689, 30361439, -16689753, -9135940, 1513226, 22922121, 6382134, -5766928, 8371348}}
}, {
{{9923462, 11271500, 12616794, 3544722, -29998368, -1721626, 12891687, -8193132, -26442943, 10486144},
{-22597207, -7012665, 8587003, -8257861, 4084309, -12970062, 361726, 2610596, -23921530, -11455195},
{5408411, -1136691, -4969122, 10561668, 24145918, 14240566, 31319731, -4235541, 19985175, -3436086}},
{{-13994457, 16616821, 14549246, 3341099, 32155958, 13648976, -17577068, 8849297, 65030, 8370684},
{-8320926, -12049626, 31204563, 5839400, -20627288, -1057277, -19442942, 6922164, 12743482, -9800518},
{-2361371, 12678785, 28815050, 4759974, -23893047, 4884717, 23783145, 11038569, 18800704, 255233}},
{{-5269658, -1773886, 13957886, 7990715, 23132995, 728773, 13393847, 9066957, 19258688, -14753793},
{-2936654, -10827535, -10432089, 14516793, -3640786, 4372541, -31934921, 2209390, -1524053, 2055794},
{580882, 16705327, 5468415, -2683018, -30926419, -14696000, -7203346, -8994389, -30021019, 7394435}},
{{23838809, 1822728, -15738443, 15242727, 8318092, -3733104, -21672180, -3492205, -4821741, 14799921},
{13345610, 9759151, 3371034, -16137791, 16353039, 8577942, 31129804, 13496856, -9056018, 7402518},
{2286874, -4435931, -20042458, -2008336, -13696227, 5038122, 11006906, -15760352, 8205061, 1607563}},
{{14414086, -8002132, 3331830, -3208217, 22249151, -5594188, 18364661, -2906958, 30019587, -9029278},
{-27688051, 1585953, -10775053, 931069, -29120221, -11002319, -14410829, 12029093, 9944378, 8024},
{4368715, -3709630, 29874200, -15022983, -20230386, -11410704, -16114594, -999085, -8142388, 5640030}},
{{10299610, 13746483, 11661824, 16234854, 7630238, 5998374, 9809887, -16694564, 15219798, -14327783},
{27425505, -5719081, 3055006, 10660664, 23458024, 595578, -15398605, -1173195, -18342183, 9742717},
{6744077, 2427284, 26042789, 2720740, -847906, 1118974, 32324614, 7406442, 12420155, 1994844}},
{{14012521, -5024720, -18384453, -9578469, -26485342, -3936439, -13033478, -10909803, 24319929, -6446333},
{16412690, -4507367, 10772641, 15929391, -17068788, -4658621, 10555945, -10484049, -30102368, -4739048},
{22397382, -7767684, -9293161, -12792868, 17166287, -9755136, -27333065, 6199366, 21880021, -12250760}},
{{-4283307, 5368523, -31117018, 8163389, -30323063, 3209128, 16557151, 8890729, 8840445, 4957760},
{-15447727, 709327, -6919446, -10870178, -29777922, 6522332, -21720181, 12130072, -14796503, 5005757},
{-2114751, -14308128, 23019042, 15765735, -25269683, 6002752, 10183197, -13239326, -16395286, -2176112}}
}, {
{{-19025756, 1632005, 13466291, -7995100, -23640451, 16573537, -32013908, -3057104, 22208662, 2000468},
{3065073, -1412761, -25598674, -361432, -17683065, -5703415, -8164212, 11248527, -3691214, -7414184},
{10379208, -6045554, 8877319, 1473647, -29291284, -12507580, 16690915, 2553332, -3132688, 16400289}},
{{15716668, 1254266, -18472690, 7446274, -8448918, 6344164, -22097271, -7285580, 26894937, 9132066},
{24158887, 12938817, 11085297, -8177598, -28063478, -4457083, -30576463, 64452, -6817084, -2692882},
{13488534, 7794716, 22236231, 5989356, 25426474, -12578208, 2350710, -3418511, -4688006, 2364226}},
{{16335052, 9132434, 25640582, 6678888, 1725628, 8517937, -11807024, -11697457, 15445875, -7798101},
{29004207, -7867081, 28661402, -640412, -12794003, -7943086, 31863255, -4135540, -278050, -15759279},
{-6122061, -14866665, -28614905, 14569919, -10857999, -3591829, 10343412, -6976290, -29828287, -10815811}},
{{27081650, 3463984, 14099042, -4517604, 1616303, -6205604, 29542636, 15372179, 17293797, 960709},
{20263915, 11434237, -5765435, 11236810, 13505955, -10857102, -16111345, 6493122, -19384511, 7639714},
{-2830798, -14839232, 25403038, -8215196, -8317012, -16173699, 18006287, -16043750, 29994677, -15808121}},
{{9769828, 5202651, -24157398, -13631392, -28051003, -11561624, -24613141, -13860782, -31184575, 709464},
{12286395, 13076066, -21775189, -1176622, -25003198, 4057652, -32018128, -8890874, 16102007, 13205847},
{13733362, 5599946, 10557076, 3195751, -5557991, 8536970, -25540170, 8525972, 10151379, 10394400}},
{{4024660, -16137551, 22436262, 12276534, -9099015, -2686099, 19698229, 11743039, -33302334, 8934414},
{-15879800, -4525240, -8580747, -2934061, 14634845, -698278, -9449077, 3137094, -11536886, 11721158},
{17555939, -5013938, 8268606, 2331751, -22738815, 9761013, 9319229, 8835153, -9205489, -1280045}},
{{-461409, -7830014, 20614118, 16688288, -7514766, -4807119, 22300304, 505429, 6108462, -6183415},
{-5070281, 12367917, -30663534, 3234473, 32617080, -8422642, 29880583, -13483331, -26898490, -7867459},
{-31975283, 5726539, 26934134, 10237677, -3173717, -605053, 24199304, 3795095, 7592688, -14992079}},
{{21594432, -14964228, 17466408, -4077222, 32537084, 2739898, 6407723, 12018833, -28256052, 4298412},
{-20650503, -11961496, -27236275, 570498, 3767144, -1717540, 13891942, -1569194, 13717174, 10805743},
{-14676630, -15644296, 15287174, 11927123, 24177847, -8175568, -796431, 14860609, -26938930, -5863836}}
}, {
{{12962541, 5311799, -10060768, 11658280, 18855286, -7954201, 13286263, -12808704, -4381056, 9882022},
{18512079, 11319350, -20123124, 15090309, 18818594, 5271736, -22727904, 3666879, -23967430, -3299429},
{-6789020, -3146043, 16192429, 13241070, 15898607, -14206114, -10084880, -6661110, -2403099, 5276065}},
{{30169808, -5317648, 26306206, -11750859, 27814964, 7069267, 7152851, 3684982, 1449224, 13082861},
{10342826, 3098505, 2119311, 193222, 25702612, 12233820, 23697382, 15056736, -21016438, -8202000},
{-33150110, 3261608, 22745853, 7948688, 19370557, -15177665, -26171976, 6482814, -10300080, -11060101}},
{{32869458, -5408545, 25609743, 15678670, -10687769, -15471071, 26112421, 2521008, -22664288, 6904815},
{29506923, 4457497, 3377935, -9796444, -30510046, 12935080, 1561737, 3841096, -29003639, -6657642},
{10340844, -6630377, -18656632, -2278430, 12621151, -13339055, 30878497, -11824370, -25584551, 5181966}},
{{25940115, -12658025, 17324188, -10307374, -8671468, 15029094, 24396252, -16450922, -2322852, -12388574},
{-21765684, 9916823, -1300409, 4079498, -1028346, 11909559, 1782390, 12641087, 20603771, -6561742},
{-18882287, -11673380, 24849422, 11501709, 13161720, -4768874, 1925523, 11914390, 4662781, 7820689}},
{{12241050, -425982, 8132691, 9393934, 32846760, -1599620, 29749456, 12172924, 16136752, 15264020},
{-10349955, -14680563, -8211979, 2330220, -17662549, -14545780, 10658213, 6671822, 19012087, 3772772},
{3753511, -3421066, 10617074, 2028709, 14841030, -6721664, 28718732, -15762884, 20527771, 12988982}},
{{-14822485, -5797269, -3707987, 12689773, -898983, -10914866, -24183046, -10564943, 3299665, -12424953},
{-16777703, -15253301, -9642417, 4978983, 3308785, 8755439, 6943197, 6461331, -25583147, 8991218},
{-17226263, 1816362, -1673288, -6086439, 31783888, -8175991, -32948145, 7417950, -30242287, 1507265}},
{{29692663, 6829891, -10498800, 4334896, 20945975, -11906496, -28887608, 8209391, 14606362, -10647073},
{-3481570, 8707081, 32188102, 5672294, 22096700, 1711240, -33020695, 9761487, 4170404, -2085325},
{-11587470, 14855945, -4127778, -1531857, -26649089, 15084046, 22186522, 16002000, -14276837, -8400798}},
{{-4811456, 13761029, -31703877, -2483919, -3312471, 7869047, -7113572, -9620092, 13240845, 10965870},
{-7742563, -8256762, -14768334, -13656260, -23232383, 12387166, 4498947, 14147411, 29514390, 4302863},
{-13413405, -12407859, 20757302, -13801832, 14785143, 8976368, -5061276, -2144373, 17846988, -13971927}}
}, {
{{-2244452, -754728, -4597030, -1066309, -6247172, 1455299, -21647728, -9214789, -5222701, 12650267},
{-9906797, -16070310, 21134160, 12198166, -27064575, 708126, 387813, 13770293, -19134326, 10958663},
{22470984, 12369526, 23446014, -5441109, -21520802, -9698723, -11772496, -11574455, -25083830, 4271862}},
{{-25169565, -10053642, -19909332, 15361595, -5984358, 2159192, 75375, -4278529, -32526221, 8469673},
{15854970, 4148314, -8893890, 7259002, 11666551, 13824734, -30531198, 2697372, 24154791, -9460943},
{15446137, -15806644, 29759747, 14019369, 30811221, -9610191, -31582008, 12840104, 24913809, 9815020}},
{{-4709286, -5614269, -31841498, -12288893, -14443537, 10799414, -9103676, 13438769, 18735128, 9466238},
{11933045, 9281483, 5081055, -5183824, -2628162, -4905629, -7727821, -10896103, -22728655, 16199064},
{14576810, 379472, -26786533, -8317236, -29426508, -10812974, -102766, 1876699, 30801119, 2164795}},
{{15995086, 3199873, 13672555, 13712240, -19378835, -4647646, -13081610, -15496269, -13492807, 1268052},
{-10290614, -3659039, -3286592, 10948818, 23037027, 3794475, -3470338, -12600221, -17055369, 3565904},
{29210088, -9419337, -5919792, -4952785, 10834811, -13327726, -16512102, -10820713, -27162222, -14030531}},
{{-13161890, 15508588, 16663704, -8156150, -28349942, 9019123, -29183421, -3769423, 2244111, -14001979},
{-5152875, -3800936, -9306475, -6071583, 16243069, 14684434, -25673088, -16180800, 13491506, 4641841},
{10813417, 643330, -19188515, -728916, 30292062, -16600078, 27548447, -7721242, 14476989, -12767431}},
{{10292079, 9984945, 6481436, 8279905, -7251514, 7032743, 27282937, -1644259, -27912810, 12651324},
{-31185513, -813383, 22271204, 11835308, 10201545, 15351028, 17099662, 3988035, 21721536, -3148940},
{10202177, -6545839, -31373232, -9574638, -32150642, -8119683, -12906320, 3852694, 13216206, 14842320}},
{{-15815640, -10601066, -6538952, -7258995, -6984659, -6581778, -31500847, 13765824, -27434397, 9900184},
{14465505, -13833331, -32133984, -14738873, -27443187, 12990492, 33046193, 15796406, -7051866, -8040114},
{30924417, -8279620, 6359016, -12816335, 16508377, 9071735, -25488601, 15413635, 9524356, -7018878}},
{{12274201, -13175547, 32627641, -1785326, 6736625, 13267305, 5237659, -5109483, 15663516, 4035784},
{-2951309, 8903985, 17349946, 601635, -16432815, -4612556, -13732739, -15889334, -22258478, 4659091},
{-16916263, -4952973, -30393711, -15158821, 20774812, 15897498, 5736189, 15026997, -2178256, -13455585}}
}, {
{{-8858980, -2219056, 28571666, -10155518, -474467, -10105698, -3801496, 278095, 23440562, -290208},
{10226241, -5928702, 15139956, 120818, -14867693, 5218603, 32937275, 11551483, -16571960, -7442864},
{17932739, -12437276, -24039557, 10749060, 11316803, 7535897, 22503767, 5561594, -3646624, 3898661}},
{{7749907, -969567, -16339731, -16464, -25018111, 15122143, -1573531, 7152530, 21831162, 1245233},
{26958459, -14658026, 4314586, 8346991, -5677764, 11960072, -32589295, -620035, -30402091, -16716212},
{-12165896, 9166947, 33491384, 13673479, 29787085, 13096535, 6280834, 14587357, -22338025, 13987525}},
{{-24349909, 7778775, 21116000, 15572597, -4833266, -5357778, -4300898, -5124639, -7469781, -2858068},
{9681908, -6737123, -31951644, 13591838, -6883821, 386950, 31622781, 6439245, -14581012, 4091397},
{-8426427, 1470727, -28109679, -1596990, 3978627, -5123623, -19622683, 12092163, 29077877, -14741988}},
{{5269168, -6859726, -13230211, -8020715, 25932563, 1763552, -5606110, -5505881, -20017847, 2357889},
{32264008, -15407652, -5387735, -1160093, -2091322, -3946900, 23104804, -12869908, 5727338, 189038},
{14609123, -8954470, -6000566, -16622781, -14577387, -7743898, -26745169, 10942115, -25888931, -14884697}},
{{20513500, 5557931, -15604613, 7829531, 26413943, -2019404, -21378968, 7471781, 13913677, -5137875},
{-25574376, 11967826, 29233242, 12948236, -6754465, 4713227, -8940970, 14059180, 12878652, 8511905},
{-25656801, 3393631, -2955415, -7075526, -2250709, 9366908, -30223418, 6812974, 5568676, -3127656}},
{{11630004, 12144454, 2116339, 13606037, 27378885, 15676917, -17408753, -13504373, -14395196, 8070818},
{27117696, -10007378, -31282771, -5570088, 1127282, 12772488, -29845906, 10483306, -11552749, -1028714},
{10637467, -5688064, 5674781, 1072708, -26343588, -6982302, -1683975, 9177853, -27493162, 15431203}},
{{20525145, 10892566, -12742472, 12779443, -29493034, 16150075, -28240519, 14943142, -15056790, -7935931},
{-30024462, 5626926, -551567, -9981087, 753598, 11981191, 25244767, -3239766, -3356550, 9594024},
{-23752644, 2636870, -5163910, -10103818, 585134, 7877383, 11345683, -6492290, 13352335, -10977084}},
{{-1931799, -5407458, 3304649, -12884869, 17015806, -4877091, -29783850, -7752482, -13215537, -319204},
{20239939, 6607058, 6203985, 3483793, -18386976, -779229, -20723742, 15077870, -22750759, 14523817},
{27406042, -6041657, 27423596, -4497394, 4996214, 10002360, -28842031, -4545494, -30172742, -4805667}}
}, {
{{11374242, 12660715, 17861383, -12540833, 10935568, 1099227, -13886076, -9091740, -27727044, 11358504},
{-12730809, 10311867, 1510375, 10778093, -2119455, -9145702, 32676003, 11149336, -26123651, 4985768},
{-19096303, 341147, -6197485, -239033, 15756973, -8796662, -983043, 13794114, -19414307, -15621255}},
{{6490081, 11940286, 25495923, -7726360, 8668373, -8751316, 3367603, 6970005, -1691065, -9004790},
{1656497, 13457317, 15370807, 6364910, 13605745, 8362338, -19174622, -5475723, -16796596, -5031438},
{-22273315, -13524424, -64685, -4334223, -18605636, -10921968, -20571065, -7007978, -99853, -10237333}},
{{17747465, 10039260, 19368299, -4050591, -20630635, -16041286, 31992683, -15857976, -29260363, -5511971},
{31932027, -4986141, -19612382, 16366580, 22023614, 88450, 11371999, -3744247, 4882242, -10626905},
{29796507, 37186, 19818052, 10115756, -11829032, 3352736, 18551198, 3272828, -5190932, -4162409}},
{{12501286, 4044383, -8612957, -13392385, -32430052, 5136599, -19230378, -3529697, 330070, -3659409},
{6384877, 2899513, 17807477, 7663917, -2358888, 12363165, 25366522, -8573892, -271295, 12071499},
{-8365515, -4042521, 25133448, -4517355, -6211027, 2265927, -32769618, 1936675, -5159697, 3829363}},
{{28425966, -5835433, -577090, -4697198, -14217555, 6870930, 7921550, -6567787, 26333140, 14267664},
{-11067219, 11871231, 27385719, -10559544, -4585914, -11189312, 10004786, -8709488, -21761224, 8930324},
{-21197785, -16396035, 25654216, -1725397, 12282012, 11008919, 1541940, 4757911, -26491501, -16408940}},
{{13537262, -7759490, -20604840, 10961927, -5922820, -13218065, -13156584, 6217254, -15943699, 13814990},
{-17422573, 15157790, 18705543, 29619, 24409717, -260476, 27361681, 9257833, -1956526, -1776914},
{-25045300, -10191966, 15366585, 15166509, -13105086, 8423556, -29171540, 12361135, -18685978, 4578290}},
{{24579768, 3711570, 1342322, -11180126, -27005135, 14124956, -22544529, 14074919, 21964432, 8235257},
{-6528613, -2411497, 9442966, -5925588, 12025640, -1487420, -2981514, -1669206, 13006806, 2355433},
{-16304899, -13605259, -6632427, -5142349, 16974359, -10911083, 27202044, 1719366, 1141648, -12796236}},
{{-12863944, -13219986, -8318266, -11018091, -6810145, -4843894, 13475066, -3133972, 32674895, 13715045},
{11423335, -5468059, 32344216, 8962751, 24989809, 9241752, -13265253, 16086212, -28740881, -15642093},
{-1409668, 12530728, -6368726, 10847387, 19531186, -14132160, -11709148, 7791794, -27245943, 4383347}}
}, {
{{-28970898, 5271447, -1266009, -9736989, -12455236, 16732599, -4862407, -4906449, 27193557, 6245191},
{-15193956, 5362278, -1783893, 2695834, 4960227, 12840725, 23061898, 3260492, 22510453, 8577507},
{-12632451, 11257346, -32692994, 13548177, -721004, 10879011, 31168030, 13952092, -29571492, -3635906}},
{{3877321, -9572739, 32416692, 5405324, -11004407, -13656635, 3759769, 11935320, 5611860, 8164018},
{-16275802, 14667797, 15906460, 12155291, -22111149, -9039718, 32003002, -8832289, 5773085, -8422109},
{-23788118, -8254300, 1950875, 8937633, 18686727, 16459170, -905725, 12376320, 31632953, 190926}},
{{-24593607, -16138885, -8423991, 13378746, 14162407, 6901328, -8288749, 4508564, -25341555, -3627528},
{8884438, -5884009, 6023974, 10104341, -6881569, -4941533, 18722941, -14786005, -1672488, 827625},
{-32720583, -16289296, -32503547, 7101210, 13354605, 2659080, -1800575, -14108036, -24878478, 1541286}},
{{2901347, -1117687, 3880376, -10059388, -17620940, -3612781, -21802117, -3567481, 20456845, -1885033},
{27019610, 12299467, -13658288, -1603234, -12861660, -4861471, -19540150, -5016058, 29439641, 15138866},
{21536104, -6626420, -32447818, -10690208, -22408077, 5175814, -5420040, -16361163, 7779328, 109896}},
{{30279744, 14648750, -8044871, 6425558, 13639621, -743509, 28698390, 12180118, 23177719, -554075},
{26572847, 3405927, -31701700, 12890905, -19265668, 5335866, -6493768, 2378492, 4439158, -13279347},
{-22716706, 3489070, -9225266, -332753, 18875722, -1140095, 14819434, -12731527, -17717757, -5461437}},
{{-5056483, 16566551, 15953661, 3767752, -10436499, 15627060, -820954, 2177225, 8550082, -15114165},
{-18473302, 16596775, -381660, 15663611, 22860960, 15585581, -27844109, -3582739, -23260460, -8428588},
{-32480551, 15707275, -8205912, -5652081, 29464558, 2713815, -22725137, 15860482, -21902570, 1494193}},
{{-19562091, -14087393, -25583872, -9299552, 13127842, 759709, 21923482, 16529112, 8742704, 12967017},
{-28464899, 1553205, 32536856, -10473729, -24691605, -406174, -8914625, -2933896, -29903758, 15553883},
{21877909, 3230008, 9881174, 10539357, -4797115, 2841332, 11543572, 14513274, 19375923, -12647961}},
{{8832269, -14495485, 13253511, 5137575, 5037871, 4078777, 24880818, -6222716, 2862653, 9455043},
{29306751, 5123106, 20245049, -14149889, 9592566, 8447059, -2077124, -2990080, 15511449, 4789663},
{-20679756, 7004547, 8824831, -9434977, -4045704, -3750736, -5754762, 108893, 23513200, 16652362}}
}, {
{{-33256173, 4144782, -4476029, -6579123, 10770039, -7155542, -6650416, -12936300, -18319198, 10212860},
{2756081, 8598110, 7383731, -6859892, 22312759, -1105012, 21179801, 2600940, -9988298, -12506466},
{-24645692, 13317462, -30449259, -15653928, 21365574, -10869657, 11344424, 864440, -2499677, -16710063}},
{{-26432803, 6148329, -17184412, -14474154, 18782929, -275997, -22561534, 211300, 2719757, 4940997},
{-1323882, 3911313, -6948744, 14759765, -30027150, 7851207, 21690126, 8518463, 26699843, 5276295},
{-13149873, -6429067, 9396249, 365013, 24703301, -10488939, 1321586, 149635, -15452774, 7159369}},
{{9987780, -3404759, 17507962, 9505530, 9731535, -2165514, 22356009, 8312176, 22477218, -8403385},
{18155857, -16504990, 19744716, 9006923, 15154154, -10538976, 24256460, -4864995, -22548173, 9334109},
{2986088, -4911893, 10776628, -3473844, 10620590, -7083203, -21413845, 14253545, -22587149, 536906}},
{{4377756, 8115836, 24567078, 15495314, 11625074, 13064599, 7390551, 10589625, 10838060, -15420424},
{-19342404, 867880, 9277171, -3218459, -14431572, -1986443, 19295826, -15796950, 6378260, 699185},
{7895026, 4057113, -7081772, -13077756, -17886831, -323126, -716039, 15693155, -5045064, -13373962}},
{{-7737563, -5869402, -14566319, -7406919, 11385654, 13201616, 31730678, -10962840, -3918636, -9669325},
{10188286, -15770834, -7336361, 13427543, 22223443, 14896287, 30743455, 7116568, -21786507, 5427593},
{696102, 13206899, 27047647, -10632082, 15285305, -9853179, 10798490, -4578720, 19236243, 12477404}},
{{-11229439, 11243796, -17054270, -8040865, -788228, -8167967, -3897669, 11180504, -23169516, 7733644},
{17800790, -14036179, -27000429, -11766671, 23887827, 3149671, 23466177, -10538171, 10322027, 15313801},
{26246234, 11968874, 32263343, -5468728, 6830755, -13323031, -15794704, -101982, -24449242, 10890804}},
{{-31365647, 10271363, -12660625, -6267268, 16690207, -13062544, -14982212, 16484931, 25180797, -5334884},
{-586574, 10376444, -32586414, -11286356, 19801893, 10997610, 2276632, 9482883, 316878, 13820577},
{-9882808, -4510367, -2115506, 16457136, -11100081, 11674996, 30756178, -7515054, 30696930, -3712849}},
{{32988917, -9603412, 12499366, 7910787, -10617257, -11931514, -7342816, -9985397, -32349517, 7392473},
{-8855661, 15927861, 9866406, -3649411, -2396914, -16655781, -30409476, -9134995, 25112947, -2926644},
{-2504044, -436966, 25621774, -5678772, 15085042, -5479877, -24884878, -13526194, 5537438, -13914319}}
}, {
{{-11225584, 2320285, -9584280, 10149187, -33444663, 5808648, -14876251, -1729667, 31234590, 6090599},
{-9633316, 116426, 26083934, 2897444, -6364437, -2688086, 609721, 15878753, -6970405, -9034768},
{-27757857, 247744, -15194774, -9002551, 23288161, -10011936, -23869595, 6503646, 20650474, 1804084}},
{{-27589786, 15456424, 8972517, 8469608, 15640622, 4439847, 3121995, -10329713, 27842616, -202328},
{-15306973, 2839644, 22530074, 10026331, 4602058, 5048462, 28248656, 5031932, -11375082, 12714369},
{20807691, -7270825, 29286141, 11421711, -27876523, -13868230, -21227475, 1035546, -19733229, 12796920}},
{{12076899, -14301286, -8785001, -11848922, -25012791, 16400684, -17591495, -12899438, 3480665, -15182815},
{-32361549, 5457597, 28548107, 7833186, 7303070, -11953545, -24363064, -15921875, -33374054, 2771025},
{-21389266, 421932, 26597266, 6860826, 22486084, -6737172, -17137485, -4210226, -24552282, 15673397}},
{{-20184622, 2338216, 19788685, -9620956, -4001265, -8740893, -20271184, 4733254, 3727144, -12934448},
{6120119, 814863, -11794402, -622716, 6812205, -15747771, 2019594, 7975683, 31123697, -10958981},
{30069250, -11435332, 30434654, 2958439, 18399564, -976289, 12296869, 9204260, -16432438, 9648165}},
{{32705432, -1550977, 30705658, 7451065, -11805606, 9631813, 3305266, 5248604, -26008332, -11377501},
{17219865, 2375039, -31570947, -5575615, -19459679, 9219903, 294711, 15298639, 2662509, -16297073},
{-1172927, -7558695, -4366770, -4287744, -21346413, -8434326, 32087529, -1222777, 32247248, -14389861}},
{{14312628, 1221556, 17395390, -8700143, -4945741, -8684635, -28197744, -9637817, -16027623, -13378845},
{-1428825, -9678990, -9235681, 6549687, -7383069, -468664, 23046502, 9803137, 17597934, 2346211},
{18510800, 15337574, 26171504, 981392, -22241552, 7827556, -23491134, -11323352, 3059833, -11782870}},
{{10141598, 6082907, 17829293, -1947643, 9830092, 13613136, -25556636, -5544586, -33502212, 3592096},
{33114168, -15889352, -26525686, -13343397, 33076705, 8716171, 1151462, 1521897, -982665, -6837803},
{-32939165, -4255815, 23947181, -324178, -33072974, -12305637, -16637686, 3891704, 26353178, 693168}},
{{30374239, 1595580, -16884039, 13186931, 4600344, 406904, 9585294, -400668, 31375464, 14369965},
{-14370654, -7772529, 1510301, 6434173, -18784789, -6262728, 32732230, -13108839, 17901441, 16011505},
{18171223, -11934626, -12500402, 15197122, -11038147, -15230035, -19172240, -16046376, 8764035, 12309598}}
}, {
{{5975908, -5243188, -19459362, -9681747, -11541277, 14015782, -23665757, 1228319, 17544096, -10593782},
{5811932, -1715293, 3442887, -2269310, -18367348, -8359541, -18044043, -15410127, -5565381, 12348900},
{-31399660, 11407555, 25755363, 6891399, -3256938, 14872274, -24849353, 8141295, -10632534, -585479}},
{{-12675304, 694026, -5076145, 13300344, 14015258, -14451394, -9698672, -11329050, 30944593, 1130208},
{8247766, -6710942, -26562381, -7709309, -14401939, -14648910, 4652152, 2488540, 23550156, -271232},
{17294316, -3788438, 7026748, 15626851, 22990044, 113481, 2267737, -5908146, -408818, -137719}},
{{16091085, -16253926, 18599252, 7340678, 2137637, -1221657, -3364161, 14550936, 3260525, -7166271},
{-4910104, -13332887, 18550887, 10864893, -16459325, -7291596, -23028869, -13204905, -12748722, 2701326},
{-8574695, 16099415, 4629974, -16340524, -20786213, -6005432, -10018363, 9276971, 11329923, 1862132}},
{{14763076, -15903608, -30918270, 3689867, 3511892, 10313526, -21951088, 12219231, -9037963, -940300},
{8894987, -3446094, 6150753, 3013931, 301220, 15693451, -31981216, -2909717, -15438168, 11595570},
{15214962, 3537601, -26238722, -14058872, 4418657, -15230761, 13947276, 10730794, -13489462, -4363670}},
{{-2538306, 7682793, 32759013, 263109, -29984731, -7955452, -22332124, -10188635, 977108, 699994},
{-12466472, 4195084, -9211532, 550904, -15565337, 12917920, 19118110, -439841, -30534533, -14337913},
{31788461, -14507657, 4799989, 7372237, 8808585, -14747943, 9408237, -10051775, 12493932, -5409317}},
{{-25680606, 5260744, -19235809, -6284470, -3695942, 16566087, 27218280, 2607121, 29375955, 6024730},
{842132, -2794693, -4763381, -8722815, 26332018, -12405641, 11831880, 6985184, -9940361, 2854096},
{-4847262, -7969331, 2516242, -5847713, 9695691, -7221186, 16512645, 960770, 12121869, 16648078}},
{{-15218652, 14667096, -13336229, 2013717, 30598287, -464137, -31504922, -7882064, 20237806, 2838411},
{-19288047, 4453152, 15298546, -16178388, 22115043, -15972604, 12544294, -13470457, 1068881, -12499905},
{-9558883, -16518835, 33238498, 13506958, 30505848, -1114596, -8486907, -2630053, 12521378, 4845654}},
{{-28198521, 10744108, -2958380, 10199664, 7759311, -13088600, 3409348, -873400, -6482306, -12885870},
{-23561822, 6230156, -20382013, 10655314, -24040585, -11621172, 10477734, -1240216, -3113227, 13974498},
{12966261, 15550616, -32038948, -1615346, 21025980, -629444, 5642325, 7188737, 18895762, 12629579}}
}, {
{{14741879, -14946887, 22177208, -11721237, 1279741, 8058600, 11758140, 789443, 32195181, 3895677},
{10758205, 15755439, -4509950, 9243698, -4879422, 6879879, -2204575, -3566119, -8982069, 4429647},
{-2453894, 15725973, -20436342, -10410672, -5803908, -11040220, -7135870, -11642895, 18047436, -15281743}},
{{-25173001, -11307165, 29759956, 11776784, -22262383, -15820455, 10993114, -12850837, -17620701, -9408468},
{21987233, 700364, -24505048, 14972008, -7774265, -5718395, 32155026, 2581431, -29958985, 8773375},
{-25568350, 454463, -13211935, 16126715, 25240068, 8594567, 20656846, 12017935, -7874389, -13920155}},
{{6028182, 6263078, -31011806, -11301710, -818919, 2461772, -31841174, -5468042, -1721788, -2776725},
{-12278994, 16624277, 987579, -5922598, 32908203, 1248608, 7719845, -4166698, 28408820, 6816612},
{-10358094, -8237829, 19549651, -12169222, 22082623, 16147817, 20613181, 13982702, -10339570, 5067943}},
{{-30505967, -3821767, 12074681, 13582412, -19877972, 2443951, -19719286, 12746132, 5331210, -10105944},
{30528811, 3601899, -1957090, 4619785, -27361822, -15436388, 24180793, -12570394, 27679908, -1648928},
{9402404, -13957065, 32834043, 10838634, -26580150, -13237195, 26653274, -8685565, 22611444, -12715406}},
{{22190590, 1118029, 22736441, 15130463, -30460692, -5991321, 19189625, -4648942, 4854859, 6622139},
{-8310738, -2953450, -8262579, -3388049, -10401731, -271929, 13424426, -3567227, 26404409, 13001963},
{-31241838, -15415700, -2994250, 8939346, 11562230, -12840670, -26064365, -11621720, -15405155, 11020693}},
{{1866042, -7949489, -7898649, -10301010, 12483315, 13477547, 3175636, -12424163, 28761762, 1406734},
{-448555, -1777666, 13018551, 3194501, -9580420, -11161737, 24760585, -4347088, 25577411, -13378680},
{-24290378, 4759345, -690653, -1852816, 2066747, 10693769, -29595790, 9884936, -9368926, 4745410}},
{{-9141284, 6049714, -19531061, -4341411, -31260798, 9944276, -15462008, -11311852, 10931924, -11931931},
{-16561513, 14112680, -8012645, 4817318, -8040464, -11414606, -22853429, 10856641, -20470770, 13434654},
{22759489, -10073434, -16766264, -1871422, 13637442, -10168091, 1765144, -12654326, 28445307, -5364710}},
{{29875063, 12493613, 2795536, -3786330, 1710620, 15181182, -10195717, -8788675, 9074234, 1167180},
{-26205683, 11014233, -9842651, -2635485, -26908120, 7532294, -18716888, -9535498, 3843903, 9367684},
{-10969595, -6403711, 9591134, 9582310, 11349256, 108879, 16235123, 8601684, -139197, 4242895}}
}, {
{{22092954, -13191123, -2042793, -11968512, 32186753, -11517388, -6574341, 2470660, -27417366, 16625501},
{-11057722, 3042016, 13770083, -9257922, 584236, -544855, -7770857, 2602725, -27351616, 14247413},
{6314175, -10264892, -32772502, 15957557, -10157730, 168750, -8618807, 14290061, 27108877, -1180880}},
{{-8586597, -7170966, 13241782, 10960156, -32991015, -13794596, 33547976, -11058889, -27148451, 981874},
{22833440, 9293594, -32649448, -13618667, -9136966, 14756819, -22928859, -13970780, -10479804, -16197962},
{-7768587, 3326786, -28111797, 10783824, 19178761, 14905060, 22680049, 13906969, -15933690, 3797899}},
{{21721356, -4212746, -12206123, 9310182, -3882239, -13653110, 23740224, -2709232, 20491983, -8042152},
{9209270, -15135055, -13256557, -6167798, -731016, 15289673, 25947805, 15286587, 30997318, -6703063},
{7392032, 16618386, 23946583, -8039892, -13265164, -1533858, -14197445, -2321576, 17649998, -250080}},
{{-9301088, -14193827, 30609526, -3049543, -25175069, -1283752, -15241566, -9525724, -2233253, 7662146},
{-17558673, 1763594, -33114336, 15908610, -30040870, -12174295, 7335080, -8472199, -3174674, 3440183},
{-19889700, -5977008, -24111293, -9688870, 10799743, -16571957, 40450, -4431835, 4862400, 1133}},
{{-32856209, -7873957, -5422389, 14860950, -16319031, 7956142, 7258061, 311861, -30594991, -7379421},
{-3773428, -1565936, 28985340, 7499440, 24445838, 9325937, 29727763, 16527196, 18278453, 15405622},
{-4381906, 8508652, -19898366, -3674424, -5984453, 15149970, -13313598, 843523, -21875062, 13626197}},
{{2281448, -13487055, -10915418, -2609910, 1879358, 16164207, -10783882, 3953792, 13340839, 15928663},
{31727126, -7179855, -18437503, -8283652, 2875793, -16390330, -25269894, -7014826, -23452306, 5964753},
{4100420, -5959452, -17179337, 6017714, -18705837, 12227141, -26684835, 11344144, 2538215, -7570755}},
{{-9433605, 6123113, 11159803, -2156608, 30016280, 14966241, -20474983, 1485421, -629256, -15958862},
{-26804558, 4260919, 11851389, 9658551, -32017107, 16367492, -20205425, -13191288, 11659922, -11115118},
{26180396, 10015009, -30844224, -8581293, 5418197, 9480663, 2231568, -10170080, 33100372, -1306171}},
{{15121113, -5201871, -10389905, 15427821, -27509937, -15992507, 21670947, 4486675, -5931810, -14466380},
{16166486, -9483733, -11104130, 6023908, -31926798, -1364923, 2340060, -16254968, -10735770, -10039824},
{28042865, -3557089, -12126526, 12259706, -3717498, -6945899, 6766453, -8689599, 18036436, 5803270}}
}, {
{{-817581, 6763912, 11803561, 1585585, 10958447, -2671165, 23855391, 4598332, -6159431, -14117438},
{-31031306, -14256194, 17332029, -2383520, 31312682, -5967183, 696309, 50292, -20095739, 11763584},
{-594563, -2514283, -32234153, 12643980, 12650761, 14811489, 665117, -12613632, -19773211, -10713562}},
{{30464590, -11262872, -4127476, -12734478, 19835327, -7105613, -24396175, 2075773, -17020157, 992471},
{18357185, -6994433, 7766382, 16342475, -29324918, 411174, 14578841, 8080033, -11574335, -10601610},
{19598397, 10334610, 12555054, 2555664, 18821899, -10339780, 21873263, 16014234, 26224780, 16452269}},
{{-30223925, 5145196, 5944548, 16385966, 3976735, 2009897, -11377804, -7618186, -20533829, 3698650},
{14187449, 3448569, -10636236, -10810935, -22663880, -3433596, 7268410, -10890444, 27394301, 12015369},
{19695761, 16087646, 28032085, 12999827, 6817792, 11427614, 20244189, -1312777, -13259127, -3402461}},
{{30860103, 12735208, -1888245, -4699734, -16974906, 2256940, -8166013, 12298312, -8550524, -10393462},
{-5719826, -11245325, -1910649, 15569035, 26642876, -7587760, -5789354, -15118654, -4976164, 12651793},
{-2848395, 9953421, 11531313, -5282879, 26895123, -12697089, -13118820, -16517902, 9768698, -2533218}},
{{-24719459, 1894651, -287698, -4704085, 15348719, -8156530, 32767513, 12765450, 4940095, 10678226},
{18860224, 15980149, -18987240, -1562570, -26233012, -11071856, -7843882, 13944024, -24372348, 16582019},
{-15504260, 4970268, -29893044, 4175593, -20993212, -2199756, -11704054, 15444560, -11003761, 7989037}},
{{31490452, 5568061, -2412803, 2182383, -32336847, 4531686, -32078269, 6200206, -19686113, -14800171},
{-17308668, -15879940, -31522777, -2831, -32887382, 16375549, 8680158, -16371713, 28550068, -6857132},
{-28126887, -5688091, 16837845, -1820458, -6850681, 12700016, -30039981, 4364038, 1155602, 5988841}},
{{21890435, -13272907, -12624011, 12154349, -7831873, 15300496, 23148983, -4470481, 24618407, 8283181},
{-33136107, -10512751, 9975416, 6841041, -31559793, 16356536, 3070187, -7025928, 1466169, 10740210},
{-1509399, -15488185, -13503385, -10655916, 32799044, 909394, -13938903, -5779719, -32164649, -15327040}},
{{3960823, -14267803, -28026090, -15918051, -19404858, 13146868, 15567327, 951507, -3260321, -573935},
{24740841, 5052253, -30094131, 8961361, 25877428, 6165135, -24368180, 14397372, -7380369, -6144105},
{-28888365, 3510803, -28103278, -1158478, -11238128, -10631454, -15441463, -14453128, -1625486, -6494814}}
}, {
{{793299, -9230478, 8836302, -6235707, -27360908, -2369593, 33152843, -4885251, -9906200, -621852},
{5666233, 525582, 20782575, -8038419, -24538499, 14657740, 16099374, 1468826, -6171428, -15186581},
{-4859255, -3779343, -2917758, -6748019, 7778750, 11688288, -30404353, -9871238, -1558923, -9863646}},
{{10896332, -7719704, 824275, 472601, -19460308, 3009587, 25248958, 14783338, -30581476, -15757844},
{10566929, 12612572, -31944212, 11118703, -12633376, 12362879, 21752402, 8822496, 24003793, 14264025},
{27713862, -7355973, -11008240, 9227530, 27050101, 2504721, 23886875, -13117525, 13958495, -5732453}},
{{-23481610, 4867226, -27247128, 3900521, 29838369, -8212291, -31889399, -10041781, 7340521, -15410068},
{4646514, -8011124, -22766023, -11532654, 23184553, 8566613, 31366726, -1381061, -15066784, -10375192},
{-17270517, 12723032, -16993061, 14878794, 21619651, -6197576, 27584817, 3093888, -8843694, 3849921}},
{{-9064912, 2103172, 25561640, -15125738, -5239824, 9582958, 32477045, -9017955, 5002294, -15550259},
{-12057553, -11177906, 21115585, -13365155, 8808712, -12030708, 16489530, 13378448, -25845716, 12741426},
{-5946367, 10645103, -30911586, 15390284, -3286982, -7118677, 24306472, 15852464, 28834118, -7646072}},
{{-17335748, -9107057, -24531279, 9434953, -8472084, -583362, -13090771, 455841, 20461858, 5491305},
{13669248, -16095482, -12481974, -10203039, -14569770, -11893198, -24995986, 11293807, -28588204, -9421832},
{28497928, 6272777, -33022994, 14470570, 8906179, -1225630, 18504674, -14165166, 29867745, -8795943}},
{{-16207023, 13517196, -27799630, -13697798, 24009064, -6373891, -6367600, -13175392, 22853429, -4012011},
{24191378, 16712145, -13931797, 15217831, 14542237, 1646131, 18603514, -11037887, 12876623, -2112447},
{17902668, 4518229, -411702, -2829247, 26878217, 5258055, -12860753, 608397, 16031844, 3723494}},
{{-28632773, 12763728, -20446446, 7577504, 33001348, -13017745, 17558842, -7872890, 23896954, -4314245},
{-20005381, -12011952, 31520464, 605201, 2543521, 5991821, -2945064, 7229064, -9919646, -8826859},
{28816045, 298879, -28165016, -15920938, 19000928, -1665890, -12680833, -2949325, -18051778, -2082915}},
{{16000882, -344896, 3493092, -11447198, -29504595, -13159789, 12577740, 16041268, -19715240, 7847707},
{10151868, 10572098, 27312476, 7922682, 14825339, 4723128, -32855931, -6519018, -10020567, 3852848},
{-11430470, 15697596, -21121557, -4420647, 5386314, 15063598, 16514493, -15932110, 29330899, -15076224}}
}, {
{{-25499735, -4378794, -15222908, -6901211, 16615731, 2051784, 3303702, 15490, -27548796, 12314391},
{15683520, -6003043, 18109120, -9980648, 15337968, -5997823, -16717435, 15921866, 16103996, -3731215},
{-23169824, -10781249, 13588192, -1628807, -3798557, -1074929, -19273607, 5402699, -29815713, -9841101}},
{{23190676, 2384583, -32714340, 3462154, -29903655, -1529132, -11266856, 8911517, -25205859, 2739713},
{21374101, -3554250, -33524649, 9874411, 15377179, 11831242, -33529904, 6134907, 4931255, 11987849},
{-7732, -2978858, -16223486, 7277597, 105524, -322051, -31480539, 13861388, -30076310, 10117930}},
{{-29501170, -10744872, -26163768, 13051539, -25625564, 5089643, -6325503, 6704079, 12890019, 15728940},
{-21972360, -11771379, -951059, -4418840, 14704840, 2695116, 903376, -10428139, 12885167, 8311031},
{-17516482, 5352194, 10384213, -13811658, 7506451, 13453191, 26423267, 4384730, 1888765, -5435404}},
{{-25817338, -3107312, -13494599, -3182506, 30896459, -13921729, -32251644, -12707869, -19464434, -3340243},
{-23607977, -2665774, -526091, 4651136, 5765089, 4618330, 6092245, 14845197, 17151279, -9854116},
{-24830458, -12733720, -15165978, 10367250, -29530908, -265356, 22825805, -7087279, -16866484, 16176525}},
{{-23583256, 6564961, 20063689, 3798228, -4740178, 7359225, 2006182, -10363426, -28746253, -10197509},
{-10626600, -4486402, -13320562, -5125317, 3432136, -6393229, 23632037, -1940610, 32808310, 1099883},
{15030977, 5768825, -27451236, -2887299, -6427378, -15361371, -15277896, -6809350, 2051441, -15225865}},
{{-3362323, -7239372, 7517890, 9824992, 23555850, 295369, 5148398, -14154188, -22686354, 16633660},
{4577086, -16752288, 13249841, -15304328, 19958763, -14537274, 18559670, -10759549, 8402478, -9864273},
{-28406330, -1051581, -26790155, -907698, -17212414, -11030789, 9453451, -14980072, 17983010, 9967138}},
{{-25762494, 6524722, 26585488, 9969270, 24709298, 1220360, -1677990, 7806337, 17507396, 3651560},
{-10420457, -4118111, 14584639, 15971087, -15768321, 8861010, 26556809, -5574557, -18553322, -11357135},
{2839101, 14284142, 4029895, 3472686, 14402957, 12689363, -26642121, 8459447, -5605463, -7621941}},
{{-4839289, -3535444, 9744961, 2871048, 25113978, 3187018, -25110813, -849066, 17258084, -7977739},
{18164541, -10595176, -17154882, -1542417, 19237078, -9745295, 23357533, -15217008, 26908270, 12150756},
{-30264870, -7647865, 5112249, -7036672, -1499807, -6974257, 43168, -5537701, -32302074, 16215819}}
}, {
{{-6898905, 9824394, -12304779, -4401089, -31397141, -6276835, 32574489, 12532905, -7503072, -8675347},
{-27343522, -16515468, -27151524, -10722951, 946346, 16291093, 254968, 7168080, 21676107, -1943028},
{21260961, -8424752, -16831886, -11920822, -23677961, 3968121, -3651949, -6215466, -3556191, -7913075}},
{{16544754, 13250366, -16804428, 15546242, -4583003, 12757258, -2462308, -8680336, -18907032, -9662799},
{-2415239, -15577728, 18312303, 4964443, -15272530, -12653564, 26820651, 16690659, 25459437, -4564609},
{-25144690, 11425020, 28423002, -11020557, -6144921, -15826224, 9142795, -2391602, -6432418, -1644817}},
{{-23104652, 6253476, 16964147, -3768872, -25113972, -12296437, -27457225, -16344658, 6335692, 7249989},
{-30333227, 13979675, 7503222, -12368314, -11956721, -4621693, -30272269, 2682242, 25993170, -12478523},
{4364628, 5930691, 32304656, -10044554, -8054781, 15091131, 22857016, -10598955, 31820368, 15075278}},
{{31879134, -8918693, 17258761, 90626, -8041836, -4917709, 24162788, -9650886, -17970238, 12833045},
{19073683, 14851414, -24403169, -11860168, 7625278, 11091125, -19619190, 2074449, -9413939, 14905377},
{24483667, -11935567, -2518866, -11547418, -1553130, 15355506, -25282080, 9253129, 27628530, -7555480}},
{{17597607, 8340603, 19355617, 552187, 26198470, -3176583, 4593324, -9157582, -14110875, 15297016},
{510886, 14337390, -31785257, 16638632, 6328095, 2713355, -20217417, -11864220, 8683221, 2921426},
{18606791, 11874196, 27155355, -5281482, -24031742, 6265446, -25178240, -1278924, 4674690, 13890525}},
{{13609624, 13069022, -27372361, -13055908, 24360586, 9592974, 14977157, 9835105, 4389687, 288396},
{9922506, -519394, 13613107, 5883594, -18758345, -434263, -12304062, 8317628, 23388070, 16052080},
{12720016, 11937594, -31970060, -5028689, 26900120, 8561328, -20155687, -11632979, -14754271, -10812892}},
{{15961858, 14150409, 26716931, -665832, -22794328, 13603569, 11829573, 7467844, -28822128, 929275},
{11038231, -11582396, -27310482, -7316562, -10498527, -16307831, -23479533, -9371869, -21393143, 2465074},
{20017163, -4323226, 27915242, 1529148, 12396362, 15675764, 13817261, -9658066, 2463391, -4622140}},
{{-16358878, -12663911, -12065183, 4996454, -1256422, 1073572, 9583558, 12851107, 4003896, 12673717},
{-1731589, -15155870, -3262930, 16143082, 19294135, 13385325, 14741514, -9103726, 7903886, 2348101},
{24536016, -16515207, 12715592, -3862155, 1511293, 10047386, -3842346, -7129159, -28377538, 10048127}}
}, {
{{-12622226, -6204820, 30718825, 2591312, -10617028, 12192840, 18873298, -7297090, -32297756, 15221632},
{-26478122, -11103864, 11546244, -1852483, 9180880, 7656409, -21343950, 2095755, 29769758, 6593415},
{-31994208, -2907461, 4176912, 3264766, 12538965, -868111, 26312345, -6118678, 30958054, 8292160}},
{{31429822, -13959116, 29173532, 15632448, 12174511, -2760094, 32808831, 3977186, 26143136, -3148876},
{22648901, 1402143, -22799984, 13746059, 7936347, 365344, -8668633, -1674433, -3758243, -2304625},
{-15491917, 8012313, -2514730, -12702462, -23965846, -10254029, -1612713, -1535569, -16664475, 8194478}},
{{27338066, -7507420, -7414224, 10140405, -19026427, -6589889, 27277191, 8855376, 28572286, 3005164},
{26287124, 4821776, 25476601, -4145903, -3764513, -15788984, -18008582, 1182479, -26094821, -13079595},
{-7171154, 3178080, 23970071, 6201893, -17195577, -4489192, -21876275, -13982627, 32208683, -1198248}},
{{-16657702, 2817643, -10286362, 14811298, 6024667, 13349505, -27315504, -10497842, -27672585, -11539858},
{15941029, -9405932, -21367050, 8062055, 31876073, -238629, -15278393, -1444429, 15397331, -4130193},
{8934485, -13485467, -23286397, -13423241, -32446090, 14047986, 31170398, -1441021, -27505566, 15087184}},
{{-18357243, -2156491, 24524913, -16677868, 15520427, -6360776, -15502406, 11461896, 16788528, -5868942},
{-1947386, 16013773, 21750665, 3714552, -17401782, -16055433, -3770287, -10323320, 31322514, -11615635},
{21426655, -5650218, -13648287, -5347537, -28812189, -4920970, -18275391, -14621414, 13040862, -12112948}},
{{11293895, 12478086, -27136401, 15083750, -29307421, 14748872, 14555558, -13417103, 1613711, 4896935},
{-25894883, 15323294, -8489791, -8057900, 25967126, -13425460, 2825960, -4897045, -23971776, -11267415},
{-15924766, -5229880, -17443532, 6410664, 3622847, 10243618, 20615400, 12405433, -23753030, -8436416}},
{{-7091295, 12556208, -20191352, 9025187, -17072479, 4333801, 4378436, 2432030, 23097949, -566018},
{4565804, -16025654, 20084412, -7842817, 1724999, 189254, 24767264, 10103221, -18512313, 2424778},
{366633, -11976806, 8173090, -6890119, 30788634, 5745705, -7168678, 1344109, -3642553, 12412659}},
{{-24001791, 7690286, 14929416, -168257, -32210835, -13412986, 24162697, -15326504, -3141501, 11179385},
{18289522, -14724954, 8056945, 16430056, -21729724, 7842514, -6001441, -1486897, -18684645, -11443503},
{476239, 6601091, -6152790, -9723375, 17503545, -4863900, 27672959, 13403813, 11052904, 5219329}}
}, {
{{20678546, -8375738, -32671898, 8849123, -5009758, 14574752, 31186971, -3973730, 9014762, -8579056},
{-13644050, -10350239, -15962508, 5075808, -1514661, -11534600, -33102500, 9160280, 8473550, -3256838},
{24900749, 14435722, 17209120, -15292541, -22592275, 9878983, -7689309, -16335821, -24568481, 11788948}},
{{-3118155, -11395194, -13802089, 14797441, 9652448, -6845904, -20037437, 10410733, -24568470, -1458691},
{-15659161, 16736706, -22467150, 10215878, -9097177, 7563911, 11871841, -12505194, -18513325, 8464118},
{-23400612, 8348507, -14585951, -861714, -3950205, -6373419, 14325289, 8628612, 33313881, -8370517}},
{{-20186973, -4967935, 22367356, 5271547, -1097117, -4788838, -24805667, -10236854, -8940735, -5818269},
{-6948785, -1795212, -32625683, -16021179, 32635414, -7374245, 15989197, -12838188, 28358192, -4253904},
{-23561781, -2799059, -32351682, -1661963, -9147719, 10429267, -16637684, 4072016, -5351664, 5596589}},
{{-28236598, -3390048, 12312896, 6213178, 3117142, 16078565, 29266239, 2557221, 1768301, 15373193},
{-7243358, -3246960, -4593467, -7553353, -127927, -912245, -1090902, -4504991, -24660491, 3442910},
{-30210571, 5124043, 14181784, 8197961, 18964734, -11939093, 22597931, 7176455, -18585478, 13365930}},
{{-7877390, -1499958, 8324673, 4690079, 6261860, 890446, 24538107, -8570186, -9689599, -3031667},
{25008904, -10771599, -4305031, -9638010, 16265036, 15721635, 683793, -11823784, 15723479, -15163481},
{-9660625, 12374379, -27006999, -7026148, -7724114, -12314514, 11879682, 5400171, 519526, -1235876}},
{{22258397, -16332233, -7869817, 14613016, -22520255, -2950923, -20353881, 7315967, 16648397, 7605640},
{-8081308, -8464597, -8223311, 9719710, 19259459, -15348212, 23994942, -5281555, -9468848, 4763278},
{-21699244, 9220969, -15730624, 1084137, -25476107, -2852390, 31088447, -7764523, -11356529, 728112}},
{{26047220, -11751471, -6900323, -16521798, 24092068, 9158119, -4273545, -12555558, -29365436, -5498272},
{17510331, -322857, 5854289, 8403524, 17133918, -3112612, -28111007, 12327945, 10750447, 10014012},
{-10312768, 3936952, 9156313, -8897683, 16498692, -994647, -27481051, -666732, 3424691, 7540221}},
{{30322361, -6964110, 11361005, -4143317, 7433304, 4989748, -7071422, -16317219, -9244265, 15258046},
{13054562, -2779497, 19155474, 469045, -12482797, 4566042, 5631406, 2711395, 1062915, -5136345},
{-19240248, -11254599, -29509029, -7499965, -5835763, 13005411, -6066489, 12194497, 32960380, 1459310}}
}, {
{{19852034, 7027924, 23669353, 10020366, 8586503, -6657907, 394197, -6101885, 18638003, -11174937},
{31395534, 15098109, 26581030, 8030562, -16527914, -5007134, 9012486, -7584354, -6643087, -5442636},
{-9192165, -2347377, -1997099, 4529534, 25766844, 607986, -13222, 9677543, -32294889, -6456008}},
{{-2444496, -149937, 29348902, 8186665, 1873760, 12489863, -30934579, -7839692, -7852844, -8138429},
{-15236356, -15433509, 7766470, 746860, 26346930, -10221762, -27333451, 10754588, -9431476, 5203576},
{31834314, 14135496, -770007, 5159118, 20917671, -16768096, -7467973, -7337524, 31809243, 7347066}},
{{-9606723, -11874240, 20414459, 13033986, 13716524, -11691881, 19797970, -12211255, 15192876, -2087490},
{-12663563, -2181719, 1168162, -3804809, 26747877, -14138091, 10609330, 12694420, 33473243, -13382104},
{33184999, 11180355, 15832085, -11385430, -1633671, 225884, 15089336, -11023903, -6135662, 14480053}},
{{31308717, -5619998, 31030840, -1897099, 15674547, -6582883, 5496208, 13685227, 27595050, 8737275},
{-20318852, -15150239, 10933843, -16178022, 8335352, -7546022, -31008351, -12610604, 26498114, 66511},
{22644454, -8761729, -16671776, 4884562, -3105614, -13559366, 30540766, -4286747, -13327787, -7515095}},
{{-28017847, 9834845, 18617207, -2681312, -3401956, -13307506, 8205540, 13585437, -17127465, 15115439},
{23711543, -672915, 31206561, -8362711, 6164647, -9709987, -33535882, -1426096, 8236921, 16492939},
{-23910559, -13515526, -26299483, -4503841, 25005590, -7687270, 19574902, 10071562, 6708380, -6222424}},
{{2101391, -4930054, 19702731, 2367575, -15427167, 1047675, 5301017, 9328700, 29955601, -11678310},
{3096359, 9271816, -21620864, -15521844, -14847996, -7592937, -25892142, -12635595, -9917575, 6216608},
{-32615849, 338663, -25195611, 2510422, -29213566, -13820213, 24822830, -6146567, -26767480, 7525079}},
{{-23066649, -13985623, 16133487, -7896178, -3389565, 778788, -910336, -2782495, -19386633, 11994101},
{21691500, -13624626, -641331, -14367021, 3285881, -3483596, -25064666, 9718258, -7477437, 13381418},
{18445390, -4202236, 14979846, 11622458, -1727110, -3582980, 23111648, -6375247, 28535282, 15779576}},
{{30098053, 3089662, -9234387, 16662135, -21306940, 11308411, -14068454, 12021730, 9955285, -16303356},
{9734894, -14576830, -7473633, -9138735, 2060392, 11313496, -18426029, 9924399, 20194861, 13380996},
{-26378102, -7965207, -22167821, 15789297, -18055342, -6168792, -1984914, 15707771, 26342023, 10146099}}
}, {
{{-26016874, -219943, 21339191, -41388, 19745256, -2878700, -29637280, 2227040, 21612326, -545728},
{-13077387, 1184228, 23562814, -5970442, -20351244, -6348714, 25764461, 12243797, -20856566, 11649658},
{-10031494, 11262626, 27384172, 2271902, 26947504, -15997771, 39944, 6114064, 33514190, 2333242}},
{{-21433588, -12421821, 8119782, 7219913, -21830522, -9016134, -6679750, -12670638, 24350578, -13450001},
{-4116307, -11271533, -23886186, 4843615, -30088339, 690623, -31536088, -10406836, 8317860, 12352766},
{18200138, -14475911, -33087759, -2696619, -23702521, -9102511, -23552096, -2287550, 20712163, 6719373}},
{{26656208, 6075253, -7858556, 1886072, -28344043, 4262326, 11117530, -3763210, 26224235, -3297458},
{-17168938, -14854097, -3395676, -16369877, -19954045, 14050420, 21728352, 9493610, 18620611, -16428628},
{-13323321, 13325349, 11432106, 5964811, 18609221, 6062965, -5269471, -9725556, -30701573, -16479657}},
{{-23860538, -11233159, 26961357, 1640861, -32413112, -16737940, 12248509, -5240639, 13735342, 1934062},
{25089769, 6742589, 17081145, -13406266, 21909293, -16067981, -15136294, -3765346, -21277997, 5473616},
{31883677, -7961101, 1083432, -11572403, 22828471, 13290673, -7125085, 12469656, 29111212, -5451014}},
{{24244947, -15050407, -26262976, 2791540, -14997599, 16666678, 24367466, 6388839, -10295587, 452383},
{-25640782, -3417841, 5217916, 16224624, 19987036, -4082269, -24236251, -5915248, 15766062, 8407814},
{-20406999, 13990231, 15495425, 16395525, 5377168, 15166495, -8917023, -4388953, -8067909, 2276718}},
{{30157918, 12924066, -17712050, 9245753, 19895028, 3368142, -23827587, 5096219, 22740376, -7303417},
{2041139, -14256350, 7783687, 13876377, -25946985, -13352459, 24051124, 13742383, -15637599, 13295222},
{33338237, -8505733, 12532113, 7977527, 9106186, -1715251, -17720195, -4612972, -4451357, -14669444}},
{{-20045281, 5454097, -14346548, 6447146, 28862071, 1883651, -2469266, -4141880, 7770569, 9620597},
{23208068, 7979712, 33071466, 8149229, 1758231, -10834995, 30945528, -1694323, -33502340, -14767970},
{1439958, -16270480, -1079989, -793782, 4625402, 10647766, -5043801, 1220118, 30494170, -11440799}},
{{-5037580, -13028295, -2970559, -3061767, 15640974, -6701666, -26739026, 926050, -1684339, -13333647},
{13908495, -3549272, 30919928, -6273825, -21521863, 7989039, 9021034, 9078865, 3353509, 4033511},
{-29663431, -15113610, 32259991, -344482, 24295849, -12912123, 23161163, 8839127, 27485041, 7356032}}
}, {
{{9661027, 705443, 11980065, -5370154, -1628543, 14661173, -6346142, 2625015, 28431036, -16771834},
{-23839233, -8311415, -25945511, 7480958, -17681669, -8354183, -22545972, 14150565, 15970762, 4099461},
{29262576, 16756590, 26350592, -8793563, 8529671, -11208050, 13617293, -9937143, 11465739, 8317062}},
{{-25493081, -6962928, 32500200, -9419051, -23038724, -2302222, 14898637, 3848455, 20969334, -5157516},
{-20384450, -14347713, -18336405, 13884722, -33039454, 2842114, -21610826, -3649888, 11177095, 14989547},
{-24496721, -11716016, 16959896, 2278463, 12066309, 10137771, 13515641, 2581286, -28487508, 9930240}},
{{-17751622, -2097826, 16544300, -13009300, -15914807, -14949081, 18345767, -13403753, 16291481, -5314038},
{-33229194, 2553288, 32678213, 9875984, 8534129, 6889387, -9676774, 6957617, 4368891, 9788741},
{16660756, 7281060, -10830758, 12911820, 20108584, -8101676, -21722536, -8613148, 16250552, -11111103}},
{{-19765507, 2390526, -16551031, 14161980, 1905286, 6414907, 4689584, 10604807, -30190403, 4782747},
{-1354539, 14736941, -7367442, -13292886, 7710542, -14155590, -9981571, 4383045, 22546403, 437323},
{31665577, -12180464, -16186830, 1491339, -18368625, 3294682, 27343084, 2786261, -30633590, -14097016}},
{{-14467279, -683715, -33374107, 7448552, 19294360, 14334329, -19690631, 2355319, -19284671, -6114373},
{15121312, -15796162, 6377020, -6031361, -10798111, -12957845, 18952177, 15496498, -29380133, 11754228},
{-2637277, -13483075, 8488727, -14303896, 12728761, -1622493, 7141596, 11724556, 22761615, -10134141}},
{{16918416, 11729663, -18083579, 3022987, -31015732, -13339659, -28741185, -12227393, 32851222, 11717399},
{11166634, 7338049, -6722523, 4531520, -29468672, -7302055, 31474879, 3483633, -1193175, -4030831},
{-185635, 9921305, 31456609, -13536438, -12013818, 13348923, 33142652, 6546660, -19985279, -3948376}},
{{-32460596, 11266712, -11197107, -7899103, 31703694, 3855903, -8537131, -12833048, -30772034, -15486313},
{-18006477, 12709068, 3991746, -6479188, -21491523, -10550425, -31135347, -16049879, 10928917, 3011958},
{-6957757, -15594337, 31696059, 334240, 29576716, 14796075, -30831056, -12805180, 18008031, 10258577}},
{{-22448644, 15655569, 7018479, -4410003, -30314266, -1201591, -1853465, 1367120, 25127874, 6671743},
{29701166, -14373934, -10878120, 9279288, -17568, 13127210, 21382910, 11042292, 25838796, 4642684},
{-20430234, 14955537, -24126347, 8124619, -5369288, -5990470, 30468147, -13900640, 18423289, 4177476}}
}
};
const ge_precomp ge_Bi[8] = {
{{25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605},
{-12545711, 934262, -2722910, 3049990, -727428, 9406986, 12720692, 5043384, 19500929, -15469378},
{-8738181, 4489570, 9688441, -14785194, 10184609, -12363380, 29287919, 11864899, -24514362, -4438546}}, {{15636291, -9688557, 24204773, -7912398, 616977, -16685262, 27787600, -14772189, 28944400, -1550024},
{16568933, 4717097, -11556148, -1102322, 15682896, -11807043, 16354577, -11775962, 7689662, 11199574},
{30464156, -5976125, -11779434, -15670865, 23220365, 15915852, 7512774, 10017326, -17749093, -9920357}}, {{10861363, 11473154, 27284546, 1981175, -30064349, 12577861, 32867885, 14515107, -15438304, 10819380},
{4708026, 6336745, 20377586, 9066809, -11272109, 6594696, -25653668, 12483688, -12668491, 5581306},
{19563160, 16186464, -29386857, 4097519, 10237984, -4348115, 28542350, 13850243, -23678021, -15815942}}, {{5153746, 9909285, 1723747, -2777874, 30523605, 5516873, 19480852, 5230134, -23952439, -15175766},
{-30269007, -3463509, 7665486, 10083793, 28475525, 1649722, 20654025, 16520125, 30598449, 7715701},
{28881845, 14381568, 9657904, 3680757, -20181635, 7843316, -31400660, 1370708, 29794553, -1409300}}, {{-22518993, -6692182, 14201702, -8745502, -23510406, 8844726, 18474211, -1361450, -13062696, 13821877},
{-6455177, -7839871, 3374702, -4740862, -27098617, -10571707, 31655028, -7212327, 18853322, -14220951},
{4566830, -12963868, -28974889, -12240689, -7602672, -2830569, -8514358, -10431137, 2207753, -3209784}}, {{-25154831, -4185821, 29681144, 7868801, -6854661, -9423865, -12437364, -663000, -31111463, -16132436},
{25576264, -2703214, 7349804, -11814844, 16472782, 9300885, 3844789, 15725684, 171356, 6466918},
{23103977, 13316479, 9739013, -16149481, 817875, -15038942, 8965339, -14088058, -30714912, 16193877}}, {{-33521811, 3180713, -2394130, 14003687, -16903474, -16270840, 17238398, 4729455, -18074513, 9256800},
{-25182317, -4174131, 32336398, 5036987, -21236817, 11360617, 22616405, 9761698, -19827198, 630305},
{-13720693, 2639453, -24237460, -7406481, 9494427, -5774029, -6554551, -15960994, -2449256, -14291300}}, {{-3151181, -5046075, 9282714, 6866145, -31907062, -863023, -18940575, 15033784, 25105118, -7894876},
{-24326370, 15950226, -31801215, -14592823, -11662737, -5090925, 1573892, -2625887, 2198790, -15804619},
{-3099351, 10324967, -2241613, 7453183, -5446979, -2735503, -13812022, -16236442, -32461234, -12290683}}
};
/* A = 2 * (1 - d) / (1 + d) = 486662 */
const fe fe_ma2 = {-12721188, -3529, 0, 0, 0, 0, 0, 0, 0, 0}; /* -A^2 */
const fe fe_ma = {-486662, 0, 0, 0, 0, 0, 0, 0, 0, 0}; /* -A */
const fe fe_fffb1 = {-31702527, -2466483, -26106795, -12203692, -12169197, -321052, 14850977, -10296299, -16929438, -407568}; /* sqrt(-2 * A * (A + 2)) */
const fe fe_fffb2 = {8166131, -6741800, -17040804, 3154616, 21461005, 1466302, -30876704, -6368709, 10503587, -13363080}; /* sqrt(2 * A * (A + 2)) */
const fe fe_fffb3 = {-13620103, 14639558, 4532995, 7679154, 16815101, -15883539, -22863840, -14813421, 13716513, -6477756}; /* sqrt(-sqrt(-1) * A * (A + 2)) */
const fe fe_fffb4 = {-21786234, -12173074, 21573800, 4524538, -4645904, 16204591, 8012863, -8444712, 3212926, 6885324}; /* sqrt(sqrt(-1) * A * (A + 2)) */
const ge_p3 ge_p3_identity = { {0}, {1, 0}, {1, 0}, {0} };
const ge_p3 ge_p3_H = {
{7329926, -15101362, 31411471, 7614783, 27996851, -3197071, -11157635, -6878293, 466949, -7986503},
{5858699, 5096796, 21321203, -7536921, -5553480, -11439507, -5627669, 15045946, 19977121, 5275251},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{23443568, -5110398, -8776029, -4345135, 6889568, -14710814, 7474843, 3279062, 14550766, -7453428}
};

View file

@ -1,82 +0,0 @@
// Copyright (c) 2014-2023, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#pragma once
#include <cstddef>
#include <cstring>
#include <functional>
#include <sodium/crypto_verify_32.h>
#define CRYPTO_MAKE_COMPARABLE(type) \
namespace crypto { \
inline bool operator==(const type &_v1, const type &_v2) { \
return !memcmp(&_v1, &_v2, sizeof(_v1)); \
} \
inline bool operator!=(const type &_v1, const type &_v2) { \
return !operator==(_v1, _v2); \
} \
}
#define CRYPTO_MAKE_COMPARABLE_CONSTANT_TIME(type) \
namespace crypto { \
inline bool operator==(const type &_v1, const type &_v2) { \
static_assert(sizeof(_v1) == 32, "constant time comparison is only implenmted for 32 bytes"); \
return crypto_verify_32((const unsigned char*)&_v1, (const unsigned char*)&_v2) == 0; \
} \
inline bool operator!=(const type &_v1, const type &_v2) { \
return !operator==(_v1, _v2); \
} \
}
#define CRYPTO_DEFINE_HASH_FUNCTIONS(type) \
namespace crypto { \
static_assert(sizeof(std::size_t) <= sizeof(type), "Size of " #type " must be at least that of size_t"); \
inline std::size_t hash_value(const type &_v) { \
return reinterpret_cast<const std::size_t &>(_v); \
} \
} \
namespace std { \
template<> \
struct hash<crypto::type> { \
std::size_t operator()(const crypto::type &_v) const { \
return reinterpret_cast<const std::size_t &>(_v); \
} \
}; \
}
#define CRYPTO_MAKE_HASHABLE(type) \
CRYPTO_MAKE_COMPARABLE(type) \
CRYPTO_DEFINE_HASH_FUNCTIONS(type)
#define CRYPTO_MAKE_HASHABLE_CONSTANT_TIME(type) \
CRYPTO_MAKE_COMPARABLE_CONSTANT_TIME(type) \
CRYPTO_DEFINE_HASH_FUNCTIONS(type)

View file

@ -1,367 +0,0 @@
/* hash.c April 2012
* Groestl ANSI C code optimised for 32-bit machines
* Author: Thomas Krinninger
*
* This work is based on the implementation of
* Soeren S. Thomsen and Krystian Matusiewicz
*
*
*/
#include <stddef.h>
#include "groestl.h"
#include "groestl_tables.h"
#define P_TYPE 0
#define Q_TYPE 1
const uint8_t shift_Values[2][8] = {{0,1,2,3,4,5,6,7},{1,3,5,7,0,2,4,6}};
const uint8_t indices_cyclic[15] = {0,1,2,3,4,5,6,7,0,1,2,3,4,5,6};
#if BYTE_ORDER == LITTLE_ENDIAN
#define ROTATE_COLUMN_DOWN(v1, v2, amount_bytes, temp_var) {temp_var = (v1<<(8*amount_bytes))|(v2>>(8*(4-amount_bytes))); \
v2 = (v2<<(8*amount_bytes))|(v1>>(8*(4-amount_bytes))); \
v1 = temp_var;}
#else
#define ROTATE_COLUMN_DOWN(v1, v2, amount_bytes, temp_var) {temp_var = (v1>>(8*amount_bytes))|(v2<<(8*(4-amount_bytes))); \
v2 = (v2>>(8*amount_bytes))|(v1<<(8*(4-amount_bytes))); \
v1 = temp_var;}
#endif
#define COLUMN(x,y,i,c0,c1,c2,c3,c4,c5,c6,c7,tv1,tv2,tu,tl,t) \
tu = T[2*(uint32_t)x[4*c0+0]]; \
tl = T[2*(uint32_t)x[4*c0+0]+1]; \
tv1 = T[2*(uint32_t)x[4*c1+1]]; \
tv2 = T[2*(uint32_t)x[4*c1+1]+1]; \
ROTATE_COLUMN_DOWN(tv1,tv2,1,t) \
tu ^= tv1; \
tl ^= tv2; \
tv1 = T[2*(uint32_t)x[4*c2+2]]; \
tv2 = T[2*(uint32_t)x[4*c2+2]+1]; \
ROTATE_COLUMN_DOWN(tv1,tv2,2,t) \
tu ^= tv1; \
tl ^= tv2; \
tv1 = T[2*(uint32_t)x[4*c3+3]]; \
tv2 = T[2*(uint32_t)x[4*c3+3]+1]; \
ROTATE_COLUMN_DOWN(tv1,tv2,3,t) \
tu ^= tv1; \
tl ^= tv2; \
tl ^= T[2*(uint32_t)x[4*c4+0]]; \
tu ^= T[2*(uint32_t)x[4*c4+0]+1]; \
tv1 = T[2*(uint32_t)x[4*c5+1]]; \
tv2 = T[2*(uint32_t)x[4*c5+1]+1]; \
ROTATE_COLUMN_DOWN(tv1,tv2,1,t) \
tl ^= tv1; \
tu ^= tv2; \
tv1 = T[2*(uint32_t)x[4*c6+2]]; \
tv2 = T[2*(uint32_t)x[4*c6+2]+1]; \
ROTATE_COLUMN_DOWN(tv1,tv2,2,t) \
tl ^= tv1; \
tu ^= tv2; \
tv1 = T[2*(uint32_t)x[4*c7+3]]; \
tv2 = T[2*(uint32_t)x[4*c7+3]+1]; \
ROTATE_COLUMN_DOWN(tv1,tv2,3,t) \
tl ^= tv1; \
tu ^= tv2; \
y[i] = tu; \
y[i+1] = tl;
/* compute one round of P (short variants) */
static void RND512P(uint8_t *x, uint32_t *y, uint32_t r) {
uint32_t temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp;
uint32_t* x32 = (uint32_t*)x;
x32[ 0] ^= SWAP32LE(0x00000000)^r;
x32[ 2] ^= SWAP32LE(0x00000010)^r;
x32[ 4] ^= SWAP32LE(0x00000020)^r;
x32[ 6] ^= SWAP32LE(0x00000030)^r;
x32[ 8] ^= SWAP32LE(0x00000040)^r;
x32[10] ^= SWAP32LE(0x00000050)^r;
x32[12] ^= SWAP32LE(0x00000060)^r;
x32[14] ^= SWAP32LE(0x00000070)^r;
COLUMN(x,y, 0, 0, 2, 4, 6, 9, 11, 13, 15, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
COLUMN(x,y, 2, 2, 4, 6, 8, 11, 13, 15, 1, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
COLUMN(x,y, 4, 4, 6, 8, 10, 13, 15, 1, 3, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
COLUMN(x,y, 6, 6, 8, 10, 12, 15, 1, 3, 5, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
COLUMN(x,y, 8, 8, 10, 12, 14, 1, 3, 5, 7, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
COLUMN(x,y,10, 10, 12, 14, 0, 3, 5, 7, 9, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
COLUMN(x,y,12, 12, 14, 0, 2, 5, 7, 9, 11, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
COLUMN(x,y,14, 14, 0, 2, 4, 7, 9, 11, 13, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
}
/* compute one round of Q (short variants) */
static void RND512Q(uint8_t *x, uint32_t *y, uint32_t r) {
uint32_t temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp;
uint32_t* x32 = (uint32_t*)x;
x32[ 0] = ~x32[ 0];
x32[ 1] ^= SWAP32LE(0xffffffff)^r;
x32[ 2] = ~x32[ 2];
x32[ 3] ^= SWAP32LE(0xefffffff)^r;
x32[ 4] = ~x32[ 4];
x32[ 5] ^= SWAP32LE(0xdfffffff)^r;
x32[ 6] = ~x32[ 6];
x32[ 7] ^= SWAP32LE(0xcfffffff)^r;
x32[ 8] = ~x32[ 8];
x32[ 9] ^= SWAP32LE(0xbfffffff)^r;
x32[10] = ~x32[10];
x32[11] ^= SWAP32LE(0xafffffff)^r;
x32[12] = ~x32[12];
x32[13] ^= SWAP32LE(0x9fffffff)^r;
x32[14] = ~x32[14];
x32[15] ^= SWAP32LE(0x8fffffff)^r;
COLUMN(x,y, 0, 2, 6, 10, 14, 1, 5, 9, 13, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
COLUMN(x,y, 2, 4, 8, 12, 0, 3, 7, 11, 15, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
COLUMN(x,y, 4, 6, 10, 14, 2, 5, 9, 13, 1, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
COLUMN(x,y, 6, 8, 12, 0, 4, 7, 11, 15, 3, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
COLUMN(x,y, 8, 10, 14, 2, 6, 9, 13, 1, 5, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
COLUMN(x,y,10, 12, 0, 4, 8, 11, 15, 3, 7, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
COLUMN(x,y,12, 14, 2, 6, 10, 13, 1, 5, 9, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
COLUMN(x,y,14, 0, 4, 8, 12, 15, 3, 7, 11, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
}
/* compute compression function (short variants) */
static void F512(uint32_t *h, const uint32_t *m) {
int i;
uint32_t Ptmp[2*COLS512];
uint32_t Qtmp[2*COLS512];
uint32_t y[2*COLS512];
uint32_t z[2*COLS512];
for (i = 0; i < 2*COLS512; i++) {
z[i] = m[i];
Ptmp[i] = h[i]^m[i];
}
/* compute Q(m) */
RND512Q((uint8_t*)z, y, SWAP32LE(0x00000000));
RND512Q((uint8_t*)y, z, SWAP32LE(0x01000000));
RND512Q((uint8_t*)z, y, SWAP32LE(0x02000000));
RND512Q((uint8_t*)y, z, SWAP32LE(0x03000000));
RND512Q((uint8_t*)z, y, SWAP32LE(0x04000000));
RND512Q((uint8_t*)y, z, SWAP32LE(0x05000000));
RND512Q((uint8_t*)z, y, SWAP32LE(0x06000000));
RND512Q((uint8_t*)y, z, SWAP32LE(0x07000000));
RND512Q((uint8_t*)z, y, SWAP32LE(0x08000000));
RND512Q((uint8_t*)y, Qtmp, SWAP32LE(0x09000000));
/* compute P(h+m) */
RND512P((uint8_t*)Ptmp, y, SWAP32LE(0x00000000));
RND512P((uint8_t*)y, z, SWAP32LE(0x00000001));
RND512P((uint8_t*)z, y, SWAP32LE(0x00000002));
RND512P((uint8_t*)y, z, SWAP32LE(0x00000003));
RND512P((uint8_t*)z, y, SWAP32LE(0x00000004));
RND512P((uint8_t*)y, z, SWAP32LE(0x00000005));
RND512P((uint8_t*)z, y, SWAP32LE(0x00000006));
RND512P((uint8_t*)y, z, SWAP32LE(0x00000007));
RND512P((uint8_t*)z, y, SWAP32LE(0x00000008));
RND512P((uint8_t*)y, Ptmp, SWAP32LE(0x00000009));
/* compute P(h+m) + Q(m) + h */
for (i = 0; i < 2*COLS512; i++) {
h[i] ^= Ptmp[i]^Qtmp[i];
}
}
/* digest up to msglen bytes of input (full blocks only) */
static void Transform(hashState *ctx,
const uint8_t *input,
int msglen) {
/* digest message, one block at a time */
for (; msglen >= SIZE512;
msglen -= SIZE512, input += SIZE512) {
F512(ctx->chaining,(uint32_t*)input);
/* increment block counter */
ctx->block_counter1++;
if (ctx->block_counter1 == 0) ctx->block_counter2++;
}
}
/* given state h, do h <- P(h)+h */
static void OutputTransformation(hashState *ctx) {
int j;
uint32_t temp[2*COLS512];
uint32_t y[2*COLS512];
uint32_t z[2*COLS512];
for (j = 0; j < 2*COLS512; j++) {
temp[j] = ctx->chaining[j];
}
RND512P((uint8_t*)temp, y, SWAP32LE(0x00000000));
RND512P((uint8_t*)y, z, SWAP32LE(0x00000001));
RND512P((uint8_t*)z, y, SWAP32LE(0x00000002));
RND512P((uint8_t*)y, z, SWAP32LE(0x00000003));
RND512P((uint8_t*)z, y, SWAP32LE(0x00000004));
RND512P((uint8_t*)y, z, SWAP32LE(0x00000005));
RND512P((uint8_t*)z, y, SWAP32LE(0x00000006));
RND512P((uint8_t*)y, z, SWAP32LE(0x00000007));
RND512P((uint8_t*)z, y, SWAP32LE(0x00000008));
RND512P((uint8_t*)y, temp, SWAP32LE(0x00000009));
for (j = 0; j < 2*COLS512; j++) {
ctx->chaining[j] ^= temp[j];
}
}
/* initialise context */
static void Init(hashState* ctx) {
/* allocate memory for state and data buffer */
for(size_t i = 0; i < (SIZE512/sizeof(uint32_t)); i++)
{
ctx->chaining[i] = 0;
}
/* set initial value */
ctx->chaining[2*COLS512-1] = SWAP32LE(u32BIG((uint32_t)HASH_BIT_LEN));
/* set other variables */
ctx->buf_ptr = 0;
ctx->block_counter1 = 0;
ctx->block_counter2 = 0;
ctx->bits_in_last_byte = 0;
}
/* update state with databitlen bits of input */
static void Update(hashState* ctx,
const BitSequence* input,
DataLength databitlen) {
int index = 0;
int msglen = (int)(databitlen/8);
int rem = (int)(databitlen%8);
/* if the buffer contains data that has not yet been digested, first
add data to buffer until full */
if (ctx->buf_ptr) {
while (ctx->buf_ptr < SIZE512 && index < msglen) {
ctx->buffer[(int)ctx->buf_ptr++] = input[index++];
}
if (ctx->buf_ptr < SIZE512) {
/* buffer still not full, return */
if (rem) {
ctx->bits_in_last_byte = rem;
ctx->buffer[(int)ctx->buf_ptr++] = input[index];
}
return;
}
/* digest buffer */
ctx->buf_ptr = 0;
Transform(ctx, ctx->buffer, SIZE512);
}
/* digest bulk of message */
Transform(ctx, input+index, msglen-index);
index += ((msglen-index)/SIZE512)*SIZE512;
/* store remaining data in buffer */
while (index < msglen) {
ctx->buffer[(int)ctx->buf_ptr++] = input[index++];
}
/* if non-integral number of bytes have been supplied, store
remaining bits in last byte, together with information about
number of bits */
if (rem) {
ctx->bits_in_last_byte = rem;
ctx->buffer[(int)ctx->buf_ptr++] = input[index];
}
}
#define BILB ctx->bits_in_last_byte
/* finalise: process remaining data (including padding), perform
output transformation, and write hash result to 'output' */
static void Final(hashState* ctx,
BitSequence* output) {
int i, j = 0, hashbytelen = HASH_BIT_LEN/8;
uint8_t *s = (BitSequence*)ctx->chaining;
/* pad with '1'-bit and first few '0'-bits */
if (BILB) {
ctx->buffer[(int)ctx->buf_ptr-1] &= ((1<<BILB)-1)<<(8-BILB);
ctx->buffer[(int)ctx->buf_ptr-1] ^= 0x1<<(7-BILB);
BILB = 0;
}
else ctx->buffer[(int)ctx->buf_ptr++] = 0x80;
/* pad with '0'-bits */
if (ctx->buf_ptr > SIZE512-LENGTHFIELDLEN) {
/* padding requires two blocks */
while (ctx->buf_ptr < SIZE512) {
ctx->buffer[(int)ctx->buf_ptr++] = 0;
}
/* digest first padding block */
Transform(ctx, ctx->buffer, SIZE512);
ctx->buf_ptr = 0;
}
while (ctx->buf_ptr < SIZE512-LENGTHFIELDLEN) {
ctx->buffer[(int)ctx->buf_ptr++] = 0;
}
/* length padding */
ctx->block_counter1++;
if (ctx->block_counter1 == 0) ctx->block_counter2++;
ctx->buf_ptr = SIZE512;
while (ctx->buf_ptr > SIZE512-(int)sizeof(uint32_t)) {
ctx->buffer[(int)--ctx->buf_ptr] = (uint8_t)ctx->block_counter1;
ctx->block_counter1 >>= 8;
}
while (ctx->buf_ptr > SIZE512-LENGTHFIELDLEN) {
ctx->buffer[(int)--ctx->buf_ptr] = (uint8_t)ctx->block_counter2;
ctx->block_counter2 >>= 8;
}
/* digest final padding block */
Transform(ctx, ctx->buffer, SIZE512);
/* perform output transformation */
OutputTransformation(ctx);
/* store hash result in output */
for (i = SIZE512-hashbytelen; i < SIZE512; i++,j++) {
output[j] = s[i];
}
/* zeroise relevant variables and deallocate memory */
for (i = 0; i < COLS512; i++) {
ctx->chaining[i] = 0;
}
for (i = 0; i < SIZE512; i++) {
ctx->buffer[i] = 0;
}
}
/* hash bit sequence */
void groestl(const BitSequence* data,
DataLength databitlen,
BitSequence* hashval) {
hashState context;
/* initialise */
Init(&context);
/* process message */
Update(&context, data, databitlen);
/* finalise */
Final(&context, hashval);
}
/*
static int crypto_hash(unsigned char *out,
const unsigned char *in,
unsigned long long len)
{
groestl(in, 8*len, out);
return 0;
}
*/

View file

@ -1,88 +0,0 @@
// Copyright (c) 2014-2023, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef __hash_h
#define __hash_h
/*
#include "crypto_uint8.h"
#include "crypto_uint32.h"
#include "crypto_uint64.h"
#include "crypto_hash.h"
typedef crypto_uint8 uint8_t;
typedef crypto_uint32 uint32_t;
typedef crypto_uint64 uint64_t;
*/
#include <stdint.h>
/* some sizes (number of bytes) */
#define ROWS 8
#define LENGTHFIELDLEN ROWS
#define COLS512 8
#define SIZE512 (ROWS*COLS512)
#define ROUNDS512 10
#define HASH_BIT_LEN 256
#define ROTL32(v, n) ((((v)<<(n))|((v)>>(32-(n))))&li_32(ffffffff))
#define li_32(h) 0x##h##u
#define EXT_BYTE(var,n) ((uint8_t)((uint32_t)(var) >> (8*n)))
#define u32BIG(a) \
((ROTL32(a,8) & li_32(00FF00FF)) | \
(ROTL32(a,24) & li_32(FF00FF00)))
/* NIST API begin */
typedef unsigned char BitSequence;
typedef unsigned long long DataLength;
typedef struct {
uint32_t chaining[SIZE512/sizeof(uint32_t)]; /* actual state */
uint32_t block_counter1,
block_counter2; /* message block counter(s) */
BitSequence buffer[SIZE512]; /* data buffer */
int buf_ptr; /* data buffer pointer */
int bits_in_last_byte; /* no. of message bits in last byte of
data buffer */
} hashState;
/*void Init(hashState*);
void Update(hashState*, const BitSequence*, DataLength);
void Final(hashState*, BitSequence*); */
void groestl(const BitSequence*, DataLength, BitSequence*);
/* NIST API end */
/*
int crypto_hash(unsigned char *out,
const unsigned char *in,
unsigned long long len);
*/
#endif /* __hash_h */

View file

@ -1,103 +0,0 @@
// Copyright (c) 2014-2023, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef __tables_h
#define __tables_h
#include "int-util.h"
#if BYTE_ORDER == LITTLE_ENDIAN
const uint32_t T[512] = {0xa5f432c6, 0xc6a597f4, 0x84976ff8, 0xf884eb97, 0x99b05eee, 0xee99c7b0, 0x8d8c7af6, 0xf68df78c, 0xd17e8ff, 0xff0de517, 0xbddc0ad6, 0xd6bdb7dc, 0xb1c816de, 0xdeb1a7c8, 0x54fc6d91, 0x915439fc
, 0x50f09060, 0x6050c0f0, 0x3050702, 0x2030405, 0xa9e02ece, 0xcea987e0, 0x7d87d156, 0x567dac87, 0x192bcce7, 0xe719d52b, 0x62a613b5, 0xb56271a6, 0xe6317c4d, 0x4de69a31, 0x9ab559ec, 0xec9ac3b5
, 0x45cf408f, 0x8f4505cf, 0x9dbca31f, 0x1f9d3ebc, 0x40c04989, 0x894009c0, 0x879268fa, 0xfa87ef92, 0x153fd0ef, 0xef15c53f, 0xeb2694b2, 0xb2eb7f26, 0xc940ce8e, 0x8ec90740, 0xb1de6fb, 0xfb0bed1d
, 0xec2f6e41, 0x41ec822f, 0x67a91ab3, 0xb3677da9, 0xfd1c435f, 0x5ffdbe1c, 0xea256045, 0x45ea8a25, 0xbfdaf923, 0x23bf46da, 0xf7025153, 0x53f7a602, 0x96a145e4, 0xe496d3a1, 0x5bed769b, 0x9b5b2ded
, 0xc25d2875, 0x75c2ea5d, 0x1c24c5e1, 0xe11cd924, 0xaee9d43d, 0x3dae7ae9, 0x6abef24c, 0x4c6a98be, 0x5aee826c, 0x6c5ad8ee, 0x41c3bd7e, 0x7e41fcc3, 0x206f3f5, 0xf502f106, 0x4fd15283, 0x834f1dd1
, 0x5ce48c68, 0x685cd0e4, 0xf4075651, 0x51f4a207, 0x345c8dd1, 0xd134b95c, 0x818e1f9, 0xf908e918, 0x93ae4ce2, 0xe293dfae, 0x73953eab, 0xab734d95, 0x53f59762, 0x6253c4f5, 0x3f416b2a, 0x2a3f5441
, 0xc141c08, 0x80c1014, 0x52f66395, 0x955231f6, 0x65afe946, 0x46658caf, 0x5ee27f9d, 0x9d5e21e2, 0x28784830, 0x30286078, 0xa1f8cf37, 0x37a16ef8, 0xf111b0a, 0xa0f1411, 0xb5c4eb2f, 0x2fb55ec4
, 0x91b150e, 0xe091c1b, 0x365a7e24, 0x2436485a, 0x9bb6ad1b, 0x1b9b36b6, 0x3d4798df, 0xdf3da547, 0x266aa7cd, 0xcd26816a, 0x69bbf54e, 0x4e699cbb, 0xcd4c337f, 0x7fcdfe4c, 0x9fba50ea, 0xea9fcfba
, 0x1b2d3f12, 0x121b242d, 0x9eb9a41d, 0x1d9e3ab9, 0x749cc458, 0x5874b09c, 0x2e724634, 0x342e6872, 0x2d774136, 0x362d6c77, 0xb2cd11dc, 0xdcb2a3cd, 0xee299db4, 0xb4ee7329, 0xfb164d5b, 0x5bfbb616
, 0xf601a5a4, 0xa4f65301, 0x4dd7a176, 0x764decd7, 0x61a314b7, 0xb76175a3, 0xce49347d, 0x7dcefa49, 0x7b8ddf52, 0x527ba48d, 0x3e429fdd, 0xdd3ea142, 0x7193cd5e, 0x5e71bc93, 0x97a2b113, 0x139726a2
, 0xf504a2a6, 0xa6f55704, 0x68b801b9, 0xb96869b8, 0x0, 0x0, 0x2c74b5c1, 0xc12c9974, 0x60a0e040, 0x406080a0, 0x1f21c2e3, 0xe31fdd21, 0xc8433a79, 0x79c8f243, 0xed2c9ab6, 0xb6ed772c
, 0xbed90dd4, 0xd4beb3d9, 0x46ca478d, 0x8d4601ca, 0xd9701767, 0x67d9ce70, 0x4bddaf72, 0x724be4dd, 0xde79ed94, 0x94de3379, 0xd467ff98, 0x98d42b67, 0xe82393b0, 0xb0e87b23, 0x4ade5b85, 0x854a11de
, 0x6bbd06bb, 0xbb6b6dbd, 0x2a7ebbc5, 0xc52a917e, 0xe5347b4f, 0x4fe59e34, 0x163ad7ed, 0xed16c13a, 0xc554d286, 0x86c51754, 0xd762f89a, 0x9ad72f62, 0x55ff9966, 0x6655ccff, 0x94a7b611, 0x119422a7
, 0xcf4ac08a, 0x8acf0f4a, 0x1030d9e9, 0xe910c930, 0x60a0e04, 0x406080a, 0x819866fe, 0xfe81e798, 0xf00baba0, 0xa0f05b0b, 0x44ccb478, 0x7844f0cc, 0xbad5f025, 0x25ba4ad5, 0xe33e754b, 0x4be3963e
, 0xf30eaca2, 0xa2f35f0e, 0xfe19445d, 0x5dfeba19, 0xc05bdb80, 0x80c01b5b, 0x8a858005, 0x58a0a85, 0xadecd33f, 0x3fad7eec, 0xbcdffe21, 0x21bc42df, 0x48d8a870, 0x7048e0d8, 0x40cfdf1, 0xf104f90c
, 0xdf7a1963, 0x63dfc67a, 0xc1582f77, 0x77c1ee58, 0x759f30af, 0xaf75459f, 0x63a5e742, 0x426384a5, 0x30507020, 0x20304050, 0x1a2ecbe5, 0xe51ad12e, 0xe12effd, 0xfd0ee112, 0x6db708bf, 0xbf6d65b7
, 0x4cd45581, 0x814c19d4, 0x143c2418, 0x1814303c, 0x355f7926, 0x26354c5f, 0x2f71b2c3, 0xc32f9d71, 0xe13886be, 0xbee16738, 0xa2fdc835, 0x35a26afd, 0xcc4fc788, 0x88cc0b4f, 0x394b652e, 0x2e395c4b
, 0x57f96a93, 0x93573df9, 0xf20d5855, 0x55f2aa0d, 0x829d61fc, 0xfc82e39d, 0x47c9b37a, 0x7a47f4c9, 0xacef27c8, 0xc8ac8bef, 0xe73288ba, 0xbae76f32, 0x2b7d4f32, 0x322b647d, 0x95a442e6, 0xe695d7a4
, 0xa0fb3bc0, 0xc0a09bfb, 0x98b3aa19, 0x199832b3, 0xd168f69e, 0x9ed12768, 0x7f8122a3, 0xa37f5d81, 0x66aaee44, 0x446688aa, 0x7e82d654, 0x547ea882, 0xabe6dd3b, 0x3bab76e6, 0x839e950b, 0xb83169e
, 0xca45c98c, 0x8cca0345, 0x297bbcc7, 0xc729957b, 0xd36e056b, 0x6bd3d66e, 0x3c446c28, 0x283c5044, 0x798b2ca7, 0xa779558b, 0xe23d81bc, 0xbce2633d, 0x1d273116, 0x161d2c27, 0x769a37ad, 0xad76419a
, 0x3b4d96db, 0xdb3bad4d, 0x56fa9e64, 0x6456c8fa, 0x4ed2a674, 0x744ee8d2, 0x1e223614, 0x141e2822, 0xdb76e492, 0x92db3f76, 0xa1e120c, 0xc0a181e, 0x6cb4fc48, 0x486c90b4, 0xe4378fb8, 0xb8e46b37
, 0x5de7789f, 0x9f5d25e7, 0x6eb20fbd, 0xbd6e61b2, 0xef2a6943, 0x43ef862a, 0xa6f135c4, 0xc4a693f1, 0xa8e3da39, 0x39a872e3, 0xa4f7c631, 0x31a462f7, 0x37598ad3, 0xd337bd59, 0x8b8674f2, 0xf28bff86
, 0x325683d5, 0xd532b156, 0x43c54e8b, 0x8b430dc5, 0x59eb856e, 0x6e59dceb, 0xb7c218da, 0xdab7afc2, 0x8c8f8e01, 0x18c028f, 0x64ac1db1, 0xb16479ac, 0xd26df19c, 0x9cd2236d, 0xe03b7249, 0x49e0923b
, 0xb4c71fd8, 0xd8b4abc7, 0xfa15b9ac, 0xacfa4315, 0x709faf3, 0xf307fd09, 0x256fa0cf, 0xcf25856f, 0xafea20ca, 0xcaaf8fea, 0x8e897df4, 0xf48ef389, 0xe9206747, 0x47e98e20, 0x18283810, 0x10182028
, 0xd5640b6f, 0x6fd5de64, 0x888373f0, 0xf088fb83, 0x6fb1fb4a, 0x4a6f94b1, 0x7296ca5c, 0x5c72b896, 0x246c5438, 0x3824706c, 0xf1085f57, 0x57f1ae08, 0xc7522173, 0x73c7e652, 0x51f36497, 0x975135f3
, 0x2365aecb, 0xcb238d65, 0x7c8425a1, 0xa17c5984, 0x9cbf57e8, 0xe89ccbbf, 0x21635d3e, 0x3e217c63, 0xdd7cea96, 0x96dd377c, 0xdc7f1e61, 0x61dcc27f, 0x86919c0d, 0xd861a91, 0x85949b0f, 0xf851e94
, 0x90ab4be0, 0xe090dbab, 0x42c6ba7c, 0x7c42f8c6, 0xc4572671, 0x71c4e257, 0xaae529cc, 0xccaa83e5, 0xd873e390, 0x90d83b73, 0x50f0906, 0x6050c0f, 0x103f4f7, 0xf701f503, 0x12362a1c, 0x1c123836
, 0xa3fe3cc2, 0xc2a39ffe, 0x5fe18b6a, 0x6a5fd4e1, 0xf910beae, 0xaef94710, 0xd06b0269, 0x69d0d26b, 0x91a8bf17, 0x17912ea8, 0x58e87199, 0x995829e8, 0x2769533a, 0x3a277469, 0xb9d0f727, 0x27b94ed0
, 0x384891d9, 0xd938a948, 0x1335deeb, 0xeb13cd35, 0xb3cee52b, 0x2bb356ce, 0x33557722, 0x22334455, 0xbbd604d2, 0xd2bbbfd6, 0x709039a9, 0xa9704990, 0x89808707, 0x7890e80, 0xa7f2c133, 0x33a766f2
, 0xb6c1ec2d, 0x2db65ac1, 0x22665a3c, 0x3c227866, 0x92adb815, 0x15922aad, 0x2060a9c9, 0xc9208960, 0x49db5c87, 0x874915db, 0xff1ab0aa, 0xaaff4f1a, 0x7888d850, 0x5078a088, 0x7a8e2ba5, 0xa57a518e
, 0x8f8a8903, 0x38f068a, 0xf8134a59, 0x59f8b213, 0x809b9209, 0x980129b, 0x1739231a, 0x1a173439, 0xda751065, 0x65daca75, 0x315384d7, 0xd731b553, 0xc651d584, 0x84c61351, 0xb8d303d0, 0xd0b8bbd3
, 0xc35edc82, 0x82c31f5e, 0xb0cbe229, 0x29b052cb, 0x7799c35a, 0x5a77b499, 0x11332d1e, 0x1e113c33, 0xcb463d7b, 0x7bcbf646, 0xfc1fb7a8, 0xa8fc4b1f, 0xd6610c6d, 0x6dd6da61, 0x3a4e622c, 0x2c3a584e};
#else
const uint32_t T[512] = {0xc632f4a5, 0xf497a5c6, 0xf86f9784, 0x97eb84f8, 0xee5eb099, 0xb0c799ee, 0xf67a8c8d, 0x8cf78df6, 0xffe8170d, 0x17e50dff, 0xd60adcbd, 0xdcb7bdd6, 0xde16c8b1, 0xc8a7b1de, 0x916dfc54, 0xfc395491
, 0x6090f050, 0xf0c05060, 0x02070503, 0x05040302, 0xce2ee0a9, 0xe087a9ce, 0x56d1877d, 0x87ac7d56, 0xe7cc2b19, 0x2bd519e7, 0xb513a662, 0xa67162b5, 0x4d7c31e6, 0x319ae64d, 0xec59b59a, 0xb5c39aec
, 0x8f40cf45, 0xcf05458f, 0x1fa3bc9d, 0xbc3e9d1f, 0x8949c040, 0xc0094089, 0xfa689287, 0x92ef87fa, 0xefd03f15, 0x3fc515ef, 0xb29426eb, 0x267febb2, 0x8ece40c9, 0x4007c98e, 0xfbe61d0b, 0x1ded0bfb
, 0x416e2fec, 0x2f82ec41, 0xb31aa967, 0xa97d67b3, 0x5f431cfd, 0x1cbefd5f, 0x456025ea, 0x258aea45, 0x23f9dabf, 0xda46bf23, 0x535102f7, 0x02a6f753, 0xe445a196, 0xa1d396e4, 0x9b76ed5b, 0xed2d5b9b
, 0x75285dc2, 0x5deac275, 0xe1c5241c, 0x24d91ce1, 0x3dd4e9ae, 0xe97aae3d, 0x4cf2be6a, 0xbe986a4c, 0x6c82ee5a, 0xeed85a6c, 0x7ebdc341, 0xc3fc417e, 0xf5f30602, 0x06f102f5, 0x8352d14f, 0xd11d4f83
, 0x688ce45c, 0xe4d05c68, 0x515607f4, 0x07a2f451, 0xd18d5c34, 0x5cb934d1, 0xf9e11808, 0x18e908f9, 0xe24cae93, 0xaedf93e2, 0xab3e9573, 0x954d73ab, 0x6297f553, 0xf5c45362, 0x2a6b413f, 0x41543f2a
, 0x081c140c, 0x14100c08, 0x9563f652, 0xf6315295, 0x46e9af65, 0xaf8c6546, 0x9d7fe25e, 0xe2215e9d, 0x30487828, 0x78602830, 0x37cff8a1, 0xf86ea137, 0x0a1b110f, 0x11140f0a, 0x2febc4b5, 0xc45eb52f
, 0x0e151b09, 0x1b1c090e, 0x247e5a36, 0x5a483624, 0x1badb69b, 0xb6369b1b, 0xdf98473d, 0x47a53ddf, 0xcda76a26, 0x6a8126cd, 0x4ef5bb69, 0xbb9c694e, 0x7f334ccd, 0x4cfecd7f, 0xea50ba9f, 0xbacf9fea
, 0x123f2d1b, 0x2d241b12, 0x1da4b99e, 0xb93a9e1d, 0x58c49c74, 0x9cb07458, 0x3446722e, 0x72682e34, 0x3641772d, 0x776c2d36, 0xdc11cdb2, 0xcda3b2dc, 0xb49d29ee, 0x2973eeb4, 0x5b4d16fb, 0x16b6fb5b
, 0xa4a501f6, 0x0153f6a4, 0x76a1d74d, 0xd7ec4d76, 0xb714a361, 0xa37561b7, 0x7d3449ce, 0x49face7d, 0x52df8d7b, 0x8da47b52, 0xdd9f423e, 0x42a13edd, 0x5ecd9371, 0x93bc715e, 0x13b1a297, 0xa2269713
, 0xa6a204f5, 0x0457f5a6, 0xb901b868, 0xb86968b9, 0x00000000, 0x00000000, 0xc1b5742c, 0x74992cc1, 0x40e0a060, 0xa0806040, 0xe3c2211f, 0x21dd1fe3, 0x793a43c8, 0x43f2c879, 0xb69a2ced, 0x2c77edb6
, 0xd40dd9be, 0xd9b3bed4, 0x8d47ca46, 0xca01468d, 0x671770d9, 0x70ced967, 0x72afdd4b, 0xdde44b72, 0x94ed79de, 0x7933de94, 0x98ff67d4, 0x672bd498, 0xb09323e8, 0x237be8b0, 0x855bde4a, 0xde114a85
, 0xbb06bd6b, 0xbd6d6bbb, 0xc5bb7e2a, 0x7e912ac5, 0x4f7b34e5, 0x349ee54f, 0xedd73a16, 0x3ac116ed, 0x86d254c5, 0x5417c586, 0x9af862d7, 0x622fd79a, 0x6699ff55, 0xffcc5566, 0x11b6a794, 0xa7229411
, 0x8ac04acf, 0x4a0fcf8a, 0xe9d93010, 0x30c910e9, 0x040e0a06, 0x0a080604, 0xfe669881, 0x98e781fe, 0xa0ab0bf0, 0x0b5bf0a0, 0x78b4cc44, 0xccf04478, 0x25f0d5ba, 0xd54aba25, 0x4b753ee3, 0x3e96e34b
, 0xa2ac0ef3, 0x0e5ff3a2, 0x5d4419fe, 0x19bafe5d, 0x80db5bc0, 0x5b1bc080, 0x0580858a, 0x850a8a05, 0x3fd3ecad, 0xec7ead3f, 0x21fedfbc, 0xdf42bc21, 0x70a8d848, 0xd8e04870, 0xf1fd0c04, 0x0cf904f1
, 0x63197adf, 0x7ac6df63, 0x772f58c1, 0x58eec177, 0xaf309f75, 0x9f4575af, 0x42e7a563, 0xa5846342, 0x20705030, 0x50403020, 0xe5cb2e1a, 0x2ed11ae5, 0xfdef120e, 0x12e10efd, 0xbf08b76d, 0xb7656dbf
, 0x8155d44c, 0xd4194c81, 0x18243c14, 0x3c301418, 0x26795f35, 0x5f4c3526, 0xc3b2712f, 0x719d2fc3, 0xbe8638e1, 0x3867e1be, 0x35c8fda2, 0xfd6aa235, 0x88c74fcc, 0x4f0bcc88, 0x2e654b39, 0x4b5c392e
, 0x936af957, 0xf93d5793, 0x55580df2, 0x0daaf255, 0xfc619d82, 0x9de382fc, 0x7ab3c947, 0xc9f4477a, 0xc827efac, 0xef8bacc8, 0xba8832e7, 0x326fe7ba, 0x324f7d2b, 0x7d642b32, 0xe642a495, 0xa4d795e6
, 0xc03bfba0, 0xfb9ba0c0, 0x19aab398, 0xb3329819, 0x9ef668d1, 0x6827d19e, 0xa322817f, 0x815d7fa3, 0x44eeaa66, 0xaa886644, 0x54d6827e, 0x82a87e54, 0x3bdde6ab, 0xe676ab3b, 0x0b959e83, 0x9e16830b
, 0x8cc945ca, 0x4503ca8c, 0xc7bc7b29, 0x7b9529c7, 0x6b056ed3, 0x6ed6d36b, 0x286c443c, 0x44503c28, 0xa72c8b79, 0x8b5579a7, 0xbc813de2, 0x3d63e2bc, 0x1631271d, 0x272c1d16, 0xad379a76, 0x9a4176ad
, 0xdb964d3b, 0x4dad3bdb, 0x649efa56, 0xfac85664, 0x74a6d24e, 0xd2e84e74, 0x1436221e, 0x22281e14, 0x92e476db, 0x763fdb92, 0x0c121e0a, 0x1e180a0c, 0x48fcb46c, 0xb4906c48, 0xb88f37e4, 0x376be4b8
, 0x9f78e75d, 0xe7255d9f, 0xbd0fb26e, 0xb2616ebd, 0x43692aef, 0x2a86ef43, 0xc435f1a6, 0xf193a6c4, 0x39dae3a8, 0xe372a839, 0x31c6f7a4, 0xf762a431, 0xd38a5937, 0x59bd37d3, 0xf274868b, 0x86ff8bf2
, 0xd5835632, 0x56b132d5, 0x8b4ec543, 0xc50d438b, 0x6e85eb59, 0xebdc596e, 0xda18c2b7, 0xc2afb7da, 0x018e8f8c, 0x8f028c01, 0xb11dac64, 0xac7964b1, 0x9cf16dd2, 0x6d23d29c, 0x49723be0, 0x3b92e049
, 0xd81fc7b4, 0xc7abb4d8, 0xacb915fa, 0x1543faac, 0xf3fa0907, 0x09fd07f3, 0xcfa06f25, 0x6f8525cf, 0xca20eaaf, 0xea8fafca, 0xf47d898e, 0x89f38ef4, 0x476720e9, 0x208ee947, 0x10382818, 0x28201810
, 0x6f0b64d5, 0x64ded56f, 0xf0738388, 0x83fb88f0, 0x4afbb16f, 0xb1946f4a, 0x5cca9672, 0x96b8725c, 0x38546c24, 0x6c702438, 0x575f08f1, 0x08aef157, 0x732152c7, 0x52e6c773, 0x9764f351, 0xf3355197
, 0xcbae6523, 0x658d23cb, 0xa125847c, 0x84597ca1, 0xe857bf9c, 0xbfcb9ce8, 0x3e5d6321, 0x637c213e, 0x96ea7cdd, 0x7c37dd96, 0x611e7fdc, 0x7fc2dc61, 0x0d9c9186, 0x911a860d, 0x0f9b9485, 0x941e850f
, 0xe04bab90, 0xabdb90e0, 0x7cbac642, 0xc6f8427c, 0x712657c4, 0x57e2c471, 0xcc29e5aa, 0xe583aacc, 0x90e373d8, 0x733bd890, 0x06090f05, 0x0f0c0506, 0xf7f40301, 0x03f501f7, 0x1c2a3612, 0x3638121c
, 0xc23cfea3, 0xfe9fa3c2, 0x6a8be15f, 0xe1d45f6a, 0xaebe10f9, 0x1047f9ae, 0x69026bd0, 0x6bd2d069, 0x17bfa891, 0xa82e9117, 0x9971e858, 0xe8295899, 0x3a536927, 0x6974273a, 0x27f7d0b9, 0xd04eb927
, 0xd9914838, 0x48a938d9, 0xebde3513, 0x35cd13eb, 0x2be5ceb3, 0xce56b32b, 0x22775533, 0x55443322, 0xd204d6bb, 0xd6bfbbd2, 0xa9399070, 0x904970a9, 0x07878089, 0x800e8907, 0x33c1f2a7, 0xf266a733
, 0x2decc1b6, 0xc15ab62d, 0x3c5a6622, 0x6678223c, 0x15b8ad92, 0xad2a9215, 0xc9a96020, 0x608920c9, 0x875cdb49, 0xdb154987, 0xaab01aff, 0x1a4fffaa, 0x50d88878, 0x88a07850, 0xa52b8e7a, 0x8e517aa5
, 0x03898a8f, 0x8a068f03, 0x594a13f8, 0x13b2f859, 0x09929b80, 0x9b128009, 0x1a233917, 0x3934171a, 0x651075da, 0x75cada65, 0xd7845331, 0x53b531d7, 0x84d551c6, 0x5113c684, 0xd003d3b8, 0xd3bbb8d0
, 0x82dc5ec3, 0x5e1fc382, 0x29e2cbb0, 0xcb52b029, 0x5ac39977, 0x99b4775a, 0x1e2d3311, 0x333c111e, 0x7b3d46cb, 0x46f6cb7b, 0xa8b71ffc, 0x1f4bfca8, 0x6d0c61d6, 0x61dad66d, 0x2c624e3a, 0x4e583a2c};
#endif
#endif /* __tables_h */

View file

@ -1,38 +0,0 @@
// Copyright (c) 2014-2023, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#include <stddef.h>
#include <stdint.h>
#include "blake256.h"
void hash_extra_blake(const void *data, size_t length, char *hash) {
blake256_hash((uint8_t*)hash, data, length);
}

View file

@ -1,38 +0,0 @@
// Copyright (c) 2014-2023, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#include <stddef.h>
#include <stdint.h>
#include "groestl.h"
void hash_extra_groestl(const void *data, size_t length, char *hash) {
groestl(data, length * 8, (uint8_t*)hash);
}

View file

@ -1,44 +0,0 @@
// Copyright (c) 2014-2023, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "jh.h"
#include "hash-ops.h"
#define JH_HASH_BITLEN HASH_SIZE * 8
void hash_extra_jh(const void *data, size_t length, char *hash) {
// No need to check for failure b/c jh_hash only fails for invalid hash size
jh_hash(JH_HASH_BITLEN, data, 8 * length, (uint8_t*)hash);
}

View file

@ -1,42 +0,0 @@
// Copyright (c) 2014-2023, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#include <stddef.h>
#include <stdint.h>
#include "hash-ops.h"
#include "skein.h"
#define SKEIN_HASH_BITLEN HASH_SIZE * 8
void hash_extra_skein(const void *data, size_t length, char *hash) {
// No need to check for failure b/c skein_hash only fails for invalid hash size
skein_hash(SKEIN_HASH_BITLEN, data, 8 * length, (uint8_t*)hash);
}

View file

@ -1,87 +0,0 @@
// Copyright (c) 2014-2023, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#pragma once
#if !defined(__cplusplus)
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "int-util.h"
#include "warnings.h"
static inline void *padd(void *p, size_t i) {
return (char *) p + i;
}
static inline const void *cpadd(const void *p, size_t i) {
return (const char *) p + i;
}
PUSH_WARNINGS
DISABLE_VS_WARNINGS(4267)
static_assert(sizeof(size_t) == 4 || sizeof(size_t) == 8, "size_t must be 4 or 8 bytes long");
static inline void place_length(uint8_t *buffer, size_t bufsize, size_t length) {
if (sizeof(size_t) == 4) {
*(uint32_t *) padd(buffer, bufsize - 4) = swap32be(length);
} else {
*(uint64_t *) padd(buffer, bufsize - 8) = swap64be(length);
}
}
POP_WARNINGS
#pragma pack(push, 1)
union hash_state {
uint8_t b[200];
uint64_t w[25];
};
#pragma pack(pop)
static_assert(sizeof(union hash_state) == 200, "Invalid structure size");
void hash_permutation(union hash_state *state);
void hash_process(union hash_state *state, const uint8_t *buf, size_t count);
#endif
enum {
HASH_SIZE = 32,
HASH_DATA_AREA = 136
};
void cn_fast_hash(const void *data, size_t length, char *hash);
void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int prehashed, uint64_t height);
void hash_extra_blake(const void *data, size_t length, char *hash);
void hash_extra_groestl(const void *data, size_t length, char *hash);
void hash_extra_jh(const void *data, size_t length, char *hash);
void hash_extra_skein(const void *data, size_t length, char *hash);

View file

@ -1,57 +0,0 @@
// Copyright (c) 2014-2023, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "hash-ops.h"
#include "keccak.h"
void hash_permutation(union hash_state *state) {
#if BYTE_ORDER == LITTLE_ENDIAN
keccakf((uint64_t*)state, 24);
#else
uint64_t le_state[25];
memcpy_swap64le(le_state, state, 25);
keccakf(le_state, 24);
memcpy_swap64le(state, le_state, 25);
#endif
}
void hash_process(union hash_state *state, const uint8_t *buf, size_t count) {
keccak1600(buf, count, (uint8_t*)state);
}
void cn_fast_hash(const void *data, size_t length, char *hash) {
union hash_state state;
hash_process(&state, data, length);
memcpy(hash, &state, HASH_SIZE);
}

View file

@ -1,66 +0,0 @@
// Copyright (c) 2014-2023, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#pragma once
#include <stddef.h>
#include <iostream>
#include "common/pod-class.h"
#include "generic-ops.h"
#include "hex.h"
#include "span.h"
namespace crypto {
extern "C" {
#include "hash-ops.h"
}
#pragma pack(push, 1)
POD_CLASS hash {
char data[HASH_SIZE];
};
#pragma pack(pop)
static_assert(sizeof(hash) == HASH_SIZE, "Invalid structure size");
/*
Cryptonight hash functions
*/
inline void cn_slow_hash(const void *data, std::size_t length, hash &hash, int variant = 0, uint64_t height = 0) {
cn_slow_hash(data, length, reinterpret_cast<char *>(&hash), variant, 0/*prehashed*/, height);
}
constexpr static crypto::hash null_hash = {};
}
CRYPTO_MAKE_HASHABLE(hash)

View file

@ -1,320 +0,0 @@
// Copyright (c) 2014-2023, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#pragma once
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#ifndef _MSC_VER
#include <sys/param.h>
#endif
#if defined(__ANDROID__)
#include <byteswap.h>
#endif
#if defined(__sun) && defined(__SVR4)
#include <endian.h>
#endif
#if defined(_MSC_VER)
#include <stdlib.h>
static inline uint32_t rol32(uint32_t x, int r) {
static_assert(sizeof(uint32_t) == sizeof(unsigned int), "this code assumes 32-bit integers");
return _rotl(x, r);
}
static inline uint64_t rol64(uint64_t x, int r) {
return _rotl64(x, r);
}
#else
static inline uint32_t rol32(uint32_t x, int r) {
return (x << (r & 31)) | (x >> (-r & 31));
}
static inline uint64_t rol64(uint64_t x, int r) {
return (x << (r & 63)) | (x >> (-r & 63));
}
#endif
static inline uint64_t hi_dword(uint64_t val) {
return val >> 32;
}
static inline uint64_t lo_dword(uint64_t val) {
return val & 0xFFFFFFFF;
}
static inline uint64_t mul128(uint64_t multiplier, uint64_t multiplicand, uint64_t* product_hi) {
// multiplier = ab = a * 2^32 + b
// multiplicand = cd = c * 2^32 + d
// ab * cd = a * c * 2^64 + (a * d + b * c) * 2^32 + b * d
uint64_t a = hi_dword(multiplier);
uint64_t b = lo_dword(multiplier);
uint64_t c = hi_dword(multiplicand);
uint64_t d = lo_dword(multiplicand);
uint64_t ac = a * c;
uint64_t ad = a * d;
uint64_t bc = b * c;
uint64_t bd = b * d;
uint64_t adbc = ad + bc;
uint64_t adbc_carry = adbc < ad ? 1 : 0;
// multiplier * multiplicand = product_hi * 2^64 + product_lo
uint64_t product_lo = bd + (adbc << 32);
uint64_t product_lo_carry = product_lo < bd ? 1 : 0;
*product_hi = ac + (adbc >> 32) + (adbc_carry << 32) + product_lo_carry;
assert(ac <= *product_hi);
return product_lo;
}
static inline uint64_t div_with_reminder(uint64_t dividend, uint32_t divisor, uint32_t* remainder) {
dividend |= ((uint64_t)*remainder) << 32;
*remainder = dividend % divisor;
return dividend / divisor;
}
// Long division with 2^32 base
static inline uint32_t div128_32(uint64_t dividend_hi, uint64_t dividend_lo, uint32_t divisor, uint64_t* quotient_hi, uint64_t* quotient_lo) {
uint64_t dividend_dwords[4];
uint32_t remainder = 0;
dividend_dwords[3] = hi_dword(dividend_hi);
dividend_dwords[2] = lo_dword(dividend_hi);
dividend_dwords[1] = hi_dword(dividend_lo);
dividend_dwords[0] = lo_dword(dividend_lo);
*quotient_hi = div_with_reminder(dividend_dwords[3], divisor, &remainder) << 32;
*quotient_hi |= div_with_reminder(dividend_dwords[2], divisor, &remainder);
*quotient_lo = div_with_reminder(dividend_dwords[1], divisor, &remainder) << 32;
*quotient_lo |= div_with_reminder(dividend_dwords[0], divisor, &remainder);
return remainder;
}
// Long divisor with 2^64 base
void div128_64(uint64_t dividend_hi, uint64_t dividend_lo, uint64_t divisor, uint64_t* quotient_hi, uint64_t *quotient_lo, uint64_t *remainder_hi, uint64_t *remainder_lo);
static inline void add64clamp(uint64_t *value, uint64_t add)
{
static const uint64_t maxval = (uint64_t)-1;
if (*value > maxval - add)
*value = maxval;
else
*value += add;
}
static inline void sub64clamp(uint64_t *value, uint64_t sub)
{
if (*value < sub)
*value = 0;
else
*value -= sub;
}
#define IDENT16(x) ((uint16_t) (x))
#define IDENT32(x) ((uint32_t) (x))
#define IDENT64(x) ((uint64_t) (x))
#define SWAP16(x) ((((uint16_t) (x) & 0x00ff) << 8) | \
(((uint16_t) (x) & 0xff00) >> 8))
#define SWAP32(x) ((((uint32_t) (x) & 0x000000ff) << 24) | \
(((uint32_t) (x) & 0x0000ff00) << 8) | \
(((uint32_t) (x) & 0x00ff0000) >> 8) | \
(((uint32_t) (x) & 0xff000000) >> 24))
#define SWAP64(x) ((((uint64_t) (x) & 0x00000000000000ff) << 56) | \
(((uint64_t) (x) & 0x000000000000ff00) << 40) | \
(((uint64_t) (x) & 0x0000000000ff0000) << 24) | \
(((uint64_t) (x) & 0x00000000ff000000) << 8) | \
(((uint64_t) (x) & 0x000000ff00000000) >> 8) | \
(((uint64_t) (x) & 0x0000ff0000000000) >> 24) | \
(((uint64_t) (x) & 0x00ff000000000000) >> 40) | \
(((uint64_t) (x) & 0xff00000000000000) >> 56))
static inline uint16_t ident16(uint16_t x) { return x; }
static inline uint32_t ident32(uint32_t x) { return x; }
static inline uint64_t ident64(uint64_t x) { return x; }
#ifndef __OpenBSD__
# if defined(__ANDROID__) && defined(__swap16) && !defined(swap16)
# define swap16 __swap16
# elif !defined(swap16)
static inline uint16_t swap16(uint16_t x) {
return ((x & 0x00ff) << 8) | ((x & 0xff00) >> 8);
}
# endif
# if defined(__ANDROID__) && defined(__swap32) && !defined(swap32)
# define swap32 __swap32
# elif !defined(swap32)
static inline uint32_t swap32(uint32_t x) {
x = ((x & 0x00ff00ff) << 8) | ((x & 0xff00ff00) >> 8);
return (x << 16) | (x >> 16);
}
# endif
# if defined(__ANDROID__) && defined(__swap64) && !defined(swap64)
# define swap64 __swap64
# elif !defined(swap64)
static inline uint64_t swap64(uint64_t x) {
x = ((x & 0x00ff00ff00ff00ff) << 8) | ((x & 0xff00ff00ff00ff00) >> 8);
x = ((x & 0x0000ffff0000ffff) << 16) | ((x & 0xffff0000ffff0000) >> 16);
return (x << 32) | (x >> 32);
}
# endif
#endif /* __OpenBSD__ */
#if defined(__GNUC__)
#define UNUSED __attribute__((unused))
#else
#define UNUSED
#endif
static inline void mem_inplace_ident(void *mem UNUSED, size_t n UNUSED) { }
#undef UNUSED
static inline void mem_inplace_swap16(void *mem, size_t n) {
size_t i;
for (i = 0; i < n; i++) {
((uint16_t *) mem)[i] = swap16(((const uint16_t *) mem)[i]);
}
}
static inline void mem_inplace_swap32(void *mem, size_t n) {
size_t i;
for (i = 0; i < n; i++) {
((uint32_t *) mem)[i] = swap32(((const uint32_t *) mem)[i]);
}
}
static inline void mem_inplace_swap64(void *mem, size_t n) {
size_t i;
for (i = 0; i < n; i++) {
((uint64_t *) mem)[i] = swap64(((const uint64_t *) mem)[i]);
}
}
static inline void memcpy_ident16(void *dst, const void *src, size_t n) {
memcpy(dst, src, 2 * n);
}
static inline void memcpy_ident32(void *dst, const void *src, size_t n) {
memcpy(dst, src, 4 * n);
}
static inline void memcpy_ident64(void *dst, const void *src, size_t n) {
memcpy(dst, src, 8 * n);
}
static inline void memcpy_swap16(void *dst, const void *src, size_t n) {
size_t i;
for (i = 0; i < n; i++) {
((uint16_t *) dst)[i] = swap16(((const uint16_t *) src)[i]);
}
}
static inline void memcpy_swap32(void *dst, const void *src, size_t n) {
size_t i;
for (i = 0; i < n; i++) {
((uint32_t *) dst)[i] = swap32(((const uint32_t *) src)[i]);
}
}
static inline void memcpy_swap64(void *dst, const void *src, size_t n) {
size_t i;
for (i = 0; i < n; i++) {
((uint64_t *) dst)[i] = swap64(((const uint64_t *) src)[i]);
}
}
#ifdef _MSC_VER
# define LITTLE_ENDIAN 1234
# define BIG_ENDIAN 4321
# define BYTE_ORDER LITTLE_ENDIAN
#endif
#if !defined(BYTE_ORDER) || !defined(LITTLE_ENDIAN) || !defined(BIG_ENDIAN)
static_assert(false, "BYTE_ORDER is undefined. Perhaps, GNU extensions are not enabled");
#endif
#if BYTE_ORDER == LITTLE_ENDIAN
#define SWAP16LE IDENT16
#define SWAP16BE SWAP16
#define swap16le ident16
#define swap16be swap16
#define mem_inplace_swap16le mem_inplace_ident
#define mem_inplace_swap16be mem_inplace_swap16
#define memcpy_swap16le memcpy_ident16
#define memcpy_swap16be memcpy_swap16
#define SWAP32LE IDENT32
#define SWAP32BE SWAP32
#define swap32le ident32
#define swap32be swap32
#define mem_inplace_swap32le mem_inplace_ident
#define mem_inplace_swap32be mem_inplace_swap32
#define memcpy_swap32le memcpy_ident32
#define memcpy_swap32be memcpy_swap32
#define SWAP64LE IDENT64
#define SWAP64BE SWAP64
#define swap64le ident64
#define swap64be swap64
#define mem_inplace_swap64le mem_inplace_ident
#define mem_inplace_swap64be mem_inplace_swap64
#define memcpy_swap64le memcpy_ident64
#define memcpy_swap64be memcpy_swap64
#endif
#if BYTE_ORDER == BIG_ENDIAN
#define SWAP16BE IDENT16
#define SWAP16LE SWAP16
#define swap16be ident16
#define swap16le swap16
#define mem_inplace_swap16be mem_inplace_ident
#define mem_inplace_swap16le mem_inplace_swap16
#define memcpy_swap16be memcpy_ident16
#define memcpy_swap16le memcpy_swap16
#define SWAP32BE IDENT32
#define SWAP32LE SWAP32
#define swap32be ident32
#define swap32le swap32
#define mem_inplace_swap32be mem_inplace_ident
#define mem_inplace_swap32le mem_inplace_swap32
#define memcpy_swap32be memcpy_ident32
#define memcpy_swap32le memcpy_swap32
#define SWAP64BE IDENT64
#define SWAP64LE SWAP64
#define swap64be ident64
#define swap64le swap64
#define mem_inplace_swap64be mem_inplace_ident
#define mem_inplace_swap64le mem_inplace_swap64
#define memcpy_swap64be memcpy_ident64
#define memcpy_swap64le memcpy_swap64
#endif

View file

@ -1,369 +0,0 @@
/*This program gives the 64-bit optimized bitslice implementation of JH using ANSI C
--------------------------------
Performance
Microprocessor: Intel CORE 2 processor (Core 2 Duo Mobile T6600 2.2GHz)
Operating System: 64-bit Ubuntu 10.04 (Linux kernel 2.6.32-22-generic)
Speed for long message:
1) 45.8 cycles/byte compiler: Intel C++ Compiler 11.1 compilation option: icc -O2
2) 56.8 cycles/byte compiler: gcc 4.4.3 compilation option: gcc -O3
--------------------------------
Last Modified: January 16, 2011
*/
#include "jh.h"
#include <stdint.h>
#include <string.h>
/*typedef unsigned long long uint64;*/
typedef uint64_t uint64;
/*define data alignment for different C compilers*/
#if defined(__GNUC__)
#define DATA_ALIGN16(x) x __attribute__ ((aligned(16)))
#else
#define DATA_ALIGN16(x) __declspec(align(16)) x
#endif
typedef struct {
int hashbitlen; /*the message digest size*/
unsigned long long databitlen; /*the message size in bits*/
unsigned long long datasize_in_buffer; /*the size of the message remained in buffer; assumed to be multiple of 8bits except for the last partial block at the end of the message*/
DATA_ALIGN16(uint64 x[8][2]); /*the 1024-bit state, ( x[i][0] || x[i][1] ) is the ith row of the state in the pseudocode*/
unsigned char buffer[64]; /*the 512-bit message block to be hashed;*/
} hashState;
/*The initial hash value H(0)*/
const unsigned char JH224_H0[128]={0x2d,0xfe,0xdd,0x62,0xf9,0x9a,0x98,0xac,0xae,0x7c,0xac,0xd6,0x19,0xd6,0x34,0xe7,0xa4,0x83,0x10,0x5,0xbc,0x30,0x12,0x16,0xb8,0x60,0x38,0xc6,0xc9,0x66,0x14,0x94,0x66,0xd9,0x89,0x9f,0x25,0x80,0x70,0x6f,0xce,0x9e,0xa3,0x1b,0x1d,0x9b,0x1a,0xdc,0x11,0xe8,0x32,0x5f,0x7b,0x36,0x6e,0x10,0xf9,0x94,0x85,0x7f,0x2,0xfa,0x6,0xc1,0x1b,0x4f,0x1b,0x5c,0xd8,0xc8,0x40,0xb3,0x97,0xf6,0xa1,0x7f,0x6e,0x73,0x80,0x99,0xdc,0xdf,0x93,0xa5,0xad,0xea,0xa3,0xd3,0xa4,0x31,0xe8,0xde,0xc9,0x53,0x9a,0x68,0x22,0xb4,0xa9,0x8a,0xec,0x86,0xa1,0xe4,0xd5,0x74,0xac,0x95,0x9c,0xe5,0x6c,0xf0,0x15,0x96,0xd,0xea,0xb5,0xab,0x2b,0xbf,0x96,0x11,0xdc,0xf0,0xdd,0x64,0xea,0x6e};
const unsigned char JH256_H0[128]={0xeb,0x98,0xa3,0x41,0x2c,0x20,0xd3,0xeb,0x92,0xcd,0xbe,0x7b,0x9c,0xb2,0x45,0xc1,0x1c,0x93,0x51,0x91,0x60,0xd4,0xc7,0xfa,0x26,0x0,0x82,0xd6,0x7e,0x50,0x8a,0x3,0xa4,0x23,0x9e,0x26,0x77,0x26,0xb9,0x45,0xe0,0xfb,0x1a,0x48,0xd4,0x1a,0x94,0x77,0xcd,0xb5,0xab,0x26,0x2,0x6b,0x17,0x7a,0x56,0xf0,0x24,0x42,0xf,0xff,0x2f,0xa8,0x71,0xa3,0x96,0x89,0x7f,0x2e,0x4d,0x75,0x1d,0x14,0x49,0x8,0xf7,0x7d,0xe2,0x62,0x27,0x76,0x95,0xf7,0x76,0x24,0x8f,0x94,0x87,0xd5,0xb6,0x57,0x47,0x80,0x29,0x6c,0x5c,0x5e,0x27,0x2d,0xac,0x8e,0xd,0x6c,0x51,0x84,0x50,0xc6,0x57,0x5,0x7a,0xf,0x7b,0xe4,0xd3,0x67,0x70,0x24,0x12,0xea,0x89,0xe3,0xab,0x13,0xd3,0x1c,0xd7,0x69};
const unsigned char JH384_H0[128]={0x48,0x1e,0x3b,0xc6,0xd8,0x13,0x39,0x8a,0x6d,0x3b,0x5e,0x89,0x4a,0xde,0x87,0x9b,0x63,0xfa,0xea,0x68,0xd4,0x80,0xad,0x2e,0x33,0x2c,0xcb,0x21,0x48,0xf,0x82,0x67,0x98,0xae,0xc8,0x4d,0x90,0x82,0xb9,0x28,0xd4,0x55,0xea,0x30,0x41,0x11,0x42,0x49,0x36,0xf5,0x55,0xb2,0x92,0x48,0x47,0xec,0xc7,0x25,0xa,0x93,0xba,0xf4,0x3c,0xe1,0x56,0x9b,0x7f,0x8a,0x27,0xdb,0x45,0x4c,0x9e,0xfc,0xbd,0x49,0x63,0x97,0xaf,0xe,0x58,0x9f,0xc2,0x7d,0x26,0xaa,0x80,0xcd,0x80,0xc0,0x8b,0x8c,0x9d,0xeb,0x2e,0xda,0x8a,0x79,0x81,0xe8,0xf8,0xd5,0x37,0x3a,0xf4,0x39,0x67,0xad,0xdd,0xd1,0x7a,0x71,0xa9,0xb4,0xd3,0xbd,0xa4,0x75,0xd3,0x94,0x97,0x6c,0x3f,0xba,0x98,0x42,0x73,0x7f};
const unsigned char JH512_H0[128]={0x6f,0xd1,0x4b,0x96,0x3e,0x0,0xaa,0x17,0x63,0x6a,0x2e,0x5,0x7a,0x15,0xd5,0x43,0x8a,0x22,0x5e,0x8d,0xc,0x97,0xef,0xb,0xe9,0x34,0x12,0x59,0xf2,0xb3,0xc3,0x61,0x89,0x1d,0xa0,0xc1,0x53,0x6f,0x80,0x1e,0x2a,0xa9,0x5,0x6b,0xea,0x2b,0x6d,0x80,0x58,0x8e,0xcc,0xdb,0x20,0x75,0xba,0xa6,0xa9,0xf,0x3a,0x76,0xba,0xf8,0x3b,0xf7,0x1,0x69,0xe6,0x5,0x41,0xe3,0x4a,0x69,0x46,0xb5,0x8a,0x8e,0x2e,0x6f,0xe6,0x5a,0x10,0x47,0xa7,0xd0,0xc1,0x84,0x3c,0x24,0x3b,0x6e,0x71,0xb1,0x2d,0x5a,0xc1,0x99,0xcf,0x57,0xf6,0xec,0x9d,0xb1,0xf8,0x56,0xa7,0x6,0x88,0x7c,0x57,0x16,0xb1,0x56,0xe3,0xc2,0xfc,0xdf,0xe6,0x85,0x17,0xfb,0x54,0x5a,0x46,0x78,0xcc,0x8c,0xdd,0x4b};
/*42 round constants, each round constant is 32-byte (256-bit)*/
const unsigned char E8_bitslice_roundconstant[42][32]={
{0x72,0xd5,0xde,0xa2,0xdf,0x15,0xf8,0x67,0x7b,0x84,0x15,0xa,0xb7,0x23,0x15,0x57,0x81,0xab,0xd6,0x90,0x4d,0x5a,0x87,0xf6,0x4e,0x9f,0x4f,0xc5,0xc3,0xd1,0x2b,0x40},
{0xea,0x98,0x3a,0xe0,0x5c,0x45,0xfa,0x9c,0x3,0xc5,0xd2,0x99,0x66,0xb2,0x99,0x9a,0x66,0x2,0x96,0xb4,0xf2,0xbb,0x53,0x8a,0xb5,0x56,0x14,0x1a,0x88,0xdb,0xa2,0x31},
{0x3,0xa3,0x5a,0x5c,0x9a,0x19,0xe,0xdb,0x40,0x3f,0xb2,0xa,0x87,0xc1,0x44,0x10,0x1c,0x5,0x19,0x80,0x84,0x9e,0x95,0x1d,0x6f,0x33,0xeb,0xad,0x5e,0xe7,0xcd,0xdc},
{0x10,0xba,0x13,0x92,0x2,0xbf,0x6b,0x41,0xdc,0x78,0x65,0x15,0xf7,0xbb,0x27,0xd0,0xa,0x2c,0x81,0x39,0x37,0xaa,0x78,0x50,0x3f,0x1a,0xbf,0xd2,0x41,0x0,0x91,0xd3},
{0x42,0x2d,0x5a,0xd,0xf6,0xcc,0x7e,0x90,0xdd,0x62,0x9f,0x9c,0x92,0xc0,0x97,0xce,0x18,0x5c,0xa7,0xb,0xc7,0x2b,0x44,0xac,0xd1,0xdf,0x65,0xd6,0x63,0xc6,0xfc,0x23},
{0x97,0x6e,0x6c,0x3,0x9e,0xe0,0xb8,0x1a,0x21,0x5,0x45,0x7e,0x44,0x6c,0xec,0xa8,0xee,0xf1,0x3,0xbb,0x5d,0x8e,0x61,0xfa,0xfd,0x96,0x97,0xb2,0x94,0x83,0x81,0x97},
{0x4a,0x8e,0x85,0x37,0xdb,0x3,0x30,0x2f,0x2a,0x67,0x8d,0x2d,0xfb,0x9f,0x6a,0x95,0x8a,0xfe,0x73,0x81,0xf8,0xb8,0x69,0x6c,0x8a,0xc7,0x72,0x46,0xc0,0x7f,0x42,0x14},
{0xc5,0xf4,0x15,0x8f,0xbd,0xc7,0x5e,0xc4,0x75,0x44,0x6f,0xa7,0x8f,0x11,0xbb,0x80,0x52,0xde,0x75,0xb7,0xae,0xe4,0x88,0xbc,0x82,0xb8,0x0,0x1e,0x98,0xa6,0xa3,0xf4},
{0x8e,0xf4,0x8f,0x33,0xa9,0xa3,0x63,0x15,0xaa,0x5f,0x56,0x24,0xd5,0xb7,0xf9,0x89,0xb6,0xf1,0xed,0x20,0x7c,0x5a,0xe0,0xfd,0x36,0xca,0xe9,0x5a,0x6,0x42,0x2c,0x36},
{0xce,0x29,0x35,0x43,0x4e,0xfe,0x98,0x3d,0x53,0x3a,0xf9,0x74,0x73,0x9a,0x4b,0xa7,0xd0,0xf5,0x1f,0x59,0x6f,0x4e,0x81,0x86,0xe,0x9d,0xad,0x81,0xaf,0xd8,0x5a,0x9f},
{0xa7,0x5,0x6,0x67,0xee,0x34,0x62,0x6a,0x8b,0xb,0x28,0xbe,0x6e,0xb9,0x17,0x27,0x47,0x74,0x7,0x26,0xc6,0x80,0x10,0x3f,0xe0,0xa0,0x7e,0x6f,0xc6,0x7e,0x48,0x7b},
{0xd,0x55,0xa,0xa5,0x4a,0xf8,0xa4,0xc0,0x91,0xe3,0xe7,0x9f,0x97,0x8e,0xf1,0x9e,0x86,0x76,0x72,0x81,0x50,0x60,0x8d,0xd4,0x7e,0x9e,0x5a,0x41,0xf3,0xe5,0xb0,0x62},
{0xfc,0x9f,0x1f,0xec,0x40,0x54,0x20,0x7a,0xe3,0xe4,0x1a,0x0,0xce,0xf4,0xc9,0x84,0x4f,0xd7,0x94,0xf5,0x9d,0xfa,0x95,0xd8,0x55,0x2e,0x7e,0x11,0x24,0xc3,0x54,0xa5},
{0x5b,0xdf,0x72,0x28,0xbd,0xfe,0x6e,0x28,0x78,0xf5,0x7f,0xe2,0xf,0xa5,0xc4,0xb2,0x5,0x89,0x7c,0xef,0xee,0x49,0xd3,0x2e,0x44,0x7e,0x93,0x85,0xeb,0x28,0x59,0x7f},
{0x70,0x5f,0x69,0x37,0xb3,0x24,0x31,0x4a,0x5e,0x86,0x28,0xf1,0x1d,0xd6,0xe4,0x65,0xc7,0x1b,0x77,0x4,0x51,0xb9,0x20,0xe7,0x74,0xfe,0x43,0xe8,0x23,0xd4,0x87,0x8a},
{0x7d,0x29,0xe8,0xa3,0x92,0x76,0x94,0xf2,0xdd,0xcb,0x7a,0x9,0x9b,0x30,0xd9,0xc1,0x1d,0x1b,0x30,0xfb,0x5b,0xdc,0x1b,0xe0,0xda,0x24,0x49,0x4f,0xf2,0x9c,0x82,0xbf},
{0xa4,0xe7,0xba,0x31,0xb4,0x70,0xbf,0xff,0xd,0x32,0x44,0x5,0xde,0xf8,0xbc,0x48,0x3b,0xae,0xfc,0x32,0x53,0xbb,0xd3,0x39,0x45,0x9f,0xc3,0xc1,0xe0,0x29,0x8b,0xa0},
{0xe5,0xc9,0x5,0xfd,0xf7,0xae,0x9,0xf,0x94,0x70,0x34,0x12,0x42,0x90,0xf1,0x34,0xa2,0x71,0xb7,0x1,0xe3,0x44,0xed,0x95,0xe9,0x3b,0x8e,0x36,0x4f,0x2f,0x98,0x4a},
{0x88,0x40,0x1d,0x63,0xa0,0x6c,0xf6,0x15,0x47,0xc1,0x44,0x4b,0x87,0x52,0xaf,0xff,0x7e,0xbb,0x4a,0xf1,0xe2,0xa,0xc6,0x30,0x46,0x70,0xb6,0xc5,0xcc,0x6e,0x8c,0xe6},
{0xa4,0xd5,0xa4,0x56,0xbd,0x4f,0xca,0x0,0xda,0x9d,0x84,0x4b,0xc8,0x3e,0x18,0xae,0x73,0x57,0xce,0x45,0x30,0x64,0xd1,0xad,0xe8,0xa6,0xce,0x68,0x14,0x5c,0x25,0x67},
{0xa3,0xda,0x8c,0xf2,0xcb,0xe,0xe1,0x16,0x33,0xe9,0x6,0x58,0x9a,0x94,0x99,0x9a,0x1f,0x60,0xb2,0x20,0xc2,0x6f,0x84,0x7b,0xd1,0xce,0xac,0x7f,0xa0,0xd1,0x85,0x18},
{0x32,0x59,0x5b,0xa1,0x8d,0xdd,0x19,0xd3,0x50,0x9a,0x1c,0xc0,0xaa,0xa5,0xb4,0x46,0x9f,0x3d,0x63,0x67,0xe4,0x4,0x6b,0xba,0xf6,0xca,0x19,0xab,0xb,0x56,0xee,0x7e},
{0x1f,0xb1,0x79,0xea,0xa9,0x28,0x21,0x74,0xe9,0xbd,0xf7,0x35,0x3b,0x36,0x51,0xee,0x1d,0x57,0xac,0x5a,0x75,0x50,0xd3,0x76,0x3a,0x46,0xc2,0xfe,0xa3,0x7d,0x70,0x1},
{0xf7,0x35,0xc1,0xaf,0x98,0xa4,0xd8,0x42,0x78,0xed,0xec,0x20,0x9e,0x6b,0x67,0x79,0x41,0x83,0x63,0x15,0xea,0x3a,0xdb,0xa8,0xfa,0xc3,0x3b,0x4d,0x32,0x83,0x2c,0x83},
{0xa7,0x40,0x3b,0x1f,0x1c,0x27,0x47,0xf3,0x59,0x40,0xf0,0x34,0xb7,0x2d,0x76,0x9a,0xe7,0x3e,0x4e,0x6c,0xd2,0x21,0x4f,0xfd,0xb8,0xfd,0x8d,0x39,0xdc,0x57,0x59,0xef},
{0x8d,0x9b,0xc,0x49,0x2b,0x49,0xeb,0xda,0x5b,0xa2,0xd7,0x49,0x68,0xf3,0x70,0xd,0x7d,0x3b,0xae,0xd0,0x7a,0x8d,0x55,0x84,0xf5,0xa5,0xe9,0xf0,0xe4,0xf8,0x8e,0x65},
{0xa0,0xb8,0xa2,0xf4,0x36,0x10,0x3b,0x53,0xc,0xa8,0x7,0x9e,0x75,0x3e,0xec,0x5a,0x91,0x68,0x94,0x92,0x56,0xe8,0x88,0x4f,0x5b,0xb0,0x5c,0x55,0xf8,0xba,0xbc,0x4c},
{0xe3,0xbb,0x3b,0x99,0xf3,0x87,0x94,0x7b,0x75,0xda,0xf4,0xd6,0x72,0x6b,0x1c,0x5d,0x64,0xae,0xac,0x28,0xdc,0x34,0xb3,0x6d,0x6c,0x34,0xa5,0x50,0xb8,0x28,0xdb,0x71},
{0xf8,0x61,0xe2,0xf2,0x10,0x8d,0x51,0x2a,0xe3,0xdb,0x64,0x33,0x59,0xdd,0x75,0xfc,0x1c,0xac,0xbc,0xf1,0x43,0xce,0x3f,0xa2,0x67,0xbb,0xd1,0x3c,0x2,0xe8,0x43,0xb0},
{0x33,0xa,0x5b,0xca,0x88,0x29,0xa1,0x75,0x7f,0x34,0x19,0x4d,0xb4,0x16,0x53,0x5c,0x92,0x3b,0x94,0xc3,0xe,0x79,0x4d,0x1e,0x79,0x74,0x75,0xd7,0xb6,0xee,0xaf,0x3f},
{0xea,0xa8,0xd4,0xf7,0xbe,0x1a,0x39,0x21,0x5c,0xf4,0x7e,0x9,0x4c,0x23,0x27,0x51,0x26,0xa3,0x24,0x53,0xba,0x32,0x3c,0xd2,0x44,0xa3,0x17,0x4a,0x6d,0xa6,0xd5,0xad},
{0xb5,0x1d,0x3e,0xa6,0xaf,0xf2,0xc9,0x8,0x83,0x59,0x3d,0x98,0x91,0x6b,0x3c,0x56,0x4c,0xf8,0x7c,0xa1,0x72,0x86,0x60,0x4d,0x46,0xe2,0x3e,0xcc,0x8,0x6e,0xc7,0xf6},
{0x2f,0x98,0x33,0xb3,0xb1,0xbc,0x76,0x5e,0x2b,0xd6,0x66,0xa5,0xef,0xc4,0xe6,0x2a,0x6,0xf4,0xb6,0xe8,0xbe,0xc1,0xd4,0x36,0x74,0xee,0x82,0x15,0xbc,0xef,0x21,0x63},
{0xfd,0xc1,0x4e,0xd,0xf4,0x53,0xc9,0x69,0xa7,0x7d,0x5a,0xc4,0x6,0x58,0x58,0x26,0x7e,0xc1,0x14,0x16,0x6,0xe0,0xfa,0x16,0x7e,0x90,0xaf,0x3d,0x28,0x63,0x9d,0x3f},
{0xd2,0xc9,0xf2,0xe3,0x0,0x9b,0xd2,0xc,0x5f,0xaa,0xce,0x30,0xb7,0xd4,0xc,0x30,0x74,0x2a,0x51,0x16,0xf2,0xe0,0x32,0x98,0xd,0xeb,0x30,0xd8,0xe3,0xce,0xf8,0x9a},
{0x4b,0xc5,0x9e,0x7b,0xb5,0xf1,0x79,0x92,0xff,0x51,0xe6,0x6e,0x4,0x86,0x68,0xd3,0x9b,0x23,0x4d,0x57,0xe6,0x96,0x67,0x31,0xcc,0xe6,0xa6,0xf3,0x17,0xa,0x75,0x5},
{0xb1,0x76,0x81,0xd9,0x13,0x32,0x6c,0xce,0x3c,0x17,0x52,0x84,0xf8,0x5,0xa2,0x62,0xf4,0x2b,0xcb,0xb3,0x78,0x47,0x15,0x47,0xff,0x46,0x54,0x82,0x23,0x93,0x6a,0x48},
{0x38,0xdf,0x58,0x7,0x4e,0x5e,0x65,0x65,0xf2,0xfc,0x7c,0x89,0xfc,0x86,0x50,0x8e,0x31,0x70,0x2e,0x44,0xd0,0xb,0xca,0x86,0xf0,0x40,0x9,0xa2,0x30,0x78,0x47,0x4e},
{0x65,0xa0,0xee,0x39,0xd1,0xf7,0x38,0x83,0xf7,0x5e,0xe9,0x37,0xe4,0x2c,0x3a,0xbd,0x21,0x97,0xb2,0x26,0x1,0x13,0xf8,0x6f,0xa3,0x44,0xed,0xd1,0xef,0x9f,0xde,0xe7},
{0x8b,0xa0,0xdf,0x15,0x76,0x25,0x92,0xd9,0x3c,0x85,0xf7,0xf6,0x12,0xdc,0x42,0xbe,0xd8,0xa7,0xec,0x7c,0xab,0x27,0xb0,0x7e,0x53,0x8d,0x7d,0xda,0xaa,0x3e,0xa8,0xde},
{0xaa,0x25,0xce,0x93,0xbd,0x2,0x69,0xd8,0x5a,0xf6,0x43,0xfd,0x1a,0x73,0x8,0xf9,0xc0,0x5f,0xef,0xda,0x17,0x4a,0x19,0xa5,0x97,0x4d,0x66,0x33,0x4c,0xfd,0x21,0x6a},
{0x35,0xb4,0x98,0x31,0xdb,0x41,0x15,0x70,0xea,0x1e,0xf,0xbb,0xed,0xcd,0x54,0x9b,0x9a,0xd0,0x63,0xa1,0x51,0x97,0x40,0x72,0xf6,0x75,0x9d,0xbf,0x91,0x47,0x6f,0xe2}};
static void E8(hashState *state); /*The bijective function E8, in bitslice form*/
static void F8(hashState *state); /*The compression function F8 */
/*The API functions*/
static HashReturn Init(hashState *state, int hashbitlen);
static HashReturn Update(hashState *state, const BitSequence *data, DataLength databitlen);
static HashReturn Final(hashState *state, BitSequence *hashval);
HashReturn jh_hash(int hashbitlen, const BitSequence *data,DataLength databitlen, BitSequence *hashval);
/*swapping bit 2i with bit 2i+1 of 64-bit x*/
#define SWAP1(x) (x) = ((((x) & 0x5555555555555555ULL) << 1) | (((x) & 0xaaaaaaaaaaaaaaaaULL) >> 1));
/*swapping bits 4i||4i+1 with bits 4i+2||4i+3 of 64-bit x*/
#define SWAP2(x) (x) = ((((x) & 0x3333333333333333ULL) << 2) | (((x) & 0xccccccccccccccccULL) >> 2));
/*swapping bits 8i||8i+1||8i+2||8i+3 with bits 8i+4||8i+5||8i+6||8i+7 of 64-bit x*/
#define SWAP4(x) (x) = ((((x) & 0x0f0f0f0f0f0f0f0fULL) << 4) | (((x) & 0xf0f0f0f0f0f0f0f0ULL) >> 4));
/*swapping bits 16i||16i+1||......||16i+7 with bits 16i+8||16i+9||......||16i+15 of 64-bit x*/
#define SWAP8(x) (x) = ((((x) & 0x00ff00ff00ff00ffULL) << 8) | (((x) & 0xff00ff00ff00ff00ULL) >> 8));
/*swapping bits 32i||32i+1||......||32i+15 with bits 32i+16||32i+17||......||32i+31 of 64-bit x*/
#define SWAP16(x) (x) = ((((x) & 0x0000ffff0000ffffULL) << 16) | (((x) & 0xffff0000ffff0000ULL) >> 16));
/*swapping bits 64i||64i+1||......||64i+31 with bits 64i+32||64i+33||......||64i+63 of 64-bit x*/
#define SWAP32(x) (x) = (((x) << 32) | ((x) >> 32));
/*The MDS transform*/
#define L(m0,m1,m2,m3,m4,m5,m6,m7) \
(m4) ^= (m1); \
(m5) ^= (m2); \
(m6) ^= (m0) ^ (m3); \
(m7) ^= (m0); \
(m0) ^= (m5); \
(m1) ^= (m6); \
(m2) ^= (m4) ^ (m7); \
(m3) ^= (m4);
/*Two Sboxes are computed in parallel, each Sbox implements S0 and S1, selected by a constant bit*/
/*The reason to compute two Sboxes in parallel is to try to fully utilize the parallel processing power*/
#define SS(m0,m1,m2,m3,m4,m5,m6,m7,cc0,cc1) \
m3 = ~(m3); \
m7 = ~(m7); \
m0 ^= ((~(m2)) & (cc0)); \
m4 ^= ((~(m6)) & (cc1)); \
temp0 = (cc0) ^ ((m0) & (m1));\
temp1 = (cc1) ^ ((m4) & (m5));\
m0 ^= ((m2) & (m3)); \
m4 ^= ((m6) & (m7)); \
m3 ^= ((~(m1)) & (m2)); \
m7 ^= ((~(m5)) & (m6)); \
m1 ^= ((m0) & (m2)); \
m5 ^= ((m4) & (m6)); \
m2 ^= ((m0) & (~(m3))); \
m6 ^= ((m4) & (~(m7))); \
m0 ^= ((m1) | (m3)); \
m4 ^= ((m5) | (m7)); \
m3 ^= ((m1) & (m2)); \
m7 ^= ((m5) & (m6)); \
m1 ^= (temp0 & (m0)); \
m5 ^= (temp1 & (m4)); \
m2 ^= temp0; \
m6 ^= temp1;
/*The bijective function E8, in bitslice form*/
static void E8(hashState *state)
{
uint64 i,roundnumber,temp0,temp1;
for (roundnumber = 0; roundnumber < 42; roundnumber = roundnumber+7) {
/*round 7*roundnumber+0: Sbox, MDS and Swapping layers*/
for (i = 0; i < 2; i++) {
SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+0])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+0])[i+2] );
L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]);
SWAP1(state->x[1][i]); SWAP1(state->x[3][i]); SWAP1(state->x[5][i]); SWAP1(state->x[7][i]);
}
/*round 7*roundnumber+1: Sbox, MDS and Swapping layers*/
for (i = 0; i < 2; i++) {
SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+1])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+1])[i+2] );
L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]);
SWAP2(state->x[1][i]); SWAP2(state->x[3][i]); SWAP2(state->x[5][i]); SWAP2(state->x[7][i]);
}
/*round 7*roundnumber+2: Sbox, MDS and Swapping layers*/
for (i = 0; i < 2; i++) {
SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+2])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+2])[i+2] );
L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]);
SWAP4(state->x[1][i]); SWAP4(state->x[3][i]); SWAP4(state->x[5][i]); SWAP4(state->x[7][i]);
}
/*round 7*roundnumber+3: Sbox, MDS and Swapping layers*/
for (i = 0; i < 2; i++) {
SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+3])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+3])[i+2] );
L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]);
SWAP8(state->x[1][i]); SWAP8(state->x[3][i]); SWAP8(state->x[5][i]); SWAP8(state->x[7][i]);
}
/*round 7*roundnumber+4: Sbox, MDS and Swapping layers*/
for (i = 0; i < 2; i++) {
SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+4])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+4])[i+2] );
L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]);
SWAP16(state->x[1][i]); SWAP16(state->x[3][i]); SWAP16(state->x[5][i]); SWAP16(state->x[7][i]);
}
/*round 7*roundnumber+5: Sbox, MDS and Swapping layers*/
for (i = 0; i < 2; i++) {
SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+5])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+5])[i+2] );
L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]);
SWAP32(state->x[1][i]); SWAP32(state->x[3][i]); SWAP32(state->x[5][i]); SWAP32(state->x[7][i]);
}
/*round 7*roundnumber+6: Sbox and MDS layers*/
for (i = 0; i < 2; i++) {
SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+6])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+6])[i+2] );
L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]);
}
/*round 7*roundnumber+6: swapping layer*/
for (i = 1; i < 8; i = i+2) {
temp0 = state->x[i][0]; state->x[i][0] = state->x[i][1]; state->x[i][1] = temp0;
}
}
}
/*The compression function F8 */
static void F8(hashState *state)
{
uint64_t* x = (uint64_t*)state->x;
const uint64_t* buf = (uint64*)state->buffer;
/*xor the 512-bit message with the fist half of the 1024-bit hash state*/
for (int i = 0; i < 8; ++i) x[i] ^= buf[i];
/*the bijective function E8 */
E8(state);
/*xor the 512-bit message with the second half of the 1024-bit hash state*/
for (int i = 0; i < 8; ++i) x[i + 8] ^= buf[i];
}
/*before hashing a message, initialize the hash state as H0 */
static HashReturn Init(hashState *state, int hashbitlen)
{
state->databitlen = 0;
state->datasize_in_buffer = 0;
/*initialize the initial hash value of JH*/
state->hashbitlen = hashbitlen;
/*load the intital hash value into state*/
switch (hashbitlen)
{
case 224: memcpy(state->x,JH224_H0,128); break;
case 256: memcpy(state->x,JH256_H0,128); break;
case 384: memcpy(state->x,JH384_H0,128); break;
default:
case 512: memcpy(state->x,JH512_H0,128); break;
}
return(SUCCESS);
}
/*hash each 512-bit message block, except the last partial block*/
static HashReturn Update(hashState *state, const BitSequence *data, DataLength databitlen)
{
DataLength index; /*the starting address of the data to be compressed*/
state->databitlen += databitlen;
index = 0;
/*if there is remaining data in the buffer, fill it to a full message block first*/
/*we assume that the size of the data in the buffer is the multiple of 8 bits if it is not at the end of a message*/
/*There is data in the buffer, but the incoming data is insufficient for a full block*/
if ( (state->datasize_in_buffer > 0 ) && (( state->datasize_in_buffer + databitlen) < 512) ) {
if ( (databitlen & 7) == 0 ) {
memcpy(state->buffer + (state->datasize_in_buffer >> 3), data, 64-(state->datasize_in_buffer >> 3)) ;
}
else memcpy(state->buffer + (state->datasize_in_buffer >> 3), data, 64-(state->datasize_in_buffer >> 3)+1) ;
state->datasize_in_buffer += databitlen;
databitlen = 0;
}
/*There is data in the buffer, and the incoming data is sufficient for a full block*/
if ( (state->datasize_in_buffer > 0 ) && (( state->datasize_in_buffer + databitlen) >= 512) ) {
memcpy( state->buffer + (state->datasize_in_buffer >> 3), data, 64-(state->datasize_in_buffer >> 3) ) ;
index = 64-(state->datasize_in_buffer >> 3);
databitlen = databitlen - (512 - state->datasize_in_buffer);
F8(state);
state->datasize_in_buffer = 0;
}
/*hash the remaining full message blocks*/
for ( ; databitlen >= 512; index = index+64, databitlen = databitlen - 512) {
memcpy(state->buffer, data+index, 64);
F8(state);
}
/*store the partial block into buffer, assume that -- if part of the last byte is not part of the message, then that part consists of 0 bits*/
if ( databitlen > 0) {
if ((databitlen & 7) == 0)
memcpy(state->buffer, data+index, (databitlen & 0x1ff) >> 3);
else
memcpy(state->buffer, data+index, ((databitlen & 0x1ff) >> 3)+1);
state->datasize_in_buffer = databitlen;
}
return(SUCCESS);
}
/*pad the message, process the padded block(s), truncate the hash value H to obtain the message digest*/
static HashReturn Final(hashState *state, BitSequence *hashval)
{
unsigned int i;
if ( (state->databitlen & 0x1ff) == 0 ) {
/*pad the message when databitlen is multiple of 512 bits, then process the padded block*/
memset(state->buffer, 0, 64);
state->buffer[0] = 0x80;
state->buffer[63] = state->databitlen & 0xff;
state->buffer[62] = (state->databitlen >> 8) & 0xff;
state->buffer[61] = (state->databitlen >> 16) & 0xff;
state->buffer[60] = (state->databitlen >> 24) & 0xff;
state->buffer[59] = (state->databitlen >> 32) & 0xff;
state->buffer[58] = (state->databitlen >> 40) & 0xff;
state->buffer[57] = (state->databitlen >> 48) & 0xff;
state->buffer[56] = (state->databitlen >> 56) & 0xff;
F8(state);
}
else {
/*set the rest of the bytes in the buffer to 0*/
if ( (state->datasize_in_buffer & 7) == 0)
for (i = (state->databitlen & 0x1ff) >> 3; i < 64; i++) state->buffer[i] = 0;
else
for (i = ((state->databitlen & 0x1ff) >> 3)+1; i < 64; i++) state->buffer[i] = 0;
/*pad and process the partial block when databitlen is not multiple of 512 bits, then hash the padded blocks*/
state->buffer[((state->databitlen & 0x1ff) >> 3)] |= 1 << (7- (state->databitlen & 7));
F8(state);
memset(state->buffer, 0, 64);
state->buffer[63] = state->databitlen & 0xff;
state->buffer[62] = (state->databitlen >> 8) & 0xff;
state->buffer[61] = (state->databitlen >> 16) & 0xff;
state->buffer[60] = (state->databitlen >> 24) & 0xff;
state->buffer[59] = (state->databitlen >> 32) & 0xff;
state->buffer[58] = (state->databitlen >> 40) & 0xff;
state->buffer[57] = (state->databitlen >> 48) & 0xff;
state->buffer[56] = (state->databitlen >> 56) & 0xff;
F8(state);
}
/*truncating the final hash value to generate the message digest*/
switch(state->hashbitlen) {
case 224: memcpy(hashval,(unsigned char*)state->x+64+36,28); break;
case 256: memcpy(hashval,(unsigned char*)state->x+64+32,32); break;
case 384: memcpy(hashval,(unsigned char*)state->x+64+16,48); break;
case 512: memcpy(hashval,(unsigned char*)state->x+64,64); break;
}
return(SUCCESS);
}
/* hash a message,
three inputs: message digest size in bits (hashbitlen); message (data); message length in bits (databitlen)
one output: message digest (hashval)
*/
HashReturn jh_hash(int hashbitlen, const BitSequence *data,DataLength databitlen, BitSequence *hashval)
{
hashState state;
if ( hashbitlen == 224 || hashbitlen == 256 || hashbitlen == 384 || hashbitlen == 512 ) {
Init(&state, hashbitlen);
Update(&state, data, databitlen);
Final(&state, hashval);
return SUCCESS;
}
else
return(BAD_HASHLEN);
}

View file

@ -1,21 +0,0 @@
/*This program gives the 64-bit optimized bitslice implementation of JH using ANSI C
--------------------------------
Performance
Microprocessor: Intel CORE 2 processor (Core 2 Duo Mobile T6600 2.2GHz)
Operating System: 64-bit Ubuntu 10.04 (Linux kernel 2.6.32-22-generic)
Speed for long message:
1) 45.8 cycles/byte compiler: Intel C++ Compiler 11.1 compilation option: icc -O2
2) 56.8 cycles/byte compiler: gcc 4.4.3 compilation option: gcc -O3
--------------------------------
Last Modified: January 16, 2011
*/
#pragma once
typedef unsigned char BitSequence;
typedef unsigned long long DataLength;
typedef enum {SUCCESS = 0, FAIL = 1, BAD_HASHLEN = 2} HashReturn;
HashReturn jh_hash(int hashbitlen, const BitSequence *data, DataLength databitlen, BitSequence *hashval);

View file

@ -1,239 +0,0 @@
// keccak.c
// 19-Nov-11 Markku-Juhani O. Saarinen <mjos@iki.fi>
// A baseline Keccak (3rd round) implementation.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "int-util.h"
#include "hash-ops.h"
#include "keccak.h"
static void local_abort(const char *msg)
{
fprintf(stderr, "%s\n", msg);
#ifdef NDEBUG
_exit(1);
#else
abort();
#endif
}
const uint64_t keccakf_rndc[24] =
{
0x0000000000000001, 0x0000000000008082, 0x800000000000808a,
0x8000000080008000, 0x000000000000808b, 0x0000000080000001,
0x8000000080008081, 0x8000000000008009, 0x000000000000008a,
0x0000000000000088, 0x0000000080008009, 0x000000008000000a,
0x000000008000808b, 0x800000000000008b, 0x8000000000008089,
0x8000000000008003, 0x8000000000008002, 0x8000000000000080,
0x000000000000800a, 0x800000008000000a, 0x8000000080008081,
0x8000000000008080, 0x0000000080000001, 0x8000000080008008
};
// update the state with given number of rounds
void keccakf(uint64_t st[25], int rounds)
{
int round;
uint64_t t, bc[5];
for (round = 0; round < rounds; ++round) {
// Theta
bc[0] = st[0] ^ st[5] ^ st[10] ^ st[15] ^ st[20];
bc[1] = st[1] ^ st[6] ^ st[11] ^ st[16] ^ st[21];
bc[2] = st[2] ^ st[7] ^ st[12] ^ st[17] ^ st[22];
bc[3] = st[3] ^ st[8] ^ st[13] ^ st[18] ^ st[23];
bc[4] = st[4] ^ st[9] ^ st[14] ^ st[19] ^ st[24];
#define THETA(i) { \
t = bc[(i + 4) % 5] ^ ROTL64(bc[(i + 1) % 5], 1); \
st[i ] ^= t; \
st[i + 5] ^= t; \
st[i + 10] ^= t; \
st[i + 15] ^= t; \
st[i + 20] ^= t; \
}
THETA(0);
THETA(1);
THETA(2);
THETA(3);
THETA(4);
// Rho Pi
t = st[1];
st[ 1] = ROTL64(st[ 6], 44);
st[ 6] = ROTL64(st[ 9], 20);
st[ 9] = ROTL64(st[22], 61);
st[22] = ROTL64(st[14], 39);
st[14] = ROTL64(st[20], 18);
st[20] = ROTL64(st[ 2], 62);
st[ 2] = ROTL64(st[12], 43);
st[12] = ROTL64(st[13], 25);
st[13] = ROTL64(st[19], 8);
st[19] = ROTL64(st[23], 56);
st[23] = ROTL64(st[15], 41);
st[15] = ROTL64(st[ 4], 27);
st[ 4] = ROTL64(st[24], 14);
st[24] = ROTL64(st[21], 2);
st[21] = ROTL64(st[ 8], 55);
st[ 8] = ROTL64(st[16], 45);
st[16] = ROTL64(st[ 5], 36);
st[ 5] = ROTL64(st[ 3], 28);
st[ 3] = ROTL64(st[18], 21);
st[18] = ROTL64(st[17], 15);
st[17] = ROTL64(st[11], 10);
st[11] = ROTL64(st[ 7], 6);
st[ 7] = ROTL64(st[10], 3);
st[10] = ROTL64(t, 1);
// Chi
#define CHI(j) { \
const uint64_t st0 = st[j ]; \
const uint64_t st1 = st[j + 1]; \
const uint64_t st2 = st[j + 2]; \
const uint64_t st3 = st[j + 3]; \
const uint64_t st4 = st[j + 4]; \
st[j ] ^= ~st1 & st2; \
st[j + 1] ^= ~st2 & st3; \
st[j + 2] ^= ~st3 & st4; \
st[j + 3] ^= ~st4 & st0; \
st[j + 4] ^= ~st0 & st1; \
}
CHI( 0);
CHI( 5);
CHI(10);
CHI(15);
CHI(20);
// Iota
st[0] ^= keccakf_rndc[round];
}
}
// compute a keccak hash (md) of given byte length from "in"
typedef uint64_t state_t[25];
void keccak(const uint8_t *in, size_t inlen, uint8_t *md, int mdlen)
{
state_t st;
uint8_t temp[144];
size_t i, rsiz, rsizw;
static_assert(HASH_DATA_AREA <= sizeof(temp), "Bad keccak preconditions");
if (mdlen <= 0 || (mdlen >= 100 && sizeof(st) != (size_t)mdlen))
{
local_abort("Bad keccak use");
}
rsiz = sizeof(state_t) == mdlen ? HASH_DATA_AREA : 200 - 2 * mdlen;
rsizw = rsiz / 8;
memset(st, 0, sizeof(st));
for ( ; inlen >= rsiz; inlen -= rsiz, in += rsiz) {
for (i = 0; i < rsizw; i++) {
uint64_t ina;
memcpy(&ina, in + i * 8, 8);
st[i] ^= swap64le(ina);
}
keccakf(st, KECCAK_ROUNDS);
}
// last block and padding
if (inlen + 1 >= sizeof(temp) || inlen > rsiz || rsiz - inlen + inlen + 1 >= sizeof(temp) || rsiz == 0 || rsiz - 1 >= sizeof(temp) || rsizw * 8 > sizeof(temp))
{
local_abort("Bad keccak use");
}
if (inlen > 0)
memcpy(temp, in, inlen);
temp[inlen++] = 1;
memset(temp + inlen, 0, rsiz - inlen);
temp[rsiz - 1] |= 0x80;
for (i = 0; i < rsizw; i++)
st[i] ^= swap64le(((uint64_t *) temp)[i]);
keccakf(st, KECCAK_ROUNDS);
if (((size_t)mdlen % sizeof(uint64_t)) != 0)
{
local_abort("Bad keccak use");
}
memcpy_swap64le(md, st, mdlen/sizeof(uint64_t));
}
void keccak1600(const uint8_t *in, size_t inlen, uint8_t *md)
{
keccak(in, inlen, md, sizeof(state_t));
}
#define KECCAK_FINALIZED 0x80000000
#define KECCAK_BLOCKLEN 136
#define KECCAK_WORDS 17
#define KECCAK_DIGESTSIZE 32
#define KECCAK_PROCESS_BLOCK(st, block) { \
for (int i_ = 0; i_ < KECCAK_WORDS; i_++){ \
((st))[i_] ^= swap64le(((block))[i_]); \
}; \
keccakf(st, KECCAK_ROUNDS); }
void keccak_init(KECCAK_CTX * ctx){
memset(ctx, 0, sizeof(KECCAK_CTX));
}
void keccak_update(KECCAK_CTX * ctx, const uint8_t *in, size_t inlen){
if (ctx->rest & KECCAK_FINALIZED) {
local_abort("Bad keccak use");
}
const size_t idx = ctx->rest;
ctx->rest = (ctx->rest + inlen) % KECCAK_BLOCKLEN;
// fill partial block
if (idx) {
size_t left = KECCAK_BLOCKLEN - idx;
memcpy((char*)ctx->message + idx, in, (inlen < left ? inlen : left));
if (inlen < left) return;
KECCAK_PROCESS_BLOCK(ctx->hash, ctx->message);
in += left;
inlen -= left;
}
while (inlen >= KECCAK_BLOCKLEN) {
memcpy(ctx->message, in, KECCAK_BLOCKLEN);
KECCAK_PROCESS_BLOCK(ctx->hash, ctx->message);
in += KECCAK_BLOCKLEN;
inlen -= KECCAK_BLOCKLEN;
}
if (inlen) {
memcpy(ctx->message, in, inlen);
}
}
void keccak_finish(KECCAK_CTX * ctx, uint8_t *md){
if (!(ctx->rest & KECCAK_FINALIZED))
{
// clear the rest of the data queue
memset((char*)ctx->message + ctx->rest, 0, KECCAK_BLOCKLEN - ctx->rest);
((char*)ctx->message)[ctx->rest] |= 0x01;
((char*)ctx->message)[KECCAK_BLOCKLEN - 1] |= 0x80;
// process final block
KECCAK_PROCESS_BLOCK(ctx->hash, ctx->message);
ctx->rest = KECCAK_FINALIZED; // mark context as finalized
}
static_assert(KECCAK_BLOCKLEN > KECCAK_DIGESTSIZE, "");
static_assert(KECCAK_DIGESTSIZE % sizeof(uint64_t) == 0, "");
if (md) {
memcpy_swap64le(md, ctx->hash, KECCAK_DIGESTSIZE / sizeof(uint64_t));
}
}

View file

@ -1,40 +0,0 @@
// keccak.h
// 19-Nov-11 Markku-Juhani O. Saarinen <mjos@iki.fi>
#ifndef KECCAK_H
#define KECCAK_H
#include <stdint.h>
#include <string.h>
#ifndef KECCAK_ROUNDS
#define KECCAK_ROUNDS 24
#endif
#ifndef ROTL64
#define ROTL64(x, y) (((x) << (y)) | ((x) >> (64 - (y))))
#endif
// SHA3 Algorithm context.
typedef struct KECCAK_CTX
{
// 1600 bits algorithm hashing state
uint64_t hash[25];
// 1088-bit buffer for leftovers, block size = 136 B for 256-bit keccak
uint64_t message[17];
// count of bytes in the message[] buffer
size_t rest;
} KECCAK_CTX;
// compute a keccak hash (md) of given byte length from "in"
void keccak(const uint8_t *in, size_t inlen, uint8_t *md, int mdlen);
// update the state
void keccakf(uint64_t st[25], int norounds);
void keccak1600(const uint8_t *in, size_t inlen, uint8_t *md);
void keccak_init(KECCAK_CTX * ctx);
void keccak_update(KECCAK_CTX * ctx, const uint8_t *in, size_t inlen);
void keccak_finish(KECCAK_CTX * ctx, uint8_t *md);
#endif

View file

@ -1,115 +0,0 @@
// Copyright (c) 2017-2023, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Parts of this file Copyright (c) 2009-2015 The Bitcoin Core developers
#define __STDC_WANT_LIB_EXT1__ 1
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#ifdef HAVE_EXPLICIT_BZERO
#include <strings.h>
#endif
#include "memwipe.h"
#if defined(_MSC_VER)
#define SCARECROW \
__asm;
#else
#define SCARECROW \
__asm__ __volatile__("" : : "r"(ptr) : "memory");
#endif
#ifdef HAVE_MEMSET_S
void *memwipe(void *ptr, size_t n)
{
if (n > 0 && memset_s(ptr, n, 0, n))
{
#ifdef NDEBUG
fprintf(stderr, "Error: memset_s failed\n");
_exit(1);
#else
abort();
#endif
}
SCARECROW // might as well...
return ptr;
}
#elif defined HAVE_EXPLICIT_BZERO
void *memwipe(void *ptr, size_t n)
{
if (n > 0)
explicit_bzero(ptr, n);
SCARECROW
return ptr;
}
#else
/* The memory_cleanse implementation is taken from Bitcoin */
/* Compilers have a bad habit of removing "superfluous" memset calls that
* are trying to zero memory. For example, when memset()ing a buffer and
* then free()ing it, the compiler might decide that the memset is
* unobservable and thus can be removed.
*
* Previously we used OpenSSL which tried to stop this by a) implementing
* memset in assembly on x86 and b) putting the function in its own file
* for other platforms.
*
* This change removes those tricks in favour of using asm directives to
* scare the compiler away. As best as our compiler folks can tell, this is
* sufficient and will continue to be so.
*
* Adam Langley <agl@google.com>
* Commit: ad1907fe73334d6c696c8539646c21b11178f20f
* BoringSSL (LICENSE: ISC)
*/
static void memory_cleanse(void *ptr, size_t len)
{
memset(ptr, 0, len);
/* As best as we can tell, this is sufficient to break any optimisations that
might try to eliminate "superfluous" memsets. If there's an easy way to
detect memset_s, it would be better to use that. */
SCARECROW
}
void *memwipe(void *ptr, size_t n)
{
if (n > 0)
memory_cleanse(ptr, n);
SCARECROW
return ptr;
}
#endif

View file

@ -1,81 +0,0 @@
// Copyright (c) 2017-2023, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#pragma once
#ifdef __cplusplus
#include <array>
#include <cstddef>
extern "C" {
#endif
void *memwipe(void *src, size_t n);
#ifdef __cplusplus
}
#endif
#ifdef __cplusplus
namespace tools {
/// Scrubs data in the contained type upon destruction.
///
/// Primarily useful for making sure that private keys don't stick around in
/// memory after the objects that held them have gone out of scope.
template <class T>
struct scrubbed : public T {
using type = T;
~scrubbed() {
scrub();
}
/// Destroy the contents of the contained type.
void scrub() {
static_assert(std::is_pod<T>::value,
"T cannot be auto-scrubbed. T must be POD.");
static_assert(std::is_trivially_destructible<T>::value,
"T cannot be auto-scrubbed. T must be trivially destructable.");
memwipe(this, sizeof(T));
}
};
template<typename T>
T& unwrap(scrubbed<T>& src) { return src; }
template<typename T>
const T& unwrap(scrubbed<T> const& src) { return src; }
template <class T, size_t N>
using scrubbed_arr = scrubbed<std::array<T, N>>;
} // namespace tools
#endif // __cplusplus

File diff suppressed because it is too large Load diff

View file

@ -1,215 +0,0 @@
/*
* ---------------------------------------------------------------------------
* OpenAES License
* ---------------------------------------------------------------------------
* Copyright (c) 2012, Nabil S. Al Ramli, www.nalramli.com
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* ---------------------------------------------------------------------------
*/
#ifndef _OAES_LIB_H
#define _OAES_LIB_H
#include <stdint.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _WIN32
# ifdef OAES_SHARED
# ifdef oaes_lib_EXPORTS
# define OAES_API __declspec(dllexport)
# else
# define OAES_API __declspec(dllimport)
# endif
# else
# define OAES_API
# endif
#else
# define OAES_API
#endif // WIN32
#define OAES_VERSION "0.8.1"
#define OAES_BLOCK_SIZE 16
typedef void OAES_CTX;
typedef enum
{
OAES_RET_FIRST = 0,
OAES_RET_SUCCESS = 0,
OAES_RET_UNKNOWN,
OAES_RET_ARG1,
OAES_RET_ARG2,
OAES_RET_ARG3,
OAES_RET_ARG4,
OAES_RET_ARG5,
OAES_RET_NOKEY,
OAES_RET_MEM,
OAES_RET_BUF,
OAES_RET_HEADER,
OAES_RET_COUNT
} OAES_RET;
/*
* oaes_set_option() takes one of these values for its [option] parameter
* some options accept either an optional or a required [value] parameter
*/
// no option
#define OAES_OPTION_NONE 0
// enable ECB mode, disable CBC mode
#define OAES_OPTION_ECB 1
// enable CBC mode, disable ECB mode
// value is optional, may pass uint8_t iv[OAES_BLOCK_SIZE] to specify
// the value of the initialization vector, iv
#define OAES_OPTION_CBC 2
#ifdef OAES_DEBUG
typedef int ( * oaes_step_cb ) (
const uint8_t state[OAES_BLOCK_SIZE],
const char * step_name,
int step_count,
void * user_data );
// enable state stepping mode
// value is required, must pass oaes_step_cb to receive the state at each step
#define OAES_OPTION_STEP_ON 4
// disable state stepping mode
#define OAES_OPTION_STEP_OFF 8
#endif // OAES_DEBUG
typedef uint16_t OAES_OPTION;
typedef struct _oaes_key
{
size_t data_len;
uint8_t *data;
size_t exp_data_len;
uint8_t *exp_data;
size_t num_keys;
size_t key_base;
} oaes_key;
typedef struct _oaes_ctx
{
#ifdef OAES_HAVE_ISAAC
randctx * rctx;
#endif // OAES_HAVE_ISAAC
#ifdef OAES_DEBUG
oaes_step_cb step_cb;
#endif // OAES_DEBUG
oaes_key * key;
OAES_OPTION options;
uint8_t iv[OAES_BLOCK_SIZE];
} oaes_ctx;
/*
* // usage:
*
* OAES_CTX * ctx = oaes_alloc();
* .
* .
* .
* {
* oaes_gen_key_xxx( ctx );
* {
* oaes_key_export( ctx, _buf, &_buf_len );
* // or
* oaes_key_export_data( ctx, _buf, &_buf_len );\
* }
* }
* // or
* {
* oaes_key_import( ctx, _buf, _buf_len );
* // or
* oaes_key_import_data( ctx, _buf, _buf_len );
* }
* .
* .
* .
* oaes_encrypt( ctx, m, m_len, c, &c_len );
* .
* .
* .
* oaes_decrypt( ctx, c, c_len, m, &m_len );
* .
* .
* .
* oaes_free( &ctx );
*/
OAES_API OAES_CTX * oaes_alloc(void);
OAES_API OAES_RET oaes_free( OAES_CTX ** ctx );
OAES_API OAES_RET oaes_set_option( OAES_CTX * ctx,
OAES_OPTION option, const void * value );
OAES_API OAES_RET oaes_key_gen_128( OAES_CTX * ctx );
OAES_API OAES_RET oaes_key_gen_192( OAES_CTX * ctx );
OAES_API OAES_RET oaes_key_gen_256( OAES_CTX * ctx );
// export key with header information
// set data == NULL to get the required data_len
OAES_API OAES_RET oaes_key_export( OAES_CTX * ctx,
uint8_t * data, size_t * data_len );
// directly export the data from key
// set data == NULL to get the required data_len
OAES_API OAES_RET oaes_key_export_data( OAES_CTX * ctx,
uint8_t * data, size_t * data_len );
// import key with header information
OAES_API OAES_RET oaes_key_import( OAES_CTX * ctx,
const uint8_t * data, size_t data_len );
// directly import data into key
OAES_API OAES_RET oaes_key_import_data( OAES_CTX * ctx,
const uint8_t * data, size_t data_len );
// set c == NULL to get the required c_len
OAES_API OAES_RET oaes_encrypt( OAES_CTX * ctx,
const uint8_t * m, size_t m_len, uint8_t * c, size_t * c_len );
// set m == NULL to get the required m_len
OAES_API OAES_RET oaes_decrypt( OAES_CTX * ctx,
const uint8_t * c, size_t c_len, uint8_t * m, size_t * m_len );
// set buf == NULL to get the required buf_len
OAES_API OAES_RET oaes_sprintf(
char * buf, size_t * buf_len, const uint8_t * data, size_t data_len );
OAES_API OAES_RET oaes_encryption_round( const uint8_t * key, uint8_t * c );
OAES_API OAES_RET oaes_pseudo_encrypt_ecb( OAES_CTX * ctx, uint8_t * c );
#ifdef __cplusplus
}
#endif
#endif // _OAES_LIB_H

File diff suppressed because it is too large Load diff

View file

@ -1,47 +0,0 @@
#ifndef _SKEIN_H_
#define _SKEIN_H_ 1
/**************************************************************************
**
** Interface declarations and internal definitions for Skein hashing.
**
** Source code author: Doug Whiting, 2008.
**
** This algorithm and source code is released to the public domain.
**
***************************************************************************
**
** The following compile-time switches may be defined to control some
** tradeoffs between speed, code size, error checking, and security.
**
** The "default" note explains what happens when the switch is not defined.
**
** SKEIN_DEBUG -- make callouts from inside Skein code
** to examine/display intermediate values.
** [default: no callouts (no overhead)]
**
** SKEIN_ERR_CHECK -- how error checking is handled inside Skein
** code. If not defined, most error checking
** is disabled (for performance). Otherwise,
** the switch value is interpreted as:
** 0: use assert() to flag errors
** 1: return SKEIN_FAIL to flag errors
**
***************************************************************************/
#include "skein_port.h" /* get platform-specific definitions */
typedef enum
{
SKEIN_SUCCESS = 0, /* return codes from Skein calls */
SKEIN_FAIL = 1,
SKEIN_BAD_HASHLEN = 2
}
HashReturn;
typedef size_t DataLength; /* bit count type */
typedef u08b_t BitSequence; /* bit stream type */
/* "all-in-one" call */
HashReturn skein_hash(int hashbitlen, const BitSequence *data,
DataLength databitlen, BitSequence *hashval);
#endif /* ifndef _SKEIN_H_ */

View file

@ -1,218 +0,0 @@
// Copyright (c) 2014-2023, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef _SKEIN_PORT_H_
#define _SKEIN_PORT_H_
#include <limits.h>
#include <stdint.h>
#ifndef RETURN_VALUES
# define RETURN_VALUES
# if defined( DLL_EXPORT )
# if defined( _MSC_VER ) || defined ( __INTEL_COMPILER )
# define VOID_RETURN __declspec( dllexport ) void __stdcall
# define INT_RETURN __declspec( dllexport ) int __stdcall
# elif defined( __GNUC__ )
# define VOID_RETURN __declspec( __dllexport__ ) void
# define INT_RETURN __declspec( __dllexport__ ) int
# else
# error Use of the DLL is only available on the Microsoft, Intel and GCC compilers
# endif
# elif defined( DLL_IMPORT )
# if defined( _MSC_VER ) || defined ( __INTEL_COMPILER )
# define VOID_RETURN __declspec( dllimport ) void __stdcall
# define INT_RETURN __declspec( dllimport ) int __stdcall
# elif defined( __GNUC__ )
# define VOID_RETURN __declspec( __dllimport__ ) void
# define INT_RETURN __declspec( __dllimport__ ) int
# else
# error Use of the DLL is only available on the Microsoft, Intel and GCC compilers
# endif
# elif defined( __WATCOMC__ )
# define VOID_RETURN void __cdecl
# define INT_RETURN int __cdecl
# else
# define VOID_RETURN void
# define INT_RETURN int
# endif
#endif
/* These defines are used to declare buffers in a way that allows
faster operations on longer variables to be used. In all these
defines 'size' must be a power of 2 and >= 8
dec_unit_type(size,x) declares a variable 'x' of length
'size' bits
dec_bufr_type(size,bsize,x) declares a buffer 'x' of length 'bsize'
bytes defined as an array of variables
each of 'size' bits (bsize must be a
multiple of size / 8)
ptr_cast(x,size) casts a pointer to a pointer to a
variable of length 'size' bits
*/
#define ui_type(size) uint##size##_t
#define dec_unit_type(size,x) typedef ui_type(size) x
#define dec_bufr_type(size,bsize,x) typedef ui_type(size) x[bsize / (size >> 3)]
#define ptr_cast(x,size) ((ui_type(size)*)(x))
typedef unsigned int uint_t; /* native unsigned integer */
typedef uint8_t u08b_t; /* 8-bit unsigned integer */
typedef uint64_t u64b_t; /* 64-bit unsigned integer */
#ifndef RotL_64
#define RotL_64(x,N) (((x) << (N)) | ((x) >> (64-(N))))
#endif
/*
* Skein is "natively" little-endian (unlike SHA-xxx), for optimal
* performance on x86 CPUs. The Skein code requires the following
* definitions for dealing with endianness:
*
* SKEIN_NEED_SWAP: 0 for little-endian, 1 for big-endian
* Skein_Put64_LSB_First
* Skein_Get64_LSB_First
* Skein_Swap64
*
* If SKEIN_NEED_SWAP is defined at compile time, it is used here
* along with the portable versions of Put64/Get64/Swap64, which
* are slow in general.
*
* Otherwise, an "auto-detect" of endianness is attempted below.
* If the default handling doesn't work well, the user may insert
* platform-specific code instead (e.g., for big-endian CPUs).
*
*/
#ifndef SKEIN_NEED_SWAP /* compile-time "override" for endianness? */
#include "int-util.h"
#define IS_BIG_ENDIAN 4321 /* byte 0 is most significant (mc68k) */
#define IS_LITTLE_ENDIAN 1234 /* byte 0 is least significant (i386) */
#if BYTE_ORDER == LITTLE_ENDIAN
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
#endif
#if BYTE_ORDER == BIG_ENDIAN
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
#endif
/* special handler for IA64, which may be either endianness (?) */
/* here we assume little-endian, but this may need to be changed */
#if defined(__ia64) || defined(__ia64__) || defined(_M_IA64)
# define PLATFORM_MUST_ALIGN (1)
#ifndef PLATFORM_BYTE_ORDER
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
#endif
#endif
#ifndef PLATFORM_MUST_ALIGN
# define PLATFORM_MUST_ALIGN (0)
#endif
#if PLATFORM_BYTE_ORDER == IS_BIG_ENDIAN
/* here for big-endian CPUs */
#define SKEIN_NEED_SWAP (1)
#elif PLATFORM_BYTE_ORDER == IS_LITTLE_ENDIAN
/* here for x86 and x86-64 CPUs (and other detected little-endian CPUs) */
#define SKEIN_NEED_SWAP (0)
#if PLATFORM_MUST_ALIGN == 0 /* ok to use "fast" versions? */
#define Skein_Put64_LSB_First(dst08,src64,bCnt) memcpy(dst08,src64,bCnt)
#define Skein_Get64_LSB_First(dst64,src08,wCnt) memcpy(dst64,src08,8*(wCnt))
#endif
#else
#error "Skein needs endianness setting!"
#endif
#endif /* ifndef SKEIN_NEED_SWAP */
/*
******************************************************************
* Provide any definitions still needed.
******************************************************************
*/
#ifndef Skein_Swap64 /* swap for big-endian, nop for little-endian */
#if SKEIN_NEED_SWAP
#define Skein_Swap64(w64) \
( (( ((u64b_t)(w64)) & 0xFF) << 56) | \
(((((u64b_t)(w64)) >> 8) & 0xFF) << 48) | \
(((((u64b_t)(w64)) >>16) & 0xFF) << 40) | \
(((((u64b_t)(w64)) >>24) & 0xFF) << 32) | \
(((((u64b_t)(w64)) >>32) & 0xFF) << 24) | \
(((((u64b_t)(w64)) >>40) & 0xFF) << 16) | \
(((((u64b_t)(w64)) >>48) & 0xFF) << 8) | \
(((((u64b_t)(w64)) >>56) & 0xFF) ) )
#else
#define Skein_Swap64(w64) (w64)
#endif
#endif /* ifndef Skein_Swap64 */
#ifndef Skein_Put64_LSB_First
void Skein_Put64_LSB_First(u08b_t *dst,const u64b_t *src,size_t bCnt)
#ifdef SKEIN_PORT_CODE /* instantiate the function code here? */
{ /* this version is fully portable (big-endian or little-endian), but slow */
size_t n;
for (n=0;n<bCnt;n++)
dst[n] = (u08b_t) (src[n>>3] >> (8*(n&7)));
}
#else
; /* output only the function prototype */
#endif
#endif /* ifndef Skein_Put64_LSB_First */
#ifndef Skein_Get64_LSB_First
void Skein_Get64_LSB_First(u64b_t *dst,const u08b_t *src,size_t wCnt)
#ifdef SKEIN_PORT_CODE /* instantiate the function code here? */
{ /* this version is fully portable (big-endian or little-endian), but slow */
size_t n;
for (n=0;n<8*wCnt;n+=8)
dst[n/8] = (((u64b_t) src[n ]) ) +
(((u64b_t) src[n+1]) << 8) +
(((u64b_t) src[n+2]) << 16) +
(((u64b_t) src[n+3]) << 24) +
(((u64b_t) src[n+4]) << 32) +
(((u64b_t) src[n+5]) << 40) +
(((u64b_t) src[n+6]) << 48) +
(((u64b_t) src[n+7]) << 56) ;
}
#else
; /* output only the function prototype */
#endif
#endif /* ifndef Skein_Get64_LSB_First */
#endif /* ifndef _SKEIN_PORT_H_ */

File diff suppressed because it is too large Load diff

View file

@ -1,163 +0,0 @@
#ifndef VARIANT2_INT_SQRT_H
#define VARIANT2_INT_SQRT_H
#include <math.h>
#include <float.h>
#define VARIANT2_INTEGER_MATH_SQRT_STEP_SSE2() \
do { \
const __m128i exp_double_bias = _mm_set_epi64x(0, 1023ULL << 52); \
__m128d x = _mm_castsi128_pd(_mm_add_epi64(_mm_cvtsi64_si128(sqrt_input >> 12), exp_double_bias)); \
x = _mm_sqrt_sd(_mm_setzero_pd(), x); \
sqrt_result = (uint64_t)(_mm_cvtsi128_si64(_mm_sub_epi64(_mm_castpd_si128(x), exp_double_bias))) >> 19; \
} while(0)
#define VARIANT2_INTEGER_MATH_SQRT_STEP_FP64() \
do { \
sqrt_result = sqrt(sqrt_input + 18446744073709551616.0) * 2.0 - 8589934592.0; \
} while(0)
#define VARIANT2_INTEGER_MATH_SQRT_STEP_REF() \
sqrt_result = integer_square_root_v2(sqrt_input)
// Reference implementation of the integer square root for Cryptonight variant 2
// Computes integer part of "sqrt(2^64 + n) * 2 - 2^33"
//
// In other words, given 64-bit unsigned integer n:
// 1) Write it as x = 1.NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN000... in binary (1 <= x < 2, all 64 bits of n are used)
// 2) Calculate sqrt(x) = 1.0RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR... (1 <= sqrt(x) < sqrt(2), so it will always start with "1.0" in binary)
// 3) Take 32 bits that come after "1.0" and return them as a 32-bit unsigned integer, discard all remaining bits
//
// Some sample inputs and outputs:
//
// Input | Output | Exact value of "sqrt(2^64 + n) * 2 - 2^33"
// -----------------|------------|-------------------------------------------
// 0 | 0 | 0
// 2^32 | 0 | 0.99999999994179233909330885695244...
// 2^32 + 1 | 1 | 1.0000000001746229827200734316305...
// 2^50 | 262140 | 262140.00012206565608606978175873...
// 2^55 + 20963331 | 8384515 | 8384515.9999999997673963974959744...
// 2^55 + 20963332 | 8384516 | 8384516
// 2^62 + 26599786 | 1013904242 | 1013904242.9999999999479374853545...
// 2^62 + 26599787 | 1013904243 | 1013904243.0000000001561875439364...
// 2^64 - 1 | 3558067407 | 3558067407.9041987696409179931096...
// The reference implementation as it is now uses only unsigned int64 arithmetic, so it can't have undefined behavior
// It was tested once for all edge cases and confirmed correct
static inline uint32_t integer_square_root_v2(uint64_t n)
{
uint64_t r = 1ULL << 63;
for (uint64_t bit = 1ULL << 60; bit; bit >>= 2)
{
const bool b = (n < r + bit);
const uint64_t n_next = n - (r + bit);
const uint64_t r_next = r + bit * 2;
n = b ? n : n_next;
r = b ? r : r_next;
r >>= 1;
}
return r * 2 + ((n > r) ? 1 : 0);
}
/*
VARIANT2_INTEGER_MATH_SQRT_FIXUP checks that "r" is an integer part of "sqrt(2^64 + sqrt_input) * 2 - 2^33" and adds or subtracts 1 if needed
It's hard to understand how it works, so here is a full calculation of formulas used in VARIANT2_INTEGER_MATH_SQRT_FIXUP
The following inequalities must hold for r if it's an integer part of "sqrt(2^64 + sqrt_input) * 2 - 2^33":
1) r <= sqrt(2^64 + sqrt_input) * 2 - 2^33
2) r + 1 > sqrt(2^64 + sqrt_input) * 2 - 2^33
We need to check them using only unsigned integer arithmetic to avoid rounding errors and undefined behavior
First inequality: r <= sqrt(2^64 + sqrt_input) * 2 - 2^33
-----------------------------------------------------------------------------------
r <= sqrt(2^64 + sqrt_input) * 2 - 2^33
r + 2^33 <= sqrt(2^64 + sqrt_input) * 2
r/2 + 2^32 <= sqrt(2^64 + sqrt_input)
(r/2 + 2^32)^2 <= 2^64 + sqrt_input
Rewrite r as r = s * 2 + b (s = trunc(r/2), b is 0 or 1)
((s*2+b)/2 + 2^32)^2 <= 2^64 + sqrt_input
(s*2+b)^2/4 + 2*2^32*(s*2+b)/2 + 2^64 <= 2^64 + sqrt_input
(s*2+b)^2/4 + 2*2^32*(s*2+b)/2 <= sqrt_input
(s*2+b)^2/4 + 2^32*r <= sqrt_input
(s^2*4+2*s*2*b+b^2)/4 + 2^32*r <= sqrt_input
s^2+s*b+b^2/4 + 2^32*r <= sqrt_input
s*(s+b) + b^2/4 + 2^32*r <= sqrt_input
Let r2 = s*(s+b) + r*2^32
r2 + b^2/4 <= sqrt_input
If this inequality doesn't hold, then we must decrement r: IF "r2 + b^2/4 > sqrt_input" THEN r = r - 1
b can be 0 or 1
If b is 0 then we need to compare "r2 > sqrt_input"
If b is 1 then b^2/4 = 0.25, so we need to compare "r2 + 0.25 > sqrt_input"
Since both r2 and sqrt_input are integers, we can safely replace it with "r2 + 1 > sqrt_input"
-----------------------------------------------------------------------------------
Both cases can be merged to a single expression "r2 + b > sqrt_input"
-----------------------------------------------------------------------------------
There will be no overflow when calculating "r2 + b", so it's safe to compare with sqrt_input:
r2 + b = s*(s+b) + r*2^32 + b
The largest value s, b and r can have is s = 1779033703, b = 1, r = 3558067407 when sqrt_input = 2^64 - 1
r2 + b <= 1779033703*1779033704 + 3558067407*2^32 + 1 = 18446744068217447385 < 2^64
Second inequality: r + 1 > sqrt(2^64 + sqrt_input) * 2 - 2^33
-----------------------------------------------------------------------------------
r + 1 > sqrt(2^64 + sqrt_input) * 2 - 2^33
r + 1 + 2^33 > sqrt(2^64 + sqrt_input) * 2
((r+1)/2 + 2^32)^2 > 2^64 + sqrt_input
Rewrite r as r = s * 2 + b (s = trunc(r/2), b is 0 or 1)
((s*2+b+1)/2 + 2^32)^2 > 2^64 + sqrt_input
(s*2+b+1)^2/4 + 2*(s*2+b+1)/2*2^32 + 2^64 > 2^64 + sqrt_input
(s*2+b+1)^2/4 + (s*2+b+1)*2^32 > sqrt_input
(s*2+b+1)^2/4 + (r+1)*2^32 > sqrt_input
(s*2+(b+1))^2/4 + r*2^32 + 2^32 > sqrt_input
(s^2*4+2*s*2*(b+1)+(b+1)^2)/4 + r*2^32 + 2^32 > sqrt_input
s^2+s*(b+1)+(b+1)^2/4 + r*2^32 + 2^32 > sqrt_input
s*(s+b) + s + (b+1)^2/4 + r*2^32 + 2^32 > sqrt_input
Let r2 = s*(s+b) + r*2^32
r2 + s + (b+1)^2/4 + 2^32 > sqrt_input
r2 + 2^32 + (b+1)^2/4 > sqrt_input - s
If this inequality doesn't hold, then we must decrement r: IF "r2 + 2^32 + (b+1)^2/4 <= sqrt_input - s" THEN r = r - 1
b can be 0 or 1
If b is 0 then we need to compare "r2 + 2^32 + 1/4 <= sqrt_input - s" which is equal to "r2 + 2^32 < sqrt_input - s" because all numbers here are integers
If b is 1 then (b+1)^2/4 = 1, so we need to compare "r2 + 2^32 + 1 <= sqrt_input - s" which is also equal to "r2 + 2^32 < sqrt_input - s"
-----------------------------------------------------------------------------------
Both cases can be merged to a single expression "r2 + 2^32 < sqrt_input - s"
-----------------------------------------------------------------------------------
There will be no overflow when calculating "r2 + 2^32":
r2 + 2^32 = s*(s+b) + r*2^32 + 2^32 = s*(s+b) + (r+1)*2^32
The largest value s, b and r can have is s = 1779033703, b = 1, r = 3558067407 when sqrt_input = 2^64 - 1
r2 + b <= 1779033703*1779033704 + 3558067408*2^32 = 18446744072512414680 < 2^64
There will be no integer overflow when calculating "sqrt_input - s", i.e. "sqrt_input >= s" at all times:
s = trunc(r/2) = trunc(sqrt(2^64 + sqrt_input) - 2^32) < sqrt(2^64 + sqrt_input) - 2^32 + 1
sqrt_input > sqrt(2^64 + sqrt_input) - 2^32 + 1
sqrt_input + 2^32 - 1 > sqrt(2^64 + sqrt_input)
(sqrt_input + 2^32 - 1)^2 > sqrt_input + 2^64
sqrt_input^2 + 2*sqrt_input*(2^32 - 1) + (2^32-1)^2 > sqrt_input + 2^64
sqrt_input^2 + sqrt_input*(2^33 - 2) + (2^32-1)^2 > sqrt_input + 2^64
sqrt_input^2 + sqrt_input*(2^33 - 3) + (2^32-1)^2 > 2^64
sqrt_input^2 + sqrt_input*(2^33 - 3) + 2^64-2^33+1 > 2^64
sqrt_input^2 + sqrt_input*(2^33 - 3) - 2^33 + 1 > 0
This inequality is true if sqrt_input > 1 and it's easy to check that s = 0 if sqrt_input is 0 or 1, so there will be no integer overflow
*/
#define VARIANT2_INTEGER_MATH_SQRT_FIXUP(r) \
do { \
const uint64_t s = r >> 1; \
const uint64_t b = r & 1; \
const uint64_t r2 = (uint64_t)(s) * (s + b) + (r << 32); \
r += ((r2 + b > sqrt_input) ? -1 : 0) + ((r2 + (1ULL << 32) < sqrt_input - s) ? 1 : 0); \
} while(0)
#endif

View file

@ -1,441 +0,0 @@
#ifndef VARIANT4_RANDOM_MATH_H
#define VARIANT4_RANDOM_MATH_H
// Register size can be configured to either 32 bit (uint32_t) or 64 bit (uint64_t)
typedef uint32_t v4_reg;
enum V4_Settings
{
// Generate code with minimal theoretical latency = 45 cycles, which is equivalent to 15 multiplications
TOTAL_LATENCY = 15 * 3,
// Always generate at least 60 instructions
NUM_INSTRUCTIONS_MIN = 60,
// Never generate more than 70 instructions (final RET instruction doesn't count here)
NUM_INSTRUCTIONS_MAX = 70,
// Available ALUs for MUL
// Modern CPUs typically have only 1 ALU which can do multiplications
ALU_COUNT_MUL = 1,
// Total available ALUs
// Modern CPUs have 4 ALUs, but we use only 3 because random math executes together with other main loop code
ALU_COUNT = 3,
};
enum V4_InstructionList
{
MUL, // a*b
ADD, // a+b + C, C is an unsigned 32-bit constant
SUB, // a-b
ROR, // rotate right "a" by "b & 31" bits
ROL, // rotate left "a" by "b & 31" bits
XOR, // a^b
RET, // finish execution
V4_INSTRUCTION_COUNT = RET,
};
// V4_InstructionDefinition is used to generate code from random data
// Every random sequence of bytes is a valid code
//
// There are 9 registers in total:
// - 4 variable registers
// - 5 constant registers initialized from loop variables
// This is why dst_index is 2 bits
enum V4_InstructionDefinition
{
V4_OPCODE_BITS = 3,
V4_DST_INDEX_BITS = 2,
V4_SRC_INDEX_BITS = 3,
};
struct V4_Instruction
{
uint8_t opcode;
uint8_t dst_index;
uint8_t src_index;
uint32_t C;
};
#ifndef FORCEINLINE
#if defined(__GNUC__)
#define FORCEINLINE __attribute__((always_inline)) inline
#elif defined(_MSC_VER)
#define FORCEINLINE __forceinline
#else
#define FORCEINLINE inline
#endif
#endif
#ifndef UNREACHABLE_CODE
#if defined(__GNUC__)
#define UNREACHABLE_CODE __builtin_unreachable()
#elif defined(_MSC_VER)
#define UNREACHABLE_CODE __assume(false)
#else
#define UNREACHABLE_CODE
#endif
#endif
// Random math interpreter's loop is fully unrolled and inlined to achieve 100% branch prediction on CPU:
// every switch-case will point to the same destination on every iteration of Cryptonight main loop
//
// This is about as fast as it can get without using low-level machine code generation
static FORCEINLINE void v4_random_math(const struct V4_Instruction* code, v4_reg* r)
{
enum
{
REG_BITS = sizeof(v4_reg) * 8,
};
#define V4_EXEC(i) \
{ \
const struct V4_Instruction* op = code + i; \
const v4_reg src = r[op->src_index]; \
v4_reg* dst = r + op->dst_index; \
switch (op->opcode) \
{ \
case MUL: \
*dst *= src; \
break; \
case ADD: \
*dst += src + op->C; \
break; \
case SUB: \
*dst -= src; \
break; \
case ROR: \
{ \
const uint32_t shift = src % REG_BITS; \
*dst = (*dst >> shift) | (*dst << ((REG_BITS - shift) % REG_BITS)); \
} \
break; \
case ROL: \
{ \
const uint32_t shift = src % REG_BITS; \
*dst = (*dst << shift) | (*dst >> ((REG_BITS - shift) % REG_BITS)); \
} \
break; \
case XOR: \
*dst ^= src; \
break; \
case RET: \
return; \
default: \
UNREACHABLE_CODE; \
break; \
} \
}
#define V4_EXEC_10(j) \
V4_EXEC(j + 0) \
V4_EXEC(j + 1) \
V4_EXEC(j + 2) \
V4_EXEC(j + 3) \
V4_EXEC(j + 4) \
V4_EXEC(j + 5) \
V4_EXEC(j + 6) \
V4_EXEC(j + 7) \
V4_EXEC(j + 8) \
V4_EXEC(j + 9)
// Generated program can have 60 + a few more (usually 2-3) instructions to achieve required latency
// I've checked all block heights < 10,000,000 and here is the distribution of program sizes:
//
// 60 27960
// 61 105054
// 62 2452759
// 63 5115997
// 64 1022269
// 65 1109635
// 66 153145
// 67 8550
// 68 4529
// 69 102
// Unroll 70 instructions here
V4_EXEC_10(0); // instructions 0-9
V4_EXEC_10(10); // instructions 10-19
V4_EXEC_10(20); // instructions 20-29
V4_EXEC_10(30); // instructions 30-39
V4_EXEC_10(40); // instructions 40-49
V4_EXEC_10(50); // instructions 50-59
V4_EXEC_10(60); // instructions 60-69
#undef V4_EXEC_10
#undef V4_EXEC
}
// If we don't have enough data available, generate more
static FORCEINLINE void check_data(size_t* data_index, const size_t bytes_needed, int8_t* data, const size_t data_size)
{
if (*data_index + bytes_needed > data_size)
{
hash_extra_blake(data, data_size, (char*) data);
*data_index = 0;
}
}
// Generates as many random math operations as possible with given latency and ALU restrictions
// "code" array must have space for NUM_INSTRUCTIONS_MAX+1 instructions
static inline int v4_random_math_init(struct V4_Instruction* code, const uint64_t height)
{
// MUL is 3 cycles, 3-way addition and rotations are 2 cycles, SUB/XOR are 1 cycle
// These latencies match real-life instruction latencies for Intel CPUs starting from Sandy Bridge and up to Skylake/Coffee lake
//
// AMD Ryzen has the same latencies except 1-cycle ROR/ROL, so it'll be a bit faster than Intel Sandy Bridge and newer processors
// Surprisingly, Intel Nehalem also has 1-cycle ROR/ROL, so it'll also be faster than Intel Sandy Bridge and newer processors
// AMD Bulldozer has 4 cycles latency for MUL (slower than Intel) and 1 cycle for ROR/ROL (faster than Intel), so average performance will be the same
// Source: https://www.agner.org/optimize/instruction_tables.pdf
const int op_latency[V4_INSTRUCTION_COUNT] = { 3, 2, 1, 2, 2, 1 };
// Instruction latencies for theoretical ASIC implementation
const int asic_op_latency[V4_INSTRUCTION_COUNT] = { 3, 1, 1, 1, 1, 1 };
// Available ALUs for each instruction
const int op_ALUs[V4_INSTRUCTION_COUNT] = { ALU_COUNT_MUL, ALU_COUNT, ALU_COUNT, ALU_COUNT, ALU_COUNT, ALU_COUNT };
int8_t data[32];
memset(data, 0, sizeof(data));
uint64_t tmp = SWAP64LE(height);
memcpy(data, &tmp, sizeof(uint64_t));
data[20] = -38; // change seed
// Set data_index past the last byte in data
// to trigger full data update with blake hash
// before we start using it
size_t data_index = sizeof(data);
int code_size;
// There is a small chance (1.8%) that register R8 won't be used in the generated program
// So we keep track of it and try again if it's not used
bool r8_used;
do {
int latency[9];
int asic_latency[9];
// Tracks previous instruction and value of the source operand for registers R0-R3 throughout code execution
// byte 0: current value of the destination register
// byte 1: instruction opcode
// byte 2: current value of the source register
//
// Registers R4-R8 are constant and are treated as having the same value because when we do
// the same operation twice with two constant source registers, it can be optimized into a single operation
uint32_t inst_data[9] = { 0, 1, 2, 3, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF };
bool alu_busy[TOTAL_LATENCY + 1][ALU_COUNT];
bool is_rotation[V4_INSTRUCTION_COUNT];
bool rotated[4];
int rotate_count = 0;
memset(latency, 0, sizeof(latency));
memset(asic_latency, 0, sizeof(asic_latency));
memset(alu_busy, 0, sizeof(alu_busy));
memset(is_rotation, 0, sizeof(is_rotation));
memset(rotated, 0, sizeof(rotated));
is_rotation[ROR] = true;
is_rotation[ROL] = true;
int num_retries = 0;
code_size = 0;
int total_iterations = 0;
r8_used = false;
// Generate random code to achieve minimal required latency for our abstract CPU
// Try to get this latency for all 4 registers
while (((latency[0] < TOTAL_LATENCY) || (latency[1] < TOTAL_LATENCY) || (latency[2] < TOTAL_LATENCY) || (latency[3] < TOTAL_LATENCY)) && (num_retries < 64))
{
// Fail-safe to guarantee loop termination
++total_iterations;
if (total_iterations > 256)
break;
check_data(&data_index, 1, data, sizeof(data));
const uint8_t c = ((uint8_t*)data)[data_index++];
// MUL = opcodes 0-2
// ADD = opcode 3
// SUB = opcode 4
// ROR/ROL = opcode 5, shift direction is selected randomly
// XOR = opcodes 6-7
uint8_t opcode = c & ((1 << V4_OPCODE_BITS) - 1);
if (opcode == 5)
{
check_data(&data_index, 1, data, sizeof(data));
opcode = (data[data_index++] >= 0) ? ROR : ROL;
}
else if (opcode >= 6)
{
opcode = XOR;
}
else
{
opcode = (opcode <= 2) ? MUL : (opcode - 2);
}
uint8_t dst_index = (c >> V4_OPCODE_BITS) & ((1 << V4_DST_INDEX_BITS) - 1);
uint8_t src_index = (c >> (V4_OPCODE_BITS + V4_DST_INDEX_BITS)) & ((1 << V4_SRC_INDEX_BITS) - 1);
const int a = dst_index;
int b = src_index;
// Don't do ADD/SUB/XOR with the same register
if (((opcode == ADD) || (opcode == SUB) || (opcode == XOR)) && (a == b))
{
// Use register R8 as source instead
b = 8;
src_index = 8;
}
// Don't do rotation with the same destination twice because it's equal to a single rotation
if (is_rotation[opcode] && rotated[a])
{
continue;
}
// Don't do the same instruction (except MUL) with the same source value twice because all other cases can be optimized:
// 2xADD(a, b, C) = ADD(a, b*2, C1+C2), same for SUB and rotations
// 2xXOR(a, b) = NOP
if ((opcode != MUL) && ((inst_data[a] & 0xFFFF00) == (opcode << 8) + ((inst_data[b] & 255) << 16)))
{
continue;
}
// Find which ALU is available (and when) for this instruction
int next_latency = (latency[a] > latency[b]) ? latency[a] : latency[b];
int alu_index = -1;
while (next_latency < TOTAL_LATENCY)
{
for (int i = op_ALUs[opcode] - 1; i >= 0; --i)
{
if (!alu_busy[next_latency][i])
{
// ADD is implemented as two 1-cycle instructions on a real CPU, so do an additional availability check
if ((opcode == ADD) && alu_busy[next_latency + 1][i])
{
continue;
}
// Rotation can only start when previous rotation is finished, so do an additional availability check
if (is_rotation[opcode] && (next_latency < rotate_count * op_latency[opcode]))
{
continue;
}
alu_index = i;
break;
}
}
if (alu_index >= 0)
{
break;
}
++next_latency;
}
// Don't generate instructions that leave some register unchanged for more than 7 cycles
if (next_latency > latency[a] + 7)
{
continue;
}
next_latency += op_latency[opcode];
if (next_latency <= TOTAL_LATENCY)
{
if (is_rotation[opcode])
{
++rotate_count;
}
// Mark ALU as busy only for the first cycle when it starts executing the instruction because ALUs are fully pipelined
alu_busy[next_latency - op_latency[opcode]][alu_index] = true;
latency[a] = next_latency;
// ASIC is supposed to have enough ALUs to run as many independent instructions per cycle as possible, so latency calculation for ASIC is simple
asic_latency[a] = ((asic_latency[a] > asic_latency[b]) ? asic_latency[a] : asic_latency[b]) + asic_op_latency[opcode];
rotated[a] = is_rotation[opcode];
inst_data[a] = code_size + (opcode << 8) + ((inst_data[b] & 255) << 16);
code[code_size].opcode = opcode;
code[code_size].dst_index = dst_index;
code[code_size].src_index = src_index;
code[code_size].C = 0;
if (src_index == 8)
{
r8_used = true;
}
if (opcode == ADD)
{
// ADD instruction is implemented as two 1-cycle instructions on a real CPU, so mark ALU as busy for the next cycle too
alu_busy[next_latency - op_latency[opcode] + 1][alu_index] = true;
// ADD instruction requires 4 more random bytes for 32-bit constant "C" in "a = a + b + C"
check_data(&data_index, sizeof(uint32_t), data, sizeof(data));
uint32_t t;
memcpy(&t, data + data_index, sizeof(uint32_t));
code[code_size].C = SWAP32LE(t);
data_index += sizeof(uint32_t);
}
++code_size;
if (code_size >= NUM_INSTRUCTIONS_MIN)
{
break;
}
}
else
{
++num_retries;
}
}
// ASIC has more execution resources and can extract as much parallelism from the code as possible
// We need to add a few more MUL and ROR instructions to achieve minimal required latency for ASIC
// Get this latency for at least 1 of the 4 registers
const int prev_code_size = code_size;
while ((code_size < NUM_INSTRUCTIONS_MAX) && (asic_latency[0] < TOTAL_LATENCY) && (asic_latency[1] < TOTAL_LATENCY) && (asic_latency[2] < TOTAL_LATENCY) && (asic_latency[3] < TOTAL_LATENCY))
{
int min_idx = 0;
int max_idx = 0;
for (int i = 1; i < 4; ++i)
{
if (asic_latency[i] < asic_latency[min_idx]) min_idx = i;
if (asic_latency[i] > asic_latency[max_idx]) max_idx = i;
}
const uint8_t pattern[3] = { ROR, MUL, MUL };
const uint8_t opcode = pattern[(code_size - prev_code_size) % 3];
latency[min_idx] = latency[max_idx] + op_latency[opcode];
asic_latency[min_idx] = asic_latency[max_idx] + asic_op_latency[opcode];
code[code_size].opcode = opcode;
code[code_size].dst_index = min_idx;
code[code_size].src_index = max_idx;
code[code_size].C = 0;
++code_size;
}
// There is ~98.15% chance that loop condition is false, so this loop will execute only 1 iteration most of the time
// It never does more than 4 iterations for all block heights < 10,000,000
} while (!r8_used || (code_size < NUM_INSTRUCTIONS_MIN) || (code_size > NUM_INSTRUCTIONS_MAX));
// It's guaranteed that NUM_INSTRUCTIONS_MIN <= code_size <= NUM_INSTRUCTIONS_MAX here
// Add final instruction to stop the interpreter
code[code_size].opcode = RET;
code[code_size].dst_index = 0;
code[code_size].src_index = 0;
code[code_size].C = 0;
return code_size;
}
#endif

View file

@ -1,30 +0,0 @@
#pragma once
#if defined(_MSC_VER)
#define PUSH_WARNINGS __pragma(warning(push))
#define POP_WARNINGS __pragma(warning(pop))
#define DISABLE_VS_WARNINGS(w) __pragma(warning(disable: w))
#define DISABLE_GCC_WARNING(w)
#define DISABLE_CLANG_WARNING(w)
#define DISABLE_GCC_AND_CLANG_WARNING(w)
#else
#include <boost/preprocessor/stringize.hpp>
#define PUSH_WARNINGS _Pragma("GCC diagnostic push")
#define POP_WARNINGS _Pragma("GCC diagnostic pop")
#define DISABLE_VS_WARNINGS(w)
#if defined(__clang__)
#define DISABLE_GCC_WARNING(w)
#define DISABLE_CLANG_WARNING DISABLE_GCC_AND_CLANG_WARNING
#else
#define DISABLE_GCC_WARNING DISABLE_GCC_AND_CLANG_WARNING
#define DISABLE_CLANG_WARNING(w)
#endif
#define DISABLE_GCC_AND_CLANG_WARNING(w) _Pragma(BOOST_PP_STRINGIZE(GCC diagnostic ignored BOOST_PP_STRINGIZE(-W##w)))
#endif

589
cryptonight/src/blake256.rs Normal file

File diff suppressed because one or more lines are too long

451
cryptonight/src/cnaes.rs Normal file
View file

@ -0,0 +1,451 @@
use crate::util::subarray_copy;
pub(crate) const AES_BLOCK_SIZE: usize = 16;
/// 16 bytes, the same as AES 128 and 256
const ROUND_KEY_SIZE: usize = 16;
/// AES-128 uses 11 round keys and AES-256 uses 15 round keys. Cryptonight's
/// version of AES uses one less round key than AES-128 (even though they both
/// perform 10 rounds), because Cryptonight uses the first (0th) round in the
/// first round, while AES mixes the first round key into the state.
const NUM_AES_ROUND_KEYS: usize = 10;
/// Cryptonight's hash uses the key size of AES256, but it only does 10 AES
/// rounds like AES128.
pub(crate) const CN_AES_KEY_SIZE: usize = 32;
#[rustfmt::skip]
const AES_SBOX: [[u8; 16]; 16] = [
[0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76],
[0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0],
[0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15],
[0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75],
[0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84],
[0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf],
[0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8],
[0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2],
[0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73],
[0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb],
[0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79],
[0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08],
[0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a],
[0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e],
[0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf],
[0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16]
];
/// Cryptonight extends the AES S-Box to 4096 bytes (1024 32-bit words) using a complicated
/// system of nested macros:
/// <https://github.com/monero-project/monero/blob/v0.18.3.4/src/crypto/aesb.c#L64-L142>
/// The table below is the fully processed result.
#[rustfmt::skip]
const CRYPTONIGHT_SBOX: [u32; 1024] = [
0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0x0df2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591,
0x50303060, 0x03010102, 0xa96767ce, 0x7d2b2b56, 0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec,
0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa, 0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb,
0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, 0xbf9c9c23, 0xf7a4a453, 0x967272e4, 0x5bc0c09b,
0xc2b7b775, 0x1cfdfde1, 0xae93933d, 0x6a26264c, 0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83,
0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9, 0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a,
0x0c040408, 0x52c7c795, 0x65232346, 0x5ec3c39d, 0x28181830, 0xa1969637, 0x0f05050a, 0xb59a9a2f,
0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df, 0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea,
0x1b090912, 0x9e83831d, 0x742c2c58, 0x2e1a1a34, 0x2d1b1b36, 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b,
0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d, 0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413,
0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1, 0x60202040, 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6,
0xbe6a6ad4, 0x46cbcb8d, 0xd9bebe67, 0x4b393972, 0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85,
0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed, 0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511,
0xcf45458a, 0x10f9f9e9, 0x06020204, 0x817f7ffe, 0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b,
0xf35151a2, 0xfea3a35d, 0xc0404080, 0x8a8f8f05, 0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1,
0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, 0x30101020, 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf,
0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3, 0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e,
0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a, 0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6,
0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3, 0x66222244, 0x7e2a2a54, 0xab90903b, 0x8388880b,
0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428, 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad,
0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, 0xdb494992, 0x0a06060c, 0x6c242448, 0xe45c5cb8,
0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4, 0xa8919139, 0xa4959531, 0x37e4e4d3, 0x8b7979f2,
0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda, 0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949,
0xb46c6cd8, 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf, 0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810,
0xd5baba6f, 0x887878f0, 0x6f25254a, 0x722e2e5c, 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697,
0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, 0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f,
0x907070e0, 0x423e3e7c, 0xc4b5b571, 0xaa6666cc, 0xd8484890, 0x05030306, 0x01f6f6f7, 0x120e0e1c,
0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969, 0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27,
0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122, 0xbb6969d2, 0x70d9d9a9, 0x898e8e07, 0xa7949433,
0xb69b9b2d, 0x221e1e3c, 0x92878715, 0x20e9e9c9, 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5,
0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0,
0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e, 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c,
0x6363c6a5, 0x7c7cf884, 0x7777ee99, 0x7b7bf68d, 0xf2f2ff0d, 0x6b6bd6bd, 0x6f6fdeb1, 0xc5c59154,
0x30306050, 0x01010203, 0x6767cea9, 0x2b2b567d, 0xfefee719, 0xd7d7b562, 0xabab4de6, 0x7676ec9a,
0xcaca8f45, 0x82821f9d, 0xc9c98940, 0x7d7dfa87, 0xfafaef15, 0x5959b2eb, 0x47478ec9, 0xf0f0fb0b,
0xadad41ec, 0xd4d4b367, 0xa2a25ffd, 0xafaf45ea, 0x9c9c23bf, 0xa4a453f7, 0x7272e496, 0xc0c09b5b,
0xb7b775c2, 0xfdfde11c, 0x93933dae, 0x26264c6a, 0x36366c5a, 0x3f3f7e41, 0xf7f7f502, 0xcccc834f,
0x3434685c, 0xa5a551f4, 0xe5e5d134, 0xf1f1f908, 0x7171e293, 0xd8d8ab73, 0x31316253, 0x15152a3f,
0x0404080c, 0xc7c79552, 0x23234665, 0xc3c39d5e, 0x18183028, 0x969637a1, 0x05050a0f, 0x9a9a2fb5,
0x07070e09, 0x12122436, 0x80801b9b, 0xe2e2df3d, 0xebebcd26, 0x27274e69, 0xb2b27fcd, 0x7575ea9f,
0x0909121b, 0x83831d9e, 0x2c2c5874, 0x1a1a342e, 0x1b1b362d, 0x6e6edcb2, 0x5a5ab4ee, 0xa0a05bfb,
0x5252a4f6, 0x3b3b764d, 0xd6d6b761, 0xb3b37dce, 0x2929527b, 0xe3e3dd3e, 0x2f2f5e71, 0x84841397,
0x5353a6f5, 0xd1d1b968, 0x00000000, 0xededc12c, 0x20204060, 0xfcfce31f, 0xb1b179c8, 0x5b5bb6ed,
0x6a6ad4be, 0xcbcb8d46, 0xbebe67d9, 0x3939724b, 0x4a4a94de, 0x4c4c98d4, 0x5858b0e8, 0xcfcf854a,
0xd0d0bb6b, 0xefefc52a, 0xaaaa4fe5, 0xfbfbed16, 0x434386c5, 0x4d4d9ad7, 0x33336655, 0x85851194,
0x45458acf, 0xf9f9e910, 0x02020406, 0x7f7ffe81, 0x5050a0f0, 0x3c3c7844, 0x9f9f25ba, 0xa8a84be3,
0x5151a2f3, 0xa3a35dfe, 0x404080c0, 0x8f8f058a, 0x92923fad, 0x9d9d21bc, 0x38387048, 0xf5f5f104,
0xbcbc63df, 0xb6b677c1, 0xdadaaf75, 0x21214263, 0x10102030, 0xffffe51a, 0xf3f3fd0e, 0xd2d2bf6d,
0xcdcd814c, 0x0c0c1814, 0x13132635, 0xececc32f, 0x5f5fbee1, 0x979735a2, 0x444488cc, 0x17172e39,
0xc4c49357, 0xa7a755f2, 0x7e7efc82, 0x3d3d7a47, 0x6464c8ac, 0x5d5dbae7, 0x1919322b, 0x7373e695,
0x6060c0a0, 0x81811998, 0x4f4f9ed1, 0xdcdca37f, 0x22224466, 0x2a2a547e, 0x90903bab, 0x88880b83,
0x46468cca, 0xeeeec729, 0xb8b86bd3, 0x1414283c, 0xdedea779, 0x5e5ebce2, 0x0b0b161d, 0xdbdbad76,
0xe0e0db3b, 0x32326456, 0x3a3a744e, 0x0a0a141e, 0x494992db, 0x06060c0a, 0x2424486c, 0x5c5cb8e4,
0xc2c29f5d, 0xd3d3bd6e, 0xacac43ef, 0x6262c4a6, 0x919139a8, 0x959531a4, 0xe4e4d337, 0x7979f28b,
0xe7e7d532, 0xc8c88b43, 0x37376e59, 0x6d6ddab7, 0x8d8d018c, 0xd5d5b164, 0x4e4e9cd2, 0xa9a949e0,
0x6c6cd8b4, 0x5656acfa, 0xf4f4f307, 0xeaeacf25, 0x6565caaf, 0x7a7af48e, 0xaeae47e9, 0x08081018,
0xbaba6fd5, 0x7878f088, 0x25254a6f, 0x2e2e5c72, 0x1c1c3824, 0xa6a657f1, 0xb4b473c7, 0xc6c69751,
0xe8e8cb23, 0xdddda17c, 0x7474e89c, 0x1f1f3e21, 0x4b4b96dd, 0xbdbd61dc, 0x8b8b0d86, 0x8a8a0f85,
0x7070e090, 0x3e3e7c42, 0xb5b571c4, 0x6666ccaa, 0x484890d8, 0x03030605, 0xf6f6f701, 0x0e0e1c12,
0x6161c2a3, 0x35356a5f, 0x5757aef9, 0xb9b969d0, 0x86861791, 0xc1c19958, 0x1d1d3a27, 0x9e9e27b9,
0xe1e1d938, 0xf8f8eb13, 0x98982bb3, 0x11112233, 0x6969d2bb, 0xd9d9a970, 0x8e8e0789, 0x949433a7,
0x9b9b2db6, 0x1e1e3c22, 0x87871592, 0xe9e9c920, 0xcece8749, 0x5555aaff, 0x28285078, 0xdfdfa57a,
0x8c8c038f, 0xa1a159f8, 0x89890980, 0x0d0d1a17, 0xbfbf65da, 0xe6e6d731, 0x424284c6, 0x6868d0b8,
0x414182c3, 0x999929b0, 0x2d2d5a77, 0x0f0f1e11, 0xb0b07bcb, 0x5454a8fc, 0xbbbb6dd6, 0x16162c3a,
0x63c6a563, 0x7cf8847c, 0x77ee9977, 0x7bf68d7b, 0xf2ff0df2, 0x6bd6bd6b, 0x6fdeb16f, 0xc59154c5,
0x30605030, 0x01020301, 0x67cea967, 0x2b567d2b, 0xfee719fe, 0xd7b562d7, 0xab4de6ab, 0x76ec9a76,
0xca8f45ca, 0x821f9d82, 0xc98940c9, 0x7dfa877d, 0xfaef15fa, 0x59b2eb59, 0x478ec947, 0xf0fb0bf0,
0xad41ecad, 0xd4b367d4, 0xa25ffda2, 0xaf45eaaf, 0x9c23bf9c, 0xa453f7a4, 0x72e49672, 0xc09b5bc0,
0xb775c2b7, 0xfde11cfd, 0x933dae93, 0x264c6a26, 0x366c5a36, 0x3f7e413f, 0xf7f502f7, 0xcc834fcc,
0x34685c34, 0xa551f4a5, 0xe5d134e5, 0xf1f908f1, 0x71e29371, 0xd8ab73d8, 0x31625331, 0x152a3f15,
0x04080c04, 0xc79552c7, 0x23466523, 0xc39d5ec3, 0x18302818, 0x9637a196, 0x050a0f05, 0x9a2fb59a,
0x070e0907, 0x12243612, 0x801b9b80, 0xe2df3de2, 0xebcd26eb, 0x274e6927, 0xb27fcdb2, 0x75ea9f75,
0x09121b09, 0x831d9e83, 0x2c58742c, 0x1a342e1a, 0x1b362d1b, 0x6edcb26e, 0x5ab4ee5a, 0xa05bfba0,
0x52a4f652, 0x3b764d3b, 0xd6b761d6, 0xb37dceb3, 0x29527b29, 0xe3dd3ee3, 0x2f5e712f, 0x84139784,
0x53a6f553, 0xd1b968d1, 0x00000000, 0xedc12ced, 0x20406020, 0xfce31ffc, 0xb179c8b1, 0x5bb6ed5b,
0x6ad4be6a, 0xcb8d46cb, 0xbe67d9be, 0x39724b39, 0x4a94de4a, 0x4c98d44c, 0x58b0e858, 0xcf854acf,
0xd0bb6bd0, 0xefc52aef, 0xaa4fe5aa, 0xfbed16fb, 0x4386c543, 0x4d9ad74d, 0x33665533, 0x85119485,
0x458acf45, 0xf9e910f9, 0x02040602, 0x7ffe817f, 0x50a0f050, 0x3c78443c, 0x9f25ba9f, 0xa84be3a8,
0x51a2f351, 0xa35dfea3, 0x4080c040, 0x8f058a8f, 0x923fad92, 0x9d21bc9d, 0x38704838, 0xf5f104f5,
0xbc63dfbc, 0xb677c1b6, 0xdaaf75da, 0x21426321, 0x10203010, 0xffe51aff, 0xf3fd0ef3, 0xd2bf6dd2,
0xcd814ccd, 0x0c18140c, 0x13263513, 0xecc32fec, 0x5fbee15f, 0x9735a297, 0x4488cc44, 0x172e3917,
0xc49357c4, 0xa755f2a7, 0x7efc827e, 0x3d7a473d, 0x64c8ac64, 0x5dbae75d, 0x19322b19, 0x73e69573,
0x60c0a060, 0x81199881, 0x4f9ed14f, 0xdca37fdc, 0x22446622, 0x2a547e2a, 0x903bab90, 0x880b8388,
0x468cca46, 0xeec729ee, 0xb86bd3b8, 0x14283c14, 0xdea779de, 0x5ebce25e, 0x0b161d0b, 0xdbad76db,
0xe0db3be0, 0x32645632, 0x3a744e3a, 0x0a141e0a, 0x4992db49, 0x060c0a06, 0x24486c24, 0x5cb8e45c,
0xc29f5dc2, 0xd3bd6ed3, 0xac43efac, 0x62c4a662, 0x9139a891, 0x9531a495, 0xe4d337e4, 0x79f28b79,
0xe7d532e7, 0xc88b43c8, 0x376e5937, 0x6ddab76d, 0x8d018c8d, 0xd5b164d5, 0x4e9cd24e, 0xa949e0a9,
0x6cd8b46c, 0x56acfa56, 0xf4f307f4, 0xeacf25ea, 0x65caaf65, 0x7af48e7a, 0xae47e9ae, 0x08101808,
0xba6fd5ba, 0x78f08878, 0x254a6f25, 0x2e5c722e, 0x1c38241c, 0xa657f1a6, 0xb473c7b4, 0xc69751c6,
0xe8cb23e8, 0xdda17cdd, 0x74e89c74, 0x1f3e211f, 0x4b96dd4b, 0xbd61dcbd, 0x8b0d868b, 0x8a0f858a,
0x70e09070, 0x3e7c423e, 0xb571c4b5, 0x66ccaa66, 0x4890d848, 0x03060503, 0xf6f701f6, 0x0e1c120e,
0x61c2a361, 0x356a5f35, 0x57aef957, 0xb969d0b9, 0x86179186, 0xc19958c1, 0x1d3a271d, 0x9e27b99e,
0xe1d938e1, 0xf8eb13f8, 0x982bb398, 0x11223311, 0x69d2bb69, 0xd9a970d9, 0x8e07898e, 0x9433a794,
0x9b2db69b, 0x1e3c221e, 0x87159287, 0xe9c920e9, 0xce8749ce, 0x55aaff55, 0x28507828, 0xdfa57adf,
0x8c038f8c, 0xa159f8a1, 0x89098089, 0x0d1a170d, 0xbf65dabf, 0xe6d731e6, 0x4284c642, 0x68d0b868,
0x4182c341, 0x9929b099, 0x2d5a772d, 0x0f1e110f, 0xb07bcbb0, 0x54a8fc54, 0xbb6dd6bb, 0x162c3a16,
0xc6a56363, 0xf8847c7c, 0xee997777, 0xf68d7b7b, 0xff0df2f2, 0xd6bd6b6b, 0xdeb16f6f, 0x9154c5c5,
0x60503030, 0x02030101, 0xcea96767, 0x567d2b2b, 0xe719fefe, 0xb562d7d7, 0x4de6abab, 0xec9a7676,
0x8f45caca, 0x1f9d8282, 0x8940c9c9, 0xfa877d7d, 0xef15fafa, 0xb2eb5959, 0x8ec94747, 0xfb0bf0f0,
0x41ecadad, 0xb367d4d4, 0x5ffda2a2, 0x45eaafaf, 0x23bf9c9c, 0x53f7a4a4, 0xe4967272, 0x9b5bc0c0,
0x75c2b7b7, 0xe11cfdfd, 0x3dae9393, 0x4c6a2626, 0x6c5a3636, 0x7e413f3f, 0xf502f7f7, 0x834fcccc,
0x685c3434, 0x51f4a5a5, 0xd134e5e5, 0xf908f1f1, 0xe2937171, 0xab73d8d8, 0x62533131, 0x2a3f1515,
0x080c0404, 0x9552c7c7, 0x46652323, 0x9d5ec3c3, 0x30281818, 0x37a19696, 0x0a0f0505, 0x2fb59a9a,
0x0e090707, 0x24361212, 0x1b9b8080, 0xdf3de2e2, 0xcd26ebeb, 0x4e692727, 0x7fcdb2b2, 0xea9f7575,
0x121b0909, 0x1d9e8383, 0x58742c2c, 0x342e1a1a, 0x362d1b1b, 0xdcb26e6e, 0xb4ee5a5a, 0x5bfba0a0,
0xa4f65252, 0x764d3b3b, 0xb761d6d6, 0x7dceb3b3, 0x527b2929, 0xdd3ee3e3, 0x5e712f2f, 0x13978484,
0xa6f55353, 0xb968d1d1, 0x00000000, 0xc12ceded, 0x40602020, 0xe31ffcfc, 0x79c8b1b1, 0xb6ed5b5b,
0xd4be6a6a, 0x8d46cbcb, 0x67d9bebe, 0x724b3939, 0x94de4a4a, 0x98d44c4c, 0xb0e85858, 0x854acfcf,
0xbb6bd0d0, 0xc52aefef, 0x4fe5aaaa, 0xed16fbfb, 0x86c54343, 0x9ad74d4d, 0x66553333, 0x11948585,
0x8acf4545, 0xe910f9f9, 0x04060202, 0xfe817f7f, 0xa0f05050, 0x78443c3c, 0x25ba9f9f, 0x4be3a8a8,
0xa2f35151, 0x5dfea3a3, 0x80c04040, 0x058a8f8f, 0x3fad9292, 0x21bc9d9d, 0x70483838, 0xf104f5f5,
0x63dfbcbc, 0x77c1b6b6, 0xaf75dada, 0x42632121, 0x20301010, 0xe51affff, 0xfd0ef3f3, 0xbf6dd2d2,
0x814ccdcd, 0x18140c0c, 0x26351313, 0xc32fecec, 0xbee15f5f, 0x35a29797, 0x88cc4444, 0x2e391717,
0x9357c4c4, 0x55f2a7a7, 0xfc827e7e, 0x7a473d3d, 0xc8ac6464, 0xbae75d5d, 0x322b1919, 0xe6957373,
0xc0a06060, 0x19988181, 0x9ed14f4f, 0xa37fdcdc, 0x44662222, 0x547e2a2a, 0x3bab9090, 0x0b838888,
0x8cca4646, 0xc729eeee, 0x6bd3b8b8, 0x283c1414, 0xa779dede, 0xbce25e5e, 0x161d0b0b, 0xad76dbdb,
0xdb3be0e0, 0x64563232, 0x744e3a3a, 0x141e0a0a, 0x92db4949, 0x0c0a0606, 0x486c2424, 0xb8e45c5c,
0x9f5dc2c2, 0xbd6ed3d3, 0x43efacac, 0xc4a66262, 0x39a89191, 0x31a49595, 0xd337e4e4, 0xf28b7979,
0xd532e7e7, 0x8b43c8c8, 0x6e593737, 0xdab76d6d, 0x018c8d8d, 0xb164d5d5, 0x9cd24e4e, 0x49e0a9a9,
0xd8b46c6c, 0xacfa5656, 0xf307f4f4, 0xcf25eaea, 0xcaaf6565, 0xf48e7a7a, 0x47e9aeae, 0x10180808,
0x6fd5baba, 0xf0887878, 0x4a6f2525, 0x5c722e2e, 0x38241c1c, 0x57f1a6a6, 0x73c7b4b4, 0x9751c6c6,
0xcb23e8e8, 0xa17cdddd, 0xe89c7474, 0x3e211f1f, 0x96dd4b4b, 0x61dcbdbd, 0x0d868b8b, 0x0f858a8a,
0xe0907070, 0x7c423e3e, 0x71c4b5b5, 0xccaa6666, 0x90d84848, 0x06050303, 0xf701f6f6, 0x1c120e0e,
0xc2a36161, 0x6a5f3535, 0xaef95757, 0x69d0b9b9, 0x17918686, 0x9958c1c1, 0x3a271d1d, 0x27b99e9e,
0xd938e1e1, 0xeb13f8f8, 0x2bb39898, 0x22331111, 0xd2bb6969, 0xa970d9d9, 0x07898e8e, 0x33a79494,
0x2db69b9b, 0x3c221e1e, 0x15928787, 0xc920e9e9, 0x8749cece, 0xaaff5555, 0x50782828, 0xa57adfdf,
0x038f8c8c, 0x59f8a1a1, 0x09808989, 0x1a170d0d, 0x65dabfbf, 0xd731e6e6, 0x84c64242, 0xd0b86868,
0x82c34141, 0x29b09999, 0x5a772d2d, 0x1e110f0f, 0x7bcbb0b0, 0xa8fc5454, 0x6dd6bbbb, 0x2c3a1616,
];
const fn substitute_word(word: u32) -> u32 {
let wb: [u8; 4] = word.to_le_bytes();
u32::from_le_bytes([
AES_SBOX[(wb[0] >> 4) as usize][(wb[0] & 0x0F) as usize],
AES_SBOX[(wb[1] >> 4) as usize][(wb[1] & 0x0F) as usize],
AES_SBOX[(wb[2] >> 4) as usize][(wb[2] & 0x0F) as usize],
AES_SBOX[(wb[3] >> 4) as usize][(wb[3] & 0x0F) as usize],
])
}
/// Extends the key in the same way as it is extended for AES256, but for
/// Cryptonight's hash we only need to extend to 10 round keys instead of 15
/// like AES256.
#[expect(clippy::cast_possible_truncation)]
pub(crate) fn key_extend(key_bytes: &[u8; CN_AES_KEY_SIZE]) -> [u128; NUM_AES_ROUND_KEYS] {
// NK comes from the AES specification, it is the number of 32-bit words in
// the non-expanded key (For AES-256: 32/4 = 8)
const NK: usize = 8;
let mut expanded_key = [0_u128; NUM_AES_ROUND_KEYS];
// The next 2 lines, which set the first 2 round keys without using
// the expansion algorithm, are specific to Cryptonight.
expanded_key[0] = u128::from_le_bytes(subarray_copy(key_bytes, 0));
expanded_key[1] = u128::from_le_bytes(subarray_copy(key_bytes, ROUND_KEY_SIZE));
/// See FIPS-197, especially figure 11 to better understand how the
/// expansion happens: <https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.197.pdf>
const ROUND_CONSTS: [u8; 11] = [
0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36,
];
// the word before w0 in the loop below
let mut w0_prev = (expanded_key[1] >> 96) as u32;
// expand to 10, 16-byte round keys (160 total bytes, or 40 4-byte words)
for i in 2..NUM_AES_ROUND_KEYS {
let word_num = i * 4;
// if `i` is even, `word_num` for `w0` is divisible by 8 (`NK`), otherwise it
// is divisible by 4
let mut w0 = if i & 1 == 0 {
substitute_word(w0_prev.rotate_right(8)) ^ u32::from(ROUND_CONSTS[word_num / NK])
} else {
substitute_word(w0_prev)
};
let pprev_key = expanded_key[i - 2];
w0 ^= pprev_key as u32;
let w1 = w0 ^ ((pprev_key >> 32) as u32);
let w2 = w1 ^ ((pprev_key >> 64) as u32);
let w3 = w2 ^ ((pprev_key >> 96) as u32);
expanded_key[i] =
u128::from(w0) | u128::from(w1) << 32 | u128::from(w2) << 64 | u128::from(w3) << 96;
w0_prev = w3;
}
expanded_key
}
#[expect(clippy::cast_possible_truncation)]
pub(crate) fn round_fwd(state: u128, key: u128) -> u128 {
let mut r1 = CRYPTONIGHT_SBOX[usize::from(state as u8)];
r1 ^= CRYPTONIGHT_SBOX[256 + usize::from((state >> 40) as u8)];
r1 ^= CRYPTONIGHT_SBOX[512 + usize::from((state >> 80) as u8)];
r1 ^= CRYPTONIGHT_SBOX[768 + usize::from((state >> 120) as u8)];
let mut r2 = CRYPTONIGHT_SBOX[usize::from((state >> 32) as u8)];
r2 ^= CRYPTONIGHT_SBOX[256 + usize::from((state >> 72) as u8)];
r2 ^= CRYPTONIGHT_SBOX[512 + usize::from((state >> 112) as u8)];
r2 ^= CRYPTONIGHT_SBOX[768 + usize::from((state >> 24) as u8)];
let mut r3 = CRYPTONIGHT_SBOX[usize::from((state >> 64) as u8)];
r3 ^= CRYPTONIGHT_SBOX[256 + usize::from((state >> 104) as u8)];
r3 ^= CRYPTONIGHT_SBOX[512 + usize::from((state >> 16) as u8)];
r3 ^= CRYPTONIGHT_SBOX[768 + usize::from((state >> 56) as u8)];
let mut r4 = CRYPTONIGHT_SBOX[usize::from((state >> 96) as u8)];
r4 ^= CRYPTONIGHT_SBOX[256 + usize::from((state >> 8) as u8)];
r4 ^= CRYPTONIGHT_SBOX[512 + usize::from((state >> 48) as u8)];
r4 ^= CRYPTONIGHT_SBOX[768 + usize::from((state >> 88) as u8)];
let mut new_state =
u128::from(r4) << 96 | u128::from(r3) << 64 | u128::from(r2) << 32 | u128::from(r1);
new_state ^= key;
new_state
}
pub(crate) fn aesb_pseudo_round(block: u128, expanded_key: &[u128; NUM_AES_ROUND_KEYS]) -> u128 {
let mut block = block;
for round_key in expanded_key {
block = round_fwd(block, *round_key);
}
block
}
pub(crate) fn aesb_single_round(block: &mut u128, round_key: u128) {
*block = round_fwd(*block, round_key);
}
#[cfg(test)]
mod tests {
use super::*;
use crate::util::hex_to_array;
#[test]
fn test_substitute_word() {
assert_eq!(substitute_word(0x12345678), 3373838780);
assert_eq!(substitute_word(0x00000000), 1667457891);
assert_eq!(substitute_word(0xFFFFFFFF), 370546198);
assert_eq!(substitute_word(0xAAAAAAAA), 2896997548);
assert_eq!(substitute_word(0x55555555), 4244438268);
}
#[test]
fn test_key_schedule() {
fn test(key_hex: &str, expected_out: &str) {
let key = hex_to_array(key_hex);
let expanded_key = key_extend(&key);
let expanded_key_hex = expanded_key
.iter()
.map(|value| hex::encode(value.to_le_bytes()))
.collect::<String>();
assert_eq!(expected_out[..64], expanded_key_hex[..64]);
assert_eq!(expected_out[64..], expanded_key_hex[64..]);
}
test(
"ac156e17cdabc0b92e3e724a06ef21e5317eb71fbc7f1587403b30ae6962a21a",
"ac156e17cdabc0b92e3e724a06ef21e5317eb71fbc7f1587403b30ae6962a21a072fcceeca840c57e4ba7e1de2555ff8a982785e15fd6dd955c65d773ca4ff6d4c39f00586bdfc526207824f8052ddb76482b9f7717fd42e24b98959181d7634ec01e8a86abc14fa08bb96b588e94b02a09c0a80d1e3deaef55a57f7ed4721c344fcc6fd2e40d20726fb44b2ae120fb044557c6795b6a2c960ecf53e8dabd4fd",
);
test(
"688dcc56a1c9b8c9cd9e378a98a1388f17a2c05a698a37232ecd4a567dccdf79",
"688dcc56a1c9b8c9cd9e378a98a1388f17a2c05a698a37232ecd4a567dccdf7922137aa983dac2604e44f5ead6e5cd65e17b7d1788f14a34a63c0062dbf0df1bac8dd5102f5717706113e29ab7f62fff48396801c0c8223566f42257bd04fd4c5ad9fc6a758eeb1a149d0980a36b267f42469fd3828ebde6e47a9fb1597e62fda173a8a1d4fd43bbc0604a3b630b6c44b96dcfc83be3722edf99ed9f86e78f62",
);
test(
"a6116fc295f15ff03d538581a560a9c1fdaa1e7f5745d8e6125d6eb092c71b15",
"a6116fc295f15ff03d538581a560a9c1fdaa1e7f5745d8e6125d6eb092c71b1561be368df44f697dc91cecfc6c7c453dadba7058faffa8bee8a2c60e7a65dd1b2e7f9957da30f02a132c1cd67f5059eb7fe9bbb18516130f6db4d50117d1081a144f3ba7ce7fcb8ddd53d75ba2038eb04592a256c084b159ad306458bae16c42e41f17532a60dcdef7330b8555308535b99635c079128499d422e0c16ec38c83",
);
test(
"80784e1c1d3730e6f422aae6b10596ab16b190e41eea452af9aeedc97aee4b74",
"80784e1c1d3730e6f422aae6b10596ab16b190e41eea452af9aeedc97aee4b74a9cbdcc6b4fcec2040de46c6f1dbd06db708e0d8a9e2a5f2504c483b2aa2034f91b05823254cb4036592f2c5944922a89533731a3cd1d6e86c9d9ed3463f9d9ce0ee8679c5a2327aa030c0bf3479e2178d85ebeab1543d02ddc9a3d19bf63e4daa5c656d6ffe5717cfce97a8fbb775bf822c76e233784be0eeb1e8317547d67c",
);
test(
"cc08712809fd4c0f0b63dc21657f22b3752fba8f2ed5882e7d75e65906bb3399",
"cc08712809fd4c0f0b63dc21657f22b3752fba8f2ed5882e7d75e65906bb339927cb9f472e36d34825550f69402a2dda7cca62d8521feaf62f6a0caf29d13f361bbe9ae2358849aa10dd46c350f76b192fa21d0c7dbdf7fa52d7fb557b06c46370a261c3452a286955f76eaa050005b344c17661397c819b6bab7ace10adbeaded0cf409a826dc60fdd1b2caf8d1b77905ffdfd73c835e4c5728248247859a2f",
);
}
#[test]
fn test_aesb_pseudo_round() {
fn test(key_hex: &str, input_hex: &str, expected_out: &str) {
let key: [u8; 32] = hex_to_array(key_hex);
let extended_key = key_extend(&key);
let mut block = u128::from_le_bytes(hex_to_array(input_hex));
block = aesb_pseudo_round(block, &extended_key);
assert_eq!(expected_out, hex::encode(block.to_le_bytes()));
}
test(
"1d0b47a047340e32cbe890ca0d61720a09bcfb39e01b7541d1100d1ef91f955f",
"274fe9eeb2d1e4c71f0f0244a80e93a1",
"be98612d6b05a6cd72df39326180066a",
);
test(
"0093d86fe74698f7b02774e6d4f67e9e29eb71d1754804a19b77d986b8141434",
"110f2e5d81f73a512ec95aa5b8e0d7be",
"1f1750d997704943b828df66661f7cbf",
);
test(
"d5044939d15af565447ef76445405cd899f81c6f41f4493a5a1323712f815e53",
"6022f491b67e27909f74d0e71becebaa",
"9f75d250681954d60e418b4333d247a5",
);
test(
"256670ed9eba1db67e6ddec5dfb78f6bfbf55d0f74e2a46d06f2e3592a208014",
"4de6ecad6a885ac88f09f9b2be4145fb",
"cb286e70825609cb97b7c7ae72548fa9",
);
test(
"e1077c3566d1e8bfeb2e8e48540ed76fb61e973f4951a821c3e8bb918facc03d",
"2a2ff0dd38c79ab13fb6b06751824e93",
"82f65ba66f8fc6d8e1f4e1f41976eed8",
);
test(
"dee818b6a894121e5e967e2218bb8772b9486bec2241377fdcfed7db75f3b724",
"eebc705f33d00fdf7c8add2481c62767",
"bee070b25e969ea87578daa1c7831651",
);
test(
"c9b653644f3d3adc3498c029a1373b63f548e853deadc48e559b1a0a05e5c543",
"bef0968fc6adb8ce96bfa99642481624",
"859fc5f637ee1ee835b6f9a3f16a41f8",
);
test(
"8e65798ebbae347c969ef9778e04e06649e3765aa58f5cd776b6ee58afde98ff",
"629f87e95b67e7bd5a3af528379cbef7",
"04a697b4fb82466950e9c0668e8c3eb9",
);
test(
"4c0f6a402316b3a73e2a778f20ca3f8335e7a7bb5aecdaf9db91664604b74d62",
"3c9ab665451100d8d21029f96edf85f3",
"de5e23b1ba21a16ac01098937b26f3a9",
);
test(
"a0b2cb30088b6145d9651ed019b0d051e4e6bf6cc0c8165dc76e3aa9fa9849f0",
"6a007f218c3f8b97c8489fe56433c99a",
"1885d448a81b0a048cc241275b9d7dce",
);
}
#[test]
fn test_aesb_single_round() {
let test = |key_hex: &str, input_hex: &str, expected_out: &str| {
// TODO: Show that both big and little endian work
let round_key = u128::from_ne_bytes(hex_to_array(key_hex));
let mut block = u128::from_ne_bytes(hex_to_array(input_hex));
aesb_single_round(&mut block, round_key);
assert_eq!(expected_out, hex::encode(block.to_ne_bytes()));
};
test(
"9af7bd044f96bba5251ebd8065f4c757",
"8844d7f6f6aa2df5706ef0e7b26a3410",
"a03593fc2b9b906069bfc3a86a12e7fe",
);
test(
"9749a59d1ee692c3b70b9c38a0c88369",
"f96b5a1984f7c57b92d7b2e82dd0ce46",
"6b03d4c6edf7a914265ca765b784c5ee",
);
test(
"20959275e137a08267e35afe66f9adeb",
"3fce6f546d8fbc15bd9c6ac7d533eae4",
"34692b49471e37df3cbe43a9459ebe97",
);
test(
"5c429524d022dc5dd48f7cd529fdf4f2",
"3edae93308c9aab4dfb6bfcd8e4012af",
"2e3061ce680d75177bac5b7af3182543",
);
test(
"e76c56ca69a7309866a730e8976da086",
"39d8ee732a115b6b21f89ca181bd9ddc",
"069ef0b7aaada2b65ea9665827dae9ae",
);
test(
"afd540af324c4fcda6246c657424a3ce",
"a5a01d75141522ff1ea717083abc5b5e",
"e0320cbc9dd8279c5f7d121ef7e1ae46",
);
test(
"dfe9ba9468ccf1ac20a305730d1bdcb7",
"7be56ce9d924bf2fc4b574e225676f3c",
"bee2b49ed0b578b2c94b03a8930d990c",
);
test(
"381e788a8d3389f27fe9aff054a0b407",
"b8d2600f71b0e9535d17c00ba90246f6",
"2a305ae7f7f3f44a43cd0342180b9394",
);
test(
"16a94460158a5512052626f6cb080d6d",
"5ea0c238c05b8f3a913c1b36102eabeb",
"ab8040d7395cc940ea2a47610989ceb1",
);
test(
"7e584682efb38bf2adfc6f1958fe08ff",
"80c78bb6ca2f114cbcb49fbaadaee9d1",
"25f7717cdbaa9c614424ef3d4e9543ec",
);
}
}

470
cryptonight/src/hash_v2.rs Normal file
View file

@ -0,0 +1,470 @@
use crate::slow_hash::{Variant, MEMORY_BLOCKS};
const U64_MASK: u128 = u64::MAX as u128;
/// Original C code:
/// <https://github.com/monero-project/monero/blob/v0.18.3.4/src/crypto/slow-hash.c#L217-L254>
/// If we kept the C code organization, this function would be in `slow_hash.rs`, but it's
/// here in the rust code to keep the `slow_hash.rs` file size manageable.
pub(crate) fn variant2_shuffle_add(
c1: &mut u128,
a: u128,
b: &[u128; 2],
long_state: &mut [u128; MEMORY_BLOCKS],
offset: usize,
variant: Variant,
) {
if !matches!(variant, Variant::V2 | Variant::R) {
return;
}
let chunk1_start = offset ^ 0x1;
let chunk2_start = offset ^ 0x2;
let chunk3_start = offset ^ 0x3;
let chunk1 = long_state[chunk1_start];
let chunk2 = long_state[chunk2_start];
let chunk3 = long_state[chunk3_start];
let chunk1_old = chunk1;
let chunk2_old = chunk2;
let chunk3_old = chunk3;
let b1 = b[1];
let chunk1 = &mut long_state[chunk1_start];
let sum1 = chunk3_old.wrapping_add(b1) & U64_MASK;
let sum2 = (chunk3_old >> 64).wrapping_add(b1 >> 64) & U64_MASK;
*chunk1 = sum2 << 64 | sum1; // TODO remove some shifting above
let chunk3 = &mut long_state[chunk3_start];
let sum1 = chunk2_old.wrapping_add(a) & U64_MASK;
let sum2 = (chunk2_old >> 64).wrapping_add(a >> 64) & U64_MASK;
*chunk3 = sum2 << 64 | sum1;
let b0 = b[0];
let chunk2 = &mut long_state[chunk2_start];
let sum1 = chunk1_old.wrapping_add(b0) & U64_MASK;
let sum2 = (chunk1_old >> 64).wrapping_add(b0 >> 64) & U64_MASK;
*chunk2 = sum2 << 64 | sum1;
if variant == Variant::R {
*c1 ^= chunk1_old ^ chunk2_old ^ chunk3_old;
}
}
#[expect(
clippy::cast_sign_loss,
clippy::cast_precision_loss,
clippy::cast_possible_truncation
)]
pub(crate) fn variant2_integer_math_sqrt(sqrt_input: u64) -> u64 {
// Get an approximation using floating point math
let mut sqrt_result =
((sqrt_input as f64 + 18_446_744_073_709_552_000.0).sqrt() * 2.0 - 8589934592.0) as u64;
// Fixup the edge cases to get the exact integer result. For more information,
// see: https://github.com/monero-project/monero/blob/v0.18.3.3/src/crypto/variant2_int_sqrt.h#L65-L152
let sqrt_div2 = sqrt_result >> 1;
let lsb = sqrt_result & 1;
let r2 = sqrt_div2
.wrapping_mul(sqrt_div2 + lsb)
.wrapping_add(sqrt_result << 32);
if r2.wrapping_add(lsb) > sqrt_input {
sqrt_result = sqrt_result.wrapping_sub(1);
}
if r2.wrapping_add(1 << 32) < sqrt_input.wrapping_sub(sqrt_div2) {
// Not sure that this is possible. I tried writing a test program
// to search subsets of u64 for a value that can trigger this
// branch, but couldn't find anything. The Go implementation came
// to the same conclusion:
// https://github.com/Equim-chan/cryptonight/blob/v0.3.0/arith_ref.go#L39-L45
sqrt_result = sqrt_result.wrapping_add(1);
}
sqrt_result
}
/// Original C code:
/// <https://github.com/monero-project/monero/blob/v0.18.3.4/src/crypto/slow-hash.c#L277-L283>
#[expect(clippy::cast_possible_truncation)]
pub(crate) fn variant2_integer_math(
c2: &mut u128,
c1: u128,
division_result: &mut u64,
sqrt_result: &mut u64,
variant: Variant,
) {
const U32_MASK: u64 = u32::MAX as u64;
if variant != Variant::V2 {
return;
}
let tmpx = *division_result ^ (*sqrt_result << 32);
*c2 ^= u128::from(tmpx);
let c1_low = c1 as u64;
let dividend = (c1 >> 64) as u64;
let divisor = ((c1_low.wrapping_add((*sqrt_result << 1) & U32_MASK)) | 0x80000001) & U32_MASK;
*division_result = ((dividend / divisor) & U32_MASK).wrapping_add((dividend % divisor) << 32);
let sqrt_input = c1_low.wrapping_add(*division_result);
*sqrt_result = variant2_integer_math_sqrt(sqrt_input);
}
#[cfg(test)]
mod tests {
use digest::Digest;
use groestl::Groestl256;
use super::*;
use crate::{
cnaes::AES_BLOCK_SIZE,
slow_hash::MEMORY_BLOCKS,
util::{hex_to_array, subarray_mut},
};
#[test]
fn test_variant2_integer_math() {
fn test(
c2_hex: &str,
c1_hex: &str,
division_result: u64,
sqrt_result: u64,
c2_hex_end: &str,
division_result_end: u64,
sqrt_result_end: u64,
) {
let mut c2 = u128::from_le_bytes(hex_to_array(c2_hex));
let c1 = u128::from_le_bytes(hex_to_array(c1_hex));
let mut division_result = division_result;
let mut sqrt_result = sqrt_result;
variant2_integer_math(
&mut c2,
c1,
&mut division_result,
&mut sqrt_result,
Variant::V2,
);
assert_eq!(hex::encode(c2.to_le_bytes()), c2_hex_end);
assert_eq!(division_result, division_result_end);
assert_eq!(sqrt_result, sqrt_result_end);
}
test(
"00000000000000000000000000000000",
"0100000000000000ffffffffffffffff",
u64::MAX,
u64::MAX,
"ffffffff000000000000000000000000",
1,
0,
);
test(
"8b4d610801fe2049741c4cf1a11912d5",
"ef9d5925ad73f044f6310bce80f333a4",
1992885167645223034,
15156498822412360757,
"f125c247b4040b0e741c4cf1a11912d5",
11701596267494179432,
3261805857,
);
test(
"540ac7dbbddf5b93fdc90f999408b7ad",
"10d2c1fdcbf7246e8623a3d946bdf422",
6226440187041759132,
1708636566,
"c83510b077a4e4a0fdc90f999408b7ad",
6478148604080708997,
2875078897,
);
test(
"0df28c3c3570ae3b68dc9d6c5a486ed7",
"a5fba99aa63fa032acf1bd65ff4df3f2",
11107069037757228366,
2924318811,
"4397ce171fdcc70f68dc9d6c5a486ed7",
7549089838000449301,
2299293038,
);
test(
"bfe14f97a968a35d0dcd6890a03c2913",
"d4a80e16ad64e3a0624a795c7b349c8a",
15584044376391133794,
276486141,
"dd4bf8759e1a9c950dcd6890a03c2913",
4771913259875991617,
3210383690,
);
test(
"820692e47779a9aabf0621e52a142468",
"df61b75f65251ee61828166e565336a9",
3269677112081011360,
1493829760,
"2254426ff54bc3debf0621e52a142468",
2626216843989114230,
175440206,
);
test(
"0b364e61de218e00e83c4073b39daa2e",
"cc463d4543eb430d08efedf2be86e322",
7096668609104405526,
713261042,
"1d521b6fac307148e83c4073b39daa2e",
8234613052379859783,
1924288792,
);
test(
"bd8fff861f6315c2be812b64cbdcf646",
"38d1e323d9dc282fa5e68f2ecbdcb950",
9545374795048279136,
271106137,
"dd532ef48b584a56be812b64cbdcf646",
2790373411402251888,
1336862722,
);
test(
"ed57e73448f357bf04dc831d5e8fd848",
"a5dcd0971e6ded60d4d98c03cd8ba205",
5991074580974163125,
2246952057,
"580331e9a7a59e6904dc831d5e8fd848",
7395390641079862703,
2868947253,
);
test(
"07ea0ffc6e182a7e97853f82e459d625",
"7e403d950f4adc97b90140875c33d65f",
8836830558353968711,
1962375668,
"40a40e3f08db7f7097853f82e459d625",
5478469695216926448,
3219877666,
);
test(
"b77688d600a356077021e2333ee3def4",
"7a9f061760287a69b57f365163fb9dac",
3127636279441542418,
1585025819,
"a5bb34d8bba848727021e2333ee3def4",
3683326568856788118,
2315202244,
);
test(
"a246a7f62b7e3d9a0b5ac66166bfcba3",
"23329476afdbd46d3be9d3ccc9011c11",
12123559059253265496,
819016365,
"fac2e5d23dc4d3020b5ac66166bfcba3",
4214751652441358299,
2469122821,
);
test(
"3e1abb8109c688405cd6c866cbdb3e13",
"b4c10bf5e06c069928afa173f62d5017",
7368515032603121941,
2312559799,
"2b43d451df231caf5cd6c866cbdb3e13",
1324536149240623108,
2509236669,
);
test(
"a31260db7c73f249b5fbc182ae7fcc8e",
"b4214755b0003e4c82d03f80d8a06bed",
1904095218141907119,
92928147,
"0c5abeec6c3f1756b5fbc182ae7fcc8e",
9883090335304272258,
3041688469,
);
test(
"e3d0bc3e619f577a1eea5adba205e494",
"cd8040848aae39104c310c1fa0eed9b8",
4873400164336079541,
2436984787,
"56c22935133bb7a81eea5adba205e494",
8226478499779865232,
1963241245,
);
test(
"f22ac244fd17cf5e3ec21bece2581a2d",
"785152f272ffa9514ef2ae0bed5cbaa7",
6386228481616770937,
1413583152,
"8bddfda13af62e523ec21bece2581a2d",
9654977853452823978,
3069608655,
);
test(
"37b3921988d9df1b38b04dc1db01a41b",
"054b87f38d203eddb16d458048f3b97b",
5592059432235016971,
2670380708,
"3c10afec40e36fc938b04dc1db01a41b",
2475375116655310772,
3553266751,
);
test(
"cfd4afb021e526d9cbd4720cc47c4ce2",
"a2e3e7fe936c2b38e3708965f2dfc586",
11958325643570725319,
825185219,
"0895d52d3237fd4dcbd4720cc47c4ce2",
2253955666499039951,
1359567468,
);
test(
"55d2ea9570994bc0aeaf6a3189bf0b4a",
"9d102c34665382dfd36e39a67e07b8aa",
10171590341391886242,
541577843,
"f7f59fbe85f4246daeaf6a3189bf0b4a",
6907584596503955220,
1004462004,
);
test(
"bf32b60d6bbaa87cececd577f2ad15d8",
"9a8471b2b72e9d39cd2d2cb124aa270a",
9778648685358392468,
469385479,
"2b9696774746e6e0ececd577f2ad15d8",
4910280747850874346,
1899784302,
);
test(
"d70ac5de7a390e2a735726324d0b52b5",
"6cf5b75b005599047972995ffbe34101",
2318211298357120319,
1093372020,
"e8871a66ea410e4b735726324d0b52b5",
14587709575956469579,
2962700286,
);
test(
"412f463e5143eace451dcb2a2efd8022",
"38ed251c7915236b2aca4ea995b861c9",
10458537212399393571,
621387691,
"623403e9d4ecc77a451dcb2a2efd8022",
12914179687381327414,
495045866,
);
}
#[test]
fn test_variant2_integer_math_sqrt() {
// Edge case values taken from here:
// https://github.com/monero-project/monero/blob/v0.18.3.3/src/crypto/variant2_int_sqrt.h#L33-L43
let test_cases = [
(0, 0),
(1 << 32, 0),
((1 << 32) + 1, 1),
(1 << 50, 262140),
((1 << 55) + 20963331, 8384515),
((1 << 55) + 20963332, 8384516),
((1 << 62) + 26599786, 1013904242),
((1 << 62) + 26599787, 1013904243),
(u64::MAX, 3558067407),
];
for &(input, expected) in &test_cases {
assert_eq!(
variant2_integer_math_sqrt(input),
expected,
"input = {input}"
);
}
}
#[test]
fn test_variant2_shuffle_add() {
#[expect(clippy::cast_possible_truncation)]
fn test(
c1_hex: &str,
a_hex: &str,
b_hex: &str,
offset: usize,
variant: Variant,
c1_hex_end: &str,
long_state_end_hash: &str,
) {
let mut c1 = u128::from_le_bytes(hex_to_array(c1_hex));
let a = u128::from_le_bytes(hex_to_array(a_hex));
let b: [u128; 2] = [
u128::from_le_bytes(hex_to_array(&b_hex[0..AES_BLOCK_SIZE * 2])),
u128::from_le_bytes(hex_to_array(&b_hex[AES_BLOCK_SIZE * 2..])),
];
// Every byte of long_state memory is initialized with it's offset index mod 256
// when the u128 blocks are converted to bytes in native endian format.
let mut long_state: Vec<u128> = Vec::with_capacity(MEMORY_BLOCKS);
for i in 0..long_state.capacity() {
let mut block = [0_u8; AES_BLOCK_SIZE];
for (j, byte) in block.iter_mut().enumerate() {
*byte = (i * AES_BLOCK_SIZE + j) as u8;
}
long_state.push(u128::from_le_bytes(block));
}
variant2_shuffle_add(
&mut c1,
a,
&b,
subarray_mut(&mut long_state, 0),
offset,
variant,
);
assert_eq!(hex::encode(c1.to_le_bytes()), c1_hex_end);
let mut hash = Groestl256::new();
for block in long_state {
hash.update(block.to_le_bytes());
}
let hash = hex::encode(hash.finalize().as_slice());
assert_eq!(hash, long_state_end_hash);
}
test(
"d7143e3b6ffdeae4b2ceea30e9889c8a",
"875fa34de3af48f15638bad52581ef4c",
"b07d6f24f19434289b305525f094d8d7bd9d3c9bc956ac081d6186432a282a36",
221056 / AES_BLOCK_SIZE,
Variant::R,
"5795bcb8eb786c633a4760bb65051205",
"26c32c4c2eeec340d62b88f5261d1a264c74240c2f8424c6e7101cf490e5772e",
);
test(
"c7d6fe95ffd8d902d2cfc1883f7a2bc3",
"bceb9d8cb71c2ac85c24129c94708e17",
"4b3a589c187e26bea487b19ea36eb19e8369f4825642eb467c75bf07466b87ba",
1960880 / AES_BLOCK_SIZE,
Variant::V2,
"c7d6fe95ffd8d902d2cfc1883f7a2bc3",
"2d4ddadd0e53a02797c62bf37d11bb2de73e6769abd834a81c1262752176a024",
);
test(
"92ad41fc1596244e2e0f0bfed6555cef",
"d1f0337e48c4f53742cedd78b6b33b67",
"b17bce6c44e0f680aa0f0a28a4e3865b43cdd18644a383e7a9d2f17310e5b6aa",
1306832 / AES_BLOCK_SIZE,
Variant::R,
"427c932fc143f299f6d6d1250a888230",
"984440e0b9f77f1159f09b13d2d455292d5a9b4095037f4e8ca2a0ed982bee8f",
);
test(
"7e2c813d10f06d4b8af85389bc82eb18",
"74fc41829b88f55e62aec4749685b323",
"7a00c480b31d851359d78fad279dcd343bcd6a5f902ac0b55da656d735dbf329",
130160 / AES_BLOCK_SIZE,
Variant::V2,
"7e2c813d10f06d4b8af85389bc82eb18",
"6ccb68ee6fc38a6e91f546f62b8e1a64b5223a4a0ef916e6062188c4ee15a879",
);
}
}

548
cryptonight/src/hash_v4.rs Normal file
View file

@ -0,0 +1,548 @@
use std::cmp::max;
use seq_macro::seq;
use InstructionList::{Add, Mul, Ret, Rol, Ror, Sub, Xor};
use crate::{
blake256::{Blake256, Digest},
util::subarray_copy,
};
const TOTAL_LATENCY: usize = 15 * 3;
const NUM_INSTRUCTIONS_MIN: usize = 60;
pub(crate) const NUM_INSTRUCTIONS_MAX: usize = 70;
const ALU_COUNT_MUL: usize = 1;
const ALU_COUNT: usize = 3;
#[repr(u8)]
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub(crate) enum InstructionList {
Mul, // a*b
Add, // a+b + C, C is an unsigned 32-bit constant
Sub, // a-b
Ror, // rotate right "a" by "b & 31" bits
Rol, // rotate left "a" by "b & 31" bits
Xor, // a^b
#[default]
Ret, // finish execution
}
const INSTRUCTION_COUNT: usize = Ret as usize;
/// INSTRUCTION_* constants are used to generate code from random data.
/// Every random sequence of bytes is a valid code.
///
/// There are 9 registers in total:
/// - 4 variable registers
/// - 5 constant registers initialized from loop variables
const INSTRUCTION_OPCODE_BITS: usize = 3;
const INSTRUCTION_DST_INDEX_BITS: usize = 2;
const INSTRUCTION_SRC_INDEX_BITS: usize = 3;
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub(crate) struct Instruction {
pub(crate) opcode: InstructionList,
pub(crate) dst_index: u8,
pub(crate) src_index: u8,
pub(crate) c: u32,
}
/// If we don't have enough data available, generate more.
/// Original C code:
/// <https://github.com/monero-project/monero/blob/v0.18.3.4/src/crypto/variant4_random_math.h#L171-L178>
fn check_data(data_index: &mut usize, bytes_needed: usize, data: &mut [u8]) {
if *data_index + bytes_needed > data.len() {
let output = Blake256::digest(&data);
data.copy_from_slice(&output);
*data_index = 0;
}
}
/// Generates as many random math operations as possible with given latency and
/// ALU restrictions.
///
/// Original C code:
/// <https://github.com/monero-project/monero/blob/v0.18.3.4/src/crypto/variant4_random_math.h#L180-L439>
///
#[expect(clippy::cast_sign_loss)]
#[expect(clippy::cast_possible_wrap)]
#[expect(clippy::cast_possible_truncation)]
pub(crate) fn random_math_init(
code: &mut [Instruction; NUM_INSTRUCTIONS_MAX + 1],
height: u64,
) -> usize {
// MUL is 3 cycles, 3-way addition and rotations are 2 cycles, SUB/XOR are 1
// cycle These latencies match real-life instruction latencies for Intel
// CPUs starting from Sandy Bridge and up to Skylake/Coffee lake
//
// AMD Ryzen has the same latencies except 1-cycle ROR/ROL, so it'll be a bit
// faster than Intel Sandy Bridge and newer processors Surprisingly, Intel
// Nehalem also has 1-cycle ROR/ROL, so it'll also be faster than Intel Sandy
// Bridge and newer processors AMD Bulldozer has 4 cycles latency for MUL
// (slower than Intel) and 1 cycle for ROR/ROL (faster than Intel), so average
// performance will be the same Source: https://www.agner.org/optimize/instruction_tables.pdf
const OP_LATENCY: [usize; INSTRUCTION_COUNT] = [3, 2, 1, 2, 2, 1];
// Instruction latencies for theoretical ASIC implementation
const ASIC_OP_LATENCY: [usize; INSTRUCTION_COUNT] = [3, 1, 1, 1, 1, 1];
// Available ALUs for each instruction
const OP_ALUS: [usize; INSTRUCTION_COUNT] = [
ALU_COUNT_MUL,
ALU_COUNT,
ALU_COUNT,
ALU_COUNT,
ALU_COUNT,
ALU_COUNT,
];
let mut data = [0_u8; 32];
data[0..8].copy_from_slice(&height.to_le_bytes());
data[20] = -38_i8 as u8; // change seed
// Set data_index past the last byte in data
// to trigger full data update with blake hash
// before we start using it
let mut data_index: usize = data.len();
let mut code_size: usize;
// There is a small chance (1.8%) that register R8 won't be used in the
// generated program, so we keep track of it and try again if it's not used
loop {
let mut latency = [0_usize; 9];
let mut asic_latency = [0_usize; 9];
// Tracks previous instruction and value of the source operand for
// registers R0-R3 throughout code execution:
// byte 0: current value of the destination register
// byte 1: instruction opcode
// byte 2: current value of the source register
//
// Registers R4-R8 are constant and are treated as having the same
// value, because when we do the same operation twice with two constant
// source registers, it can be optimized into a single operation.
let mut inst_data: [usize; 9] =
[0, 1, 2, 3, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF];
let mut alu_busy = [[false; ALU_COUNT]; TOTAL_LATENCY + 1];
let mut is_rotation = [false; INSTRUCTION_COUNT];
is_rotation[Ror as usize] = true;
is_rotation[Rol as usize] = true;
let mut rotated = [false; 4];
let mut rotate_count = 0_usize;
let mut num_retries = 0_usize;
code_size = 0;
let mut total_iterations = 0_usize;
let mut r8_used = false;
// Generate random code to achieve minimal required latency for our abstract CPU
// Try to get this latency for all 4 registers
while (latency[0] < TOTAL_LATENCY
|| latency[1] < TOTAL_LATENCY
|| latency[2] < TOTAL_LATENCY
|| latency[3] < TOTAL_LATENCY)
&& num_retries < 64
{
// Fail-safe to guarantee loop termination
total_iterations += 1;
if total_iterations > 256 {
break;
}
check_data(&mut data_index, 1, &mut data);
let c = data[data_index];
data_index += 1;
// MUL = opcodes 0-2
// ADD = opcode 3
// SUB = opcode 4
// ROR/ROL = opcode 5, shift direction is selected randomly
// XOR = opcodes 6-7
let opcode_bits = c & ((1 << INSTRUCTION_OPCODE_BITS) - 1);
let opcode: InstructionList;
if opcode_bits == 5 {
check_data(&mut data_index, 1, &mut data);
opcode = if data[data_index] as i8 >= 0 {
Ror
} else {
Rol
};
data_index += 1;
} else if opcode_bits >= 6 {
opcode = Xor;
} else if opcode_bits <= 2 {
opcode = Mul;
} else {
// remaining values are 3-4
opcode = match opcode_bits {
3 => Add,
4 => Sub,
_ => unreachable!(),
};
}
let dst_index =
(c >> INSTRUCTION_OPCODE_BITS) & ((1 << INSTRUCTION_DST_INDEX_BITS) - 1);
let mut src_index = (c >> (INSTRUCTION_OPCODE_BITS + INSTRUCTION_DST_INDEX_BITS))
& ((1 << INSTRUCTION_SRC_INDEX_BITS) - 1);
let a = dst_index as usize;
let mut b = src_index as usize;
// Don't do ADD/SUB/XOR with the same register
if matches!(opcode, Add | Sub | Xor) && a == b {
b = 8;
src_index = 8;
}
// Don't do rotation with the same destination twice because it's equal to a
// single rotation
if is_rotation[opcode as usize] && rotated[a] {
continue;
}
// Don't do the same instruction (except MUL) with the same source value twice,
// because all other cases can be optimized:
// 2xADD(a, b, C) = ADD(a,b*2, C1+C2),
// Same for SUB and rotations:
// 2xXOR(a, b) = NOP
if opcode != Mul
&& inst_data[a] & 0xFFFF00
== ((opcode as usize) << 8) + ((inst_data[b] & 255) << 16)
{
continue;
}
// Find which ALU is available (and when) for this instruction
let mut next_latency = if latency[a] > latency[b] {
latency[a]
} else {
latency[b]
};
let mut alu_index = -1;
while next_latency < TOTAL_LATENCY {
for i in (0..OP_ALUS[opcode as usize]).rev() {
if alu_busy[next_latency][i] {
continue;
}
if opcode == Add && alu_busy[next_latency + 1][i] {
continue;
}
if is_rotation[opcode as usize]
&& next_latency < (rotate_count * OP_LATENCY[opcode as usize])
{
continue;
}
alu_index = i as isize;
break;
}
if alu_index >= 0 {
break;
}
next_latency += 1;
}
// Don't generate instructions that leave some register unchanged for more than
// 7 cycles
if next_latency > latency[a] + 7 {
continue;
}
next_latency += OP_LATENCY[opcode as usize];
if next_latency <= TOTAL_LATENCY {
if is_rotation[opcode as usize] {
rotate_count += 1;
}
// Mark ALU as busy only for the first cycle when it starts executing the
// instruction because ALUs are fully pipelined.
alu_busy[next_latency - OP_LATENCY[opcode as usize]][alu_index as usize] = true;
latency[a] = next_latency;
// ASIC is supposed to have enough ALUs to run as many independent instructions
// per cycle as possible, so latency calculation for ASIC is straightforward.
asic_latency[a] =
max(asic_latency[a], asic_latency[b]) + ASIC_OP_LATENCY[opcode as usize];
rotated[a] = is_rotation[opcode as usize];
inst_data[a] = code_size + ((opcode as usize) << 8) + ((inst_data[b] & 255) << 16);
code[code_size].opcode = opcode;
code[code_size].dst_index = dst_index;
code[code_size].src_index = src_index;
code[code_size].c = 0;
if src_index == 8 {
r8_used = true;
}
if opcode == Add {
alu_busy[next_latency - OP_LATENCY[opcode as usize] + 1][alu_index as usize] =
true;
check_data(&mut data_index, size_of::<u32>(), &mut data);
code[code_size].c = u32::from_le_bytes(subarray_copy(&data, data_index));
data_index += 4;
}
code_size += 1;
if code_size >= NUM_INSTRUCTIONS_MIN {
break;
}
} else {
num_retries += 1;
}
}
// ASIC has more execution resources and can extract as much parallelism
// from the code as possible. We need to add a few more MUL and ROR
// instructions to achieve minimal required latency for ASIC. Get this
// latency for at least 1 of the 4 registers.
let prev_code_size = code_size;
while code_size < NUM_INSTRUCTIONS_MAX
&& asic_latency.iter().take(4).all(|&lat| lat < TOTAL_LATENCY)
{
let mut min_idx: usize = 0;
let mut max_idx: usize = 0;
for i in 1..4 {
if asic_latency[i] < asic_latency[min_idx] {
min_idx = i;
}
if asic_latency[i] > asic_latency[max_idx] {
max_idx = i;
}
}
let pattern = [Ror, Mul, Mul];
let opcode = pattern[(code_size - prev_code_size) % 3];
latency[min_idx] = latency[max_idx] + OP_LATENCY[opcode as usize];
asic_latency[min_idx] = asic_latency[max_idx] + ASIC_OP_LATENCY[opcode as usize];
code[code_size] = Instruction {
opcode,
dst_index: min_idx as u8,
src_index: max_idx as u8,
c: 0,
};
code_size += 1;
}
// There is ~98.15% chance that loop condition is false, so this loop will
// execute only 1 iteration most of the time. It never does more than 4
// iterations for all block heights < 10,000,000.
if r8_used && (NUM_INSTRUCTIONS_MIN..=NUM_INSTRUCTIONS_MAX).contains(&code_size) {
break;
}
}
// It's guaranteed that NUM_INSTRUCTIONS_MIN <= code_size <=
// NUM_INSTRUCTIONS_MAX here. Add final instruction to stop the interpreter.
code[code_size].opcode = Ret;
code[code_size].dst_index = 0;
code[code_size].src_index = 0;
code[code_size].c = 0;
code_size
}
/// Original C code:
/// <https://github.com/monero-project/monero/blob/v0.18.3.4/src/crypto/variant4_random_math.h#L81-L168>
#[expect(clippy::needless_return)] // last iteration of unrolled loop
pub(crate) fn v4_random_math(code: &[Instruction; NUM_INSTRUCTIONS_MAX + 1], r: &mut [u32; 9]) {
const REG_BITS: u32 = 32;
debug_assert_eq!(NUM_INSTRUCTIONS_MAX, 70);
seq!(i in 0..70 {
let op = &code[i];
let src = r[op.src_index as usize];
let dst = &mut r[op.dst_index as usize];
match op.opcode {
Mul => *dst = dst.wrapping_mul(src),
Add => *dst = dst.wrapping_add(src).wrapping_add(op.c),
Sub => *dst = dst.wrapping_sub(src),
Ror => *dst = dst.rotate_right(src % REG_BITS),
Rol => *dst = dst.rotate_left(src % REG_BITS),
Xor => *dst ^= src,
Ret => return,
}
});
}
/// Original C code:
/// <https://github.com/monero-project/monero/blob/v0.18.3.4/src/crypto/slow-hash.c#L336-L370>
/// To match the C code organization, this function would be in `slow_hash.rs`, but
/// the test code for it is so large, that it was moved here.
#[expect(clippy::cast_possible_truncation)]
pub(crate) fn variant4_random_math(
a1: &mut u128,
c2: &mut u128,
r: &mut [u32; 9],
b: &[u128; 2],
code: &[Instruction; 71],
) {
let t64 = u64::from(r[0].wrapping_add(r[1])) | (u64::from(r[2].wrapping_add(r[3])) << 32);
*c2 ^= u128::from(t64);
r[4] = *a1 as u32;
r[5] = (*a1 >> 64) as u32;
r[6] = b[0] as u32;
r[7] = b[1] as u32;
r[8] = (b[1] >> 64) as u32;
v4_random_math(code, r);
*a1 ^=
u128::from(r[2]) | u128::from(r[3]) << 32 | u128::from(r[0]) << 64 | u128::from(r[1]) << 96;
}
#[cfg(test)]
mod tests {
use super::*;
use crate::util::hex_to_array;
#[rustfmt::skip]
const CODE: [Instruction; 71] = [
Instruction { opcode: Rol, dst_index: 0, src_index: 7, c: 0 },
Instruction { opcode: Mul, dst_index: 3, src_index: 1, c: 0 },
Instruction { opcode: Add, dst_index: 2, src_index: 7, c: 3553557725 },
Instruction { opcode: Sub, dst_index: 0, src_index: 8, c: 0 },
Instruction { opcode: Add, dst_index: 3, src_index: 4, c: 3590470404 },
Instruction { opcode: Xor, dst_index: 1, src_index: 0, c: 0 },
Instruction { opcode: Xor, dst_index: 1, src_index: 5, c: 0 },
Instruction { opcode: Xor, dst_index: 1, src_index: 0, c: 0 },
Instruction { opcode: Mul, dst_index: 0, src_index: 7, c: 0 },
Instruction { opcode: Mul, dst_index: 2, src_index: 1, c: 0 },
Instruction { opcode: Mul, dst_index: 2, src_index: 4, c: 0 },
Instruction { opcode: Mul, dst_index: 2, src_index: 7, c: 0 },
Instruction { opcode: Sub, dst_index: 1, src_index: 8, c: 0 },
Instruction { opcode: Add, dst_index: 0, src_index: 6, c: 1516169632 },
Instruction { opcode: Add, dst_index: 2, src_index: 0, c: 1587456779 },
Instruction { opcode: Mul, dst_index: 3, src_index: 5, c: 0 },
Instruction { opcode: Mul, dst_index: 1, src_index: 0, c: 0 },
Instruction { opcode: Xor, dst_index: 2, src_index: 0, c: 0 },
Instruction { opcode: Mul, dst_index: 0, src_index: 0, c: 0 },
Instruction { opcode: Sub, dst_index: 3, src_index: 6, c: 0 },
Instruction { opcode: Rol, dst_index: 3, src_index: 0, c: 0 },
Instruction { opcode: Xor, dst_index: 2, src_index: 4, c: 0 },
Instruction { opcode: Mul, dst_index: 3, src_index: 5, c: 0 },
Instruction { opcode: Xor, dst_index: 2, src_index: 0, c: 0 },
Instruction { opcode: Rol, dst_index: 2, src_index: 4, c: 0 },
Instruction { opcode: Xor, dst_index: 3, src_index: 8, c: 0 },
Instruction { opcode: Mul, dst_index: 0, src_index: 4, c: 0 },
Instruction { opcode: Add, dst_index: 2, src_index: 3, c: 2235486112 },
Instruction { opcode: Xor, dst_index: 0, src_index: 3, c: 0 },
Instruction { opcode: Mul, dst_index: 0, src_index: 2, c: 0 },
Instruction { opcode: Xor, dst_index: 2, src_index: 7, c: 0 },
Instruction { opcode: Mul, dst_index: 0, src_index: 7, c: 0 },
Instruction { opcode: Ror, dst_index: 0, src_index: 4, c: 0 },
Instruction { opcode: Mul, dst_index: 3, src_index: 2, c: 0 },
Instruction { opcode: Add, dst_index: 2, src_index: 3, c: 382729823 },
Instruction { opcode: Mul, dst_index: 1, src_index: 4, c: 0 },
Instruction { opcode: Sub, dst_index: 3, src_index: 5, c: 0 },
Instruction { opcode: Add, dst_index: 3, src_index: 7, c: 446636115 },
Instruction { opcode: Sub, dst_index: 0, src_index: 5, c: 0 },
Instruction { opcode: Add, dst_index: 1, src_index: 8, c: 1136500848 },
Instruction { opcode: Xor, dst_index: 3, src_index: 8, c: 0 },
Instruction { opcode: Mul, dst_index: 0, src_index: 4, c: 0 },
Instruction { opcode: Ror, dst_index: 3, src_index: 5, c: 0 },
Instruction { opcode: Mul, dst_index: 2, src_index: 0, c: 0 },
Instruction { opcode: Ror, dst_index: 0, src_index: 1, c: 0 },
Instruction { opcode: Add, dst_index: 0, src_index: 7, c: 4221005163 },
Instruction { opcode: Rol, dst_index: 0, src_index: 2, c: 0 },
Instruction { opcode: Add, dst_index: 0, src_index: 7, c: 1789679560 },
Instruction { opcode: Xor, dst_index: 0, src_index: 3, c: 0 },
Instruction { opcode: Add, dst_index: 2, src_index: 8, c: 2725270475 },
Instruction { opcode: Xor, dst_index: 1, src_index: 4, c: 0 },
Instruction { opcode: Sub, dst_index: 3, src_index: 8, c: 0 },
Instruction { opcode: Xor, dst_index: 3, src_index: 5, c: 0 },
Instruction { opcode: Sub, dst_index: 3, src_index: 2, c: 0 },
Instruction { opcode: Rol, dst_index: 2, src_index: 2, c: 0 },
Instruction { opcode: Add, dst_index: 3, src_index: 6, c: 4110965463 },
Instruction { opcode: Xor, dst_index: 2, src_index: 6, c: 0 },
Instruction { opcode: Sub, dst_index: 2, src_index: 7, c: 0 },
Instruction { opcode: Sub, dst_index: 3, src_index: 1, c: 0 },
Instruction { opcode: Sub, dst_index: 1, src_index: 8, c: 0 },
Instruction { opcode: Ror, dst_index: 1, src_index: 2, c: 0 },
Instruction { opcode: Mul, dst_index: 0, src_index: 1, c: 0 },
Instruction { opcode: Mul, dst_index: 2, src_index: 0, c: 0 },
Instruction { opcode: Ret, dst_index: 0, src_index: 0, c: 0 },
Instruction { opcode: Mul, dst_index: 0, src_index: 0, c: 0 },
Instruction { opcode: Mul, dst_index: 0, src_index: 0, c: 0 },
Instruction { opcode: Mul, dst_index: 0, src_index: 0, c: 0 },
Instruction { opcode: Mul, dst_index: 0, src_index: 0, c: 0 },
Instruction { opcode: Mul, dst_index: 0, src_index: 0, c: 0 },
Instruction { opcode: Mul, dst_index: 0, src_index: 0, c: 0 },
Instruction { opcode: Mul, dst_index: 0, src_index: 0, c: 0 },
];
#[test]
fn test1_variant4_random_math() {
let mut a1 = u128::from_le_bytes(hex_to_array("969ecd223474a6bb3be76c637db7457b"));
let mut c2 = u128::from_le_bytes(hex_to_array("dbd1f6404d4826c52f209951334e6ea7"));
let mut r: [u32; 9] = [1336109178, 464004736, 1552145461, 3528897376, 0, 0, 0, 0, 0];
let b_bytes: [u8; 32] =
hex_to_array("8dfa6d2c82e1806367b844c15f0439ced99c9a4bae0badfb8a8cf8504b813b7d");
let b: [u128; 2] = [
u128::from_le_bytes(subarray_copy(&b_bytes, 0)),
u128::from_le_bytes(subarray_copy(&b_bytes, 16)),
];
variant4_random_math(&mut a1, &mut c2, &mut r, &b, &CODE);
assert_eq!(
hex::encode(a1.to_le_bytes()),
"1cb6fe7738de9e764dd73ea37c438056"
);
assert_eq!(
hex::encode(c2.to_le_bytes()),
"215fbd2bd8c7fceb2f209951334e6ea7"
);
#[rustfmt::skip]
assert_eq!(r, [
3226611830, 767947777, 1429416074, 3443042828, 583900822, 1668081467, 745405069,
1268423897, 1358466186
]);
}
#[test]
fn test2_variant4_random_math() {
let mut a1 = u128::from_le_bytes(hex_to_array("643955bde578c845e4898703c3ce5eaa"));
let mut c2 = u128::from_le_bytes(hex_to_array("787e2613b8fd0a2dadad16d4ec189035"));
let mut r: [u32; 9] = [
3226611830, 767947777, 1429416074, 3443042828, 583900822, 1668081467, 745405069,
1268423897, 1358466186,
];
let b_bytes: [u8; 32] =
hex_to_array("d4d1e70f7da4089ae53b2e7545e4242a8dfa6d2c82e1806367b844c15f0439ce");
let b: [u128; 2] = [
u128::from_le_bytes(subarray_copy(&b_bytes, 0)),
u128::from_le_bytes(subarray_copy(&b_bytes, 16)),
];
variant4_random_math(&mut a1, &mut c2, &mut r, &b, &CODE);
assert_eq!(
hex::encode(a1.to_le_bytes()),
"c40cb4b3a3640a958cc919ccb4ff29e6"
);
assert_eq!(
hex::encode(c2.to_le_bytes()),
"0f5a3efd2e2f610fadad16d4ec189035"
);
#[rustfmt::skip]
assert_eq!(r, [
3483254888_u32, 1282879863, 249640352, 3502382150, 3176479076, 59214308, 266850772,
745405069, 3242506343
]);
}
}

View file

@ -1,63 +1,40 @@
#[link(name = "cryptonight")]
extern "C" {
fn cn_slow_hash(
data: *const u8,
length: usize,
hash: *mut u8,
variant: i32,
pre_hashed: i32,
height: u64,
);
}
mod blake256;
mod cnaes;
mod hash_v2;
mod hash_v4;
mod slow_hash;
mod util;
/// Calculates the CryptoNight v0 hash of buf.
///
use slow_hash::cn_slow_hash;
/// Calculates the `CryptoNight` v0 hash of buf.
pub fn cryptonight_hash_v0(buf: &[u8]) -> [u8; 32] {
let mut hash = [0; 32];
unsafe {
cn_slow_hash(buf.as_ptr(), buf.len(), hash.as_mut_ptr(), 0, 0, 0);
}
hash
cn_slow_hash(buf, slow_hash::Variant::V0, 0)
}
#[derive(thiserror::Error, Debug, Copy, Clone, Eq, PartialEq)]
#[error("Data can't be hashed")]
pub struct DataCanNotBeHashed;
/// Calculates the CryptoNight v1 hash of buf.
///
/// This will return an error if buf is less than43 bytes.
/// Calculates the `CryptoNight` v1 hash of buf.
///
/// This will return an error if buf is less than 43 bytes.
pub fn cryptonight_hash_v1(buf: &[u8]) -> Result<[u8; 32], DataCanNotBeHashed> {
if buf.len() < 43 {
return Err(DataCanNotBeHashed);
}
let mut hash = [0; 32];
unsafe {
cn_slow_hash(buf.as_ptr(), buf.len(), hash.as_mut_ptr(), 1, 0, 0);
}
Ok(hash)
Ok(cn_slow_hash(buf, slow_hash::Variant::V1, 0))
}
/// Calculates the CryptoNight v2 hash of buf.
///
/// Calculates the `CryptoNight` v2 hash of buf.
pub fn cryptonight_hash_v2(buf: &[u8]) -> [u8; 32] {
let mut hash = [0; 32];
unsafe {
cn_slow_hash(buf.as_ptr(), buf.len(), hash.as_mut_ptr(), 2, 0, 0);
}
hash
cn_slow_hash(buf, slow_hash::Variant::V2, 0)
}
/// Calculates the CryptoNight R hash of buf.
///
/// Calculates the `CryptoNight` R hash of buf.
pub fn cryptonight_hash_r(buf: &[u8], height: u64) -> [u8; 32] {
let mut hash = [0; 32];
unsafe {
cn_slow_hash(buf.as_ptr(), buf.len(), hash.as_mut_ptr(), 4, 0, height);
}
hash
cn_slow_hash(buf, slow_hash::Variant::R, height)
}
#[cfg(test)]
@ -66,10 +43,11 @@ mod tests {
#[test]
fn slow_hash_0() {
let test = |inp: &str, exp: &str| {
fn test(inp: &str, exp: &str) {
let res = hex::encode(cryptonight_hash_v0(&hex::decode(inp).unwrap()));
assert_eq!(&res, exp);
};
}
// https://github.com/monero-project/monero/blob/67d190ce7c33602b6a3b804f633ee1ddb7fbb4a1/tests/hash/tests-slow.txt
test(
"6465206f6d6e69627573206475626974616e64756d",
@ -91,10 +69,11 @@ mod tests {
#[test]
fn slow_hash_1() {
let test = |inp: &str, exp: &str| {
fn test(inp: &str, exp: &str) {
let res = hex::encode(cryptonight_hash_v1(&hex::decode(inp).unwrap()).unwrap());
assert_eq!(&res, exp);
};
}
// https://github.com/monero-project/monero/blob/67d190ce7c33602b6a3b804f633ee1ddb7fbb4a1/tests/hash/tests-slow-1.txt
test(
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
@ -120,10 +99,11 @@ mod tests {
#[test]
fn slow_hash_2() {
let test = |inp: &str, exp: &str| {
fn test(inp: &str, exp: &str) {
let res = hex::encode(cryptonight_hash_v2(&hex::decode(inp).unwrap()));
assert_eq!(&res, exp);
};
}
// https://github.com/monero-project/monero/blob/67d190ce7c33602b6a3b804f633ee1ddb7fbb4a1/tests/hash/tests-slow-2.txt
test(
"5468697320697320612074657374205468697320697320612074657374205468697320697320612074657374",
@ -169,66 +149,66 @@ mod tests {
#[test]
fn slow_hash_r() {
let test = |inp: &str, exp: &str, height: u64| {
fn test(inp: &str, exp: &str, height: u64) {
let res = hex::encode(cryptonight_hash_r(&hex::decode(inp).unwrap(), height));
assert_eq!(&res, exp);
};
}
// https://github.com/monero-project/monero/blob/67d190ce7c33602b6a3b804f633ee1ddb7fbb4a1/tests/hash/tests-slow-4.txt
test(
"5468697320697320612074657374205468697320697320612074657374205468697320697320612074657374",
"f759588ad57e758467295443a9bd71490abff8e9dad1b95b6bf2f5d0d78387bc",
1806260
1806260,
);
test(
"4c6f72656d20697073756d20646f6c6f722073697420616d65742c20636f6e73656374657475722061646970697363696e67",
"5bb833deca2bdd7252a9ccd7b4ce0b6a4854515794b56c207262f7a5b9bdb566",
1806261
1806261,
);
test(
"656c69742c2073656420646f20656975736d6f642074656d706f7220696e6369646964756e74207574206c61626f7265",
"1ee6728da60fbd8d7d55b2b1ade487a3cf52a2c3ac6f520db12c27d8921f6cab",
1806262
1806262,
);
test(
"657420646f6c6f7265206d61676e6120616c697175612e20557420656e696d206164206d696e696d2076656e69616d2c",
"6969fe2ddfb758438d48049f302fc2108a4fcc93e37669170e6db4b0b9b4c4cb",
1806263
1806263,
);
test(
"71756973206e6f737472756420657865726369746174696f6e20756c6c616d636f206c61626f726973206e697369",
"7f3048b4e90d0cbe7a57c0394f37338a01fae3adfdc0e5126d863a895eb04e02",
1806264
1806264,
);
test(
"757420616c697175697020657820656120636f6d6d6f646f20636f6e7365717561742e20447569732061757465",
"1d290443a4b542af04a82f6b2494a6ee7f20f2754c58e0849032483a56e8e2ef",
1806265
1806265,
);
test(
"757420616c697175697020657820656120636f6d6d6f646f20636f6e7365717561742e20447569732061757465",
"1d290443a4b542af04a82f6b2494a6ee7f20f2754c58e0849032483a56e8e2ef",
1806265
1806265,
);
test(
"697275726520646f6c6f7220696e20726570726568656e646572697420696e20766f6c7570746174652076656c6974",
"c43cc6567436a86afbd6aa9eaa7c276e9806830334b614b2bee23cc76634f6fd",
1806266
1806266,
);
test(
"657373652063696c6c756d20646f6c6f726520657520667567696174206e756c6c612070617269617475722e",
"87be2479c0c4e8edfdfaa5603e93f4265b3f8224c1c5946feb424819d18990a4",
1806267
1806267,
);
test(
"4578636570746575722073696e74206f6363616563617420637570696461746174206e6f6e2070726f6964656e742c",
"dd9d6a6d8e47465cceac0877ef889b93e7eba979557e3935d7f86dce11b070f3",
1806268
1806268,
);
test(
"73756e7420696e2063756c706120717569206f666669636961206465736572756e74206d6f6c6c697420616e696d20696420657374206c61626f72756d2e",
"75c6f2ae49a20521de97285b431e717125847fb8935ed84a61e7f8d36a2c3d8e",
1806269
1806269,
);
}
}

View file

@ -0,0 +1,626 @@
use std::{cmp::PartialEq, io::Write, mem::swap};
use cnaes::{AES_BLOCK_SIZE, CN_AES_KEY_SIZE};
use digest::Digest as _;
use groestl::Groestl256;
use jh::Jh256;
use skein::{consts::U32, Skein512};
use crate::{
blake256::{Blake256, Digest as _},
cnaes, hash_v2 as v2, hash_v4 as v4,
util::{subarray, subarray_copy, subarray_mut},
};
pub(crate) const MEMORY: usize = 1 << 21; // 2MB scratchpad
pub(crate) const MEMORY_BLOCKS: usize = MEMORY / AES_BLOCK_SIZE;
const ITER: usize = 1 << 20;
const AES_KEY_SIZE: usize = CN_AES_KEY_SIZE;
const INIT_BLOCKS: usize = 8;
const INIT_SIZE_BYTE: usize = INIT_BLOCKS * AES_BLOCK_SIZE;
const KECCAK1600_BYTE_SIZE: usize = 200;
#[derive(PartialEq, Eq, Clone, Copy)]
pub(crate) enum Variant {
V0,
V1,
V2,
R,
}
/// Equivalent struct in the C code:
/// <https://github.com/monero-project/monero/blob/v0.18.3.4/src/crypto/slow-hash.c#L469-L477>
struct CnSlowHashState {
b: [u8; KECCAK1600_BYTE_SIZE],
}
impl Default for CnSlowHashState {
fn default() -> Self {
Self {
b: [0; KECCAK1600_BYTE_SIZE],
}
}
}
impl CnSlowHashState {
const fn get_keccak_bytes(&self) -> &[u8; KECCAK1600_BYTE_SIZE] {
&self.b
}
fn get_keccak_bytes_mut(&mut self) -> &mut [u8; KECCAK1600_BYTE_SIZE] {
&mut self.b
}
fn get_keccak_word(&self, index: usize) -> u64 {
u64::from_le_bytes(subarray_copy(&self.b, index * 8))
}
fn get_k(&self) -> [u128; 4] {
[
u128::from_le_bytes(subarray_copy(&self.b, 0)),
u128::from_le_bytes(subarray_copy(&self.b, 16)),
u128::from_le_bytes(subarray_copy(&self.b, 32)),
u128::from_le_bytes(subarray_copy(&self.b, 48)),
]
}
fn get_aes_key0(&self) -> &[u8; AES_KEY_SIZE] {
subarray(&self.b, 0)
}
fn get_aes_key1(&self) -> &[u8; AES_KEY_SIZE] {
subarray(&self.b, AES_KEY_SIZE)
}
#[inline]
fn get_init(&self) -> [u128; INIT_BLOCKS] {
let mut init = [0_u128; INIT_BLOCKS];
for (i, block) in init.iter_mut().enumerate() {
*block = u128::from_le_bytes(subarray_copy(&self.b, 64 + i * AES_BLOCK_SIZE));
}
init
}
fn set_init(&mut self, init: &[u128; INIT_BLOCKS]) {
for (i, block) in init.iter().enumerate() {
self.b[64 + i * AES_BLOCK_SIZE..64 + (i + 1) * AES_BLOCK_SIZE]
.copy_from_slice(&block.to_le_bytes());
}
}
}
/// Original C code:
/// <https://github.com/monero-project/monero/blob/v0.18.3.4/src/crypto/hash.c#L38-L47>
fn hash_permutation(b: &mut [u8; KECCAK1600_BYTE_SIZE]) {
let mut state = [0_u64; 25];
for (i, state_i) in state.iter_mut().enumerate() {
*state_i = u64::from_le_bytes(subarray_copy(b, i * 8));
}
// Same as keccakf in the C code
keccak::keccak_p(&mut state, 24);
for (i, chunk) in state.iter().enumerate() {
b[i * 8..i * 8 + 8].copy_from_slice(&chunk.to_le_bytes());
}
}
fn keccak1600(input: &[u8], out: &mut [u8; KECCAK1600_BYTE_SIZE]) {
let mut hasher = sha3::Keccak256Full::new();
_ = hasher.write(input).unwrap();
let result = hasher.finalize();
out.copy_from_slice(result.as_slice());
}
/// Original C code:
/// <https://github.com/monero-project/monero/blob/v0.18.3.4/src/crypto/slow-hash.c#L1709C1-L1709C27>
#[inline]
#[expect(clippy::cast_possible_truncation)]
const fn e2i(a: u128) -> usize {
const MASK: u64 = ((MEMORY_BLOCKS) - 1) as u64;
// truncates upper 64 bits before dividing
let value = (a as u64) / (AES_BLOCK_SIZE as u64);
// mask is 0x1ffff, so no data is truncated if usize is 32 bits
(value & MASK) as usize
}
/// Original C code:
/// <https://github.com/monero-project/monero/blob/v0.18.3.4/src/crypto/slow-hash.c#L1711-L1720>
#[expect(clippy::cast_possible_truncation)]
fn mul(a: u64, b: u64) -> u128 {
let product = u128::from(a).wrapping_mul(u128::from(b));
let hi = (product >> 64) as u64;
let lo = product as u64;
// swap hi and low, so this isn't just a multiply
u128::from(lo) << 64 | u128::from(hi)
}
/// Original C code:
/// <https://github.com/monero-project/monero/blob/v0.18.3.4/src/crypto/slow-hash.c#L1722-L1733>
#[expect(clippy::cast_possible_truncation)]
fn sum_half_blocks(a: u128, b: u128) -> u128 {
let a_low = a as u64;
let b_low = b as u64;
let sum_low = a_low.wrapping_add(b_low);
let a_high = (a >> 64) as u64;
let b_high = (b >> 64) as u64;
let sum_high = a_high.wrapping_add(b_high);
u128::from(sum_high) << 64 | u128::from(sum_low)
}
/// Original C code:
/// <https://github.com/monero-project/monero/blob/v0.18.3.4/src/crypto/slow-hash.c#L144-L151>
fn variant1_init(state: &CnSlowHashState, data: &[u8], variant: Variant) -> u64 {
const NONCE_PTR_INDEX: usize = 35;
if variant != Variant::V1 {
return 0;
}
assert!(
data.len() >= 43,
"Cryptonight variant 1 needs at least 43 bytes of data"
);
let mut tweak1_2 = u64::from_le_bytes(subarray_copy(&state.get_keccak_bytes(), 192));
tweak1_2 ^= u64::from_le_bytes(subarray_copy(data, NONCE_PTR_INDEX));
tweak1_2
}
/// Original C code:
/// <https://github.com/monero-project/monero/blob/v0.18.3.4/src/crypto/slow-hash.c#L120-L127>
fn variant1_1(p: &mut u128, variant: Variant) {
const MASK_BYTE11: u128 = !(0xFF << (11 * 8)); // all bits except the 11th byte are ones
const TABLE: u32 = 0x75310_u32;
#[expect(clippy::cast_possible_truncation)]
if variant == Variant::V1 {
let old_byte11 = (*p >> (11 * 8)) as u8;
let index = (((old_byte11 >> 3) & 6) | (old_byte11 & 1)) << 1;
let new_byte11 = old_byte11 ^ ((TABLE >> index) & 0x30) as u8;
*p = (*p & MASK_BYTE11) | (u128::from(new_byte11) << (11 * 8));
}
}
/// Original C code:
/// <https://github.com/monero-project/monero/blob/v0.18.3.4/src/crypto/slow-hash.c#L129C1-L133C13>
fn variant1_2(c2: &mut u128, tweak1_2: u64, variant: Variant) {
if variant == Variant::V1 {
*c2 ^= u128::from(tweak1_2) << 64;
}
}
/// Original C code:
/// <https://github.com/monero-project/monero/blob/v0.18.3.4/src/crypto/slow-hash.c#L171-L181>
fn variant_2_init(b: &mut [u128; 2], state: &CnSlowHashState, variant: Variant) -> (u64, u64) {
if variant != Variant::V2 && variant != Variant::R {
return (0, 0);
}
let keccak_state_bytes = state.get_keccak_bytes();
b[1] = u128::from_le_bytes(subarray_copy(keccak_state_bytes, 64))
^ u128::from_le_bytes(subarray_copy(keccak_state_bytes, 80));
let division_result = state.get_keccak_word(12);
let sqrt_result = state.get_keccak_word(13);
(division_result, sqrt_result)
}
/// Original C code:
/// <https://github.com/monero-project/monero/blob/v0.18.3.4/src/crypto/slow-hash.c#L295-L299>
fn variant_2_2(long_state: &mut [u128; MEMORY_BLOCKS], j: usize, d: &mut u128, variant: Variant) {
if variant == Variant::V2 {
let chunk1_start = j ^ 0x1;
let chunk2_start = j ^ 0x2;
long_state[chunk1_start] ^= *d;
*d ^= long_state[chunk2_start];
}
}
/// Original C code:
/// <https://github.com/monero-project/monero/blob/v0.18.3.4/src/crypto/slow-hash.c#L319-L334>
/// The compiler would inline this code even without the `#[inline]` attribute, but we'd like
/// to avoid coping `r` and `code` between stack addresses.
#[inline]
fn variant4_math_init(
height: u64,
state: &CnSlowHashState,
variant: Variant,
) -> (
[u32; v4::NUM_INSTRUCTIONS_MAX + 1],
[v4::Instruction; v4::NUM_INSTRUCTIONS_MAX + 1],
) {
let mut r = [0_u32; v4::NUM_INSTRUCTIONS_MAX + 1];
let mut code = [v4::Instruction::default(); v4::NUM_INSTRUCTIONS_MAX + 1];
let keccak_state_bytes = state.get_keccak_bytes();
if variant == Variant::R {
for (i, r_i) in r.iter_mut().enumerate().take(4) {
*r_i = u32::from_le_bytes(subarray_copy(keccak_state_bytes, (24 + i) * 4));
}
v4::random_math_init(&mut code, height);
}
(r, code)
}
fn extra_hashes(input: &[u8; KECCAK1600_BYTE_SIZE]) -> [u8; 32] {
match input[0] & 0x3 {
0 => Blake256::digest(input),
1 => Groestl256::digest(input).into(),
2 => Jh256::digest(input).into(),
3 => Skein512::<U32>::digest(input).into(),
_ => unreachable!(),
}
}
/// Original C code:
/// <https://github.com/monero-project/monero/blob/v0.18.3.4/src/crypto/slow-hash.c#L1776-L1873>
#[expect(clippy::cast_possible_truncation)]
pub(crate) fn cn_slow_hash(data: &[u8], variant: Variant, height: u64) -> [u8; 32] {
let mut state = CnSlowHashState::default();
keccak1600(data, state.get_keccak_bytes_mut());
let aes_expanded_key = cnaes::key_extend(state.get_aes_key0());
let mut text = state.get_init();
let tweak1_2 = variant1_init(&state, data, variant);
let mut b = [0_u128; 2];
let (mut division_result, mut sqrt_result) = variant_2_init(&mut b, &state, variant);
let (mut r, code) = variant4_math_init(height, &state, variant);
// Use a vector so the memory is allocated on the heap. We might have 2MB
// available on the stack, but that optimization would only be meaningful if
// this code was still used for mining.
let mut long_state: Vec<u128> = Vec::with_capacity(MEMORY_BLOCKS);
for i in 0..MEMORY_BLOCKS {
let block = &mut text[i % INIT_BLOCKS];
*block = cnaes::aesb_pseudo_round(*block, &aes_expanded_key);
long_state.push(*block);
}
// Treat long_state as an array now that it's initialized on the heap
let long_state: &mut [u128; MEMORY_BLOCKS] = subarray_mut(&mut long_state, 0);
let k = state.get_k();
let mut a = k[0] ^ k[2];
b[0] = k[1] ^ k[3];
let mut c1;
let mut c2;
let mut a1;
for _ in 0..ITER / 2 {
/* Dependency chain: address -> read value ------+
* written value <-+ hard function (AES or MUL) <+
* next address <-+
*/
// Iteration
let mut j = e2i(a);
c1 = long_state[j];
cnaes::aesb_single_round(&mut c1, a);
v2::variant2_shuffle_add(&mut c1, a, &b, long_state, j, variant);
long_state[j] = c1 ^ b[0];
variant1_1(&mut long_state[j], variant);
/* Iteration 2 */
j = e2i(c1);
c2 = long_state[j];
a1 = a;
v2::variant2_integer_math(&mut c2, c1, &mut division_result, &mut sqrt_result, variant);
v4::variant4_random_math(&mut a1, &mut c2, subarray_mut(&mut r, 0), &b, &code);
let mut d = mul(c1 as u64, c2 as u64);
variant_2_2(long_state, j, &mut d, variant);
v2::variant2_shuffle_add(&mut c1, a, &b, long_state, j, variant);
a1 = sum_half_blocks(a1, d);
swap(&mut a1, &mut c2);
a1 ^= c2;
variant1_2(&mut c2, tweak1_2, variant);
long_state[j] = c2;
if variant == Variant::V2 || variant == Variant::R {
b[1] = b[0];
}
b[0] = c1;
a = a1;
}
let mut text = state.get_init();
let aes_expanded_key = cnaes::key_extend(state.get_aes_key1());
for i in 0..MEMORY / INIT_SIZE_BYTE {
for (j, block) in text.iter_mut().enumerate() {
let ls_index = i * INIT_BLOCKS + j;
*block ^= long_state[ls_index];
*block = cnaes::aesb_pseudo_round(*block, &aes_expanded_key);
}
}
state.set_init(&text);
hash_permutation(state.get_keccak_bytes_mut());
extra_hashes(state.get_keccak_bytes())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::util::hex_to_array;
#[test]
fn test_keccak1600() {
let input: [u8; 44] = hex_to_array(
"5468697320697320612074657374205468697320697320612074657374205468697320697320612074657374"
);
let mut output = [0_u8; KECCAK1600_BYTE_SIZE];
keccak1600(&input, &mut output);
let output_hex = "af6fe96f8cb409bdd2a61fb837e346f1a28007b0f078a8d68bc1224b6fcfcc3c39f1244db8c0af06e94173db4a54038a2f7a6a9c729928b5ec79668a30cbf5f266110665e23e891ea4ee2337fb304b35bf8d9c2e4c3524e52e62db67b0b170487a68a34f8026a81b35dc835c60b356d2c411ad227b6c67e30e9b57ba34b3cf27fccecae972850cf3889bb3ff8347b55a5710d58086973d12d75a3340a39430b65ee2f4be27c21e7b39f47341dd036fe13bf43bb2c55bce498a3adcbf07397ea66062b66d56cd8136";
assert_eq!(hex::encode(output), output_hex);
}
#[test]
fn test_mul() {
let test = |a_hex: &str, b_hex: &str, expected_hex: &str| {
let a = u64::from_le_bytes(hex_to_array(a_hex));
let b = u64::from_le_bytes(hex_to_array(b_hex));
let res = mul(a, b);
assert_eq!(hex::encode(res.to_le_bytes()), expected_hex);
};
test(
"0100000000000000",
"0100000000000000",
"00000000000000000100000000000000",
);
test(
"ffffffffffffffff",
"0200000000000000",
"0100000000000000feffffffffffffff",
);
test(
"34504affdab54e6d",
"b352de34917bcc4f",
"2d82d3509a9912225cbcbe6b16321e17",
);
test(
"26ce23ce804055ed",
"d8e42f12da72202a",
"1f531a54b7110e2710c8c956b3f98f90",
);
}
#[test]
fn test_hash_permutations() {
let mut state_bytes: [u8; KECCAK1600_BYTE_SIZE] = hex_to_array(
"af6fe96f8cb409bdd2a61fb837e346f1a28007b0f078a8d68bc1224b6fcfcc3c39f1244db8c0af06e94173db4a54038a2f7a6a9c729928b5ec79668a30cbf5f2622fea9d7982e587e6612c4e6a1d28fdbaba4af1aea99e63322a632d514f35b4fc5cf231e9a6328efb5eb22ad2cfabe571ee8b6ef7dbc64f63185d54a771bdccd207b75e10547b4928f5dcb309192d88bf313d8bc53c8fe71da7ea93355d266c5cc8d39a1273e44b074d143849a3b302edad73c2e61f936c502f6bbabb972b616062b66d56cd8136"
);
const EXPECTED: &str = "31e2fb6eb8e2e376d42a53bc88166378f2a23cf9be54645ff69e8ade3aa4b7ad35040d0e3ad0ee0d8562d53a51acdf14f44de5c097c48a29f63676346194b3af13c3c45af214335a14329491081068a32ea29b3a6856e0efa737dff49d3b5dbf3f7847f058bb41d36347c19d5cd5bdb354ac64a86156c8194e19b0f62d109a8112024a7734730a2bb221c137d3034204e1e57d9cec9689bc199de684f38aeed4624b84c39675a4755ce9b69fde9d36cabd12f1aef4a5b2bb6c6126900799f2109e9b6b55d7bb3ff5";
hash_permutation(&mut state_bytes);
assert_eq!(hex::encode(state_bytes), EXPECTED);
}
#[test]
fn test_extra_hashes() {
let mut input = [0_u8; KECCAK1600_BYTE_SIZE];
for (i, val) in input.iter_mut().enumerate() {
*val = u8::try_from(i & 0xFF).unwrap();
}
const EXPECTED_BLAKE: &str =
"c4d944c2b1c00a8ee627726b35d4cd7fe018de090bc637553cc782e25f974cba";
const EXPECTED_GROESTL: &str =
"73905cfed57520c60eb468defc58a925170cecc6b4a9f2f6e56d34d674d64111";
const EXPECTED_JH: &str =
"71a4f8ae96c48df7ace370854824a60a2f247fbf903c7b936f6f99d164c2f6b1";
const EXPECTED_SKEIN: &str =
"040e79b9daa0fc6219234a06b3889f86f8b02b78dcc25a9874ca95630cf6b5e6";
const EXPECTED: [&str; 4] = [
EXPECTED_BLAKE,
EXPECTED_GROESTL,
EXPECTED_JH,
EXPECTED_SKEIN,
];
for (i, expected) in EXPECTED.iter().enumerate() {
input[0] = u8::try_from(i).unwrap();
let output = extra_hashes(&input);
assert_eq!(hex::encode(output), *expected, "hash {i}");
}
}
#[test]
fn test_cn_slow_hash() {
let test = |input_hex: &str,
expected_v0_hex: &str,
expected_v1_hex: &str,
expected_v2_hex: &str,
expected_vr_hex: &str,
vr_height: u64| {
let input = hex::decode(input_hex).unwrap();
assert_eq!(
hex::encode(cn_slow_hash(&input, Variant::V0, 0)),
expected_v0_hex
);
assert_eq!(
hex::encode(cn_slow_hash(&input, Variant::V1, 0)),
expected_v1_hex
);
assert_eq!(
hex::encode(cn_slow_hash(&input, Variant::V2, 0)),
expected_v2_hex
);
assert_eq!(
hex::encode(cn_slow_hash(&input, Variant::R, vr_height)),
expected_vr_hex
);
};
test(
"a83cd815319596c6e4fbf2ff9399ce99eb092f58b75c351a7be64a65a118cee031c06a8542b758a15b8a7e",
"19dff098bf4f330c466480c6bf59cf89c5b4a9692a8941e7625435275e7b12e5",
"89def5411f4c877e75a0ae9a49c73e63071acedf69e730d9d56425c01ecf0c9a",
"4c058a38985b6b064d85562f0bd2ebfbaa2915de6ec90307b660b5525ef7d7c3",
"4729aa8a82fcf9b014baf5c2d2fdeadc3ea58bcca7934bb98359caea8f0227e8",
1901601,
);
test(
"0020a84a1806a9cfd957bfd243de587891d6e732322289a9de3db5b15aceacbf1d5b94d04f143bd652bc2d5c6980c2db58007d03b4e5cf94829b06b13ccd61e9edb2ea910876e2eaff62304658a07144236ac3492edfbdee9077f62622d6b9b56173b0eb822391857a33c17e4fed4a54f42f2ea7d85e9246e6879a98c9576240477060ef4f4c88056d08acbd36825b314cfba95082aa66ab6bc89b9831ece3abcc8e7764eb",
"24b03eefa6fa730cfceb1fe3043dacdff9242f69a3aff86b9d75e08d5ce6903a",
"b624fcd7345589b2531f29a9d47ab53f4f90caaf3e76f20aa3573d73421e55a2",
"6426f2a9e3274926b41965f389ec40625f32d1ae6decfff8966d5af208789bf1",
"efb1c48e81b58e0f1b0d574ab142dedbf3b089a8fc6c9b50f2bef507147d8e02",
2066323,
);
test(
"93935e3d10b73a45f77dfbbbc08c819ca65a2d279354f945d5c2b244cea6af82d9b39fd293b7ec136e2a0e584ec6faf584d669226a976f90dc61acc62f13de42a04d68dc2e80310a692fe2e1a88f05fe0e370117dd9b8edaa9bacc827571c8ba8b55dece38bd67fc22080d10b94dae5fb7caf68297b240fe026e19140c88873ee764a8a8ffcb3a1d76fcbd530dfd1b7e6cccda31362ec9b2b6eb420aba7c6088685ae5d75cdd1334dbd979b916a0f1426563e8e6ad778f1110d49ef34e446346dbc9c358b29e6f923351a8368daacf6661c19c0c1658c8f7d0386ee9f61e729e5f6fdcb4d740655afb6d2191801c0126fd1f18b82604dc753dce507313c4ade7e6c01d470f18b701e21f",
"e6bb2a8e6331b816749c0dde5036a417c0f33e373177e4e93b7bc2452d6c3fe4",
"e162d6dc79a6f2cc4497dcc65b6f7395fb9a8df4eec53e87f49c0d14bd36318a",
"8ecf8c005bd5539c0c16cac9f2e5744f641de5b886f069f31e2d90ac8287479b",
"6a26f39a459325b43aaaa38d2f746678907cb4210c1335096f8300291ab22797",
2045824,
);
test(
"4c1818705e30a631e152fd7f21f3fb836a0e441d7450a7fd38f119f95c650a66ecb79fb6d60db04dce28e0798c8e5cdb9f13738da06484b2ab302b548ca0736d0a58ace27be67b07219e9db7e50c4243e9e2a6b60eccac1b9b4b266f85d3814a846239bccfead53b752ead9ddacc9abf100dd9889c3fd7b064f4102f864df79138305b61937f5bb458cfdda2e3e1dc553e06f90efde088fb995314c539295899e31509c4198d1ad056b5fe9ac7d7e3959a3d73c7f8b5203f9f21c688b196841abf8511630864f304ba44d6fbf627164596c6cca56abbb8a3a005abe6a493ac08a3847f65cb3f90ef531d233b9953b86d7a659ec82cfb129f98ac5852fa73a2b84920669ec8d14fe1ba20f9ad488b86d7d344c143474198cdfbd6cf67df3e3dfb293c62361c3e3a4246fcf1558cdf69ec10f63770f9a8a23ff80f3ca46ee5ca35ba384bc3f8eb0d159e58b649045e87b0095e800673e0f33d4ce2cfdde727009fa0c74d9866bcb43477a3075149068868f58a33f7880d609ad2",
"3f3e491848ba252d497231c696e1538a6e1a7f6c79a8a1b2764c5810f9c4d38c",
"9e272f82a466c86a1d093a07dcf7c471d8e31a056dfa45f902bdc4ebeae9bf3f",
"8a5260d0b5a4a0e82827daff7072f95822e316f2bdbb5f021cb84a9d44f76127",
"94d96aeca25bb37bde8497e9e45f5a695ee6e7a6c5ba489efe0bb0a10494eba4",
2099507,
);
test(
"b27c89ca34c63efe96732f8cda3eceeeb12304e0e6262e9463d516994adafb11ba2db10f9de8e5fb3b271f2a10065a77a7da998c07f679d7b36bb6ed0051e6f5f6871247fa167dc2d0b19f55f9ca283e6c4486967ac7783ed4f6c292e536aaf8425e436bcc38e55f942f797b2fdc9d4d73cbe4737d2ca849b783c4560ea97cfbb448d444f46bd360aad1c3077e032fe0c43f95e4d5e263b8fb8c2eb55aa6d6403c1075883b4fe657e7b79341b3f88ad48817caaa6cadaf0483c7d643a9b2f0eae8c3470f1df4ffae2453f179c90c0efd51fe8fbfe85d9e4d306266eab9fc5739e3869767aac8ef91e4df881e2595dc235e1ea01579b21fd964f6e66269907bb19f2133534bb34be607dd582775475f81263ed5cf09a9c11a0c290de2dc9fa1a99247fc3c6031cbe46dd833dbaa7722f7dcbb5fa037c7bdc6f4b58e54e3b8157aa893eb8038eb6a0d4364c5fc66352065883e8da1b06840c8de1990c00fb88373b9971351cae3762bef7bcce71e269f76b832321e4b83528e8379132f43fd562553d3745e44dee5a0ffa8a6245c8c228831f22b865feeb7499c54b841c69279a822491eb76600afb25b22885e51822e4ef48da78756dfea36297f2ba999fe99bb80f1432c5e858d52a6ed6c",
"83698a19ea0c50b8b411e3f7206522ef96fd0419cc9fed72de6ecb43b4e8b909",
"80b760cf63d938d73dd2d13670f9425dc3a50dcb66e237facdf75ea3e6e18103",
"6a5a069cdbb29914b1e189c5665e7a7ce3bb647bc7239dc855950e5c0906fe14",
"e05b7377f8099a0c0b1dc53121fc4070d65cf3b896a06bea6a6702a37201e79a",
1930040,
);
test(
"5641ce08706166c97f2b13052aed63ed360565f0c74db968cd2cac2ed415cb173ab3583ab771ef3d126648afad09da2b35038f124238c8ca916c3e3fa4c57626965397d1bd865b904dcc3a6398eb2b501d6fd82bb28d80b38da6d4f333b260a60375faea13e3fd9ac2d2745e660965ee2624d68114fce6520f62796dcc4160d1f3cb55e48bea53911b91165782b52e05a02f71368379c428b196ef921f832383043421447784f75cc3bc5dc33ef00acdee9a77cfda31d6bf5e4bc322d09c97977aa826cf02f87a9b2d261689f25605b12997bc51cde56f6b95eb643e7ad10ce6f6b9cc1c9513bcc69fdff3ece5c7e9fe989c1f0797b8a6c0eaf17aa63c173ee7ce4a7439a93dccca735cdbaf2ac52c2626ca6dd18d190c28c7bcb74dcd5e831cfa691a9e02f9e1fc4d991d19f6c771d6a317d2335a5faef74b9485f3b708a06f9a3779d4ce1e224c1fd4c80ed682374988e9a80c16c489864cbfb9619eac25e7a529f75963dcfabcaae75921ff4f37e90771683c365dbc6e49394ed42a4930308f61dcc5493f6fbc61f089d31e38304f88b03090db752cea1ed149b01347277563c372fb9aabfa770c5324267b3a1a0c7d95ec5d787dcc6955a6075e7acf51b6f9498bbe31ca3a134fa4870e3f3d85aa8a06fdc260f67843b030b55eb57e386769481fbdc27d3a42cb7c67b626067be82008bc922d0a13cf2819426a434f867688d4c866a1323a3afd5f0d27e5f706aff5d3ae8e808dcbbbb527eba451a3fa92012f5dd450c8727d9812f4de6b35c9864b94112ea0e1a0236e905f16188be5bd909318945dbaa48c7b48537cab",
"5e63777a37718d23d4d27df6457c3287e5df76d57e8b1576dedeaa0b48f686ba",
"34b967683a272498d46eea6f0075ce8799e8b3871fcbb8e8af2016f841b0a563",
"17173452105a1d8a797d46881af00f131276c2c46aedecebee357d3400948690",
"23fb53795f04ff342508044091e9d5bc5704e637979de4491d420620f91515ed",
2013003,
);
test(
"381172bcf453dbfa7f0015823367545d83483a6c805355f26b1cb4019391c62b227530102bc19272560d2160642251ee92d009c478210e77d5fc0edd20c332648058d7a5f052423023d651eaf415bfdd6e03588afc2ccadc0b63dd187a3e585802fb6e14ee753dc778688856f9619a883de3f68300088477f26aee159ed8f67296e034e020f1577eccd56c9e5ffbf4695e756635aefa4140e346fd3977b159a950f71b506a3ffb3cb1802914ce81df8ce8ca062953eeafa7dd8fa6cdcdd85dcebdc43d411da2befff42f250c7de4a29793f1105bed7f1d7e0adcdabde04060f0370c6f66075441e06447709519cf8fa5cf89e7965399323254f0faab58c095107a61b8f07bc9a368a538c2fc2939daaaf8562c70c3d9c878821df45547caf4794e0a3e62f7f14ef4004d31e9a8feee7c9e97721d82001646e3c32551a7ac89b7cc17be74beaade5f613aa30a5b3077859c579dbdef27e27fd219947c5e5e8456c37da5ebd7fe3f1cf369ded0451098843e197db2d82788fe0ec39cb0a855cbd6a2d54aeba7f57fcea8fdfb3f153075d2b9c28dfeb3582c4f19037c45e39bfa9500fb7144f836d82c65c166f901605fb0e298396dac47d8ea44ac00ae61b16c5c53e93390698b7d6704c6a413f8244a96bcb37909404a0e1ed8219a388936e2c3a3038598aff37949b2e1f3e4b64945087914c1a24f957767e583fd875fed316aa02adce9ac1325cd88e5287c3fd7e39e8618104864297d979d27ccdb66b28005b3ef8ef2e8ebd17a1ffb5f466241a521854ef5ffc41af918bd3a4bfcef4d56fb506ece4f4e043b02815d98c64f8d3a39fd2ba5cb788cddf83e7c970113414c0b745b260336c4c376d78ccdd87c1bb1e409145c912584194cd95848039d265674b00d24a7f304d2526317bd3a60858eb05eaf9b2047905f6104371661bbeebc0e06bb6f20",
"54ff2f094bb647ff95d3fac1411021beb2519ed4921654a464ca1d91086cf566",
"26128757abddf96cf31e24b752c4f49b9f7e33b17719923412ef681a8b0b80d7",
"a2553f122fb1cd293c3d3c442705cc9875705fcc374fa0b8944bae52ea818037",
"64e11fbf279c8ef768450c5516106270f960b9c514bf945cca82a08e2db553a8",
2098488,
);
test(
"45d3cd4ada6cd0689c08ba902effa67f424b4a57da5512a9fbddf343b4872f48953485c0dd0f38a96ee61e655195354a8c7c9d73ede4581eb943fcb4bc376bae314d7853350ae805587d00958a63dc547ae4b7b217f39fff12ae684c18e1533a6acb1aba6551fc6ee78aa103543295bb81a720e3dc538d1ebf156df8510bec0960e55d853dbcdc360e3c7a39a5f4393c97b1317ea57b48d8413b67295b89860c5fe602b4a0b05724e5e1563f229645569703c3acea69d75a8ff72efb0539340747333735c74d0ad6126ee22f2b5b47b601af4f6c36f9a7227c457770dcbd31e85b63b57da98f4c6dc926afdba99851b44365f99103841c2887f4490daa63cf10954b4a8c354346307dfb3d5e2762625bdde96b6bbcf3e7af7d7bdc7a2d58ce607e97bc2e8cd39f9871debbe7b36e3652f54f54d02d5470c7662ced04435b3771ba9264c107cb0b513844ce7538d7529db455e0960dce9e309d1978a7d0d5debe55dd37cc8b1cbf1b41bdda5413ed68f51db2ce70d31232be4095dc4c4b82f9a46d8fa278970bdc72632e74eaf6ca756ca72e6f5be75823b0502ef8deefc249f8a9d37a8778ef1429cd4ad1b8c9a53e6e179d6f62f5e966a762da0db3b6974ca79c5a8be615bf57bd11a31a1b365b7f47f71a041a0c46ca18c7af20a09e22085e767948860c58e84ce56c6646d1737d4df9714362deff97ccf56021ad85ba01da06bdc46bd377cca8c731ecad9fa18013ae0a567220c4b99796d3cde96eef16aca8bf10d4e1914faeef35e505e44153eb3c2e1b0cb366751b993e662a828eb5f824ab138aa7504c8f2bf92f36a9c4c978ad064dc4e877fa37f0cbb1fd2f02eefd8b54714a7952b2efe522ae00315fd147174bb650314e20395bc13537b65aef11ebb1e54a34f169b11b895731c6eaa95ca6ea813c7aae22d19720c30265e0d7242afc4ef7fe1a685eb2d48d18b135ec6656bcb1538a6ff0086e6949be38b4d88a95279fac4475bea3c91f3cfbbff56f0896502417a8e2678e98ce4e0e184d7ba62add18082edfdecc36b79734e1d11bb62593de91d9138945caeb0d0e8e070a397388c5b010720fc9829f22fc80ae1f39b469aab343",
"26465b05a2b7d822a180e5da853c3bb31cfb541ac57bb4082ed6baad2b7a275d",
"3914d155ab3b103a29ca1733f165739dbba3fd70847680982c72378097644f5b",
"47f117624851b9f56ecd40dce1a345348c7abea4223e22c4bec1b992001c05b0",
"83be592ccfd6cbf00f2e299828836ab6a92afea6b7b32e5c4ca4ffc6abf095f9",
2051767,
);
test(
"f7ffd535353b3296adf5b9264b26462fb8944ae3aa917ac2454bd3eb967308c8665896082f1b8daf1c352dab97c0158cb88ba10eaf323e5ef7cdd3c5ab1188c23da90a1aaa46c18dcdc5f32c5160788cb6331a5fefac666210fad0365bab019d1e62f3389d23ea6de4bcee0ccbac2ee2c86dcfd446c90d3c8290526b1d818e2c28d12e8f2a09f2672578aadbd2b1b612acaf7e35727543cb14272bc807cbb24bda7cfe6ea7eaa3a0533b0b64976c24ceb855b16929c43238121c99811fdcfb80e7217825397655ada6fcfa4b5a7527dcb154ea905d8a7d9b1f7cdc5ba475aac290d8fd0ffea6c9fc08484205335b78f07985df2537301bfa1bcd96f10cad3053aca2900dce33082b01bd66c0b2d801e17f97ec693b2faffce2660b7b0ef7564d8df418ea2c150187c8dc717a737843bc1bdaab00d3d2820f592d912559da59056d659da775d62d30588a778f454b99cbc50578867c8e6274d23683886869d0655c68e65cd79292893d58a55c6ac1010856d94a7d298c1c2f9f503b1ce62bae9afe5057186a10bd7464eb03c47b0e847e6ef690c248f385a121eb7a6a3fd4e9caab6c0c6ac5d4817b01dc72ea12a73ebd47a3d32f740c12cb076a43f35ffb6afa460642f75d05f0b3ffc8999d4030a80e61ce3a54a5c5067968a113cadbcf1aba7d92bbf0aa672a5aa98dfe2f2638d5fa7b624d91f4fd66b02f7a11e798bcbede2de8cd6332fd4fb4fe6dea91cf1000ef58a9dc79b280bdb9aa178f19f39766c965370879229f1b2151a9029b601060cf4a7c28e506b14a58d0624d7838338738b7f54fa865a4ad3a8ad730bf12c2b48c57b7edced9026780d51b1cf3eb91d36e0e76c746db891e510035089225e75db6abffab62f6072d97f5e0aabf9437171026c7aaec2fd28fee570dcf6b9bec649cb6559f761a1c9b634e926e226c5b5c581dbbb1ef3f5c6c489c6d2e59679b6b8d6d9a2200bd59fe453ef70b84dcd27dc062999bafe6bc856d4bbd5276c683fbeba3e57bbc247018b22711b603d2f9ac18ee93338b4d561eef7031f7b6a76388e40d88dfaa5e7276b25911878467e7d887bef4f83417873a496474021e44330068e8081fe84a1eefa3bdd05adf962fa5ecc907d3d6e1c1cbab1079b5c65a560a337c8e305e6d6693bbf539d18d6efe8777146925741957067a0fff681ea2306d5657af9a9313eca5e879276a92e1dbc3d29dd65874accf34c399ddd2a39c765f335d49f3a3862a",
"19f361976db5833325604c31f6a3362096606d953f34e78caec6348c179112ca",
"20731740a7ac3501898a5d309ecb095abf07e4db57ae8ee25083596d2f41f747",
"170910bf127750aeee7c26b0136f2ce3c5847d0ddc91e5b7c3d1a561ddbee6ec",
"157becb8920260a38fda21c79285e9c3438e22fb1322f52cbca78aa07a90dc26",
2014127,
);
test(
"042907fec45e611bae8a453343ea30f01758a717fedf53d522e45ade68ceab671e3918875a01204b40d579672d6f1f2780f3d05a50e260af372c43900e5e314da8e15cf5a6d5c2247ab28a10cf13994a7e1bd125b157c98365930fa76c871bdfc1a2380cd15b7bf7dddadb4fe36bc5ae45f13a3ee128a4f74b9b77501d265763966d9e240093539294f9d7aeb66a87c6021ca2d9a6e0a4dc22f2845e295aceb99cca53ab3e09f72476d988f4824034a334d6f9314836fd60f35be29ee4511113070099c7bf8390af96eeb9a1a820f005181a7ebc33a68724eebfd9d841f9f574d40ec8ad93e3c65fd73f9bc042dccdc6b5f0ec0aa2fc12676baed24f1be7111cd3d221015ea9919434dbd25f987c985a0d4478d45a43627f13419e4d07d2f5c64038c9d5b04e8aabd950d98e2563a68df1ecdf22b3179969022a82acdc16e90ff9d3804bba8e3ea7f8d06a390cc97a823bfbee8096bb93c399ea2d04d592f4c1c5ddad50d977974c14711cc7e0ea339f0469b9b688688080aaca49ea33c545d3941cafc7732e1058616b22df13c9bce1923f13ebce4485c2e8591881f2f8ecd4a3553731b3a800bdf6125c7298cbcf2e060bafc7df05b4c239e553b4c491397d8033d6d3525f5da13c6397e1019cb3799c4521985cb910f186aff6998f556c3c0a1e8d9a47348c35bbec752bf5c0a689a529a50980f27220305da3ef7c550d34be357978c7774077ca623cad9dc04d1eea0a4a6db6db071edc8c6c86d77f8796d887d773190c5f351146c092030978b9ff3eaee5cda8d0715e05a2ecf08e31bc2761f95be070053f999ddc9d6936af7ad1b8177a180132a90e738e8cdc45ed0c2c7e1a4dca126610fdc286e62bda134aa75dd7ef95e5247e6a6999ef7488000692884ad450df70582003d39e1c4d1cc808ab880d02b93a3ec1f784a4ccfc60e584385a0c0e7f8dec04af24990495e7af4d43699f1d8801c4c86abaa2e6f42f3f64f634065eaf5ccee63ed884da857778cd627c4f4cc1c0ac31740731284c851258cda05ad9d9eb55760c81036c74876038f58fbc5033d944e877a92083d95eb35cfd3b480e90ac6da13ef422324d00d7fbfba7c6ebb6c726c1bb9f8be01ed3d340858769c25c6643fe2f046f2ba5761750e5a312ae2742873f845ea59940e0b6c1c0c02bc88a9047a09e63aaaaffb4c26ff416ed086d7ebfea314baec4539eba00a6b11cf7e07a0426590d07e11508116db2250cac16f225368964c632ba9d4db50d11e7e0002d8f9b2785b38fdf1eb10f6e87e6a2ba4d6e0c47c0a3fd651e9a10c4db3abd3737b53ee645d3c16696af0573f9eee37c3b66fc",
"87f56803c3079e4afc89df7285078b8f3483dc8503f3309470cf09d68dd1987f",
"88a19559dc7c0f46314cb9fbe23c7ca2946db2081eb2b19a4856f4c18e8ced24",
"f3651d3fe2e74ee010284c6a46b9eb0b888dd8271d053cef7cd3a68cbb4e67b4",
"410f675f6904e58ea5c03cb10455018032c27623cf9000a8b8efbb2847c0abb8",
1981542,
);
test(
"f7704c6b62bff847096e20a6ef8f8bb97e6887168321a1345312c547e2ab146f35e6f95b76f2e8ab26ca3d9061e0da59088ca8710731b458711c3b8f119808959987645ee92db847a4c4c5240e483b1ecc7b59d2967dca862a86c2db086e58a78367acd4579ff1353a9d695f822e7dc3751319504636182974987e0f5d5dc8783705c252678c90679243634d62841e062bee4ec7e7a4966d3f270fe6c9463acf0bcafdbe83e2d70a3c55a83ee6854f4a80a163cba43e479d3f32781570acc5150255489e159dc6a5da38f3e9d8af45bff5022262216533954e2702ead4c12b6d4b4f7bc475bc61bcbab54ab99a880218d2285a8a2db11159a2f8e8234e171ffaba33f4c2d8019c0000c50fd213c5ab40160bc89042708500c52c456d859516b5d31118c570a088db80fd42490703bd752e0ca770f4c471e1ad15855b91c7785534627bfca514fa978bc8e8ee5fe6a5941b950e8e7769e8dc25387f7844f939cfe554ee41b345dbd8dd8a13449e3e4b51f900e53c8ca9dd49d9faa87ba52c60517b8d6a866a8da41c5593dd7dfe9f5e90a726ed07977f5efa12079c374109f698e6f85321a1be2105cdceed960bb52a23f7da5dfeae630145ee61f2b33e3935ae63380f4ece5f6ede54048dcdc706d993dabcf27cc4eccb45ac28cd55ab2bb775daad1f3ef57eee8fa23fedf25e4455c51ebf9eb5610c2f17b8a95daf9c87ea1963ee95b3bbd8d5117b133f3e2b68fac2c96f480b49567e0eaa92f234a2d75917f31de96aa41ee6e591771dbef286db639ba4b8fff112b0d3a1c6d6b3e8aebf2108aa8f97c95e41c3e059dbdff6d33ff321f857fb845eeb32ad6c09cba8179ff8dccc77924605d57eea98afa8c033343379abba0ca666a77e2dafa24f22ba7e352b668d56b723b7b00d0e2a0ace7bc17ec596fab3e64c06fa5bf6ef6644bc2f2b7b007b113f241cedee319009f689fa68496ef6f186c8ed7fdc82a2373d00d326f57b743bbfd608eeca2233b694e39a3fae56a4e2a2ed638e8f11bdb633f6e7ea253f2d24cbb7270202da2b9b65ee97b362701c5f404849a1badc7f289bccc65dfd903253a71c8f0ab1fa6004420e1ca05972d3f40258762722bd6abf58617b9e4722f24eb3d2ac21304efb7fe5861051a46b409d28de0e457d66552baf80eccc72af6ec1018a7e118644ef255aaa8c0b51ed8bb78ab5da839de50c345b8275871a15a342e05fdacf0babb8fd22b502155a4e86146b554146666e623baed63fe99af9999bcf75eb3c9c4d7697693aae8e728b1c05a4b209c025e715f55aaff0cb959a477e16ceed7097968996c02f2c19bd702b32c4a063b95f855ab426b0b643727091eebb1b5162d93f9e770922e4314b1ff18fb6a3771a4fe7ce98df012e0e276bc939e608b71f05a5bf84b2b678d98bf095e99c857becdc4213e3c8837bea456ef29c585a20b3f0753057fb449a8a85c5f3c77316accb0977764348895b5c25ca4a7fa09ff201c5f78987f0323fb73ea5ed79e02f742d277d69d5840152b0",
"d42c537985350ba4d9c416a411046383d6f57654b6fea6a7d5967296ee710658",
"d66ed3af79389cf644d688fd978b84a8212fe34c5f5e57a8d993366c7e0b788f",
"46cbe4a65dbe8713727c1412d01b0b35412d8339b4f18cd594b4ad5ee616f79b",
"953d2476c2be1329cd7f2fb60a6cefaea6e4a9192491da9420669e60eb49d7a5",
2056079,
);
test(
"5f63e95421ce62ac207e1239e9e2b763ead4ecd17580d333005e5c724646f2633101f0ba797ae905ce68167412e069763838fa4c5c0d155efafcf021320cbce66df4f4288eec02f5734c866743177eaa18e32a19afa82133921108ca54311aa79cd5dd6c7bce26732412e614ce44d8f5e2867ceab20f61f44ec2a8ffffcce141aea7840924135aa68a14b9024b7726b9b7002baab89763f9997ecf5d6fc2c84e048df8f46c8dfe3bb12b5675a4f68840603860cdf58d1fe56e7cbae7b180e717891974f8a4aa032d89f2771da9b9a63578ea76b7153a4211388a0d6aa27de720100325cfd8a88c480e7e2b67685c0afdda678391e1ccb81936f96bef461131b3f4289f902d7cec94f3cd651b5c3a36134bda12297ccb7913f8e76f0972306a5bf119d6777c7caa01aa8fe8f0173134571952540d0168a895b6671bcd19532fdbe3d6138ac1ea9b7bb64ff951dd9824e037d34cf98bd0e4bc705b6dad47633017afa698dbcc20090d5741c1e02e918dd96979948ddf6c9ab8f889749af54c4f6916c20a74349ebc36f46f6b6d47bf7cdbb1a5bed4fc5b9a3766924483e2e5d837976d12122ad6e75300c30d5a94f0322dcb3825c835167699c2b1be79ad28e1ca37ab87afe90790611f3a6d07faa365dd1e754d50f8c462b8d6004ac40397e6571b5ec6dc86c164cec07f41ff82e6f4e29219eab65b0ccbae12c9fe482f18b8e51564013b1ceb3c2f3570f86330c667e21aaaea2a643500f9d758d533f6582239a1bbb0bbda04e22f749ff436ead6df6efce849879e0bd3918cd6d55e875cde0716e96da93ad752ecaf481ccc5d77a9d5207dc912f5972719e105023cd2ab8ccc3e7c5f38d04c6c37667bc8e2036bbdaa969735e07491ee9ce8191ba9a5f0d084bdf616674a98754b6b78510670c2b74ddcc744071d25aed8a6efcccb3d03be80515344915674ded598c855738b86eb68359b801d61daa1b80708dc615bbbd1051c76ad05023ec48f458403adaa0d7becd3a6799cfaf08abf42331e639012669b0398dbe44e0251bfff268dd1a38c63a9fbb22233fd22eec520976e8a9c4c4362fe555c1fc575d731a1e910b433a3d64cbc5b231b623f0c49a41355ee86028013295b8f1f59f0c3f6abea0887c74e7de2676ba4a411546fdb5f7ddb3d3c5e19e1b881fd7b623b79f9e4bbf43f0bb42d2b195130b4630ede7851cc6fba851b5e7bf145039081e95bc8b2e6e0c73e7126fe734669ce53c1ca58ebc72cc787361993d585680fda60c4158155eed6471c8997fee5259fa3405b10e1d5f955d28a12a01c8e9d04f53ba9130daf49618cb553e0d95296adcd0d4b72b73f0c6cc531bbd1d6f466d1e0f60559bdfc7b3385d671bfa3f092346ca16392871c2b8dd091f6de8ca4188b40dfb9c7ec7fdb8fd1ec83b354a599d917accf32875125f20407bc20e3f08cb959e9f84cdb95e5508b0be175156c22d4ba37f6fcb51d1ec109934ace91564ee52240ac49ad6ecd85fcef7db006fc840fd32f387800446b8b4509e917b5001297ae6515db88d28d5f19025c8370323581c47c8402cb93cc2918f8d93f109e46d92d43d95db7ce206fee34d1d4243ed7e6b49722edc4772f71",
"2c2447a2cdd8ad2cc9b02a499b2cf42c96f8439b49a52590b9ce44443f37dfd8",
"d689c14e5b89bb4e4cf64a7d60b7e242747c34b270c292e255d97c7211a44aeb",
"1f3cd81486cc6e71f6e7151fcedc271b3195c4407895eb09ae3337006aa9af4d",
"99b2220c7464edcf63925a8ed69ad4fc3d1554b9ed9b6762823881763e79aec6",
1952566,
);
test(
"fccc58bd0e81bd73e483f2d8b57b750d29ce3e6c9f18ba24317153fe06d2f5a0081bba69920baa2ad4e0e34bc4613644c67aa841e6210ffa7818de3f703cd12711a54a60377c0f24285851aeafedc5b405026957782754f3deec5c81d9958f07e377340b08c7447e1ada8201d01c8fbeb454d131e4c8bb284a69149f2caf4d0a535845ea63f5a67100bc138c3b578cc615105f76946c9eddbb2ea23a4e71c2cfb3e45d0a1eab2460b39815f652d10c7251979abf7eca0519013983266dba8c6b08858a48f1993eb5028b0491d66a32427b9554ae31251476055e912c87fe9e088db85d5610e25a728b313b58fdbb066b14746c6f35ffb35f2da95aef4c498661a95fa27f102d58e07e445415cb54ddbd74a593c02898eb4626524430bc57173864da6c84d4708be3a5006ae06a0cab5692d456a721db83c066cb871c9ea2452da767cc0520fcfb5abc45b365ed06c699178646c58fc976eacee3f2eac2c73769e3e14a989e99e67485b29f13deb17a4b28d77cd033f1f2848bcc6422023f3fce73e6fc41a7e7c52ea4e92691b6eb5d8fe9c14ee0cabe631674fd6e3eaab1f273ac22682c7884aac1026fbc4194a8a9b7134f823d42ac1db8639066bf400880413968f83b124ddfa27e91ec771dfdb31a76a27d21be47e8de0f22fad496cb6cb3b1570d410c461c360f8ffb3df08fa879e1e48627dac97fed6433d493e2c6ad4c00dea2c1f2e35ec29ac40eb7d166e13f2f08dc86000edc1875ef8be03a3c93c3dcefc0f810ba851fe788332ec10a243580ad7442e21a7d7c0463baf803c6897886071aeea69cbdfd5eed0bc1940da9cea4017f7fcf17b2c25177ebd6a8e9c91ef68ce5f356386d2d66c4d118708c097a5cde3c59e939920f8b9e9b950a905ff4099c1319cd07b0bce12d5171a9b0958315489fd200e498a3f4888899c6d5edc7bef03a8572708ff1a25f011eb86a5cf18322e009b0206dccaed059a89ca9b69fbf7c3e30929a9d87943a4ba5e4c81f4d4c9a1489c94eba20e57d5d2f0266185edc7ff292b99cadc43c43af7ae364b3a42178fd1176cb7259a1ee485871bab42dfe255a4b127211831ae24c1f2976b0872459813f5ca04750c384eefbce0da48ae1a4ab6deb87085fab8e87684b76a51a158855dd5912f7a88e806e7fffc26ba0f80bbe65086bb15e72226eb3cb535a8cc3043f720b7f9a76fe7923fe2810b55524026799bac74d7b98c0904ef6a50bac30b9cc8f89955f8d136c0ca4995f26c6436b025c04a8fb12e77fe742b962bdc447f0959233a2629799c441cc993f7790c208232c226e3d4e475edecb0c8cf7056eb40b35b2efab1492cd8c115c171d20671e7f94cbe2987efe03e9f402c08dfb1436e38ab73e4545ccb507585b351c77059f3c68ee0a5f4cf390e1655defb4c610da4c3bf5d311267f3da3f650912d50aafc4d4921e0814b8d5a6f243c99cad3145e326589d990223693c4e246709f720da817c22dda18f89261145c19a873fb51cf82486fe3cb8b6109182acae07d33d51932bb68a3befa2ef826cf4e9462d69943dc01ec88ee323f33b92062b0af4ff7c2b890ac62cd7159c153abc330716c26d7bf86d1d37a174cd6730b6c72db7f2df5d2303bb6aedd4ba45f5952ffa7992eedfe0451059ac079b4882cb0a0dbc374ca5b5aefcc435e46bf2de0dd1666142e19cbd4b261f424c533a75df07a90f3cf5dd9ed9bceb90db2cc731d34128e34b4940b7b2d067376e6a25797faf43c708937985de1abb3baba99d566daa75670b6d3a50254b0abbeb58b5ba29453ae33d1fa08d989d6c3e60037601f",
"6f8a76d9587fa93b25e384cde8311a84e5ae6fca8bd46354949353fc07c779c5",
"6dd4fdf7fe8582635559d1602e89239df518f4495306548964bd0b5eccaec1c4",
"505a269e57824be55f6936360d5652a112c06c38de6635fa4c6a954f028b19ab",
"dc96de47b8876924bdcce08f6a8105e36b90bf2a7ec21ec581dee9f3062bb43b",
1984075,
);
test(
"53b6c05215001d094d1e4269e05d98bab5b102c557df1e06997aa9e6b45228dccef00346525046bd2fee620d327d755dbf64d7f6631ebcdf6c8f6b5e148791981d51b630bee56b9ab69a18bda51419696433d83ca7921f844884d7d8b8d3e945ef2d59d833aeec84d405b27e6a857794711a5a177ed0d36ac7dfaad9af9d66c3ccfb861fb4ec2e70f2bf2fd9e3022874706c17e21698a9c3f8a3714062b7168c536cf01217704061a1eea3444db53625c8544bd8efc3bf981c3cb76e9e7a4c3784c889ac94b7ed1c6c5f72b847863f5a07b1afafbbb34099cc74d649c3fbe9c7f7032da8a144be54eb10bcd9f323a796d217b9bb38722ca1c967da61597e28122b976eca99e84b2481c73dd71d19b49dda5a510c70fd881eb25fca8df829d523b384cf780c8be5675e2ba804e197180b1d26f44f0ab5c6945593d6f00ab17427df6f15eb61cee22a4c467baccd8c5ad984d7bddb4f8f61e342af9d80674d722ae648279c2f8be70af375f15d704281d3f11ec20b8eb494479bd7de2358237db6bd17e65535bcc4b0b2f869c328c180460c279d5e76b4994789d17164e4c7ddff22eca959a939398524a927adf71704cfa973e68da45757b6bfd7762cdb7dd37aa51467d74973d81063a4e3338858c62bfd84d71493ddeb00e93e6707ace0641c695a20b6785f537cf4a38ce1a92b8a453a53ca9c691c7c26182833c9336005254d789798509ef57ad379206c70e8c3d2dec0c63644b6a994aae7bd9b37736be8384dacc75cd538fc508ad277178e59c194589c52556d69173812af631736572278a2bbc234d56c6260b45c111d94c4d8599169dea6ca7dc42942fa1cbc0787ec7e99156a28b7e76f7be17e6a9906fef8996e550b1ecb5cdd79f6e35c955cd23e225bac424a3e2949222d6cfdd26a18f623ae6f12e80c93c082f5af8049067906e06bd6c4c8d314b9e86f6242a80d7fc04960501e71215d06ead949530a7dfeef07a3ec7d5e60ad838fac4653b063cb94db33accc5e617d0c4583ebe13c5bad45f3f5ebf89e8aa5eb4ca37a030593be406c9ecf323ccbac9fb4601df6059cf2b68312c8d6188d9b68bb80391caf4519f3c87e30be936a8d60b839ef72e9c0d8ef70236b0247aa2111775d0472c09e2a0a0f66321cf8b8ceaf4ff2459eda9ad086710c7d251f513006e226d6d2e596077a0c20c5f265db081cbbe1e684cffdc101c64122a1a3570c6700f39a5bd84814e057c7f583d3d26749ead3605be0efd082bcfbb942b6594d960ced7094fd846dab043e7c2843dd4c1d2897c693a320ef333a648875c2b7cefce9157154725fafb615574b4f9d26d1b6d0b26c06d8db338fb5a625e8e54410e4123b57b829b58c22f51a8c13d3130449f17a419b34ebc3e7126b25a06074ecf37621e6091c0bcab3e6977d968081186ad8b0f810e3727b8c1b300d38c597613feb7da938cec8db8fcc3d65465f4a21a00e76ec82e52b487537b77f1f29857f087b44065d7a7fce12d1eec4bc9e3be27c939e952011aaa3c2c5776662cbc109eb3acff0f011ddf7f5daf9eaaa145def628cde1a43728296ff5de99584ec3ee11a9caac352daca0a48538d14203cb5c94d4fa204372257021ffb88f3ab20c649187588033b3af6ae22219863b77989cf3abd15e83c0a959c1fc9117c98784d89dbbf2b3b1cf7c0473d66c156ff7d050c1856b3cde628d8ad6a155ecce4eba502657519f208f84353063dd90774b8ce763372d833cd04cb4524df0e43c62d235e254a20f2cd30b2faca5dc26d67014604d79f80f4b7c56322c5719feda03725a10efb88b398437445e55d7b29dc9d9f23fa0df236d0184085954c6e088ca23af2f86368c32fb7cd332b4db5586ea17f554d9f544f5609e8cef0649b5feb48e3bfb16b9b584db98441135bc8781d17a22b3c87181c1e88",
"b6c81e5676e663f6099af4bccc6581346bcef3e5101c2be5b7f88c2138126b6c",
"50920f3d5301612bdf629fce8dc1102b7d063da89a5524441f732702dea35842",
"89eccb638ba9d300fdd97a5688654f63d2aeb75abd697af9d1d1c6ae5d7d26ac",
"1e7ced5b56c2ff576b7c8d1785b425e4485ced977bc5c4e538e7c5c0584ed288",
1926467,
);
test(
"fea0597851550364fa6f1f84e1f3200b947e560d8813d99c241b156b0671ba7d4282bb0d3120679108af6d35ff9508bd073b915e7a1d340c34866821862386d00b6cfc49e0cd3dfd20d57b21290b480ffbb16dae66b5342faa85b81d6732fd8a39449cbcb5383d38117741e07dce5b8ffc7e3c23900dac47a70256a26e064b409d441bfa31623141a516839c3d5844db9095358df83b548a3c99d7a554a05f343675fc4988c952c369873de30979d23b2635fb33cd2149e4399d8e63d97cf30ebb7d51d95414939f7cb59398fb5bad7f9167f75f2b3a58d37d67d02f3199fe9812b15085411c1cba3dbbef8e35298e2a4f47821c576d6bfac422c1d2e0531c4062cf47b3e8c7ce65f4ea164fe64c60925f05c7ac817696a199e548aedb83bda51c2378137e8d50e45f44a6dec5f72e57073c2f7c4baff0e29e126ac1fe46083869ebf11cc8882a0026029fbe0132cf467368a9f146fca65c2b2fc3a207c0fb0a3248a5336193e9beaf9f295ec054e306e7a2578da66f1304a408724c63b1d99a2bbc6f02f70d56f321e1cc0e9e6b03dc153d9e92dee74b076b8a601fd10565fda9808f657b7ee99332dec0fc99a3b305cfdd6b75b3c8233a60c9fb5e9cd65fa63d10092fa719a9aac13df4dbd1e6fd2df972ce390fa5121097400bc78bfe0585de549602efb66fcdd51605d22613f4e330649eb21c71aa8b11733be221efb6d48a0a7c2cc5e334eede7f23bea7baa2fb2d7b230bc8971174a9adb7e3eb4faea466c78005f654e24782466af155a137d637ba33448eeef4fb297a861c3b2bb42cd9e28cc35c0cd3cb57b570c99db65c9b6c7dc321991b29d9362eda56e1a347f13027367d9f29511bab14a3d38a4cb2bc13b16e4cf0d8f9cdd9271573f9f95b60d429e72547740061de74b4956efcc9fe0f3492b1c59c4535e6d6d63334a2929a12e80c555d3280aa190edcd83be4da8930c21c302e33348aa3e0072a551b80b5842b06c3a08c4a14ae9554f8a61497f40288634d969830b2f3824425b11228adc9faa055d5425371e21fd7dac9611acf9e881ebbc7e8dec3c3a4b4c89de888e58df5c5bded2808c91b2f8a2307e335a05465aecce38f00261d2f262942cea01e903240b1f15cca9af24bd115da73d71acce5aa9bb87179ae4f1f1167afeb103740a4a2512d4ad4e9698ce31d0a1d4cc6045e884408f564a01d9616db0452a7df3145aee000ce2c8b472bcbac63b142beb264c868a859effa454b83933ee81dfd7c4c841a1c5c00a4f811011ece782e5efb00407c7f55b4d1f01a8b9776e3c72396f1745b3b8b8c85bf281d6d43d16b631b8f780e041d504f8461711db8418eff66f34f19e4f65dd75a91752dbc21fcc62cf82fd15333dcf22adf55657999b07e0fa31372db80c6adc5fe5d3185ec2c6ebf17ed78fc0eeeaa3c24ffad20bba6a187726b322b1c4ef3c9d816c985c68cce3ed4559d5feeec12b856abb660cf78ddd2669dfb57f5a56f2bf5ab7f735fe55527f60685285318ba71caf56386218b97b978234d00bf7c2269a8c37cd1547601e1299a59d094a9ff748b57547a7a801452a1014f113ed91696a2659302db83813643cacf47bf1db5eb4fc90695310ef068a997a5157101859afb04317c9a2a6cc6de0285e22b5931a4028e7e03238d2622ab30de3d0124e94c59b72247a2830e93cc408ca98c75091839aa2d717f6d5ddca9282360cc7652261937a2cf47357a1ffdd0a814699c449bcfddf0162c2cad115ecac70bb2b7dcf484da9034c454d1267c5f06634de66705a8180c36ef553b8d3a405898052368203a08b6e23e2aa1aee7d2d30bc3802e48923ee2d29f77f1533c4ac2a61b14d5c9564582d2aa3dfe7f8d7af42344270c960da377f4db95def703bff359b74789dfb8624115cb41e896f9184327c7e0753e24b77f4d1d326c7b13c4d122abf430098ec1e5c9ad35b86b3688a32c5fbf203cefeb4cf3f929d689e2e193f570f219126f01165ba1c44689fd236662803020c7237c9da1d031d71786a59124f48eb6b601a5593885f0d8a32dcb9616e336dab7fc4db2d42958670604ffb76e27f5b8adf66c6f66",
"82d2dadf5e7b00fe9332c9c8260dbcc290cbfcb05045acfe020074f6f9c86344",
"cd473d1f6ed1a6b8966e94782dab630b796d429db046762848c673a799afc830",
"b5276f1c56f17be7f49d6cd76decab4fb42f8909d02c4a7a5bc271f7563dbf68",
"dd8046e7347648d685913f0e160714e9fb79d5caf7a535f6ef28a07b92ac963b",
2017232,
);
test(
"ef5ba0f749eac3dba0bdeb602279382971e858521b2fccfaef96bc67531061ae411ed6f0e50212925697dfddf5a0eccd3bd53a1082d3590cd91404650f520f26d1243c9a3bd79b4f3d2c8d2db2c4e4c9a441063adde121cbfd2be8ec08de550149f594cc1f3a17dc9d96ea0b919aafce9495caaac0c67434f924d9b94c0e2a5a5de8d687fd6d5576befdfc18c7c73dfa82f5417353b8933bbd1604c96b88947461fa3fdf46a251c1de3d4e7dbcb64748559775eb49f7cc17d76346cdb3f03fb798bc7569f405ec0a38755376afc891fa343ee4562095410c3abc2d4b3c07775dc0f5c0cfcdfa7feb3d9d7ae0662b6251a48cf54e3b80fcafbca3d0546057563cce4959be9094081776d535f10136143304d121cb3f383c006b1e969e6ae06ddef20065dcc8d1164a3f2bc965ddcb859774a0a8756c5efab7b8c5621b7a2683961dd0e2d66ebaf4087037a98f9c25ce3af778b79f78bd750609a7306fc7cd978169752918d32a48195eab0001f97d69f3134d82147fdf593c1305b895b830d19df18ddf057ec7ae5316616aa8fa722026b554b56277ad9a39ea7461d4aa2fa470a1d10410938d258925bda689e3d91455d082c6cc116d068fbb041d2fa12d9f98ee298ff7c7126ce31840e3c6a812738e13a4e67fe868ffadf29bc3de93d1815cc58e2837432a56c76680919caf86335d1779fe6233730ebe2062ff97a0d7a2361d7ad223a079b46af26d9a27a04b543ceaeca532cbcf41959e052c0227751e6cc359c95375c0a8285d5f49da8a6f8ee30621a53ac50925a5adf9f4c7c4661ca91f796ddddcbc35112ea764f0e1f30ac09aa07575611b4693769cf3f6bb7d720cece80b367e7626a51cec28baf74408cb895b4b8dd3377fa66d851123466d4feba84dbb3d0352f74fb42e0cc3527d542b227cbe322fa9aaa9acac233c852cd9a0cf5e8b2de0201aa0cd5e1331dfcda37f49edfde0d0d160c105f9a9a103a83c8d834bb30e64e938e0888de74dcf3708912d264f0ee879ec5ecef7d519139c692a4eef4511680958364dfde76530a3b025dc8b0b38f108baa90ef38e6c865ff220ff8b758bc3703f42f02f024df055e123b7031b9eac43d5586e4e56855c3f6608c07def381fd6e362f55dc9aac415ffd3b7cc76e09b674d79a1d6083ff14bad2b3486c767c327cfa2fdbe82c20ecef086a0f8283e0e097ee8daac5d3e26ed1e20a1ee323de8a9c3c3b721d7f8519d37ddd1d652a5a2f1b8dd2df7567ce818d86854c046637385eb7cb109edf2d657f2e53ff7c262556938a67d81e856859cf9c03f19ffad40c786abd410ac8017baaa4aff0b0ec9d58141c792dac57fe001b2c8567d2add35eb6c296de559ea8a1c60bd0be8e1c84bb7729d5d220d563c7f50d05832ad7c7d372d4b379e691f76d1abaeca24e2051a2caba32d8637f99260fd35d26a916ee51c23a9d7c6763e9b20c29eb96325e2492710ad980c298405c65b985fcd3b5c39faff903c828ab6d503518ac7a007c218965178aee7a4e498d18386de315d29cc47d5ac55516bebb695883482032331abbb5d34bb50ba6fad5a5d04f052e175a2a15e2f97b3708fbb74f98a6ef890a3c5d378083c979511ac19746711e1ec21699b8f35b11f9331be5e05aa810a81a58e739aacdddc7af9bc166576fe190b6ce6068876654783cc7c61ab7219a8ffb41870802397b88ade1be45bec664166ad84bc6f220a8757e0429317a38f6f12e445a3c42153b6daab1bc634d2f37ffb79584f679acc236ca57f6eed67d52daa829b03d5b736588a1b8ad39a701ff1010a35f51ebf9df71bbd1319c8b4a787e932da697a4d768ca2eb5a302881e054edf3f939f35c7e49fbba7c7c4d0086352c113db982fb03920ba47aec5841d719f844905a8f854ef7e8d56db90c53fc27a4b67e738a845f5776936370ea9297abcf4f0910e58d5cb575c8858affd438b9424a0a6711178dcee3e95b09bf1614201547f0c3f8c31691df62506ee310e72a4e6c509eed692643eb720ce99378242634f0f0eba3551f226c07ad85771ce766ab44a5b7ad833f32223ba47d4a0ebcaddb9c424cf322a8ce18cfa6e0499c9bdf27099fa11d2f826f3e1d767d28a53b1593712ce571c3daddd4b2ac116767fd4c5f6a448d927364e7af07ef01c8e901542e1d71c45128810e44d569fde355e7",
"b917d264bcef07402a7d292a4239dd9f655c4c8542e8836f6b2906b6ab47cc22",
"018559faf93f9ea06fe27dd435a5f24c7377380b0726fd2131e49f8a7381e94c",
"056b45c6a93570ebb345d2ab89a85d0191787a8ee6a91b52b1e04a1558c029f1",
"8d23a8b51eb7c738b4e6028ef43cbec3287ac96a1297bcff8f3b88b7c2b059d5",
1966223,
);
test(
"8485ba6b12bbabbcff7a44bff9f1e308a1776e256b4f15fb0f30f596a10db307f9ffb2007006430ee984050525b2cb43c0993c88f2834f462c793dc64aade4a452342c898320e237805b63caa35b4810b75f81052aebd31a08842b86aa36d2283d2032e334dbaf76dbcc67624b507b3fbf466c2b97ff73f96f3db6da969d042a79da16208f8238d02f7aeb40fe3244b30d8fc0182a32b5970838c2ddc80978e142af2a7f2cc6c6a8dabe0b30067485b9970414831475962261ae53559a5fc54e72817a77141689c56062df0658781ae3da7ffdea443468167a07a7e93e18c6f53fcef37c318e1a02210bb018edf30ac7515fa57b838943c0f2282f48a2561468ff952ee778920f98a9b19351f9fb519ca7e2d24addf4378adffc52ca71722f99dc3097fbbaf138707c50861ca01a70f9f1ed4c6559ab16006b77a84cf4eafaa2d734f5127ff73df36b2d9c665909f60fc89cae8008ce93b3bfa13427572cbf95405596b88c7d9c05478a501e6a71bb646c25155fdae5dc959e51461d4de448659eb43a03e72f378f22ecca834e410acb4293fa453cf213396ebe203ad718efc0f25c3cd6afb844300cbb61fbd64b4dd28eb6cc299a494c28416a0d3d1b8a493a55285b8c37b789d515ef80696148c1935aa46f0b6f80b3bd41decb6d82db43f58a6dac1870ac8895c2c281958e465dd8bf02c031f0e48e91fd1c7eb6e85453292c48771b51ed857e33eb8fa4b3f49df6704d8eba1c319bc675f3d9a64d192aadfad6ec755af690bc595bb4f994bd64bb5c224c24819a24a0818747d019fb45234d950c5f1d2514525a06d528b9c09b9584a2a9413b1f3bad0cbd42ee9a8a3361153323fc5d7571197a9ef5c68d485a9d9f24a97ea79f5fb44d4b231325651414b12b12bdf4b82ed7f350109130c9de47ff541fd0aafca8370a78b844d7d9e1776f5731efcde4e7dfebc4513b59e00c6f2ea02ec05cb6abecfe104d2b0c5a8e57f8698590c5857acde90b60b631eddd1185824535e7aebc9ebf1038e6645a2ef0b50e46caee5cff23d0f264660610bb5f2174e3f34e274d8af1d97b019962e6e22cfb2c3c317982cedfaf491d9936f32bb16d5fc9b99412ae1172e43f7fbc46cbf0495572a631fc9cb91b3560ec40642b8912d6a110a960943476fdf04a3d24a9a5e75feea56d638e5e06ae7fcd204d165b3fe713769e3db9be850228c36571d5e8b4e2c77802cfbc78d206d106bcde289923fc9cc8032a585de8b35a20527eb8c51e5d18aa52b7c8f54da6803ca8918a18f2371c5a4f8d64e1181a27dc6cc3968d1ec4ec5a2b1d785f37b70b0285884a69cccf743c55c8828965f73885e1e242103eaaf921d9d13513641b7098accc325639a56e09d0a218223284239d4395b78f66067931d527665ec88505ebcb2adee9adc2000a487d4054a73b1fa49d4afc8d54763f7f5eb6e037d776640b69b92cc85571788f9cd190b2116106acd6bee16d1b9c348c6852ecfe778255a92957ee8b777777716a2b6ec5ea745595bfd6a2f9086ff1c76e5f20a45bc035bae8e28ad035a6c896864f2f9308b1a97ee0d55e20950c3154dd71170f93cbc57a3055553cd48fadb555f1898955ad6ee2b64ed5a97fd392da46995cd96c22e35fb454c9422d8edd35f7413f4fd4a908fcedad250b7d99fa099eca10a5a45b5c20c10be18137dc4ad06f6dacbef7716e44b0c67611d6d31499dd3e4ce3f5f7cc14ac02f144aa9505e5a3ea68baa211ed85ce2f5d64776a660b37111b3954a35184586f54dd8cd41a323d7254f28fb915be987577dabd326f367ce41a86ec425fcc3ed727e5133f22f6166da945c6efd1e22b882b31639b2533090fc88952ed60e6566118ad7a23ec3de3b2faf7b74fb59a99bb9b804114f3302be893b91a51c449e2d2a0a583c710de85e95fccf8fcd9b41150727d412a0bda7d646b28e1b32cb359502cf7c7343b4dd5d8cba9632fc482e38b9340efcdfc232088d48587043d9b345e9a3fb7281f00a89555b664f07f47bb7930d50d3189ee25d611a1d4bee675c9ad9e388be51f67d84365639af11594a1f1737197150568daf0ae6038cb6efaeceadad067a7efb1e0663119051ba92f76dd5089927492a694dfb5b951b6d7afe51d32ef6c7c956cd3bf19d3a53033800fb62c60f5892f0b628930780c7332c1d8f1726348122f3a1966555c3732397b1d6994e1c9fb9013d6eb4f8c5ec4eb8afecc6b17aef75fb28631a2aca4f87912f51db46382614fe73da18a6e624d7206444e8e03d28bf289c9c5b6c163ddbfb9310481d86d692271081e5202323ee6553b8c9be94e140563c2900198d8a23751b76a1e1c7006e8c7c41e5b147d",
"037b5bda8b6d9deccf0ae09c3095598bb91dbcf87ff61a447799161444f690c8",
"c4e1c78612dfc921bbae49555983c7864e14a8b26267ce7564ab5efa59cb2878",
"c9e58907967f4f9c897adcfb0f8178891821f8b60e0e446c66a3a46f7e780285",
"048ff4fc551455e6f3dc792041f466fb2c58593b54119e80486418c281ea2fa1",
1909909,
);
test(
"3401683eb417146f38963c6dfd678d93d5fb4f3e1fa11526fcbb484c3cf2b79dbd1a220da3393a80a45debda44a839efcf5c66e94875c2dd3b987b5b6028bddb6ff3fa0b57b5ed9231452ba54be8a0dbf2b93bd973b5883c4c4d0a7f2a42b14f25e988515e6f1f306b9eb1d457e6162ce02ec46edf04a334cd4b75dc2210fdafd316dbe39a6f45a4e38330ec43ab366baf3b2558062bf7f1a9c7f145ebae00bab4346d2e685228c5865f1cd33060d90ad6721f37982df35f064bc9814f614e548f62d784d0c025d4ee37efb59bebca5ad6741770373c06ad176179f48a46e279e56cd5e801ce29aa2b78e040dc53d9be391abc4cc2fbee567088de723d6288d7737ad3b82fd9489fdf151fca8135af88b05a4ed431408361e0ed7c52ba6b0680ada3189a470e23b71993e059592e9efc32817158f7a94b62652d4cfba4f700436e01e83e5a99a1a43af351324cd3fff7f90eabd805feb9f41124e533761a4f49c6792c50c2611d2134aa249bb75094d9b0e95b4eefd31771025981000a3df1f875b1b04a4ae161c6a2540c5a21b5e5d134192f4d99acbaf58fc1d2c7ea440266db66b41efa328565205b65a2653cdb4a316a133b0dcb6cedf79f2fde9c0fd8bbfb1946f60cd426c677a2cdc4a79b267d70144d9c5a98652803edc3bde7a17c97e0e9ab5ef96e283045b6a9db1ad3ada916e34244bf87c4a8d468120df738fdd2a827530484b3e64f4b0baf1efe2e3d55b69418d55188e57521481bc0cdc763e4ab4a2bc3b5de426f6dd2a2977d08ff2929a8919c3345c2684e18b25fee6eadd5ee0444c2316955cbc7ec5844767ac1ea8ba347ba22d1ff4ba6b40ec36c3dfa6b488b6a3372ddeff0917d1ef166ed94dad6fe46ef3947ec1185e2a0701d537be274ff948534a8072f8e7215ecef72a41eb17b043422330b9555254d797b264baebb805f26d7a4e121f7bfd37517026761642ec12120db610a112ef527d68865ad89d8ac5ef053c99fd224cc3c2f9ee2edf23e342ab3891d5d4aca849530cf3514139dec39527dba24ca3db8ce158512a2b514eaf2bd052a5c9b3fc7217db1d6da409c172bfc60591401b32f1f51962b21227ea259dacc18be6fbb4f2f65d845c8d6445c63d9789714bf6cb2ef8ad6c5ac26556b3d23566e9e9c37a490290b8a452c25bdd7e62b0ffdfc80e3786a728d7ea5f44aae7ecd7a696a6ede1928a0e46f29b4e5c85ce1e9e26b40f267dc9706550883e3a331ccc9cd704b26341419e605365069e39ee732a047fc40406aa69d306439e8d8095e12f371f61f161b46e1b4ca3ae969daef4ba39a0c938de34b1056fea27711602bf17696bf7b3763f9e70f35a8530e004b398bd950cb1ca423abb48c8f91d469cc776cf2a5feb9c888f6aa76615402c1f401acbca4192b5f6973ab5b324cda5a8c52e1e0edb4e1b94fbc5a6782db4604ae2b01f6417e9d0d9225c0f49d4a3a4f59ff87cba68a95941ef6c4c55643bd45ff7eecb75c12b23d223dafe1fa595be4b7c1d439f126dea09f9937feff9ac6decc90f1171fd47a657a8b6ef3032f486b32173cdd8ba7f902d8c80e60f9b4da5c01b613cc6ab4205854a95b1e9f36dd66a76dbbe0fe8bc97028aff8da8e8e2846867037e35c18ce7cf9046294940b89ddebb4c8963b17f6e43552db85ce0ecf2890dc17f49c858670606a3eba4fe06f90f342794f50e52018594ec19e6a47583510fa7c59ff6a498d41335c60006c1f5f59fe84d73559bc6985f6869a6c0e6929c3901f72314b66df22b3c540a8e7b3a2db9d61060e042cf0cd1277297d7b549bd9aadcc2cccd3bde7abc546a8b47d3ee427aae9be849d4e7b0ea5fdb23eef1bec230a6d4961d229b4d4ab8d92f75df87b7672e272edae1709db31424f0d2afb809c5f696898a944694f6e5e42c497fd67581d9f768ddeee4d5ad2560662da603f7e3ae8f6133ed58d2724eaf8f729248b11f42e99cac82625970af71524545f07b13a10cc7dea21899fea71e45853d828fd351834ad3e12fcc33f6bb3fca11e73f012a3631e4aad93b8a091cfa0bfa3f0178228de9ef9e5cf84d1e0cfce439e0cb86b4b19b7580a83ed0eb07271407f6c8c336f461989d901ecda9d2dbf26e4f724c6bbfbfcda49048f7bdef5e062cc3dc600b94a833408c9bc98ea06d68435e719e2c5b13fd6708ad69a92049159bece630b8da3cad69c9017fd0e7b31b676362194f0d2f0a0c48c3a3a74325a9381d811a2380aaedee67226ac2f2839b5b93a77615ca9c1645a66c9cd44a5813610587eb93a5c0d15653d76b2bb7db5207f5a2c528667a024d2ece1c1fa337a61398a783f2785f8709c307fab83a51d246a3da9de4084262027045f3498ca561c41e373e0987ec2d69cad17f11677a663e14b600a4b5fc22ba967eac838b0ab741b75482503f81a4fd8e5d22a358f6268f976bf32dc87ffe5cf53e04cac02999ac1b01831cc4501d695d8c1bb71245933e994682d13be2e8fc1ab3cc7a",
"ee7fea6125131c1ef85ae2e02099d97a312e0274fc2e8daaad90468a12893ee0",
"67141c9a4eb517085e6f69510c2af038b5fd1e8a9839bb38a64ea16fd80cf6c6",
"2e41c9d38220c5472351c4457771aec372d6c9b175a339af8b0de5e483b9f4bd",
"b27a43a7a854e5b5cb82dd113e8212ab2d1d20e447ab2ac668948bff99d3d134",
1897015,
);
test(
"61d91c2cb6c51f6943e05c180f07fd83f1659d9d6dba2eedb34bb9cea72d865f16d1041ff034a307d33525f2c9cbf2f705d848596aee587680650c8b7ee47ecaf206da52940895df702397c7d62fdf504c67fead6c7d1e8d4b3efd66a1521b6f098d1ef3d736a4c4086e3d7390ff0d9db22e72226ebf88d66482ce056462a3d6f04e8cc05efdbb7808c1dcd8fdf998e897bf62af1f8588aab703bb83a22d08e82b35e32b08b0eeb82480c395689da89603649eb29d727cb82392b32edaf622c88c03ba841cc7070ce70c4cee6bf23f91825aa0895889523f907acede44b6f8e7d52c51ee88108e85442d0373a8afee9ca2802f27fe0dcbfb9f312afe9aacc01d12d4e3ceb91a08680bddcbe95f3871fada15deab96fe0ae5978d64c455e47e9b75a5b01be9b1b45bd062bd055eea5c865750374a3cdb77a6c880fb62dfda093283f5586c0ed63d1e056991748fe143466f6d2fb442e2ad390797f90bf46c36e35ca87ec2a6230cf0080caa335485eaa64766677d6b6677bf8d50540bf942ede603093fea16c14ecbd02da626afb0fc6667d7c0290c63f0ac34fecef58d9a0280f5a3346a3319862e871355d7047c7f5ed68a6bb6270e4972e14eb4dc03309510f022d7f0cd11bb471ed5aa217018e21a883630fed648eef25f5299c37d17c76479e715b065c2fba2b975321278eb2444497a217c49a139de95c1d1f5854d798b2da2ef55617de9e80b01fa8cbbccaeb472c6c763645e74a73a0c79b6e022d1003b7d7934ec2767b99e036d8464ba3c7a32b9657281850999535f0179d7211bacb9a9512d39fb05e91c74d0d71cc1b7d3b0d8936499be5a4e8f0798539c7344073bad3575a5602df7dc7bbb8a11b1bfe0a63c2894d409c74e0ebd1a98e77defd3112608d0a39aaebbbaf33a95ee638af8746ef9e75ebbc1132f9a98c0c660653c34b6aec8362c490acb3beb26f74d54a28adddd4c499b74dc59ba1cd553e2757b9a74c701d1a83ce0894d034526ff696810bb25da75d4397048dab03f976a11ac81716c1e4155003f0a91a58238a8642ad9927ce53a2d8cbb8ff143e57792e833e4e70f322cfe5e8756be7631df5c5a6c9754734912f3830b38c5a751b7a2cc42b803a37c171753d9183bc9048eb4bfdce4102e5c24e5b2645796aed7e23d998e2f81ba6d2783820d46c31e7385bc44bef605042cad643321b664878b2d87fff42bff80e231eacb2349ebdda5a2355366c9e08949b0bef928fcf7d593889c289529fc58f6c7f8c3fbd9e95d348dcd7ed386da420519ac62785dbfee9909760070163d0b84c8f785ea1f402d9e3243b33b8f5666797cdb6a7638b3ecea02c5b686826dff584257e4e182a3181a5b89495690270b163e0faaec5298df565e3cd06493b2def18fe59a509ea850826d931a13ae1b54fe0612a10ab79c6a1b9457c5dd8975b57d2abc72d979336531950b3d511fef096590d408cd63198be9dd7b52ecbfcfc1867f8f473c51a861b6bcb1307989f115880e4f760b5c10b1401b06421f94ec5540683bcc5eec53c2a1644ef5f4d82409674e6e0736189d135b65cd4824d2f81cec11a28f39c89bcb70caa2b206e4867172db67445df3df49edad0832759b81ee1f53945b7e68c41a783b0414c23fa61114a597fd6d4f4d0582aa1d104f0c84424938fd4985ff763ac7cbc3cf0ecb86a567b4eef0b2066e92ac1bf09ac4d009865d612a11f9169c2d43ba355a19bce0174dcb0ea6cf9551e51088b816be38c0f85defd088c76583b107b00561e82d7674fc544592b6fe72fb51cce354b69623a7c4d9938ab5184c87d740a241d667eb3ff2b331ad4f4ff8ce369e2bfeb183b7e619161b8a76011980d852494053f199b7da8ceffb7da6a068816a15f8903a672161e6276d73cd672cd20931bf68da165033dd975a879a28e4e90bb5f2087aecc93174ea2aad990e9463190c051523c73027325a6c667e0e8ad32f37504053fb0efe9c43f4e55253124fd79d2b5b452895fef0bb8059e973dd9942eaf3275dc3140d41ee82a4262436f2ebe10f3e73cfc75193c82bd9f24f0c16f04930e651fb0c2fae20721bdafb724d54c3f624145c513b5dd050f105b8160511ec79955075b777d5be23a86bb9278fab56ed564fa85d7c23a995becb589761b2f5d7f773580797e93924d6f0899e47f57dc35ae07a3d9423cdd31555518c9be510b2bc36db35e9c25f900f75c53f313ccd6b84baa932999c27ab6e347ac18706ffcc91ca823fddc48af7e49a61140e032e00347d51d0807470574953dabccbbd589a0f1dab7bce23dfaad7d894d897cb4e83ce508959691e995e082e4d44d7102495429df5bcba0e201d4263c5175d83ed1531ac206ce66969f5c6043cd7b638e8c67a9c98a6242d47e0f941d1956991a96e008c3fa9526b941a9796078cee88834e857bdeaaab3a8d4a717629450e0474486aed6f2b62650c3030f492df1bd91760860ed19074e8b9c7e253b63dd05b8399de2b4a0fcfbcf1499969e777c5f6d3f337047fa1802d4873c1ba17dcf93d0400515ceee00587b87b387a4960698f39ece4604126996e9dad7a20e25cbd9477cac28ffdacf061f1fdc19e3ffa9db8",
"6b536f96219488c8d63934b43c35dddb87f916356a07327387e8290915e39a52",
"c70653b3912e28b147f6c726e563798c90eb02eee034f3b8689f7f416b60cae3",
"441ebafdd34046af65c823abed216fa0272e1cb439f87ef1ac677565f552d75a",
"1c43ff5c2cc02cb596dec0296fbbb8e687ab63ba540054424e5e6b6c5c7e219e",
1934947,
);
test(
"3cf47bfba91d45c921bcc188c5f8895d051b65e81cb3b8eefeb9713702e815ea8791ab76be7e90a6d59bdc99d6e653e3ada83fbd209375e0924c619dca0f7596d6d18b5a881f9f02f3f310b704f62d6d84baf79c42612fd0644917c628dac313fc95b6f3da602d8d527186e2dff109a944b939aa69bba10abd9d7398fe0146631e96b38807f26dbc51c904806eaff11fcf007b48d9fc08de733bb6fd7d46781751096206979aea67c2dfa27f3850c05b75e4f41a7304a71847cff1eb6173f555a7dcdae194f8a5038bfae48fadcde0cdd3379adb5307d18e9212d8ad62674e21ab61e794b514ec7766e091a625acdad84f981dab19f8b540568e254fee6d3124628fa952c2abc5397259b048a4392ae30a529de89dd7309ce11f8c1ee3df7a1255bb60d1be45452cb6a6c35497b3127084d3820968a884cbe6c875044d17e8ab173fcb447cfbcca4bd9fa6e9af175f0c8632fcd4488cbf035aa4d218d8b6fa7431f786969404b915522174be3463f7de6ad107edf60ecfc9f7cb857bde12cb37e0a14e9af6f86428f5531c323c3911b08e98077f7292a114287ae741b6342b814fd800f321f437f59d9f2f4d21b32a0507b626d2f436726e10aa9b4554ab426863264ad2d9009f2bbdfe5fe04108e645c06a550e3061d1b84178c6da1522e2f6dc5cf308ce0829600bf03a6d404dcd983fc05077d10b0fb4f0ddd3db7332f4fe7ce0bd9c6af6c9eb5bf399ac55ab897a418370685472831a60b2f5ff1845a1ffe868ce5eaa88ed123c030f0a24c0194765dc113180d2eb2b3267b0336ec1baa94e0133089730c2580b0a97b08302303daaeb878f9f9a9d178dc4892a125eedb5f384e351fce61a7cbc1134d36b254a4a3d9a40327d0e0a67ab1d28256f0340199da6e99ec8ea6ff2f645c771c76e56f35e1ec2521d9b7ab544365c705225ca8bbbafd3fc6af43481dd3d61ce6148d88f43b23b62fbcc90b18ae186c8c9f2b5bc4644d5cc0e2e04c3eb0fea6df38cf542cc14abeaee123c1718e3afc02d78edd04d1c022360891b2a8cb6b8f17f3f862a33236d172aa9cf3940c9ec4d0735d4da4400f500d650e93f293f38558d26f5cfc6a182748dd34bd4c0b5beffc26a7faae08f9776222eca8905e6db3f03bb3e299e20c205989e33c6fcad00eda3e65d0e2d37d92aec69a84731d2b5d1a0a2965dc627b09c529ba389bd38649555844105cf5b063c05ea709adddeba6c3df08c2521109e5d83363c4bd4a4af720c5a61bda81009f01a4d5211225c518f449d40a81da0a689eef64f602baf83b90c1b9d357f1379b69c41c936320ff15ef377242f46c71836156f7f77501f61818d7faa548c14b94a118dcac7f1c0e2188c15b47ca7b48c092c8629f6fc0c22c56ea38c5e54ba4d3241ddbec37b65bd38aef833c9f102fe513c1ff4a59c26ae4e7f434330e200925ce75f475d3eb1884a752852079acc67fa5cd5f855c2b8dd335efe8f98b6bb3b0c2fc529ad150763e562a24308895adc427de32a143b0602bd9fe44d290f2d65d70dcb5c1003f4779d6569e1816942ac1d0680bdf6e791056c8c4023a9f0deaa9b7b4e8a44398dd88c06e3f8aaf591a07a1fa5ec8d5853adb85632457e18aac93caea4cc86d8d4c3e21522b0c6922e9ec7dfdef65c0a8fe70ee221a60532686dc269c203c843b201b57a66627870f6ceb69d09450e178031bbd03f8c0b1b3ada1b146a9bd307c6329a97f9e184a4ee7beffeca483b80185b9263358fd6377502699f2e3dda7a83fe38e4e9a3f7d6907cd03e384977eda1c92bbd9d93c144daf3a1b69633ae4fbf153e1b60e169cd9a371d3223e57b561446265c2b9eb9c30c8bdcd78d213bdebc71d6ad4a6265f10b798bf29d09ec42007258b3e5064e0ee817901673fd17f75332824656db8dbb47a898ad5c7c36cb8e69f9588db9123a45473a92e4ace33d9aadc52f9fe316685b7e9d44f6ce0d098be2bc91ead3b34a291d690a8df94f06344b0e925a049f49d65d6eb668191601e150f05b787c0698fa505e0fa1e4b675456bb71add9460c549aea8691ef9533325fe96094df3892debd064f99293ba5e300589b436373c93f1e104d3aa904001d5bcbffbae627db493eae5d6edf5e6c752a0517a982437c18e3e96a317d3cf4ff75629590c2e29dc5d9d33424eb4ffb5ff8490f0c02b4bdea7367962db72ba148f91f8d49f72100ad9495f11361cd52f29693a0316e8797bbd5e9affca0f7a78b267f3145f4f37de2eaaf189ea7c484323a39aa29dc409a139b7542659732b20562ffa48bbd37a99f7de44fb12204de65984d3a648b19ef971983dfd805f04006961d6a99e7c525a27dac684de4f5da77980f5d91ed7da34b9a2fb5b543185782f2960c58a849255152ba6120799f6a1b90b7d8e0ce1d9162f8a6bb68f9a60f624d551353da2f475f9f6df759f85f68e042662a553fafbf07cc105822dccf8b800919018e7b317ecf465066016eec912f25b10858da0688331c9e31f55aa76b6e338d270d45aaab0be303eda173f0208126525637e1aa7096a330f0d8d5ea159fcb84a1c3517e4796c590bb335910266edf7beaa9eef08647bb35ad56d2b0c7ea064a94b2abea71187bd9ff587a92c0cdd78aa397e4f60bc3245c6f23320858daeb89006545114a52f6f530a51f111814e232f919d071ba3eda1cf826d3e60df4e402399ff91d19de9bec47284c37f9e0886afd303cf763067681aa845c105ea59f968f2b0e5491d18a8bfaff28b09c3e2d77038e2b4a5",
"fb00c9cdc9f928e39bd5c924b50e75e3810f2337c72380e7a170eabbfcc23bb7",
"764d574f338fb5d766924371e64c2bd5fddf224d4e74788c0175e720e0d354a6",
"38be38c47eb6419c28cac8f7b09871db03f2e6cfe7962a63a4e668b5d40b0349",
"329528545b00249b54ad38569122ce9db9fb5efe2ecbe43b915a4e28ce5cd431",
1944301,
);
}
}

122
cryptonight/src/util.rs Normal file
View file

@ -0,0 +1,122 @@
/// Extracts a fixed-size subarray from an array, slice, or vector of any type.
/// No copy is made.
///
/// # Parameters
/// - `array`: Input array, slice, or vector of values.
/// - `start`: Starting index of the subarray.
///
/// # Returns
/// A reference to a fixed-size subarray of type `[U; LEN]`.
///
/// # Panics
/// Panics if `start + LEN > array.as_ref().len()`.
#[inline]
pub(crate) fn subarray<T: AsRef<[U]> + ?Sized, U, const LEN: usize>(
array: &T,
start: usize,
) -> &[U; LEN] {
array.as_ref()[start..start + LEN].try_into().unwrap()
}
/// Creates a new fixed-size array copying the elements from the specified subarray
/// of a parent array, slice, or vector.
///
/// # Parameters
/// - `array`: Input array, slice, or vector of copyable values.
/// - `start`: Starting index of the subarray.
///
/// # Returns
/// A new fixed-size array of type `[u8; LEN]`.
///
/// # Panics
/// Panics if `start + LEN > array.as_ref().len()`.
#[inline]
pub(crate) fn subarray_copy<T: AsRef<[U]> + ?Sized, U: Copy, const LEN: usize>(
array: &T,
start: usize,
) -> [U; LEN] {
array.as_ref()[start..start + LEN].try_into().unwrap()
}
/// Extracts a mutable subarray from an array, slice, or vector of any type.
/// Changes to the subarray will be reflected in the original array.
///
/// # Parameters
/// - `array`: Input array, slice, or vector of values.
/// - `start`: Starting index of the subarray.
///
/// # Returns
/// A mutable reference to a fixed-size subarray of type `[U; LEN]`.
///
/// # Panics
/// Panics if `start + LEN > array.as_ref().len()`.
#[inline]
pub(crate) fn subarray_mut<T: AsMut<[U]> + ?Sized, U, const LEN: usize>(
array: &mut T,
start: usize,
) -> &mut [U; LEN] {
(&mut array.as_mut()[start..start + LEN])
.try_into()
.unwrap()
}
#[cfg(test)]
pub(crate) fn hex_to_array<const N: usize>(hex: &str) -> [u8; N] {
assert_eq!(
hex.len(),
N * 2,
"Hex string length must be twice the array size"
);
hex::decode(hex).unwrap().try_into().unwrap()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_subarray() {
let array = [1_u8, 2, 3, 4, 5];
let sub: &[u8; 3] = subarray(&array, 1);
assert_eq!(sub, &[2, 3, 4]);
assert!(std::ptr::eq(&array[1], &sub[0])); // same memory, not copy
}
#[test]
fn test_subarray_copy() {
let mut array = [1_u8, 2, 3, 4, 5];
let sub_copied: [u8; 3] = subarray_copy(&array, 1);
assert_eq!(sub_copied, [2, 3, 4]);
array[1] = 10;
assert_eq!(sub_copied, [2, 3, 4]); // copy, not affected
}
#[test]
fn test_subarray_mut() {
let mut array = [1_u8, 2, 3, 4, 5];
let sub: &mut [u8; 2] = subarray_mut(&mut array, 1);
assert_eq!(sub, &[2_u8, 3]);
sub[0] = 10;
assert_eq!(array, [1_u8, 10, 3, 4, 5]); // original array modified
}
#[test]
#[should_panic(expected = "range end index 4 out of range for slice of length 1")]
fn subarray_panic() {
let array = [1_u8];
let _: &[u8; 3] = subarray(&array, 1);
}
#[test]
#[should_panic(expected = "range end index 4 out of range for slice of length 1")]
fn subarray_copy_panic() {
let array = [1_u8];
let _: [u8; 3] = subarray_copy(&array, 1);
}
#[test]
#[should_panic(expected = "range end index 4 out of range for slice of length 1")]
fn subarray_mut_panic() {
let mut array = [1_u8];
let _: &mut [u8; 3] = subarray_mut(&mut array, 1);
}
}

View file

@ -6,12 +6,16 @@ This allows all workspace crates to share, and aids compile times.
If a 3rd party's crate/functions/types are small enough, it could be moved here to trim dependencies and allow easy modifications.
## Features
Code can be selectively used/compiled with cargo's `--feature` or `features = ["..."]`.
Modules can be selectively used/compiled with cargo's `--feature` or `features = ["..."]`.
All features on by default.
All features are off by default.
See [`Cargo.toml`](Cargo.toml)'s `[features]` table to see what features there are and what they enable.
Special non-module related features:
- `serde`: Enables serde implementations on applicable types
- `std`: Enables usage of `std`
## `#[no_std]`
Each modules documents whether it requires `std` or not.

View file

@ -20,10 +20,7 @@ fn test_cfg() -> AddressBookConfig {
}
}
fn make_fake_address_book(
numb_white: u32,
numb_gray: u32,
) -> AddressBook<TestNetZone<true, true, true>> {
fn make_fake_address_book(numb_white: u32, numb_gray: u32) -> AddressBook<TestNetZone<true>> {
let white_list = make_fake_peer_list(0, numb_white);
let gray_list = make_fake_peer_list(numb_white, numb_gray);

View file

@ -25,7 +25,7 @@ fn make_fake_peer(
pub(crate) fn make_fake_peer_list(
start_idx: u32,
numb_o_peers: u32,
) -> PeerList<TestNetZone<true, true, true>> {
) -> PeerList<TestNetZone<true>> {
let mut peer_list = Vec::with_capacity(numb_o_peers as usize);
for idx in start_idx..(start_idx + numb_o_peers) {
@ -35,9 +35,7 @@ pub(crate) fn make_fake_peer_list(
PeerList::new(peer_list)
}
fn make_fake_peer_list_with_random_pruning_seeds(
numb_o_peers: u32,
) -> PeerList<TestNetZone<true, true, true>> {
fn make_fake_peer_list_with_random_pruning_seeds(numb_o_peers: u32) -> PeerList<TestNetZone<true>> {
let mut r = rand::thread_rng();
let mut peer_list = Vec::with_capacity(numb_o_peers as usize);

View file

@ -79,9 +79,8 @@ mod tests {
let de_ser: DeserPeerDataV1<TestNetZoneAddr> = from_slice(&data).unwrap();
let white_list_2: PeerList<TestNetZone<true, true, true>> =
PeerList::new(de_ser.white_list);
let gray_list_2: PeerList<TestNetZone<true, true, true>> = PeerList::new(de_ser.gray_list);
let white_list_2: PeerList<TestNetZone<true>> = PeerList::new(de_ser.white_list);
let gray_list_2: PeerList<TestNetZone<true>> = PeerList::new(de_ser.gray_list);
assert_eq!(white_list.peers.len(), white_list_2.peers.len());
assert_eq!(gray_list.peers.len(), gray_list_2.peers.len());

View file

@ -89,6 +89,7 @@ pub use protocol::*;
use services::*;
//re-export
pub use cuprate_helper::network::Network;
pub use cuprate_wire::CoreSyncData;
/// The direction of a connection.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
@ -139,21 +140,11 @@ pub trait NetZoneAddress:
pub trait NetworkZone: Clone + Copy + Send + 'static {
/// The network name.
const NAME: &'static str;
/// Allow syncing over this network.
///
/// Not recommended for anonymity networks.
const ALLOW_SYNC: bool;
/// Enable dandelion++ for this network.
///
/// This is unneeded on anonymity networks.
const DANDELION_PP: bool;
/// Check if our node ID matches the incoming peers node ID for this network.
///
/// This has privacy implications on an anonymity network if true so should be set
/// to false.
const CHECK_NODE_ID: bool;
/// Fixed seed nodes for this network.
const SEEDS: &'static [Self::Addr];
/// The address type of this network.
type Addr: NetZoneAddress;

View file

@ -1,5 +1,5 @@
use std::{
net::{IpAddr, Ipv4Addr, SocketAddr},
net::{IpAddr, SocketAddr},
pin::Pin,
task::{Context, Poll},
};
@ -45,26 +45,10 @@ pub struct ClearNetServerCfg {
#[derive(Clone, Copy)]
pub enum ClearNet {}
const fn ip_v4(a: u8, b: u8, c: u8, d: u8, port: u16) -> SocketAddr {
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(a, b, c, d)), port)
}
#[async_trait::async_trait]
impl NetworkZone for ClearNet {
const NAME: &'static str = "ClearNet";
const SEEDS: &'static [Self::Addr] = &[
ip_v4(176, 9, 0, 187, 18080),
ip_v4(88, 198, 163, 90, 18080),
ip_v4(66, 85, 74, 134, 18080),
ip_v4(51, 79, 173, 165, 18080),
ip_v4(192, 99, 8, 110, 18080),
ip_v4(37, 187, 74, 171, 18080),
ip_v4(77, 172, 183, 193, 18080),
];
const ALLOW_SYNC: bool = true;
const DANDELION_PP: bool = true;
const CHECK_NODE_ID: bool = true;
type Addr = SocketAddr;

View file

@ -47,9 +47,6 @@ pub enum FragNet {}
#[async_trait::async_trait]
impl NetworkZone for FragNet {
const NAME: &'static str = "FragNet";
const SEEDS: &'static [Self::Addr] = &[];
const ALLOW_SYNC: bool = true;
const DANDELION_PP: bool = true;
const CHECK_NODE_ID: bool = true;
type Addr = SocketAddr;

View file

@ -44,10 +44,10 @@ async fn handshake_cuprate_to_cuprate() {
our_basic_node_data_2.peer_id = 2344;
let mut handshaker_1 =
HandshakerBuilder::<TestNetZone<true, true, true>>::new(our_basic_node_data_1).build();
HandshakerBuilder::<TestNetZone<true>>::new(our_basic_node_data_1).build();
let mut handshaker_2 =
HandshakerBuilder::<TestNetZone<true, true, true>>::new(our_basic_node_data_2).build();
HandshakerBuilder::<TestNetZone<true>>::new(our_basic_node_data_2).build();
let (p1, p2) = duplex(50_000);

View file

@ -1,6 +1,6 @@
//! # Block Downloader
//!
//! This module contains the [`BlockDownloader`], which finds a chain to
//! This module contains the block downloader, which finds a chain to
//! download from our connected peers and downloads it. See the actual
//! `struct` documentation for implementation details.
//!

View file

@ -414,7 +414,7 @@ mod tests {
#[tokio::test]
async fn tx_broadcast_direction_correct() {
let (mut brcst, outbound_mkr, inbound_mkr) =
init_broadcast_channels::<TestNetZone<true, true, true>>(TEST_CONFIG);
init_broadcast_channels::<TestNetZone<true>>(TEST_CONFIG);
let mut outbound_stream = pin!(outbound_mkr(InternalPeerID::Unknown(1)));
let mut inbound_stream = pin!(inbound_mkr(InternalPeerID::Unknown(1)));
@ -473,7 +473,7 @@ mod tests {
#[tokio::test]
async fn block_broadcast_sent_to_all() {
let (mut brcst, outbound_mkr, inbound_mkr) =
init_broadcast_channels::<TestNetZone<true, true, true>>(TEST_CONFIG);
init_broadcast_channels::<TestNetZone<true>>(TEST_CONFIG);
let mut outbound_stream = pin!(outbound_mkr(InternalPeerID::Unknown(1)));
let mut inbound_stream = pin!(inbound_mkr(InternalPeerID::Unknown(1)));
@ -499,7 +499,7 @@ mod tests {
#[tokio::test]
async fn tx_broadcast_skipped_for_received_from_peer() {
let (mut brcst, outbound_mkr, inbound_mkr) =
init_broadcast_channels::<TestNetZone<true, true, true>>(TEST_CONFIG);
init_broadcast_channels::<TestNetZone<true>>(TEST_CONFIG);
let mut outbound_stream = pin!(outbound_mkr(InternalPeerID::Unknown(1)));
let mut outbound_stream_from = pin!(outbound_mkr(InternalPeerID::Unknown(0)));

View file

@ -153,6 +153,18 @@ impl<N: NetworkZone> ClientPool<N> {
self.borrow_clients(&peers).collect()
}
/// Checks all clients in the pool checking if any claim a higher cumulative difficulty than the
/// amount specified.
pub fn contains_client_with_more_cumulative_difficulty(
&self,
cumulative_difficulty: u128,
) -> bool {
self.clients.iter().any(|element| {
let sync_data = element.value().info.core_sync_data.lock().unwrap();
sync_data.cumulative_difficulty() > cumulative_difficulty
})
}
}
mod sealed {

View file

@ -1,13 +1,16 @@
use cuprate_address_book::AddressBookConfig;
use cuprate_helper::network::Network;
use cuprate_p2p_core::NetworkZone;
use cuprate_wire::{common::PeerSupportFlags, BasicNodeData};
pub use cuprate_address_book::AddressBookConfig;
/// P2P config.
#[derive(Clone, Debug)]
pub struct P2PConfig<N: NetworkZone> {
/// The [`Network`] we should connect to.
pub network: Network,
/// Seed nodes to connect to find peers if our address book is empty.
pub seeds: Vec<N::Addr>,
/// The number of outbound connections to make and try keep.
pub outbound_connections: usize,

View file

@ -104,12 +104,12 @@ where
clippy::significant_drop_tightening
)]
async fn connect_to_random_seeds(&mut self) -> Result<(), OutboundConnectorError> {
let seeds = N::SEEDS.choose_multiple(&mut thread_rng(), MAX_SEED_CONNECTIONS);
let seeds = self
.config
.seeds
.choose_multiple(&mut thread_rng(), MAX_SEED_CONNECTIONS);
assert!(
seeds.len() != 0,
"No seed nodes available to get peers from"
);
assert_ne!(seeds.len(), 0, "No seed nodes available to get peers from");
let mut allowed_errors = seeds.len();

View file

@ -16,14 +16,13 @@ pub(crate) const MAX_SEED_CONNECTIONS: usize = 3;
pub(crate) const OUTBOUND_CONNECTION_ATTEMPT_TIMEOUT: Duration = Duration::from_secs(5);
/// The durations of a short ban.
#[cfg_attr(not(test), expect(dead_code))]
pub(crate) const SHORT_BAN: Duration = Duration::from_secs(60 * 10);
pub const SHORT_BAN: Duration = Duration::from_secs(60 * 10);
/// The durations of a medium ban.
pub(crate) const MEDIUM_BAN: Duration = Duration::from_secs(60 * 60 * 24);
pub const MEDIUM_BAN: Duration = Duration::from_secs(60 * 60 * 24);
/// The durations of a long ban.
pub(crate) const LONG_BAN: Duration = Duration::from_secs(60 * 60 * 24 * 7);
pub const LONG_BAN: Duration = Duration::from_secs(60 * 60 * 24 * 7);
/// The default amount of time between inbound diffusion flushes.
pub(crate) const DIFFUSION_FLUSH_AVERAGE_SECONDS_INBOUND: Duration = Duration::from_secs(5);

View file

@ -12,23 +12,21 @@ use tracing::{instrument, Instrument, Span};
use cuprate_async_buffer::BufferStream;
use cuprate_p2p_core::{
client::Connector,
client::InternalPeerID,
services::{AddressBookRequest, AddressBookResponse},
CoreSyncSvc, NetworkZone, ProtocolRequestHandlerMaker,
};
mod block_downloader;
pub mod block_downloader;
mod broadcast;
mod client_pool;
pub mod config;
pub mod connection_maintainer;
mod constants;
pub mod constants;
mod inbound_server;
use block_downloader::{BlockBatch, BlockDownloaderConfig, ChainSvcRequest, ChainSvcResponse};
pub use broadcast::{BroadcastRequest, BroadcastSvc};
use client_pool::ClientPoolDropGuard;
pub use config::P2PConfig;
pub use config::{AddressBookConfig, P2PConfig};
use connection_maintainer::MakeConnectionRequest;
/// Initializes the P2P [`NetworkInterface`] for a specific [`NetworkZone`].
@ -174,9 +172,8 @@ impl<N: NetworkZone> NetworkInterface<N> {
self.address_book.clone()
}
/// Pulls a client from the client pool, returning it in a guard that will return it there when it's
/// dropped.
pub fn borrow_client(&self, peer: &InternalPeerID<N::Addr>) -> Option<ClientPoolDropGuard<N>> {
self.pool.borrow_client(peer)
/// Borrows the `ClientPool`, for access to connected peers.
pub const fn client_pool(&self) -> &Arc<client_pool::ClientPool<N>> {
&self.pool
}
}

View file

@ -16,7 +16,7 @@ epee = ["dep:cuprate-epee-encoding"]
[dependencies]
cuprate-epee-encoding = { path = "../../net/epee-encoding", optional = true }
cuprate-fixed-bytes = { path = "../../net/fixed-bytes" }
cuprate-types = { path = "../../types" }
cuprate-types = { path = "../../types", default-features = false, features = ["epee", "serde"] }
paste = { workspace = true }
serde = { workspace = true, optional = true }

View file

@ -635,7 +635,9 @@ define_request_and_response! {
AccessResponseBase {
blob: String,
block_header: BlockHeader,
json: String, // FIXME: this should be defined in a struct, it has many fields.
/// `cuprate_rpc_types::json::block::Block` should be used
/// to create this JSON string in a type-safe manner.
json: String,
miner_tx_hash: String,
tx_hashes: Vec<String> = default_vec::<String>(), "default_vec",
}

View file

@ -71,32 +71,24 @@ use cuprate_epee_encoding::{
pub enum TxEntry {
/// This entry exists in the transaction pool.
InPool {
as_hex: String,
as_json: String,
/// This field is [flattened](https://serde.rs/field-attrs.html#flatten).
#[cfg_attr(feature = "serde", serde(flatten))]
prefix: TxEntryPrefix,
block_height: u64,
block_timestamp: u64,
confirmations: u64,
double_spend_seen: bool,
output_indices: Vec<u64>,
prunable_as_hex: String,
prunable_hash: String,
pruned_as_hex: String,
tx_hash: String,
#[cfg_attr(feature = "serde", serde(serialize_with = "serde_true"))]
/// Will always be serialized as `true`.
in_pool: bool,
},
/// This entry _does not_ exist in the transaction pool.
NotInPool {
as_hex: String,
as_json: String,
double_spend_seen: bool,
prunable_as_hex: String,
prunable_hash: String,
pruned_as_hex: String,
/// This field is [flattened](https://serde.rs/field-attrs.html#flatten).
#[cfg_attr(feature = "serde", serde(flatten))]
prefix: TxEntryPrefix,
received_timestamp: u64,
relayed: bool,
tx_hash: String,
#[cfg_attr(feature = "serde", serde(serialize_with = "serde_false"))]
/// Will always be serialized as `false`.
in_pool: bool,
@ -106,20 +98,29 @@ pub enum TxEntry {
impl Default for TxEntry {
fn default() -> Self {
Self::NotInPool {
as_hex: String::default(),
as_json: String::default(),
double_spend_seen: bool::default(),
prunable_as_hex: String::default(),
prunable_hash: String::default(),
pruned_as_hex: String::default(),
prefix: Default::default(),
received_timestamp: u64::default(),
relayed: bool::default(),
tx_hash: String::default(),
in_pool: false,
}
}
}
/// Common fields in all [`TxEntry`] variants.
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct TxEntryPrefix {
as_hex: String,
/// `cuprate_rpc_types::json::tx::Transaction` should be used
/// to create this JSON string in a type-safe manner.
as_json: String,
double_spend_seen: bool,
tx_hash: String,
prunable_as_hex: String,
prunable_hash: String,
pruned_as_hex: String,
}
//---------------------------------------------------------------------------------------------------- Epee
#[cfg(feature = "epee")]
impl EpeeObjectBuilder<TxEntry> for () {

View file

@ -140,6 +140,8 @@ define_request_and_response! {
#[doc = serde_doc_test!(GET_TRANSACTIONS_RESPONSE)]
AccessResponseBase {
txs_as_hex: Vec<String> = default_vec::<String>(), "default_vec",
/// `cuprate_rpc_types::json::tx::Transaction` should be used
/// to create this JSON string in a type-safe manner.
txs_as_json: Vec<String> = default_vec::<String>(), "default_vec",
missed_tx: Vec<String> = default_vec::<String>(), "default_vec",
txs: Vec<TxEntry> = default_vec::<TxEntry>(), "default_vec",

View file

@ -69,16 +69,11 @@ impl TryFrom<NetworkAddress> for TestNetZoneAddr {
/// TODO
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct TestNetZone<const ALLOW_SYNC: bool, const DANDELION_PP: bool, const CHECK_NODE_ID: bool>;
pub struct TestNetZone<const CHECK_NODE_ID: bool>;
#[async_trait::async_trait]
impl<const ALLOW_SYNC: bool, const DANDELION_PP: bool, const CHECK_NODE_ID: bool> NetworkZone
for TestNetZone<ALLOW_SYNC, DANDELION_PP, CHECK_NODE_ID>
{
impl<const CHECK_NODE_ID: bool> NetworkZone for TestNetZone<CHECK_NODE_ID> {
const NAME: &'static str = "Testing";
const SEEDS: &'static [Self::Addr] = &[];
const ALLOW_SYNC: bool = ALLOW_SYNC;
const DANDELION_PP: bool = DANDELION_PP;
const CHECK_NODE_ID: bool = CHECK_NODE_ID;
type Addr = TestNetZoneAddr;

View file

@ -9,19 +9,23 @@ repository = "https://github.com/Cuprate/cuprate/tree/main/types"
keywords = ["cuprate", "types"]
[features]
default = ["blockchain", "epee", "serde"]
default = ["blockchain", "epee", "serde", "json", "hex"]
blockchain = []
epee = ["dep:cuprate-epee-encoding"]
serde = ["dep:serde"]
proptest = ["dep:proptest", "dep:proptest-derive"]
json = ["hex", "dep:cuprate-helper"]
hex = ["dep:hex"]
[dependencies]
cuprate-epee-encoding = { path = "../net/epee-encoding", optional = true }
cuprate-helper = { path = "../helper", optional = true, features = ["cast"] }
cuprate-fixed-bytes = { path = "../net/fixed-bytes" }
bytes = { workspace = true }
curve25519-dalek = { workspace = true }
monero-serai = { workspace = true }
hex = { workspace = true, features = ["serde", "alloc"], optional = true }
serde = { workspace = true, features = ["derive"], optional = true }
thiserror = { workspace = true }
@ -29,6 +33,9 @@ proptest = { workspace = true, optional = true }
proptest-derive = { workspace = true, optional = true }
[dev-dependencies]
hex-literal = { workspace = true }
pretty_assertions = { workspace = true }
serde_json = { workspace = true, features = ["std"] }
[lints]
workspace = true

View file

@ -10,3 +10,5 @@ This crate is a kitchen-sink for data types that are shared across Cuprate.
| `serde` | Enables `serde` on types where applicable
| `epee` | Enables `cuprate-epee-encoding` on types where applicable
| `proptest` | Enables `proptest::arbitrary::Arbitrary` on some types
| `json` | Enables the `json` module, containing JSON representations of common Monero types
| `hex` | Enables the `hex` module, containing the `HexBytes` type

74
types/src/hex.rs Normal file
View file

@ -0,0 +1,74 @@
//! Hexadecimal serde wrappers for arrays.
//!
//! This module provides transparent wrapper types for
//! arrays that (de)serialize from hexadecimal input/output.
#[cfg(feature = "epee")]
use cuprate_epee_encoding::{error, macros::bytes, EpeeValue, Marker};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
/// Wrapper type for a byte array that (de)serializes from/to hexadecimal strings.
///
/// # Deserialization
/// This struct has a custom deserialization that only applies to certain
/// `N` lengths because [`hex::FromHex`] does not implement for a generic `N`:
/// <https://docs.rs/hex/0.4.3/src/hex/lib.rs.html#220-230>
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
#[repr(transparent)]
pub struct HexBytes<const N: usize>(
#[cfg_attr(feature = "serde", serde(with = "hex::serde"))] pub [u8; N],
);
impl<'de, const N: usize> Deserialize<'de> for HexBytes<N>
where
[u8; N]: hex::FromHex,
<[u8; N] as hex::FromHex>::Error: std::fmt::Display,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
Ok(Self(hex::serde::deserialize(deserializer)?))
}
}
#[cfg(feature = "epee")]
impl<const N: usize> EpeeValue for HexBytes<N> {
const MARKER: Marker = <[u8; N] as EpeeValue>::MARKER;
fn read<B: bytes::Buf>(r: &mut B, marker: &Marker) -> error::Result<Self> {
Ok(Self(<[u8; N] as EpeeValue>::read(r, marker)?))
}
fn write<B: bytes::BufMut>(self, w: &mut B) -> error::Result<()> {
<[u8; N] as EpeeValue>::write(self.0, w)
}
}
// Default is not implemented for arrays >32, so we must do it manually.
impl<const N: usize> Default for HexBytes<N> {
fn default() -> Self {
Self([0; N])
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn hex_bytes_32() {
let hash = [1; 32];
let hex_bytes = HexBytes::<32>(hash);
let expected_json = r#""0101010101010101010101010101010101010101010101010101010101010101""#;
let to_string = serde_json::to_string(&hex_bytes).unwrap();
assert_eq!(to_string, expected_json);
let from_str = serde_json::from_str::<HexBytes<32>>(expected_json).unwrap();
assert_eq!(hex_bytes, from_str);
}
}

359
types/src/json/block.rs Normal file
View file

@ -0,0 +1,359 @@
//! JSON block types.
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use monero_serai::{block, transaction};
use cuprate_helper::cast::usize_to_u64;
use crate::{
hex::HexBytes,
json::output::{Output, TaggedKey, Target},
};
/// JSON representation of a block.
///
/// Used in:
/// - [`/get_block` -> `json`](https://www.getmonero.org/resources/developer-guides/daemon-rpc.html#get_block)
#[derive(Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Block {
pub major_version: u8,
pub minor_version: u8,
pub timestamp: u64,
pub prev_id: HexBytes<32>,
pub nonce: u32,
pub miner_tx: MinerTransaction,
pub tx_hashes: Vec<HexBytes<32>>,
}
impl From<block::Block> for Block {
fn from(b: block::Block) -> Self {
let Ok(miner_tx) = MinerTransaction::try_from(b.miner_transaction) else {
unreachable!("input is a miner tx, this should never fail");
};
let tx_hashes = b.transactions.into_iter().map(HexBytes::<32>).collect();
Self {
major_version: b.header.hardfork_version,
minor_version: b.header.hardfork_signal,
timestamp: b.header.timestamp,
prev_id: HexBytes::<32>(b.header.previous),
nonce: b.header.nonce,
miner_tx,
tx_hashes,
}
}
}
/// [`Block::miner_tx`].
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[serde(untagged)]
pub enum MinerTransaction {
V1 {
/// This field is [flattened](https://serde.rs/field-attrs.html#flatten).
#[serde(flatten)]
prefix: MinerTransactionPrefix,
signatures: [(); 0],
},
V2 {
/// This field is [flattened](https://serde.rs/field-attrs.html#flatten).
#[serde(flatten)]
prefix: MinerTransactionPrefix,
rct_signatures: MinerTransactionRctSignatures,
},
}
impl TryFrom<transaction::Transaction> for MinerTransaction {
type Error = transaction::Transaction;
/// # Errors
/// This function errors if the input is not a miner transaction.
fn try_from(tx: transaction::Transaction) -> Result<Self, transaction::Transaction> {
fn map_prefix(
prefix: transaction::TransactionPrefix,
version: u8,
) -> Result<MinerTransactionPrefix, transaction::TransactionPrefix> {
let Some(input) = prefix.inputs.first() else {
return Err(prefix);
};
let height = match input {
transaction::Input::Gen(height) => usize_to_u64(*height),
transaction::Input::ToKey { .. } => return Err(prefix),
};
let vin = {
let r#gen = Gen { height };
let input = Input { r#gen };
[input]
};
let vout = prefix
.outputs
.into_iter()
.map(|o| {
let amount = o.amount.unwrap_or(0);
let target = match o.view_tag {
Some(view_tag) => {
let tagged_key = TaggedKey {
key: HexBytes::<32>(o.key.0),
view_tag: HexBytes::<1>([view_tag]),
};
Target::TaggedKey { tagged_key }
}
None => Target::Key {
key: HexBytes::<32>(o.key.0),
},
};
Output { amount, target }
})
.collect();
let unlock_time = match prefix.additional_timelock {
transaction::Timelock::None => 0,
transaction::Timelock::Block(x) => usize_to_u64(x),
transaction::Timelock::Time(x) => x,
};
Ok(MinerTransactionPrefix {
version,
unlock_time,
vin,
vout,
extra: prefix.extra,
})
}
Ok(match tx {
transaction::Transaction::V1 { prefix, signatures } => {
let prefix = match map_prefix(prefix, 1) {
Ok(p) => p,
Err(prefix) => return Err(transaction::Transaction::V1 { prefix, signatures }),
};
Self::V1 {
prefix,
signatures: [(); 0],
}
}
transaction::Transaction::V2 { prefix, proofs } => {
let prefix = match map_prefix(prefix, 2) {
Ok(p) => p,
Err(prefix) => return Err(transaction::Transaction::V2 { prefix, proofs }),
};
Self::V2 {
prefix,
rct_signatures: MinerTransactionRctSignatures { r#type: 0 },
}
}
})
}
}
impl Default for MinerTransaction {
fn default() -> Self {
Self::V1 {
prefix: Default::default(),
signatures: Default::default(),
}
}
}
/// [`MinerTransaction::V1::prefix`] & [`MinerTransaction::V2::prefix`].
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct MinerTransactionPrefix {
pub version: u8,
pub unlock_time: u64,
pub vin: [Input; 1],
pub vout: Vec<Output>,
pub extra: Vec<u8>,
}
/// [`MinerTransaction::V2::rct_signatures`].
#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct MinerTransactionRctSignatures {
pub r#type: u8,
}
/// [`MinerTransactionPrefix::vin`].
#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Input {
pub r#gen: Gen,
}
/// [`Input::gen`].
#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Gen {
pub height: u64,
}
#[cfg(test)]
mod test {
use hex_literal::hex;
use pretty_assertions::assert_eq;
use super::*;
#[expect(clippy::needless_pass_by_value)]
fn test(block: Block, block_json: &'static str) {
let json = serde_json::from_str::<Block>(block_json).unwrap();
assert_eq!(block, json);
let string = serde_json::to_string(&json).unwrap();
assert_eq!(block_json, &string);
}
#[test]
fn block_300000() {
const JSON: &str = r#"{"major_version":1,"minor_version":0,"timestamp":1415690591,"prev_id":"e97a0ab6307de9b9f9a9872263ef3e957976fb227eb9422c6854e989e5d5d34c","nonce":2147484616,"miner_tx":{"version":1,"unlock_time":300060,"vin":[{"gen":{"height":300000}}],"vout":[{"amount":47019296802,"target":{"key":"3c1dcbf5b485987ecef4596bb700e32cbc7bd05964e3888ffc05f8a46bf5fc33"}},{"amount":200000000000,"target":{"key":"5810afc7a1b01a1c913eb6aab15d4a851cbc4a8cf0adf90bb80ac1a7ca9928aa"}},{"amount":3000000000000,"target":{"key":"520f49c5f2ce8456dc1a565f35ed3a5ccfff3a1210b340870a57d2749a81a2df"}},{"amount":10000000000000,"target":{"key":"44d7705e62c76c2e349a474df6724aa1d9932092002b03a94f9c19d9d12b9427"}}],"extra":[1,251,8,189,254,12,213,173,108,61,156,198,144,151,31,130,141,211,120,55,81,98,32,247,111,127,254,170,170,240,124,190,223,2,8,0,0,0,64,184,115,46,246],"signatures":[]},"tx_hashes":[]}"#;
let block = Block {
major_version: 1,
minor_version: 0,
timestamp: 1415690591,
prev_id: HexBytes::<32>(hex!(
"e97a0ab6307de9b9f9a9872263ef3e957976fb227eb9422c6854e989e5d5d34c"
)),
nonce: 2147484616,
miner_tx: MinerTransaction::V1 {
prefix: MinerTransactionPrefix {
version: 1,
unlock_time: 300060,
vin: [Input {
r#gen: Gen { height: 300000 },
}],
vout: vec![
Output {
amount: 47019296802,
target: Target::Key {
key: HexBytes::<32>(hex!("3c1dcbf5b485987ecef4596bb700e32cbc7bd05964e3888ffc05f8a46bf5fc33")),
}
},
Output {
amount: 200000000000,
target: Target::Key {
key: HexBytes::<32>(hex!("5810afc7a1b01a1c913eb6aab15d4a851cbc4a8cf0adf90bb80ac1a7ca9928aa")),
}
},
Output {
amount: 3000000000000,
target: Target::Key {
key: HexBytes::<32>(hex!("520f49c5f2ce8456dc1a565f35ed3a5ccfff3a1210b340870a57d2749a81a2df")),
}
},
Output {
amount: 10000000000000,
target: Target::Key {
key: HexBytes::<32>(hex!("44d7705e62c76c2e349a474df6724aa1d9932092002b03a94f9c19d9d12b9427")),
}
}
],
extra: vec![
1, 251, 8, 189, 254, 12, 213, 173, 108, 61, 156, 198, 144, 151, 31, 130,
141, 211, 120, 55, 81, 98, 32, 247, 111, 127, 254, 170, 170, 240, 124, 190,
223, 2, 8, 0, 0, 0, 64, 184, 115, 46, 246,
],
},
signatures: [],
},
tx_hashes: vec![],
};
test(block, JSON);
}
#[test]
fn block_3245409() {
const JSON: &str = r#"{"major_version":16,"minor_version":16,"timestamp":1727293028,"prev_id":"41b56c273d69def3294e56179de71c61808042d54c1e085078d21dbe99e81b6f","nonce":311,"miner_tx":{"version":2,"unlock_time":3245469,"vin":[{"gen":{"height":3245409}}],"vout":[{"amount":601012280000,"target":{"tagged_key":{"key":"8c0b16c6df02b9944b49f375d96a958a0fc5431c048879bb5bf25f64a1163b9e","view_tag":"88"}}}],"extra":[1,39,23,182,203,58,48,15,217,9,13,147,104,133,206,176,185,56,237,179,136,72,84,129,113,98,206,4,18,50,130,162,94,2,17,73,18,21,33,32,112,5,0,0,0,0,0,0,0,0,0,0],"rct_signatures":{"type":0}},"tx_hashes":["eab76986a0cbcae690d8499f0f616f783fd2c89c6f611417f18011950dbdab2e","57b19aa8c2cdbb6836cf13dd1e321a67860965c12e4418f3c30f58c8899a851e","5340185432ab6b74fb21379f7e8d8f0e37f0882b2a7121fd7c08736f079e2edc","01dc6d31db56d68116f5294c1b4f80b33b048b5cdfefcd904f23e6c0de3daff5","c9fb6a2730678203948fef2a49fa155b63f35a3649f3d32ed405a6806f3bbd56","af965cdd2a2315baf1d4a3d242f44fe07b1fd606d5f4853c9ff546ca6c12a5af","97bc9e047d25fae8c14ce6ec882224e7b722f5e79b62a2602a6bacebdac8547b","28c46992eaf10dc0cceb313c30572d023432b7bd26e85e679bc8fe419533a7bf","c32e3acde2ff2885c9cc87253b40d6827d167dfcc3022c72f27084fd98788062","19e66a47f075c7cccde8a7b52803119e089e33e3a4847cace0bd1d17b0d22bab","8e8ac560e77a1ee72e82a5eb6887adbe5979a10cd29cb2c2a3720ce87db43a70","b7ff5141524b5cca24de6780a5dbfdf71e7de1e062fd85f557fb3b43b8e285dc","f09df0f113763ef9b9a2752ac293b478102f7cab03ef803a3d9db7585aea8912"]}"#;
let block = Block {
major_version: 16,
minor_version: 16,
timestamp: 1727293028,
prev_id: HexBytes::<32>(hex!(
"41b56c273d69def3294e56179de71c61808042d54c1e085078d21dbe99e81b6f"
)),
nonce: 311,
miner_tx: MinerTransaction::V2 {
prefix: MinerTransactionPrefix {
version: 2,
unlock_time: 3245469,
vin: [Input {
r#gen: Gen { height: 3245409 },
}],
vout: vec![Output {
amount: 601012280000,
target: Target::TaggedKey {
tagged_key: TaggedKey {
key: HexBytes::<32>(hex!(
"8c0b16c6df02b9944b49f375d96a958a0fc5431c048879bb5bf25f64a1163b9e"
)),
view_tag: HexBytes::<1>(hex!("88")),
},
},
}],
extra: vec![
1, 39, 23, 182, 203, 58, 48, 15, 217, 9, 13, 147, 104, 133, 206, 176, 185,
56, 237, 179, 136, 72, 84, 129, 113, 98, 206, 4, 18, 50, 130, 162, 94, 2,
17, 73, 18, 21, 33, 32, 112, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
],
},
rct_signatures: MinerTransactionRctSignatures { r#type: 0 },
},
tx_hashes: vec![
HexBytes::<32>(hex!(
"eab76986a0cbcae690d8499f0f616f783fd2c89c6f611417f18011950dbdab2e"
)),
HexBytes::<32>(hex!(
"57b19aa8c2cdbb6836cf13dd1e321a67860965c12e4418f3c30f58c8899a851e"
)),
HexBytes::<32>(hex!(
"5340185432ab6b74fb21379f7e8d8f0e37f0882b2a7121fd7c08736f079e2edc"
)),
HexBytes::<32>(hex!(
"01dc6d31db56d68116f5294c1b4f80b33b048b5cdfefcd904f23e6c0de3daff5"
)),
HexBytes::<32>(hex!(
"c9fb6a2730678203948fef2a49fa155b63f35a3649f3d32ed405a6806f3bbd56"
)),
HexBytes::<32>(hex!(
"af965cdd2a2315baf1d4a3d242f44fe07b1fd606d5f4853c9ff546ca6c12a5af"
)),
HexBytes::<32>(hex!(
"97bc9e047d25fae8c14ce6ec882224e7b722f5e79b62a2602a6bacebdac8547b"
)),
HexBytes::<32>(hex!(
"28c46992eaf10dc0cceb313c30572d023432b7bd26e85e679bc8fe419533a7bf"
)),
HexBytes::<32>(hex!(
"c32e3acde2ff2885c9cc87253b40d6827d167dfcc3022c72f27084fd98788062"
)),
HexBytes::<32>(hex!(
"19e66a47f075c7cccde8a7b52803119e089e33e3a4847cace0bd1d17b0d22bab"
)),
HexBytes::<32>(hex!(
"8e8ac560e77a1ee72e82a5eb6887adbe5979a10cd29cb2c2a3720ce87db43a70"
)),
HexBytes::<32>(hex!(
"b7ff5141524b5cca24de6780a5dbfdf71e7de1e062fd85f557fb3b43b8e285dc"
)),
HexBytes::<32>(hex!(
"f09df0f113763ef9b9a2752ac293b478102f7cab03ef803a3d9db7585aea8912"
)),
],
};
test(block, JSON);
}
}

15
types/src/json/mod.rs Normal file
View file

@ -0,0 +1,15 @@
//! This module contains types mappings for other common types
//! to allow for easier JSON (de)serialization.
//!
//! The main types are:
//! - [`block::Block`]
//! - [`tx::Transaction`]
//!
//! Modules exist within this module as the JSON representation
//! of types sometimes differs, thus, the modules hold the types
//! that match the specific schema, for example [`block::Input`]
//! is different than [`tx::Input`].
pub mod block;
pub mod output;
pub mod tx;

43
types/src/json/output.rs Normal file
View file

@ -0,0 +1,43 @@
//! JSON output types.
//!
//! The same [`Output`] is used in both
//! [`crate::json::block::MinerTransactionPrefix::vout`]
//! and [`crate::json::tx::TransactionPrefix::vout`].
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use crate::hex::HexBytes;
/// JSON representation of an output.
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Output {
pub amount: u64,
pub target: Target,
}
/// [`Output::target`].
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[serde(untagged)]
pub enum Target {
Key { key: HexBytes<32> },
TaggedKey { tagged_key: TaggedKey },
}
impl Default for Target {
fn default() -> Self {
Self::Key {
key: Default::default(),
}
}
}
/// [`Target::TaggedKey::tagged_key`].
#[derive(Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct TaggedKey {
pub key: HexBytes<32>,
pub view_tag: HexBytes<1>,
}

1455
types/src/json/tx.rs Normal file

File diff suppressed because one or more lines are too long

View file

@ -28,4 +28,10 @@ pub use types::{
#[cfg(feature = "blockchain")]
pub mod blockchain;
#[cfg(feature = "json")]
pub mod json;
#[cfg(feature = "hex")]
pub mod hex;
//---------------------------------------------------------------------------------------------------- Private