commit
fe3381650e
@ -0,0 +1,3 @@
|
||||
/target
|
||||
Cargo.lock
|
||||
*~
|
@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "kana-hash"
|
||||
version = "0.1.0"
|
||||
authors = ["Avril <flanchan@cumallover.me>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
sha2 = "0.9"
|
||||
malloc-array = "1.3.3"
|
||||
libc = "0.2"
|
||||
crc = "1.8"
|
@ -0,0 +1,16 @@
|
||||
|
||||
|
||||
|
||||
pub fn copy_slice<T,D,S>(mut dst: D, src: S) -> usize
|
||||
where T: Clone,
|
||||
D: AsMut<[T]>,
|
||||
S: AsRef<[T]>
|
||||
{
|
||||
let mut i =0;
|
||||
for (d,s) in dst.as_mut().iter_mut().zip(src.as_ref().iter())
|
||||
{
|
||||
*d = s.clone();
|
||||
i+=1;
|
||||
}
|
||||
i
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
use std::ops::RangeInclusive;
|
||||
|
||||
#[derive(Clone,Debug,PartialEq,Eq,Hash)]
|
||||
pub enum Definition
|
||||
{
|
||||
Single(RangeInclusive<usize>),
|
||||
Any,
|
||||
None,
|
||||
}
|
||||
|
||||
impl Definition
|
||||
{
|
||||
|
||||
pub const fn single(idx: RangeInclusive<usize>) -> Self
|
||||
{
|
||||
Self::Single(idx)
|
||||
}
|
||||
pub const fn any() -> Self
|
||||
{
|
||||
Self::Any
|
||||
}
|
||||
pub const fn none() -> Self
|
||||
{
|
||||
Self::None
|
||||
}
|
||||
|
||||
pub fn contains(&self, sz: usize) -> bool
|
||||
{
|
||||
use Definition::*;
|
||||
match self {
|
||||
Single(range) => range.contains(&sz),
|
||||
Any => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
use std::{
|
||||
fmt,
|
||||
io,
|
||||
error,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error
|
||||
{
|
||||
IO(io::Error),
|
||||
Format(fmt::Error),
|
||||
Length{expected: usize, got:usize,},
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl error::Error for Error
|
||||
{
|
||||
fn source(&self) -> Option<&(dyn error::Error + 'static)>
|
||||
{
|
||||
match &self {
|
||||
Error::IO(e_io) => Some(e_io),
|
||||
Error::Format(e_fmt) => Some(e_fmt),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Error
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||
{
|
||||
write!(f, "kana-hash error: ")?;
|
||||
match self {
|
||||
Error::IO(io) => write!(f, "io: {}", io),
|
||||
Error::Format(fmt) => write!(f, "fmt: {}", fmt),
|
||||
Error::Length{expected, got} => write!(f, "invalid length: expected {}, got {}", expected, got),
|
||||
_ => write!(f, "unknown failure"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Error> for i32
|
||||
{
|
||||
fn from(er: Error) -> Self
|
||||
{
|
||||
match er {
|
||||
Error::IO(_) => 1,
|
||||
Error::Format(_) => 2,
|
||||
Error::Length{..} => 3,
|
||||
_ => -1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<io::Error> for Error
|
||||
{
|
||||
fn from(i: io::Error) -> Self
|
||||
{
|
||||
Self::IO(i)
|
||||
}
|
||||
}
|
||||
impl From<fmt::Error> for Error
|
||||
{
|
||||
fn from(i: fmt::Error) -> Self
|
||||
{
|
||||
Self::Format(i)
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
#![allow(unused_macros)]
|
||||
|
||||
pub const GENERIC_ERROR: i32 = -1;
|
||||
pub const GENERIC_SUCCESS: i32 = 0;
|
||||
|
||||
macro_rules! c_try {
|
||||
($e:expr) => {
|
||||
match $e {
|
||||
Ok(v) => v,
|
||||
Err(e) => return i32::from(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! no_unwind {
|
||||
(try $t:expr; $($e:tt)*) => {
|
||||
{
|
||||
match std::panic::catch_unwind(|| {
|
||||
$($e)*
|
||||
}) {
|
||||
Ok(v) => i32::from(v),
|
||||
Err(_) => return i32::from($t),
|
||||
}
|
||||
}
|
||||
};
|
||||
($($e:tt)*) => {
|
||||
no_unwind! {try $crate::ffi::GENERIC_ERROR; $($e)*}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
macro_rules! string_from_ffi {
|
||||
($file:expr) => {
|
||||
unsafe {
|
||||
let file = $file;
|
||||
if file.is_null() {
|
||||
return $crate::ffi::GENERIC_ERROR;
|
||||
}
|
||||
let file = CStr::from_ptr(file);
|
||||
match file.to_str() {
|
||||
Ok(file) => file.to_owned(),
|
||||
Err(_) => return $crate::ffi::GENERIC_ERROR,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
/// Group iterator output every n values into `Vec<T>`.
|
||||
pub struct GroupIter<T,I>
|
||||
where I: Iterator<Item=T>
|
||||
{
|
||||
buffer: Vec<T>,
|
||||
iter: I,
|
||||
group_at: usize,
|
||||
}
|
||||
|
||||
impl<T,I> Iterator for GroupIter<T,I>
|
||||
where I: Iterator<Item=T>
|
||||
{
|
||||
type Item = Vec<T>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item>
|
||||
{
|
||||
while self.buffer.len() < self.group_at
|
||||
{
|
||||
if let Some(value) = self.iter.next() {
|
||||
self.buffer.push(value)
|
||||
} else {
|
||||
return self.swap();
|
||||
}
|
||||
}
|
||||
self.swap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T,I> GroupIter<T,I>
|
||||
where I: Iterator<Item=T>
|
||||
{
|
||||
fn swap(&mut self) -> Option<Vec<T>>
|
||||
{
|
||||
let buff = {
|
||||
let next = Vec::with_capacity(self.group_at);
|
||||
std::mem::replace(&mut self.buffer, next)
|
||||
};
|
||||
if buff.len() > 0 {
|
||||
Some(buff)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait GroupExt: Iterator + Sized {
|
||||
fn group_at(self, at: usize) -> GroupIter<<Self as Iterator>::Item, Self>
|
||||
{
|
||||
GroupIter{
|
||||
group_at: at,
|
||||
iter: self,
|
||||
buffer: Vec::with_capacity(at),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T> GroupExt for T where T: Iterator{}
|
||||
|
@ -0,0 +1,41 @@
|
||||
use super::*;
|
||||
use crc::{Hasher32, crc32};
|
||||
|
||||
pub struct Crc32Checksum
|
||||
{
|
||||
hash: u32,
|
||||
}
|
||||
|
||||
impl provider::ByteProvider for Crc32Checksum
|
||||
{
|
||||
fn bytes(&self) -> &[u8]
|
||||
{
|
||||
unsafe{reinterpret::bytes(&self.hash)}
|
||||
}
|
||||
|
||||
fn compute<T: Read + ?Sized>(input: &mut T, done: &mut usize) -> Result<Self, error::Error>
|
||||
{
|
||||
let mut buffer = [0u8; BUFFER_SIZE];
|
||||
let mut hasher = crc32::Digest::new(crc32::IEEE);
|
||||
let mut read;
|
||||
while (read = input.read(&mut buffer[..])?, read!=0).1
|
||||
{
|
||||
hasher.write(&buffer[..read]);
|
||||
*done += read;
|
||||
}
|
||||
Ok(Self{hash: hasher.sum32()})
|
||||
}
|
||||
}
|
||||
|
||||
use std::fmt;
|
||||
impl fmt::Display for Crc32Checksum
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||
{
|
||||
write!(f, "Crc32checksum (")?;
|
||||
for b in provider::ByteProvider::bytes(self) {
|
||||
write!(f, "{:02x}", *b)?;
|
||||
}
|
||||
write!(f, ")")
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
use super::*;
|
||||
use crc::{Hasher64, crc64};
|
||||
|
||||
pub struct Crc64Checksum
|
||||
{
|
||||
hash: u64,
|
||||
}
|
||||
|
||||
impl provider::ByteProvider for Crc64Checksum
|
||||
{
|
||||
fn bytes(&self) -> &[u8]
|
||||
{
|
||||
unsafe{reinterpret::bytes(&self.hash)}
|
||||
}
|
||||
|
||||
fn compute<T: Read + ?Sized>(input: &mut T, done: &mut usize) -> Result<Self, error::Error>
|
||||
{
|
||||
let mut buffer = [0u8; BUFFER_SIZE];
|
||||
let mut hasher = crc64::Digest::new(crc64::ECMA);
|
||||
let mut read;
|
||||
while (read = input.read(&mut buffer[..])?, read!=0).1
|
||||
{
|
||||
hasher.write(&buffer[..read]);
|
||||
*done += read;
|
||||
}
|
||||
Ok(Self{hash: hasher.sum64()})
|
||||
}
|
||||
}
|
||||
|
||||
use std::fmt;
|
||||
impl fmt::Display for Crc64Checksum
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||
{
|
||||
write!(f, "Crc64checksum (")?;
|
||||
for b in provider::ByteProvider::bytes(self) {
|
||||
write!(f, "{:02x}", *b)?;
|
||||
}
|
||||
write!(f, ")")
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
use crate::*;
|
||||
|
||||
mod sha256;
|
||||
pub use sha256::*;
|
||||
|
||||
mod crc64;
|
||||
pub use crc64::*;
|
||||
|
||||
mod crc32;
|
||||
pub use crc32::*;
|
@ -0,0 +1,83 @@
|
||||
use super::*;
|
||||
use sha2::{Sha256, Digest};
|
||||
use std::{
|
||||
io::{
|
||||
self,
|
||||
Read,
|
||||
},
|
||||
};
|
||||
|
||||
pub const SHA256_SIZE: usize = 32;
|
||||
#[repr(C)]
|
||||
#[repr(packed)]
|
||||
#[derive(Copy,Clone,Debug,PartialEq,Eq,Hash)]
|
||||
pub struct Sha256Hash
|
||||
{
|
||||
hash: [u8; SHA256_SIZE],
|
||||
}
|
||||
|
||||
|
||||
fn compute_stream<T: Read +?Sized, D: Digest>(input: &mut T, output: &mut D) -> io::Result<usize>
|
||||
{
|
||||
let mut buffer = [0u8; BUFFER_SIZE];
|
||||
|
||||
let mut read;
|
||||
let mut done=0;
|
||||
while (read = input.read(&mut buffer[..])?, read!=0).1
|
||||
{
|
||||
output.update(&buffer[..read]);
|
||||
done+=read;
|
||||
}
|
||||
Ok(done)
|
||||
}
|
||||
|
||||
impl Sha256Hash
|
||||
{
|
||||
/// Compute a hash from a stream.
|
||||
pub fn compute<T: Read + ?Sized>(input: &mut T) -> io::Result<(usize, Self)>
|
||||
{
|
||||
let mut hash = [0u8; SHA256_SIZE];
|
||||
|
||||
let mut hasher = Sha256::new();
|
||||
|
||||
let ok = compute_stream(input, &mut hasher)?;
|
||||
|
||||
assert_eq!(array::copy_slice(&mut hash, hasher.finalize()), SHA256_SIZE);
|
||||
Ok((ok, Self{hash}))
|
||||
}
|
||||
|
||||
pub fn bytes(&self) -> &[u8; SHA256_SIZE]
|
||||
{
|
||||
&self.hash
|
||||
}
|
||||
}
|
||||
|
||||
use std::fmt;
|
||||
impl fmt::Display for Sha256Hash
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||
{
|
||||
write!(f, "Sha256hash (")?;
|
||||
for byte in self.hash.iter()
|
||||
{
|
||||
write!(f, "{:02x}", *byte)?;
|
||||
}
|
||||
write!(f, ")")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl provider::ByteProvider for hash::Sha256Hash
|
||||
{
|
||||
fn bytes(&self) -> &[u8]
|
||||
{
|
||||
&self.bytes()[..]
|
||||
}
|
||||
|
||||
fn compute<T: Read + ?Sized>(input: &mut T, done: &mut usize) -> Result<Self, error::Error>
|
||||
{
|
||||
let (ok, this) = Self::compute(input)?;
|
||||
*done = ok;
|
||||
Ok(this)
|
||||
}
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
#![allow(dead_code)]
|
||||
use std::{
|
||||
io::{
|
||||
Read,
|
||||
},
|
||||
fmt::Write,
|
||||
};
|
||||
|
||||
type HASHER =hash::Crc64Checksum;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn it_works() -> Result<(), error::Error>
|
||||
{
|
||||
let input = b"hello world!!";
|
||||
let kana = generate(input)?;
|
||||
println!("kana: {}", kana);
|
||||
panic!("uhh")
|
||||
}
|
||||
}
|
||||
|
||||
pub const BUFFER_SIZE: usize = 4096;
|
||||
|
||||
mod array;
|
||||
mod reinterpret;
|
||||
mod group;
|
||||
mod sixteen;
|
||||
use sixteen::Bit16IterExt;
|
||||
mod def;
|
||||
mod map;
|
||||
mod hash;
|
||||
mod provider;
|
||||
mod mnemonic;
|
||||
mod error;
|
||||
|
||||
#[macro_use]
|
||||
mod ffi;
|
||||
use ffi::*;
|
||||
|
||||
fn compute<T: Read, Digest: provider::ByteProvider>(mut from: T) -> Result<(usize, String), error::Error>
|
||||
{
|
||||
let (read, hash) = provider::compute::<_, Digest>(&mut from)?;
|
||||
|
||||
println!("hash ({}): {}", read, hash);
|
||||
let mut output = String::with_capacity(128);
|
||||
for element in hash.bytes().iter()
|
||||
.into_16()
|
||||
.map(|bytes| mnemonic::Digest::new(unsafe{reinterpret::bytes(&bytes)}))
|
||||
{
|
||||
write!(output, "{}", element)?;
|
||||
}
|
||||
|
||||
Ok((read,output))
|
||||
}
|
||||
|
||||
pub fn generate<T: AsRef<[u8]>>(bytes: T) -> Result<String, error::Error>
|
||||
{
|
||||
let bytes = bytes.as_ref();
|
||||
let mut nbytes = bytes;
|
||||
let (ok, string) = compute::<_, HASHER>(&mut nbytes)?;
|
||||
if ok == bytes.len() {
|
||||
Ok(string)
|
||||
} else {
|
||||
return Err(error::Error::Length{expected: bytes.len(), got: ok});
|
||||
}
|
||||
}
|
||||
|
||||
use std::ffi::c_void;
|
||||
use libc::{
|
||||
size_t,
|
||||
c_char,
|
||||
};
|
||||
|
||||
use malloc_array::{
|
||||
HeapArray,
|
||||
};
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn _kana_length(bin: *const c_void, sz: size_t, out_len: *mut size_t) -> i32
|
||||
{
|
||||
no_unwind!{
|
||||
try error::Error::Unknown;
|
||||
let bin = HeapArray::<u8>::from_raw_copied(bin as *const u8, usize::from(sz));
|
||||
let string = c_try!(generate(&bin));
|
||||
*out_len = (string.bytes().len()+1).into();
|
||||
|
||||
GENERIC_SUCCESS
|
||||
}
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn _kana_do(bin: *const c_void, sz: size_t, out_str: *mut c_char, str_len: size_t) -> i32
|
||||
{
|
||||
no_unwind!{
|
||||
try error::Error::Unknown;
|
||||
let bin = HeapArray::<u8>::from_raw_copied(bin as *const u8, usize::from(sz));
|
||||
let string: Vec<u8> = c_try!(generate(&bin)).bytes().collect();
|
||||
|
||||
libc::memcpy(out_str as *mut c_void, &string[0] as *const u8 as *const c_void, std::cmp::min(str_len, string.len()));
|
||||
|
||||
GENERIC_SUCCESS
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
use crate::*;
|
||||
|
||||
#[derive(Debug,Clone,PartialEq,Eq,Hash)]
|
||||
pub struct Digest(Option<char>, Option<char>);
|
||||
|
||||
impl Default for Digest
|
||||
{
|
||||
fn default() -> Self
|
||||
{
|
||||
Self(None,None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Digest {
|
||||
/// Create new single 2-byte digest.
|
||||
pub fn new(from: &[u8]) -> Self
|
||||
{
|
||||
let mut d = Self::default();
|
||||
|
||||
let master = usize::from(from[0]) % map::KANA.len();
|
||||
d.0 = Some(map::KANA[master]);
|
||||
if from[1] > 0 {
|
||||
if let Some(slaves) = map::sub(master) {
|
||||
if slaves.len() > 0 {
|
||||
d.1 = Some(slaves[usize::from(from[1]) % slaves.len()]);
|
||||
return d;
|
||||
}
|
||||
}
|
||||
let from = [from[1]];
|
||||
d.1 = Self::new(&from[..]).0;
|
||||
}
|
||||
d
|
||||
/*let master = usize::from(from) % map::KANA.len();
|
||||
d.0 = Some(map::KANA[master]);
|
||||
if let Some(slaves) = map::sub(master) {
|
||||
if slaves.len() > 0 {
|
||||
}
|
||||
} else {
|
||||
|
||||
}
|
||||
|
||||
return d;*/
|
||||
}
|
||||
}
|
||||
|
||||
use std::fmt;
|
||||
impl fmt::Display for Digest
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||
{
|
||||
if let Some(master) = self.0 {
|
||||
write!(f, "{}", master)?;
|
||||
}
|
||||
if let Some(slave) = self.1 {
|
||||
write!(f, "{}", slave)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
use crate::*;
|
||||
|
||||
pub trait ByteProvider: Sized + std::fmt::Display
|
||||
{
|
||||
fn compute<T: Read + ?Sized>(input: &mut T, provided: &mut usize) -> Result<Self, error::Error>;
|
||||
fn bytes(&self) -> &[u8];
|
||||
}
|
||||
|
||||
|
||||
pub fn compute<T: Read + ?Sized, P: ByteProvider>(input: &mut T) -> Result<(usize, P), error::Error>
|
||||
{
|
||||
let mut output = 0usize;
|
||||
let this = P::compute(input, &mut output)?;
|
||||
Ok((output, this))
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
|
||||
|
||||
pub unsafe fn bytes<'a, T>(src: &'a T) -> &'a [u8]
|
||||
where T: ?Sized
|
||||
{
|
||||
std::slice::from_raw_parts(src as *const T as *const u8, std::mem::size_of_val(src))
|
||||
}
|
||||
|
||||
pub unsafe fn bytes_mut<'a, T>(src: &'a mut T) -> &'a mut [u8]
|
||||
where T: ?Sized
|
||||
{
|
||||
std::slice::from_raw_parts_mut(src as *mut T as *mut u8, std::mem::size_of_val(src))
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
use std::borrow::Borrow;
|
||||
|
||||
/// Iter that converts 2 `u8`s into 1 `u16`
|
||||
pub struct Bit16Iter<I>
|
||||
where I: Iterator,
|
||||
<I as Iterator>::Item: Borrow<u8>
|
||||
{
|
||||
iter: I,
|
||||
}
|
||||
|
||||
impl<I> Iterator for Bit16Iter<I>
|
||||
where I: Iterator,
|
||||
<I as Iterator>::Item: Borrow<u8>
|
||||
{
|
||||
type Item = u16;
|
||||
fn next(&mut self) -> Option<Self::Item>
|
||||
{
|
||||
let mut c = 0u16;
|
||||
unsafe {
|
||||
if let Some(a) = self.iter.next() {
|
||||
crate::reinterpret::bytes_mut(&mut c)[0] = *a.borrow();
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
if let Some(b) = self.iter.next() {
|
||||
crate::reinterpret::bytes_mut(&mut c)[1] = *b.borrow();
|
||||
}
|
||||
}
|
||||
Some(c)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Bit16IterExt: Iterator + Sized
|
||||
where <Self as Iterator>::Item: Borrow<u8>
|
||||
{
|
||||
fn into_16(self) -> Bit16Iter<Self>;
|
||||
}
|
||||
|
||||
impl<I> Bit16IterExt for I
|
||||
where I: Iterator,
|
||||
<I as Iterator>::Item: Borrow<u8>
|
||||
{
|
||||
fn into_16(self) -> Bit16Iter<Self>
|
||||
{
|
||||
Bit16Iter{
|
||||
iter: self
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in new issue