lib: Add Obligation and Cert types with construction

This commit is contained in:
Davie Li 2024-04-21 14:26:47 +00:00
parent 3278f33899
commit 81d2e8b116
2 changed files with 106 additions and 0 deletions

View file

@ -6,3 +6,7 @@ edition = "2021"
[[bin]]
name = "credit5000"
path = "src/main.rs"
[dependencies]
ed25519-dalek = "2.1.1"
rand = "0.8.5"

102
src/lib.rs Normal file
View file

@ -0,0 +1,102 @@
use dalek::Verifier;
use ed25519_dalek as dalek;
use rand::prelude as rand;
pub type Address = [u8; 32];
pub type Signature = [u8; 64];
pub type Salt = [u8; 32];
/// TODO: Use hashes instead of public addresses.
/// TODO: Don't forget document endiannes.
/// TODO: Allow doubly signed obligations or implement abstract interfaces for Cert (see below).
/// Implement abstract Cert datatype to allow attestation of hyper-relations:
/// TODO: Use serializable trait to generalize over the subject field.
/// TODO: Allow per subject type verification trait. Hard not to go
/// full crypto-conditions but better not to complicate things too
/// much.
#[derive(Copy, Clone, PartialEq, Debug)]
pub struct Obligation {
pub from: Address,
pub to: Address,
pub value: u32,
}
impl Obligation {
fn serialize(self) -> Vec<u8> {
[&self.from[..], &self.value.to_le_bytes()[..], &self.to[..]].concat()
}
}
#[derive(Copy, Clone)]
pub struct Cert {
pub subject: Obligation,
pub signature: Signature,
pub salt: Salt,
}
impl Cert {
/// TODO: add optional salt argument
pub fn new(sub: Obligation, sig: Signature) -> Result<Self, &'static str> {
match dalek::VerifyingKey::from_bytes(&sub.from)
.unwrap()
.verify(&sub.serialize()[..], &dalek::Signature::from_bytes(&sig))
{
Ok(_) => Ok(Self {
subject: sub,
signature: sig,
salt: rand::random(),
}),
Err(_) => Err("Invalid signature"),
}
}
}
#[cfg(test)]
mod tests {
use crate::{Cert, Obligation};
use ed25519_dalek::{Signer, SigningKey};
#[test]
fn serialize_obligation() {
assert_eq!(
Obligation {
from: [1; 32],
to: [2; 32],
value: 4_294_967_295, // Max u32 (255 255 255 255)
}
.serialize(),
[
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 255, 255, 255, 255, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2
]
);
}
#[test]
fn cert_new() {
let sk_gen = || {
let skobj = SigningKey::from_bytes(&rand::random());
(
skobj.clone(),
skobj.to_bytes(),
skobj.verifying_key().to_bytes(),
)
};
let (f, _, fpk) = sk_gen();
let (_, _, tpk) = sk_gen();
let sub = Obligation {
from: fpk,
to: tpk,
value: 1000,
};
let sig = f.sign(&sub.serialize()[..]).to_bytes();
let cert = Cert::new(sub, sig);
assert!(cert.is_ok());
assert_eq!(cert.unwrap().subject, sub);
assert_eq!(cert.unwrap().signature, sig);
assert!(Cert::new(sub, [0; 64]).is_err());
}
}