implement signing

This commit is contained in:
tezlm 2024-02-07 16:20:23 -08:00
parent 0c96c9e7bf
commit 0daa4be975
Signed by: tezlm
GPG key ID: 649733FCD94AFBBA
6 changed files with 385 additions and 62 deletions

256
Cargo.lock generated
View file

@ -2,32 +2,153 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "base64ct"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
"generic-array",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "const-oid"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
[[package]]
name = "cpufeatures"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
dependencies = [
"libc",
]
[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "curve25519-dalek"
version = "4.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a677b8922c94e01bdbb12126b0bc852f00447528dee1782229af9c720c3f348"
dependencies = [
"cfg-if",
"cpufeatures",
"curve25519-dalek-derive",
"digest",
"fiat-crypto",
"platforms",
"rustc_version",
"subtle",
"zeroize",
]
[[package]]
name = "curve25519-dalek-derive"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "dag-resolve"
version = "0.1.0"
dependencies = [
"petgraph",
"ed25519",
"ed25519-dalek",
"hex",
"rand",
"serde",
"sha2",
"thiserror",
]
[[package]]
name = "equivalent"
version = "1.0.1"
name = "der"
version = "0.7.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c"
dependencies = [
"const-oid",
"zeroize",
]
[[package]]
name = "fixedbitset"
version = "0.4.2"
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
]
[[package]]
name = "ed25519"
version = "2.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53"
dependencies = [
"pkcs8",
"signature",
]
[[package]]
name = "ed25519-dalek"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871"
dependencies = [
"curve25519-dalek",
"ed25519",
"rand_core",
"serde",
"sha2",
"subtle",
"zeroize",
]
[[package]]
name = "fiat-crypto"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1676f435fc1dadde4d03e43f5d62b259e1ce5f40bd4ffb21db2b42ebe59c1382"
[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "getrandom"
@ -41,20 +162,10 @@ dependencies = [
]
[[package]]
name = "hashbrown"
version = "0.14.3"
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
[[package]]
name = "indexmap"
version = "2.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "824b2ae422412366ba479e8111fd301f7b5faece8149317bb81925979a53f520"
dependencies = [
"equivalent",
"hashbrown",
]
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "libc"
@ -63,15 +174,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
[[package]]
name = "petgraph"
version = "0.6.4"
name = "pkcs8"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9"
checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7"
dependencies = [
"fixedbitset",
"indexmap",
"der",
"spki",
]
[[package]]
name = "platforms"
version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "626dec3cac7cc0e1577a2ec3fc496277ec2baa084bebad95bb6fdbfae235f84c"
[[package]]
name = "ppv-lite86"
version = "0.2.17"
@ -126,6 +243,77 @@ dependencies = [
"getrandom",
]
[[package]]
name = "rustc_version"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
dependencies = [
"semver",
]
[[package]]
name = "semver"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0"
[[package]]
name = "serde"
version = "1.0.196"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.196"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "sha2"
version = "0.10.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "signature"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
dependencies = [
"rand_core",
]
[[package]]
name = "spki"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d"
dependencies = [
"base64ct",
"der",
]
[[package]]
name = "subtle"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
[[package]]
name = "syn"
version = "2.0.48"
@ -157,14 +345,32 @@ dependencies = [
"syn",
]
[[package]]
name = "typenum"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "zeroize"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d"

View file

@ -6,6 +6,10 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
petgraph = "0.6.4"
ed25519 = "2.2.3"
ed25519-dalek = { version = "2.1.1", features = ["rand_core"] }
hex = "0.4.3"
rand = "0.8.5"
serde = { version = "1.0.196", features = ["derive"] }
sha2 = "0.10.8"
thiserror = "1.0.56"

View file

@ -1,5 +1,5 @@
use std::fmt::{Debug, Display};
use ed25519_dalek::{Signer, Verifier};
use rand::{distributions::Alphanumeric, Rng};
#[derive(Hash, Clone, PartialEq, Eq, PartialOrd, Ord)]
@ -9,7 +9,13 @@ pub struct RoomId(String);
pub struct EventId(String);
#[derive(Hash, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct ActorId(String);
pub struct ActorId(ed25519::ComponentBytes);
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ActorSecret(ed25519::ComponentBytes);
#[derive(Clone, PartialEq, Eq)]
pub struct ActorSignature(ed25519::Signature);
impl RoomId {
// maybe use the initial create event hash/id as the room id?
@ -25,13 +31,34 @@ impl RoomId {
}
impl ActorId {
pub fn random() -> Self {
let rng = rand::thread_rng()
.sample_iter(Alphanumeric)
.map(char::from)
.take(12)
.collect();
Self(rng)
pub fn new_pair() -> (ActorId, ActorSecret) {
use rand::rngs::OsRng;
use ed25519_dalek::SigningKey;
let mut csprng = OsRng;
let signing_key: SigningKey = SigningKey::generate(&mut csprng);
signing_key.verifying_key();
let bytes = signing_key.to_keypair_bytes();
let id_bytes = ed25519::ComponentBytes::try_from(&bytes[0..ed25519_dalek::SECRET_KEY_LENGTH]).unwrap();
let secret_bytes = ed25519::ComponentBytes::try_from(&bytes[ed25519_dalek::SECRET_KEY_LENGTH..ed25519_dalek::SECRET_KEY_LENGTH + ed25519_dalek::PUBLIC_KEY_LENGTH]).unwrap();
(ActorId(id_bytes), ActorSecret(secret_bytes))
}
pub fn verify(&self, data: &[u8], signature: &ActorSignature) -> Result<(), ed25519::signature::Error> {
let key = ed25519_dalek::VerifyingKey::from_bytes(&self.0).unwrap();
key.verify(data, &signature.0)
}
}
impl ActorSecret {
pub fn sign(&self, data: &[u8]) -> ActorSignature {
let key = ed25519_dalek::SigningKey::from_bytes(&self.0);
ActorSignature(key.sign(data))
}
pub fn get_id(&self) -> ActorId {
let key = ed25519_dalek::SigningKey::from_bytes(&self.0);
ActorId(key.verifying_key().to_bytes())
}
}
@ -47,6 +74,24 @@ impl EventId {
}
}
impl Debug for ActorId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "^{}", hex::encode(&self.0))
}
}
impl Debug for ActorSignature {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "ActorSignature {{ {} }}", hex::encode(&self.0.to_bytes()))
}
}
// impl Debug for ActorSecret {
// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// write!(f, "ActorSecret {{ <redacted> }}")
// }
// }
macro_rules! impl_display {
($Thing:ty, $fmt:expr) => {
impl Display for $Thing {
@ -63,6 +108,5 @@ macro_rules! impl_display {
};
}
impl_display!(ActorId, "^{}");
impl_display!(EventId, "${}");
impl_display!(RoomId, "!{}");

View file

@ -1,5 +1,5 @@
use crate::atoms::{ActorId, ActorSecret, ActorSignature, EventId};
use std::fmt::Debug;
use crate::atoms::EventId;
#[derive(Debug)]
/// An event, is the basic building block/envolope containing all data.
@ -7,8 +7,25 @@ pub struct Event<T> {
pub id: EventId,
pub content: CoreContent<T>,
pub references: Vec<EventId>,
// pub author: ActorId,
// pub signature: ActorSignature,
pub author: ActorId,
pub signature: ActorSignature,
}
#[derive(Debug)]
pub struct EventBuilder<T> {
content: CoreContent<T>,
references: Vec<EventId>,
author: ActorId,
author_secret: ActorSecret,
}
#[derive(Debug)]
pub struct EventBuilderHasId<T> {
id: EventId,
content: CoreContent<T>,
references: Vec<EventId>,
author: ActorId,
author_secret: ActorSecret,
}
#[derive(Debug)]
@ -44,3 +61,50 @@ pub enum CoreContent<T> {
pub struct CreateContent {
pub resolver: String,
}
impl<T> Event<T> {
pub fn builder(content: CoreContent<T>, actor: &ActorSecret) -> EventBuilder<T> {
EventBuilder::new(content, actor)
}
}
impl<T> EventBuilder<T> {
pub fn new(content: CoreContent<T>, actor: &ActorSecret) -> Self {
EventBuilder {
content,
references: vec![],
author: actor.get_id(),
author_secret: actor.clone(),
}
}
pub fn with_references(self, references: impl IntoIterator<Item = EventId>) -> Self {
let new_refs = self.references.into_iter().chain(references).collect();
Self {
references: new_refs,
..self
}
}
pub fn then_hash(self) -> EventBuilderHasId<T> {
EventBuilderHasId {
id: EventId::random(),
content: self.content,
references: self.references,
author: self.author,
author_secret: self.author_secret,
}
}
}
impl<T> EventBuilderHasId<T> {
pub fn and_sign(self) -> Event<T> {
Event {
id: self.id,
content: self.content,
references: self.references,
author: self.author,
signature: self.author_secret.sign(&[0x00, 0x01, 0x02, 0x03]),
}
}
}

View file

@ -1,9 +1,7 @@
#![allow(dead_code)] // TODO: remove this later!
use crate::{
event::CoreContent,
resolvers::{KVEventContent, PremadeResolver},
room::Room,
atoms::ActorId, event::CoreContent, resolvers::{KVEventContent, PremadeResolver}, room::Room
};
mod atoms;
@ -14,22 +12,23 @@ mod resolvers;
mod room;
fn main() {
let (_actor, secret) = ActorId::new_pair();
let resolver = match PremadeResolver::get("kv") {
PremadeResolver::KVResolver(resolver) => resolver,
};
let mut room = Room::new("kv", Box::new(resolver));
let mut room = Room::new("kv", Box::new(resolver), &secret);
room.create_event(CoreContent::Custom(KVEventContent::Set(
"foo".into(),
"apple".into(),
)));
)), &secret);
room.create_event(CoreContent::Custom(KVEventContent::Set(
"bar".into(),
"banana".into(),
)));
)), &secret);
room.create_event(CoreContent::Custom(KVEventContent::Set(
"baz".into(),
"carrot".into(),
)));
)), &secret);
dbg!(&room);
dbg!(&room.get_state());
}

View file

@ -1,5 +1,5 @@
use crate::{
atoms::EventId,
atoms::{ActorSecret, EventId},
event::{CoreContent, CreateContent, Event},
resolver::{sort, Resolver},
};
@ -13,24 +13,31 @@ pub struct Room<E, S> {
}
impl<T: Debug, S> Room<T, S> {
pub fn new(resolver_name: impl Into<String>, resolver: Box<dyn Resolver<Type = T, State = S>>) -> Self {
let event_id = EventId::random();
let base_event = Event {
id: event_id.clone(),
content: CoreContent::Create(CreateContent {
pub fn new(
resolver_name: impl Into<String>,
resolver: Box<dyn Resolver<Type = T, State = S>>,
secret: &ActorSecret,
) -> Self {
let base_event = Event::builder(
CoreContent::Create(CreateContent {
resolver: resolver_name.into(),
}),
references: vec![],
};
secret,
)
.then_hash()
.and_sign();
Self {
heads: vec![base_event.id.clone()],
events: vec![base_event],
heads: vec![event_id],
resolver,
}
}
pub fn get_root(&self) -> &Event<T> {
self.events.first().as_ref().unwrap()
self.events
.first()
.as_ref()
.expect("room always has a root event")
}
pub fn get_resolver(&self) -> &dyn Resolver<Type = T, State = S> {
@ -43,12 +50,11 @@ impl<T: Debug, S> Room<T, S> {
resolver.resolve(&sorted)
}
pub fn create_event(&mut self, event_content: CoreContent<T>) {
let event = Event {
id: EventId::random(),
content: event_content,
references: std::mem::take(&mut self.heads),
};
pub fn create_event(&mut self, event_content: CoreContent<T>, secret: &ActorSecret) {
let event = Event::builder(event_content, secret)
.with_references(std::mem::take(&mut self.heads))
.then_hash()
.and_sign();
self.append_event(event);
}