Skip to content

Commit

Permalink
add CuckooParams::node_mask, obsolete EdgeType and sipnode shift arg (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
tromp authored Jun 26, 2020
1 parent 39ca5d1 commit 238522a
Show file tree
Hide file tree
Showing 9 changed files with 155 additions and 295 deletions.
7 changes: 2 additions & 5 deletions core/src/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use crate::consensus::{
use crate::core::block::HeaderVersion;
use crate::pow::{
self, new_cuckaroo_ctx, new_cuckarood_ctx, new_cuckaroom_ctx, new_cuckarooz_ctx,
new_cuckatoo_ctx, EdgeType, PoWContext,
new_cuckatoo_ctx, PoWContext,
};
use std::cell::Cell;
use util::OneTime;
Expand Down Expand Up @@ -219,10 +219,7 @@ pub fn create_pow_context<T>(
edge_bits: u8,
proof_size: usize,
max_sols: u32,
) -> Result<Box<dyn PoWContext<T>>, pow::Error>
where
T: EdgeType + 'static,
{
) -> Result<Box<dyn PoWContext>, pow::Error> {
let chain_type = get_chain_type();
match chain_type {
// Mainnet has Cuckaroo{,d,m,z}29 for AR and Cuckatoo31+ for AF
Expand Down
81 changes: 25 additions & 56 deletions core/src/pow/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

//! Common types and traits for cuckoo family of solvers
use crate::pow::error::{Error, ErrorKind};
use crate::pow::error::Error;
use crate::pow::num::{PrimInt, ToPrimitive};
use crate::pow::siphash::siphash24;
use blake2::blake2b::blake2b;
Expand All @@ -31,49 +31,27 @@ impl EdgeType for u64 {}

/// An edge in the Cuckoo graph, simply references two u64 nodes.
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub struct Edge<T>
where
T: EdgeType,
{
pub u: T,
pub v: T,
pub struct Edge {
pub u: u64,
pub v: u64,
}

impl<T> fmt::Display for Edge<T>
where
T: EdgeType,
{
impl fmt::Display for Edge {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"(u: {}, v: {})",
self.u.to_u64().unwrap_or(0),
self.v.to_u64().unwrap_or(0)
)
write!(f, "(u: {}, v: {})", self.u, self.v)
}
}

/// An element of an adjencency list
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Link<T>
where
T: EdgeType,
{
pub next: T,
pub to: T,
pub struct Link {
pub next: u64,
pub to: u64,
}

impl<T> fmt::Display for Link<T>
where
T: EdgeType,
{
impl fmt::Display for Link {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"(next: {}, to: {})",
self.next.to_u64().unwrap_or(0),
self.to.to_u64().unwrap_or(0)
)
write!(f, "(next: {}, to: {})", self.next, self.to)
}
}

Expand Down Expand Up @@ -135,31 +113,29 @@ macro_rules! to_edge {

/// Utility struct to calculate commonly used Cuckoo parameters calculated
/// from header, nonce, edge_bits, etc.
pub struct CuckooParams<T>
where
T: EdgeType,
{
pub struct CuckooParams {
pub edge_bits: u8,
pub proof_size: usize,
pub num_edges: u64,
pub siphash_keys: [u64; 4],
pub edge_mask: T,
pub edge_mask: u64,
pub node_mask: u64,
}

impl<T> CuckooParams<T>
where
T: EdgeType,
{
impl CuckooParams {
/// Instantiates new params and calculate edge mask, etc
pub fn new(edge_bits: u8, proof_size: usize) -> Result<CuckooParams<T>, Error> {
let num_edges = (1 as u64) << edge_bits;
let edge_mask = to_edge!(T, num_edges - 1);
pub fn new(edge_bits: u8, node_bits: u8, proof_size: usize) -> Result<CuckooParams, Error> {
let num_edges = 1u64 << edge_bits;
let edge_mask = num_edges - 1;
let num_nodes = 1u64 << node_bits;
let node_mask = num_nodes - 1;
Ok(CuckooParams {
edge_bits,
proof_size,
num_edges,
siphash_keys: [0; 4],
edge_mask,
node_mask,
})
}

Expand All @@ -170,16 +146,9 @@ where
}

/// Return siphash masked for type
pub fn sipnode(&self, edge: T, uorv: u64, shift: bool) -> Result<T, Error> {
let hash_u64 = siphash24(
&self.siphash_keys,
2 * edge.to_u64().ok_or(ErrorKind::IntegerCast)? + uorv,
);
let mut masked = hash_u64 & self.edge_mask.to_u64().ok_or(ErrorKind::IntegerCast)?;
if shift {
masked <<= 1;
masked |= uorv;
}
Ok(T::from(masked).ok_or(ErrorKind::IntegerCast)?)
pub fn sipnode(&self, edge: u64, uorv: u64) -> Result<u64, Error> {
let hash_u64 = siphash24(&self.siphash_keys, 2 * edge + uorv);
let node = hash_u64 & self.node_mask;
Ok(node)
}
}
40 changes: 12 additions & 28 deletions core/src/pow/cuckaroo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,37 +24,25 @@
//! obtain blocks of values. Nodes are then extracted from those edges.
use crate::global;
use crate::pow::common::{CuckooParams, EdgeType};
use crate::pow::common::CuckooParams;
use crate::pow::error::{Error, ErrorKind};
use crate::pow::siphash::siphash_block;
use crate::pow::{PoWContext, Proof};

/// Instantiate a new CuckarooContext as a PowContext. Note that this can't
/// be moved in the PoWContext trait as this particular trait needs to be
/// convertible to an object trait.
pub fn new_cuckaroo_ctx<T>(
edge_bits: u8,
proof_size: usize,
) -> Result<Box<dyn PoWContext<T>>, Error>
where
T: EdgeType + 'static,
{
let params = CuckooParams::new(edge_bits, proof_size)?;
pub fn new_cuckaroo_ctx(edge_bits: u8, proof_size: usize) -> Result<Box<dyn PoWContext>, Error> {
let params = CuckooParams::new(edge_bits, edge_bits, proof_size)?;
Ok(Box::new(CuckarooContext { params }))
}

/// Cuckaroo cycle context. Only includes the verifier for now.
pub struct CuckarooContext<T>
where
T: EdgeType,
{
params: CuckooParams<T>,
pub struct CuckarooContext {
params: CuckooParams,
}

impl<T> PoWContext<T> for CuckarooContext<T>
where
T: EdgeType,
{
impl PoWContext for CuckarooContext {
fn set_header_nonce(
&mut self,
header: Vec<u8>,
Expand All @@ -76,20 +64,19 @@ where
let mut uvs = vec![0u64; 2 * proof.proof_size()];
let mut xor0: u64 = 0;
let mut xor1: u64 = 0;
let node_mask: u64 = to_u64!(self.params.edge_mask);

for n in 0..proof.proof_size() {
if nonces[n] > to_u64!(self.params.edge_mask) {
if nonces[n] > self.params.edge_mask {
return Err(ErrorKind::Verification("edge too big".to_owned()).into());
}
if n > 0 && nonces[n] <= nonces[n - 1] {
return Err(ErrorKind::Verification("edges not ascending".to_owned()).into());
}
// 21 is standard siphash rotation constant
let edge: u64 = siphash_block(&self.params.siphash_keys, nonces[n], 21, false);
uvs[2 * n] = edge & node_mask;
uvs[2 * n] = edge & self.params.node_mask;
xor0 ^= uvs[2 * n];
uvs[2 * n + 1] = (edge >> 32) & node_mask;
uvs[2 * n + 1] = (edge >> 32) & self.params.node_mask;
xor1 ^= uvs[2 * n + 1];
}
if xor0 | xor1 != 0 {
Expand Down Expand Up @@ -169,19 +156,16 @@ mod test {
#[test]
fn cuckaroo19_vectors() {
global::set_local_chain_type(global::ChainTypes::Mainnet);
let mut ctx = new_impl::<u64>(19, 42);
let mut ctx = new_impl(19, 42);
ctx.params.siphash_keys = V1_19_HASH;
assert!(ctx.verify(&Proof::new(V1_19_SOL.to_vec())).is_ok());
ctx.params.siphash_keys = V2_19_HASH.clone();
assert!(ctx.verify(&Proof::new(V2_19_SOL.to_vec())).is_ok());
assert!(ctx.verify(&Proof::zero(42)).is_err());
}

fn new_impl<T>(edge_bits: u8, proof_size: usize) -> CuckarooContext<T>
where
T: EdgeType,
{
let params = CuckooParams::new(edge_bits, proof_size).unwrap();
fn new_impl(edge_bits: u8, proof_size: usize) -> CuckarooContext {
let params = CuckooParams::new(edge_bits, edge_bits, proof_size).unwrap();
CuckarooContext { params }
}
}
42 changes: 13 additions & 29 deletions core/src/pow/cuckarood.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,37 +23,25 @@
//! and requires cycles to alternate between even- and odd-indexed edges.
use crate::global;
use crate::pow::common::{CuckooParams, EdgeType};
use crate::pow::common::CuckooParams;
use crate::pow::error::{Error, ErrorKind};
use crate::pow::siphash::siphash_block;
use crate::pow::{PoWContext, Proof};

/// Instantiate a new CuckaroodContext as a PowContext. Note that this can't
/// be moved in the PoWContext trait as this particular trait needs to be
/// convertible to an object trait.
pub fn new_cuckarood_ctx<T>(
edge_bits: u8,
proof_size: usize,
) -> Result<Box<dyn PoWContext<T>>, Error>
where
T: EdgeType + 'static,
{
let params = CuckooParams::new(edge_bits, proof_size)?;
pub fn new_cuckarood_ctx(edge_bits: u8, proof_size: usize) -> Result<Box<dyn PoWContext>, Error> {
let params = CuckooParams::new(edge_bits, edge_bits - 1, proof_size)?;
Ok(Box::new(CuckaroodContext { params }))
}

/// Cuckarood cycle context. Only includes the verifier for now.
pub struct CuckaroodContext<T>
where
T: EdgeType,
{
params: CuckooParams<T>,
pub struct CuckaroodContext {
params: CuckooParams,
}

impl<T> PoWContext<T> for CuckaroodContext<T>
where
T: EdgeType,
{
impl PoWContext for CuckaroodContext {
fn set_header_nonce(
&mut self,
header: Vec<u8>,
Expand All @@ -76,14 +64,13 @@ where
let mut ndir = vec![0usize; 2];
let mut xor0: u64 = 0;
let mut xor1: u64 = 0;
let node_mask: u64 = to_u64!(self.params.edge_mask) >> 1;

for n in 0..proof.proof_size() {
let dir = (nonces[n] & 1) as usize;
if ndir[dir] >= proof.proof_size() / 2 {
return Err(ErrorKind::Verification("edges not balanced".to_owned()).into());
}
if nonces[n] > to_u64!(self.params.edge_mask) {
if nonces[n] > self.params.edge_mask {
return Err(ErrorKind::Verification("edge too big".to_owned()).into());
}
if n > 0 && nonces[n] <= nonces[n - 1] {
Expand All @@ -92,9 +79,9 @@ where
// cuckarood uses a non-standard siphash rotation constant 25 as anti-ASIC tweak
let edge: u64 = siphash_block(&self.params.siphash_keys, nonces[n], 25, false);
let idx = 4 * ndir[dir] + 2 * dir;
uvs[idx] = edge & node_mask;
uvs[idx] = edge & self.params.node_mask;
xor0 ^= uvs[idx];
uvs[idx + 1] = (edge >> 32) & node_mask;
uvs[idx + 1] = (edge >> 32) & self.params.node_mask;
xor1 ^= uvs[idx + 1];
ndir[dir] += 1;
}
Expand Down Expand Up @@ -171,21 +158,18 @@ mod test {
#[test]
fn cuckarood19_29_vectors() {
global::set_local_chain_type(global::ChainTypes::Mainnet);
let mut ctx19 = new_impl::<u64>(19, 42);
let mut ctx19 = new_impl(19, 42);
ctx19.params.siphash_keys = V1_19_HASH;
assert!(ctx19.verify(&Proof::new(V1_19_SOL.to_vec())).is_ok());
assert!(ctx19.verify(&Proof::zero(42)).is_err());
let mut ctx29 = new_impl::<u64>(29, 42);
let mut ctx29 = new_impl(29, 42);
ctx29.params.siphash_keys = V2_29_HASH;
assert!(ctx29.verify(&Proof::new(V2_29_SOL.to_vec())).is_ok());
assert!(ctx29.verify(&Proof::zero(42)).is_err());
}

fn new_impl<T>(edge_bits: u8, proof_size: usize) -> CuckaroodContext<T>
where
T: EdgeType,
{
let params = CuckooParams::new(edge_bits, proof_size).unwrap();
fn new_impl(edge_bits: u8, proof_size: usize) -> CuckaroodContext {
let params = CuckooParams::new(edge_bits, edge_bits - 1, proof_size).unwrap();
CuckaroodContext { params }
}
}
Loading

0 comments on commit 238522a

Please sign in to comment.