mirror of https://github.com/CympleTech/ESSE.git
4 changed files with 100 additions and 3 deletions
@ -0,0 +1,14 @@
@@ -0,0 +1,14 @@
|
||||
[package] |
||||
name = "esse_primitives" |
||||
version = "0.1.0" |
||||
authors = ["CympleTech <dev@cympletech.com>"] |
||||
edition = "2021" |
||||
readme = "README.md" |
||||
description = "ESSE common primitives." |
||||
repository = "https://github.com/cympletech/esse_types/primitives" |
||||
keywords = ["distributed", "p2p", "did", "ESSE"] |
||||
license = "MIT/Apache-2.0" |
||||
|
||||
[dependencies] |
||||
blake3 = "1.3" |
||||
tdn_types = { version = "0.6", default-features = false } |
@ -0,0 +1,81 @@
@@ -0,0 +1,81 @@
|
||||
pub mod bs32 { |
||||
use std::cmp::min; |
||||
|
||||
const RFC4648_ALPHABET: &'static [u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; |
||||
const RFC4648_INV_ALPHABET: [i8; 43] = [ |
||||
-1, -1, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1, -1, 0, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, |
||||
8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, |
||||
]; |
||||
|
||||
pub fn encode(data: &[u8]) -> String { |
||||
let mut ret = Vec::with_capacity((data.len() + 3) / 4 * 5); |
||||
|
||||
for chunk in data.chunks(5) { |
||||
let buf = { |
||||
let mut buf = [0u8; 5]; |
||||
for (i, &b) in chunk.iter().enumerate() { |
||||
buf[i] = b; |
||||
} |
||||
buf |
||||
}; |
||||
ret.push(RFC4648_ALPHABET[((buf[0] & 0xF8) >> 3) as usize]); |
||||
ret.push(RFC4648_ALPHABET[(((buf[0] & 0x07) << 2) | ((buf[1] & 0xC0) >> 6)) as usize]); |
||||
ret.push(RFC4648_ALPHABET[((buf[1] & 0x3E) >> 1) as usize]); |
||||
ret.push(RFC4648_ALPHABET[(((buf[1] & 0x01) << 4) | ((buf[2] & 0xF0) >> 4)) as usize]); |
||||
ret.push(RFC4648_ALPHABET[(((buf[2] & 0x0F) << 1) | (buf[3] >> 7)) as usize]); |
||||
ret.push(RFC4648_ALPHABET[((buf[3] & 0x7C) >> 2) as usize]); |
||||
ret.push(RFC4648_ALPHABET[(((buf[3] & 0x03) << 3) | ((buf[4] & 0xE0) >> 5)) as usize]); |
||||
ret.push(RFC4648_ALPHABET[(buf[4] & 0x1F) as usize]); |
||||
} |
||||
|
||||
if data.len() % 5 != 0 { |
||||
let len = ret.len(); |
||||
let num_extra = 8 - (data.len() % 5 * 8 + 4) / 5; |
||||
ret.truncate(len - num_extra); |
||||
} |
||||
|
||||
String::from_utf8(ret).unwrap() |
||||
} |
||||
|
||||
pub fn decode(data: &str) -> Option<Vec<u8>> { |
||||
if !data.is_ascii() { |
||||
return None; |
||||
} |
||||
let data = data.as_bytes(); |
||||
let mut unpadded_data_length = data.len(); |
||||
for i in 1..min(6, data.len()) + 1 { |
||||
if data[data.len() - i] != b'=' { |
||||
break; |
||||
} |
||||
unpadded_data_length -= 1; |
||||
} |
||||
let output_length = unpadded_data_length * 5 / 8; |
||||
let mut ret = Vec::with_capacity((output_length + 4) / 5 * 5); |
||||
for chunk in data.chunks(8) { |
||||
let buf = { |
||||
let mut buf = [0u8; 8]; |
||||
for (i, &c) in chunk.iter().enumerate() { |
||||
match RFC4648_INV_ALPHABET |
||||
.get(c.to_ascii_uppercase().wrapping_sub(b'0') as usize) |
||||
{ |
||||
Some(&-1) | None => return None, |
||||
Some(&value) => buf[i] = value as u8, |
||||
}; |
||||
} |
||||
buf |
||||
}; |
||||
ret.push((buf[0] << 3) | (buf[1] >> 2)); |
||||
ret.push((buf[1] << 6) | (buf[2] << 1) | (buf[3] >> 4)); |
||||
ret.push((buf[3] << 4) | (buf[4] >> 1)); |
||||
ret.push((buf[4] << 7) | (buf[5] << 2) | (buf[6] >> 3)); |
||||
ret.push((buf[6] << 5) | buf[7]); |
||||
} |
||||
ret.truncate(output_length); |
||||
Some(ret) |
||||
} |
||||
} |
||||
|
||||
pub fn id(peer: &tdn_types::primitive::PeerId) -> String { |
||||
let hash = blake3::hash(&peer.0); |
||||
bs32::encode(&hash.as_bytes()[0..30]) |
||||
} |
Loading…
Reference in new issue