Skip to content

Commit

Permalink
switch to Baid64
Browse files Browse the repository at this point in the history
Signed-off-by: Dr Maxim Orlovsky <[email protected]>
  • Loading branch information
dr-orlovsky committed Apr 24, 2024
1 parent 71e74c3 commit 37e1e58
Show file tree
Hide file tree
Showing 5 changed files with 171 additions and 64 deletions.
52 changes: 5 additions & 47 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ required-features = ["cli"]

[dependencies]
amplify = "4.6.0"
baid58 = "0.4.4"
secp256k1 = { version = "0.29.0", features = ["rand", "global-context"] }
rand = "0.8.5"
clap = { version = "4.5.4", features = ["derive"], optional = true }
Expand All @@ -23,6 +22,9 @@ rpassword = { version = "7.3.1", optional = true }
aes = { version = "0.8.4", optional = true }
crossbeam-channel = { version = "0.5.12", optional = true }

mnemonic = "1.0.1"
base64 = "0.22.0"

[features]
default = ["cli"]
cli = ["clap", "crossbeam-channel", "shellexpand", "rpassword", "aes"]
139 changes: 139 additions & 0 deletions src/baid64.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// Base64-encoded identifiers
//
// SPDX-License-Identifier: Apache-2.0
//
// Written in 2024 by
// Dr Maxim Orlovsky <[email protected]>
//
// Copyright (C) 2024 Cyphernet. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::fmt::{self, Display, Formatter};

use base64::Engine;
use sha2::Digest;

pub const HRI_MAX_LEN: usize = 16;
const LEN: usize = 32;

pub const BAID64_ALPHABET: &str =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789@$";

pub trait ToBaid64 {
const HRI: &'static str;
const CHUNKING: bool;
const PREFIX: bool;
const MNEMONIC: bool;

fn to_baid64_payload(&self) -> [u8; 32];
fn to_baid64(&self) -> Baid64 {
Baid64::with(
Self::HRI,
self.to_baid64_payload(),
Self::CHUNKING,
Self::PREFIX,
Self::MNEMONIC,
)
}
fn to_baid64_string(&self) -> String { self.to_baid64().to_string() }
fn fmt_baid64(&self, f: &mut Formatter) -> fmt::Result { Display::fmt(&self.to_baid64(), f) }
}

#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)]
pub struct Baid64 {
hri: &'static str,
chunking: bool,
mnemonic: String,
prefix: bool,
suffix: bool,
checksum: u32,
payload: [u8; LEN],
}

impl Baid64 {
pub fn with(
hri: &'static str,
payload: [u8; LEN],
chunking: bool,
prefix: bool,
suffix: bool,
) -> Self {
debug_assert!(hri.len() <= HRI_MAX_LEN, "HRI is too long");
debug_assert!(LEN > HRI_MAX_LEN, "Baid64 id must be at least 9 bytes");

let key = sha2::Sha256::digest(hri.as_bytes());
let mut sha = sha2::Sha256::new_with_prefix(key);
sha.update(&payload);
let sha = sha.finalize();
let checksum = u32::from_le_bytes([sha[0], sha[1], sha[1], sha[2]]);
let mnemonic = mnemonic::to_string(checksum.to_le_bytes());

Self {
hri,
chunking,
mnemonic,
prefix,
suffix,
checksum,
payload,
}
}

pub fn plain(hri: &'static str, payload: [u8; LEN]) -> Self {
Self::with(hri, payload, false, false, false)
}
pub fn chunked(hri: &'static str, payload: [u8; LEN]) -> Self {
Self::with(hri, payload, true, false, false)
}
pub fn full(hri: &'static str, payload: [u8; LEN]) -> Self {
Self::with(hri, payload, true, true, true)
}

pub const fn human_identifier(&self) -> &'static str { self.hri }

pub fn mnemonic(&self) -> &str { &self.mnemonic }
pub const fn checksum(&self) -> u32 { self.checksum }
}

impl Display for Baid64 {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
use base64::alphabet::Alphabet;
use base64::engine::general_purpose::NO_PAD;
use base64::engine::GeneralPurpose;

if (self.prefix && !f.sign_minus()) || (!self.prefix && f.sign_minus()) {
write!(f, "{}:", self.hri)?;
}

let alphabet = Alphabet::new(BAID64_ALPHABET).expect("invalid Baid64 alphabet");
let engine = GeneralPurpose::new(&alphabet, NO_PAD);
let s = engine.encode(self.payload);

if self.chunking {
let bytes = s.as_bytes();
f.write_str(&String::from_utf8_lossy(&bytes[..6]))?;
for chunk in bytes[6..].chunks(8) {
write!(f, "-{}", &String::from_utf8_lossy(chunk))?;
}
} else {
f.write_str(&s)?;
}

if (self.suffix && !f.alternate()) || (!self.suffix && f.alternate()) {
write!(f, "#{}", self.mnemonic)?;
}

Ok(())
}
}
36 changes: 21 additions & 15 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
#[macro_use]
extern crate amplify;

pub mod baid64;

use std::fmt;
use std::fmt::{Display, Formatter};
use std::hash::Hash;
Expand All @@ -31,10 +33,11 @@ use aes::cipher::generic_array::GenericArray;
use aes::cipher::{BlockDecrypt, BlockEncrypt, KeyInit};
use aes::{Aes256, Block};
use amplify::{Bytes, Display};
use baid58::{Baid58ParseError, Chunking, FromBaid58, ToBaid58, CHUNKING_32};
use secp256k1::SECP256K1;
use sha2::{Digest, Sha256};

use crate::baid64::ToBaid64;

#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Display, Default)]
#[non_exhaustive]
pub enum Algo {
Expand Down Expand Up @@ -133,12 +136,13 @@ pub struct Ssi {
key: Bytes<30>,
}

impl ToBaid58<32> for Ssi {
impl ToBaid64 for Ssi {
const HRI: &'static str = "ssi";
const CHUNKING: Option<Chunking> = CHUNKING_32;
const CHUNKING: bool = true;
const PREFIX: bool = true;
const MNEMONIC: bool = false;

fn to_baid58_payload(&self) -> [u8; 32] { <[u8; 32]>::from(*self) }
fn to_baid58_string(&self) -> String { self.to_string() }
fn to_baid64_payload(&self) -> [u8; 32] { <[u8; 32]>::from(*self) }
}

impl From<Ssi> for [u8; 32] {
Expand All @@ -160,17 +164,17 @@ impl From<[u8; 32]> for Ssi {
}
}

impl FromBaid58<32> for Ssi {}

impl Display for Ssi {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "{::<.2}", self.to_baid58()) }
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { self.fmt_baid64(f) }
}
/*
impl FromStr for Ssi {
type Err = Baid58ParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::from_baid58_maybe_chunked_str(s, ':', '#')
}
}
*/

#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display, Error)]
#[display("invalid public key")]
Expand All @@ -194,11 +198,13 @@ impl Ssi {
#[derive(Clone, Eq, PartialEq)]
pub struct SsiSecret(secp256k1::SecretKey);

impl ToBaid58<32> for SsiSecret {
const HRI: &'static str = "ssi";
impl ToBaid64 for SsiSecret {
const HRI: &'static str = "ssi:priv";
const CHUNKING: bool = false;
const PREFIX: bool = true;
const MNEMONIC: bool = false;

fn to_baid58_payload(&self) -> [u8; 32] { <[u8; 32]>::from(self.clone()) }
fn to_baid58_string(&self) -> String { self.to_string() }
fn to_baid64_payload(&self) -> [u8; 32] { <[u8; 32]>::from(self.clone()) }
}

impl From<SsiSecret> for [u8; 32] {
Expand All @@ -211,17 +217,17 @@ impl From<[u8; 32]> for SsiSecret {
}
}

impl FromBaid58<32> for SsiSecret {}

impl Display for SsiSecret {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "{:!<.2}", self.to_baid58()) }
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { self.fmt_baid64(f) }
}
/*
impl FromStr for SsiSecret {
type Err = Baid58ParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::from_baid58_maybe_chunked_str(s, '!', '#')
}
}
*/

impl SsiSecret {
pub fn new(chain: Chain) -> Self {
Expand Down
4 changes: 3 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,9 @@ fn main() {
let ssi = secret.to_public();
println!("{ssi}");

secret.encrypt(passwd);
if !passwd.is_empty() {
secret.encrypt(passwd);
}

let mut path = data_dir.clone();
path.push(name);
Expand Down

0 comments on commit 37e1e58

Please sign in to comment.