Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add bits_to_target #15

Merged
merged 11 commits into from
Aug 8, 2024
2 changes: 2 additions & 0 deletions src/lib.cairo
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
pub mod utils;

mod state;
mod validation;
mod main;
35 changes: 35 additions & 0 deletions src/utils.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use core::traits::Into;
use core::traits::TryInto;

// Bitwise shift left for u256
pub fn shl(value: u256, shift: u32) -> u256 {
value * fast_pow(2.into(), shift.into())
}

// Bitwise shift right for u256
pub fn shr(value: u256, shift: u32) -> u256 {
value / fast_pow(2.into(), shift.into())
}

// Fast exponentiation using the square-and-multiply algorithm
// Reference: https://github.com/keep-starknet-strange/alexandria/blob/bcdca70afdf59c9976148e95cebad5cf63d75a7f/packages/math/src/fast_power.cairo#L12
pub fn fast_pow(base: u256, exp: u32) -> u256 {
if exp == 0 {
return 1.into();
harsh-ps-2003 marked this conversation as resolved.
Show resolved Hide resolved
}

let mut res: u256 = 1.into();
harsh-ps-2003 marked this conversation as resolved.
Show resolved Hide resolved
let mut base: u256 = base;
let mut exp: u32 = exp;

loop {
if exp % 2 == 1 {
res = res * base;
}
exp = exp / 2;
if exp == 0 {
break res;
}
base = base * base;
}
}
37 changes: 37 additions & 0 deletions src/validation.cairo
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use super::state::{Block, ChainState, UtreexoState};
use raito::utils::shl;
use raito::utils::shr;

#[generate_trait]
impl BlockValidatorImpl of BlockValidator {
Expand Down Expand Up @@ -70,6 +72,41 @@ fn validate_merkle_root(self: @ChainState, block: @Block) -> Result<(), ByteArra
Result::Ok(())
}


// Helper functions
pub fn bits_to_target(bits: u32) -> Result<u256, felt252> {
// Extract exponent and mantissa
let exponent: u32 = (bits / 0x1000000);
let mantissa: u32 = bits & 0x00FFFFFF;

// Check if mantissa is valid (should be less than 0x1000000)
if mantissa > 0x7FFFFF && exponent != 0 {
return Result::Err('Invalid mantissa');
}

// Calculate the full target value
let mut target: u256 = mantissa.into();

if exponent == 0 {
// Special case: exponent 0 means we use the mantissa as-is
return Result::Ok(target);
} else if exponent <= 3 {
// For exponents 1, 2, and 3, divide by 256^(3 - exponent) i.e right shift
let shift = 8 * (3 - exponent);
target = shr(target, shift);
} else {
let shift = 8 * (exponent - 3);
target = shl(target, shift);
}

// Ensure the target doesn't exceed the maximum allowed value
if target > MAX_TARGET {
return Result::Err('Target exceeds maximum');
}

Result::Ok(target)
}

#[cfg(test)]
mod tests {
use super::{validate_target, validate_timestamp};
Expand Down
76 changes: 76 additions & 0 deletions tests/tests.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
use raito::validation::bits_to_target;

#[test]
fn test_bits_to_target_01003456() {
let result = bits_to_target(0x01003456);
assert!(result.is_ok(), "Should be valid");
assert!(result.unwrap() == 0x00_u256, "Incorrect target for 0x01003456");
}

#[test]
fn test_bits_to_target_01123456() {
let result = bits_to_target(0x01123456);
assert!(result.is_ok(), "Should be valid");
assert!(result.unwrap() == 0x12_u256, "Incorrect target for 0x01123456");
}

#[test]
fn test_bits_to_target_02008000() {
let result = bits_to_target(0x02008000);
assert!(result.is_ok(), "Should be valid");
assert!(result.unwrap() == 0x80_u256, "Incorrect target for 0x02008000");
}

#[test]
fn test_bits_to_target_181bc330() {
let result = bits_to_target(0x181bc330);
assert!(result.is_ok(), "Should be valid");
assert!(
result.unwrap() == 0x1bc330000000000000000000000000000000000000000000_u256,
"Incorrect target for 0x181bc330"
);
}

#[test]
fn test_bits_to_target_05009234() {
let result = bits_to_target(0x05009234);
assert!(result.is_ok(), "Should be valid");
assert!(result.unwrap() == 0x92340000_u256, "Incorrect target for 0x05009234");
}

#[test]
fn test_bits_to_target_04123456() {
let result = bits_to_target(0x04123456);
assert!(result.is_ok(), "Should be valid");
assert!(result.unwrap() == 0x12345600_u256, "Incorrect target for 0x04123456");
}

#[test]
fn test_bits_to_target_1d00ffff() {
let result = bits_to_target(0x1d00ffff);
assert!(result.is_ok(), "Should be valid");
assert!(
result.unwrap() == 0x00000000ffff0000000000000000000000000000000000000000000000000000_u256,
"Incorrect target for 0x1d00ffff"
);
}

#[test]
fn test_bits_to_target_1c0d3142() {
let result = bits_to_target(0x1c0d3142);
assert!(result.is_ok(), "Should be valid");
assert!(
result.unwrap() == 0x000000000d314200000000000000000000000000000000000000000000000000_u256,
"Incorrect target for 0x1c0d3142"
);
}

#[test]
fn test_bits_to_target_1707a429() {
let result = bits_to_target(0x1707a429);
assert!(result.is_ok(), "Should be valid");
assert!(
result.unwrap() == 0x00000000000000000007a4290000000000000000000000000000000000000000_u256,
"Incorrect target for 0x1707a429"
);
}
Loading