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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#![feature(macro_metavar_expr)]
use std::path::{Path, PathBuf};

use aok::{Error, Result, OK};
use blake3::Hasher;
use ed25519_dalek::{Signer, SigningKey, SECRET_KEY_LENGTH};
use rand::rngs::OsRng;
use tokio::{
  fs::{write, File},
  io::AsyncReadExt,
};
use trt::join;

pub async fn key(key: impl AsRef<Path>, create: bool) -> Result<SigningKey> {
  let key = key.as_ref();
  match File::open(key).await {
    Ok(mut k) => {
      let mut signing_key_bytes: [u8; SECRET_KEY_LENGTH] = Default::default();
      k.read_exact(&mut signing_key_bytes).await?;
      Ok::<_, Error>(SigningKey::from_bytes(&signing_key_bytes))
    }
    Err(err) => {
      if create && err.kind() == tokio::io::ErrorKind::NotFound {
        let mut csprng = OsRng;
        let signing_key: SigningKey = SigningKey::generate(&mut csprng);

        let key_str = key.as_os_str().to_string_lossy();
        let pk_fp = if key_str.ends_with(".sk") {
          key_str[..key_str.len() - 2].to_owned() + "pk"
        } else {
          (key_str + ".pk").into()
        };
        write(pk_fp, signing_key.verifying_key().as_bytes()).await?;
        write(key, signing_key.as_bytes()).await?;
        Ok(signing_key)
      } else {
        Err(err.into())
      }
    }
  }
}

pub async fn hash(path: impl AsRef<Path>) -> Result<[u8; 32], std::io::Error> {
  let mut hasher = Hasher::new();
  let mut file = File::open(path).await?;

  let mut buf = [0; 4096];
  loop {
    let n = file.read(&mut buf).await?;
    if n == 0 {
      break;
    }
    hasher.update(&buf[..n]);
  }

  Ok(*hasher.finalize().as_bytes())
}

pub async fn b3s(fp: impl AsRef<Path>, key: SigningKey) -> Result<()> {
  let fp = fp.as_ref();
  let hash = hash(fp).await?;
  let fp: PathBuf = fp.into();
  let sign = key.sign(&hash).to_bytes();
  join!(
    write(fp.with_extension("b3"), hash),
    write(fp.with_extension("b3s"), sign)
  );
  /*
  use ed25519_dalek::Verifier;
  let verifying_key = key.verifying_key();
  let r = verifying_key.verify(&hash, &Signature::from_bytes(&sign));
  dbg!(r);
  */
  OK
}