i0 0.1.4

thei.rs/i0 reference implementation written in rust
Documentation
use base64::{Engine as _, engine::general_purpose::URL_SAFE_NO_PAD};
use clap::Parser;
#[cfg(feature = "v2")]
use i0::v2;
#[cfg(feature = "v3")]
use i0::v3;
use i0::{Timestamp, cli};
use rand::TryRngCore;
use rand::rngs::OsRng;

#[derive(Parser, Debug)]
#[command(about = "generates a new thei.rs/i0", long_about = None)]
struct Cli {
    /// user-defined designation
    #[arg(short, long)]
    designation: Option<String>,

    /// creation timestamp (used for migrating from older versions)
    #[arg(short, long)]
    timestamp: Option<String>,

    /// keypair seed (used for migrating from older versions)
    #[arg(short, long)]
    seed: Option<String>,

    /// which version of the specification to use
    #[arg(short, long, default_value_t = 3)]
    version: u8,
}

fn main() {
    // parse args
    let cli = Cli::parse();

    let designation = cli.designation.unwrap_or_default();
    let timestamp = cli
        .timestamp
        .map(|s| {
            Timestamp::try_from_hex(s.as_ref())
                .expect("timestamp in an invalid format; should be hex")
        })
        .unwrap_or_else(Timestamp::new);
    let mut seed: [u8; 32] = [0u8; 32];
    match cli.seed {
        Some(s) => {
            seed = URL_SAFE_NO_PAD
                .decode(s)
                .expect("seed is not valid base64 (make sure to use url-safe b64 without padding)")
                .as_slice()
                .try_into()
                .expect("seed must be 32 bytes")
        }
        None => OsRng
            .try_fill_bytes(&mut seed)
            .expect("failed to get randomness"),
    }
    let version = cli.version;

    // call the implementation
    let (short, long) = match version {
        #[cfg(feature = "v2")]
        2 => {
            let metadata = v2::Metadata {
                designation: &designation,
                timestamp: &timestamp,
                seed: &seed,
            };
            cli::print_metadata(version, &metadata);
            v2::generate(&metadata)
        }
        #[cfg(feature = "v3")]
        3 => {
            let metadata = v3::Metadata {
                designation: &designation,
                timestamp: &timestamp,
                seed: &seed,
            };
            cli::print_metadata(version, &metadata);
            v3::generate(&metadata)
        }
        _ => panic!("version {version} hasn't been implemented"),
    };

    // hand it to the user
    cli::print(version, &long, &short);
}