Skip to content

Commit

Permalink
negative base
Browse files Browse the repository at this point in the history
  • Loading branch information
SymmetricChaos committed Nov 28, 2024
1 parent 07a50ba commit f106b77
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 22 deletions.
2 changes: 2 additions & 0 deletions codes/src/ids/code_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ code_ids_and_names!(
BalancedTernary, "Balanced Ternary";
Barbier, "Barbier";
BaseN, "Base-N";
BaseNegativeTwo, "Base Negative 2";
BaseNBijective, "Bijective Base-N";
BaseX, "BaseX";
Base16, "Base16";
Expand Down Expand Up @@ -68,6 +69,7 @@ code_ids_and_names!(
MofN, "M-of-N";
Morse, "Morse";
Needle, "Needle";
NegativeBase, "Negative Base";
ParityBit, "Parity Bit";
Pgp, "PGP Words";
Primorial, "Primorial";
Expand Down
9 changes: 5 additions & 4 deletions codes/src/mathematical/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
pub mod arithmetic;
pub mod balanced_ternary;
pub mod base_n;
pub mod base_n_bijective;
pub mod base_negative_two;
pub mod biquinary_decimal;
pub mod combinadic;
pub mod elias;
Expand All @@ -10,13 +12,12 @@ pub mod fibonacci;
pub mod fibonacci_integers;
pub mod godel;
pub mod gray;
pub mod leb128;
pub mod levenshtein;
pub mod levenshtein_integers;
pub mod negative_base;
pub mod primorial;
pub mod roman_numeral;
pub mod symmetric_unary;
pub mod twos_complement;
pub mod unary;
pub mod arithmetic;
pub mod leb128;
pub mod primorial;

102 changes: 102 additions & 0 deletions codes/src/mathematical/negative_base.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
use crate::{errors::CodeError, traits::Code};
use itertools::Itertools;
use num::{Integer, Zero};
use utils::text_functions::num_to_digit;

pub struct BaseN {
pub radix: i32,
pub little_endian: bool,
}

impl Default for BaseN {
fn default() -> Self {
Self {
radix: -2,
little_endian: true,
}
}
}

impl BaseN {
pub fn validate(&self) -> Result<(), CodeError> {
if self.radix > -2 || self.radix < -36 {
return Err(CodeError::state(
"radix must be between -2 and -36, inclusive",
));
}
Ok(())
}

pub fn encode_i32(&self, n: i32) -> Result<String, CodeError> {
if n.is_zero() {
return Ok(String::from("0"));
}
let mut n = n;
let mut s = Vec::new();
while n != 0 {
let (q, r) = n.div_rem(&self.radix);
s.push(num_to_digit(-r as u32).expect("remainder should always be less than 36"));

n = q;
}
if self.little_endian {
Ok(s.iter().rev().collect())
} else {
Ok(s.iter().collect())
}
}

pub fn decode_to_i32(&self, s: &str) -> Result<i32, CodeError> {
let word: String = if self.little_endian {
s.chars().collect()
} else {
s.chars().rev().collect()
};

i32::from_str_radix(&word, -self.radix as u32).map_err(|e| CodeError::Input(e.to_string()))
}
}

impl Code for BaseN {
fn encode(&self, text: &str) -> Result<String, CodeError> {
self.validate()?;
let mut output = Vec::new();

for group in text.split(" ") {
if group.is_empty() {
continue;
}
let n = i32::from_str_radix(group, 10)
.map_err(|_| CodeError::invalid_input_group(group))?;
output.push(self.encode_i32(n)?);
}

Ok(output.into_iter().join(" "))
}

fn decode(&self, text: &str) -> Result<String, CodeError> {
self.validate()?;
let mut output = String::new();

for s in text.split(" ") {
if s.is_empty() {
continue;
}
output.push_str(&format!("{} ", self.decode_to_i32(s)?))
}
output.pop();

Ok(output)
}
}

#[cfg(test)]
mod negative_base_n_tests {
use super::*;

const PLAINTEXT_INT: &'static str = "0 1 2 3 4 5";
const ENCODEDTEXT: &'static str = "0 1 10 11 100 101";

const PLAINTEXT_INT_BE: &'static str = "0 1 2 3 4 5";
const ENCODEDTEXT_BE: &'static str = "0 1 01 11 001 101";
}
36 changes: 18 additions & 18 deletions hashers/src/blake/blake3.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
use crate::{blake_double_round, traits::ClassicHasher};
use std::cmp::min;
use utils::byte_formatting::ByteFormat;
use utils::byte_formatting::{make_u32s_le, ByteFormat};

// https://github.com/BLAKE3-team/BLAKE3
// https://github.com/BLAKE3-team/BLAKE3-specs/blob/master/blake3.pdf
// https://github.com/BLAKE3-team/BLAKE3/blob/master/reference_impl/reference_impl.rs

const OUT_LEN: usize = 32;
const KEY_LEN: usize = 32;

// Each chunk of 1024 bytes (256 words) is divided up into blocks of 64 bytes (16 words).
// Chunks are arranged into a tree structure while blocks are a simple array within each chunk
const BLOCK_LEN: usize = 64;
const CHUNK_LEN: usize = 1024;

// Bitflags that can be set for chunks
const CHUNK_START: u32 = 1 << 0;
const CHUNK_END: u32 = 1 << 1;
const PARENT: u32 = 1 << 2;
Expand All @@ -19,6 +23,7 @@ const KEYED_HASH: u32 = 1 << 4;
const DERIVE_KEY_CONTEXT: u32 = 1 << 5;
const DERIVE_KEY_MATERIAL: u32 = 1 << 6;

// Same IV as BLAKE2s, sqrt of the first eight primes
const IV: [u32; 8] = [
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
];
Expand All @@ -36,6 +41,8 @@ fn permute(m: &mut [u32; 16]) {
*m = permuted;
}

// The compression function.
// Compresses a block into a chaining value.
fn compress(
chaining_value: &[u32; 8],
block_words: &[u32; 16],
Expand Down Expand Up @@ -88,13 +95,6 @@ fn first_8_words(compression_output: [u32; 16]) -> [u32; 8] {
compression_output[0..8].try_into().unwrap()
}

fn words_from_little_endian_bytes(bytes: &[u8], words: &mut [u32]) {
debug_assert_eq!(bytes.len(), 4 * words.len());
for (four_bytes, word) in bytes.chunks_exact(4).zip(words) {
*word = u32::from_le_bytes(four_bytes.try_into().unwrap());
}
}

// Each chunk or parent node can produce either an 8-word chaining value or, by
// setting the ROOT flag, any number of final output bytes. The Output struct
// captures the state just prior to choosing between those two possibilities.
Expand Down Expand Up @@ -174,8 +174,7 @@ impl ChunkState {
// If the block buffer is full, compress it and clear it. More
// input is coming, so this compression is not CHUNK_END.
if self.block_len as usize == BLOCK_LEN {
let mut block_words = [0; 16];
words_from_little_endian_bytes(&self.block, &mut block_words);
let block_words = make_u32s_le::<16>(&self.block);
self.chaining_value = first_8_words(compress(
&self.chaining_value,
&block_words,
Expand All @@ -198,8 +197,7 @@ impl ChunkState {
}

fn output(&self) -> Output {
let mut block_words = [0; 16];
words_from_little_endian_bytes(&self.block, &mut block_words);
let block_words = make_u32s_le::<16>(&self.block);
Output {
input_chaining_value: self.chaining_value,
block_words,
Expand Down Expand Up @@ -247,6 +245,8 @@ pub struct Blake3Hasher {
}

impl Blake3Hasher {
// Create a new instance directly
// The key_words are
fn new_internal(key_words: [u32; 8], flags: u32) -> Self {
Self {
chunk_state: ChunkState::new(key_words, 0, flags),
Expand All @@ -259,26 +259,26 @@ impl Blake3Hasher {

/// Construct a new `Hasher` for the regular hash function.
pub fn new() -> Self {
// The default IV and no modes set
Self::new_internal(IV, 0)
}

/// Construct a new `Hasher` for the keyed hash function.
pub fn new_keyed(key: &[u8; KEY_LEN]) -> Self {
let mut key_words = [0; 8];
words_from_little_endian_bytes(key, &mut key_words);
Self::new_internal(key_words, KEYED_HASH)
// The same as .new() but with the key material instead of the default IV and they KEYED_HASH mode set
Self::new_internal(make_u32s_le::<8>(key), KEYED_HASH)
}

/// Construct a new `Hasher` for the key derivation function. The context
/// string should be hardcoded, globally unique, and application-specific.
pub fn new_derive_key(context: &str) -> Self {
// The context is converted into a IV by hashing it in the DERIVE_KEY_CONTEXT mode
let mut context_hasher = Self::new_internal(IV, DERIVE_KEY_CONTEXT);
context_hasher.update(context.as_bytes());
let mut context_key = [0; KEY_LEN];
context_hasher.finalize(&mut context_key);
let mut context_key_words = [0; 8];
words_from_little_endian_bytes(&context_key, &mut context_key_words);
Self::new_internal(context_key_words, DERIVE_KEY_MATERIAL)
// The hasher used in DERIVE_KEY_MATERIAL mode
Self::new_internal(make_u32s_le::<8>(&context_key), DERIVE_KEY_MATERIAL)
}

fn push_stack(&mut self, cv: [u32; 8]) {
Expand Down

0 comments on commit f106b77

Please sign in to comment.