initial commit

This commit is contained in:
Alain Zscheile 2023-06-24 21:14:10 +02:00
commit f4ca255f06
8 changed files with 1461 additions and 0 deletions

6
.gitignore vendored Normal file
View file

@ -0,0 +1,6 @@
.#*
/target
result
result-*
perf.data*
flamegraph.svg

744
Cargo.lock generated Normal file
View file

@ -0,0 +1,744 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "ahash"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f"
dependencies = [
"cfg-if",
"once_cell",
"version_check",
]
[[package]]
name = "allocator-api2"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56fc6cf8dc8c4158eed8649f9b8b0ea1518eb62b544fe9490d66fa0b349eafe9"
[[package]]
name = "ambient-authority"
version = "0.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9d4ee0d472d1cd2e28c97dfa124b3d8d992e10eb0a035f33f5d12e3a177ba3b"
[[package]]
name = "arrayref"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545"
[[package]]
name = "arrayvec"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
[[package]]
name = "base64"
version = "0.21.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d"
[[package]]
name = "base64ct"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6dbe3c979c178231552ecba20214a8272df4e09f232a87aef4320cf06539aded"
[[package]]
name = "blake3"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "729b71f35bd3fa1a4c86b85d32c8b9069ea7fe14f7a53cfabb65f62d4265b888"
dependencies = [
"arrayref",
"arrayvec",
"cc",
"cfg-if",
"constant_time_eq",
"digest",
]
[[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 = "camino"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c530edf18f37068ac2d977409ed5cd50d53d73bc653c7647b48eb78976ac9ae2"
[[package]]
name = "cap-primitives"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4b6df5b295dca8d56f35560be8c391d59f0420f72e546997154e24e765e6451"
dependencies = [
"ambient-authority",
"fs-set-times",
"io-extras",
"io-lifetimes",
"ipnet",
"maybe-owned",
"rustix",
"windows-sys",
"winx",
]
[[package]]
name = "cap-std"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3373a62accd150b4fcba056d4c5f3b552127f0ec86d3c8c102d60b978174a012"
dependencies = [
"camino",
"cap-primitives",
"io-extras",
"io-lifetimes",
"rustix",
]
[[package]]
name = "cc"
version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
[[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.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913"
[[package]]
name = "constant_time_eq"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21a53c0a4d288377e7415b53dcfc3c04da5cdc2cc95c8d5ac178b58f0b861ad6"
[[package]]
name = "cpufeatures"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03e69e28e9f7f77debdedbaafa2866e1de9ba56df55a8bd7cfc724c25a09987c"
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.0.0-rc.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "436ace70fc06e06f7f689d2624dc4e2f0ea666efb5aa704215f7249ae6e047a7"
dependencies = [
"cfg-if",
"cpufeatures",
"curve25519-dalek-derive",
"digest",
"fiat-crypto",
"platforms",
"rustc_version",
"subtle",
"zeroize",
]
[[package]]
name = "curve25519-dalek-derive"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "der"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56acb310e15652100da43d130af8d97b509e95af61aab1c5a7939ef24337ee17"
dependencies = [
"const-oid",
"zeroize",
]
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
"subtle",
]
[[package]]
name = "ed25519"
version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fb04eee5d9d907f29e80ee6b0e78f7e2c82342c63e3580d8c4f69d9d5aad963"
dependencies = [
"pkcs8",
"signature",
]
[[package]]
name = "ed25519-dalek"
version = "2.0.0-rc.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "faa8e9049d5d72bfc12acbc05914731b5322f79b5e2f195e9f2d705fca22ab4c"
dependencies = [
"curve25519-dalek",
"ed25519",
"serde",
"sha2",
"zeroize",
]
[[package]]
name = "errno"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
dependencies = [
"errno-dragonfly",
"libc",
"windows-sys",
]
[[package]]
name = "errno-dragonfly"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
dependencies = [
"cc",
"libc",
]
[[package]]
name = "event-listener"
version = "2.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
[[package]]
name = "fallible-iterator"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
[[package]]
name = "fallible-streaming-iterator"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
[[package]]
name = "fiat-crypto"
version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e825f6987101665dea6ec934c09ec6d721de7bc1bf92248e1d5810c8cd636b77"
[[package]]
name = "floof-core"
version = "0.1.0"
dependencies = [
"blake3",
"cap-std",
"ed25519",
"ed25519-dalek",
"event-listener",
"lru",
"rusqlite",
"thiserror",
"tracing",
"yzb64",
]
[[package]]
name = "fs-set-times"
version = "0.19.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7833d0f115a013d51c55950a3b09d30e4b057be9961b709acb9b5b17a1108861"
dependencies = [
"io-lifetimes",
"rustix",
"windows-sys",
]
[[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 = "hashbrown"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
dependencies = [
"ahash",
]
[[package]]
name = "hashbrown"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
dependencies = [
"ahash",
"allocator-api2",
]
[[package]]
name = "hashlink"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "312f66718a2d7789ffef4f4b7b213138ed9f1eb3aa1d0d82fc99f88fb3ffd26f"
dependencies = [
"hashbrown 0.14.0",
]
[[package]]
name = "hermit-abi"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
[[package]]
name = "io-extras"
version = "0.17.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fde93d48f0d9277f977a333eca8313695ddd5301dc96f7e02aeddcb0dd99096f"
dependencies = [
"io-lifetimes",
"windows-sys",
]
[[package]]
name = "io-lifetimes"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
dependencies = [
"hermit-abi",
"libc",
"windows-sys",
]
[[package]]
name = "ipnet"
version = "2.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f"
[[package]]
name = "itoa"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
[[package]]
name = "libc"
version = "0.2.146"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b"
[[package]]
name = "libsqlite3-sys"
version = "0.26.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afc22eff61b133b115c6e8c74e818c628d6d5e7a502afea6f64dee076dd94326"
dependencies = [
"pkg-config",
"vcpkg",
]
[[package]]
name = "linux-raw-sys"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
[[package]]
name = "lru"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03f1160296536f10c833a82dca22267d5486734230d47bf00bf435885814ba1e"
dependencies = [
"hashbrown 0.13.2",
]
[[package]]
name = "maybe-owned"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4facc753ae494aeb6e3c22f839b158aebd4f9270f55cd3c79906c45476c47ab4"
[[package]]
name = "once_cell"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
name = "pin-project-lite"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
[[package]]
name = "pkcs8"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7"
dependencies = [
"der",
"spki",
]
[[package]]
name = "pkg-config"
version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
[[package]]
name = "platforms"
version = "3.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3d7ddaed09e0eb771a79ab0fd64609ba0afb0a8366421957936ad14cbd13630"
[[package]]
name = "proc-macro2"
version = "1.0.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rusqlite"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "549b9d036d571d42e6e85d1c1425e2ac83491075078ca9a15be021c56b1641f2"
dependencies = [
"bitflags 2.3.2",
"fallible-iterator",
"fallible-streaming-iterator",
"hashlink",
"libsqlite3-sys",
"smallvec",
]
[[package]]
name = "rustc_version"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
dependencies = [
"semver",
]
[[package]]
name = "rustix"
version = "0.37.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0"
dependencies = [
"bitflags 1.3.2",
"errno",
"io-lifetimes",
"itoa",
"libc",
"linux-raw-sys",
"once_cell",
"windows-sys",
]
[[package]]
name = "semver"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
[[package]]
name = "serde"
version = "1.0.164"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d"
[[package]]
name = "sha2"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "signature"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500"
[[package]]
name = "smallvec"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
[[package]]
name = "spki"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a"
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.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "thiserror"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tracing"
version = "0.1.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
dependencies = [
"cfg-if",
"pin-project-lite",
"tracing-attributes",
"tracing-core",
]
[[package]]
name = "tracing-attributes"
version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tracing-core"
version = "0.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a"
dependencies = [
"once_cell",
]
[[package]]
name = "typenum"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
[[package]]
name = "unicode-ident"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
[[package]]
name = "windows_i686_gnu"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
[[package]]
name = "windows_i686_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
[[package]]
name = "winx"
version = "0.35.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c52a121f0fbf9320d5f2a9a5d82f6cb7557eda5e8b47fc3e7f359ec866ae960"
dependencies = [
"bitflags 1.3.2",
"io-lifetimes",
"windows-sys",
]
[[package]]
name = "yzb64"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23e8cedcc4503bd570a10e8161e669fa7038c893311dfe6b3c21d80b30f7be38"
dependencies = [
"base64",
"once_cell",
]
[[package]]
name = "zeroize"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9"

8
Cargo.toml Normal file
View file

@ -0,0 +1,8 @@
[workspace]
members = ["crates/*"]
resolver = "2"
[profile.release]
codegen-units = 2
debug = 1
lto = "thin"

View file

@ -0,0 +1,20 @@
[package]
name = "floof-core"
version = "0.1.0"
edition = "2021"
license = "Apache-2.0"
[dependencies]
blake3 = "1.4.0"
ed25519 = "2.2"
ed25519-dalek = "2.0.0-rc.3"
event-listener = "2.5"
lru = "0.10"
rusqlite = "0.29"
thiserror = "1.0"
tracing = "0.1"
yzb64 = "0.1"
[dependencies.cap-std]
version = "1.0"
features = ["fs_utf8"]

View file

@ -0,0 +1,249 @@
use ed25519_dalek::{Signature, SigningKey, VerifyingKey};
use std::io::Read;
use std::io::{Error as IoError, ErrorKind};
pub type KVFilters = Vec<(Vec<u8>, Vec<u8>)>;
pub type KVs = std::collections::BTreeMap<Vec<u8>, Vec<u8>>;
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("I/O error: {0:?}")]
Io(#[from] std::io::Error),
#[error("database error: {0:?}")]
Database(#[from] rusqlite::Error),
}
#[derive(Clone)]
pub struct Packet {
pub ttl: u8,
pub markers: KVs,
pub pubkey: VerifyingKey,
pub signature: Signature,
pub inner: Vec<u8>,
}
pub use blake3::Hash as PHash;
pub use event_listener::{Event, EventListener};
mod mangler;
pub use mangler::{FConfig, Mangler, WrappedPacket};
mod sessmgr;
pub use sessmgr::{Key as SessionKey, SessionManager};
mod pktspool;
pub use pktspool::PacketSpool;
pub use ed25519_dalek;
pub use rusqlite::Connection as DbConnection;
/// the signed part of a packet
#[derive(Clone)]
pub struct InnerPacket {
pub attrs: KVs,
pub data: Vec<u8>,
}
fn decode_u8<R: Read>(rdr: &mut R) -> std::io::Result<u8> {
let mut buf = [0u8; 1];
rdr.read_exact(&mut buf)?;
Ok(buf[0])
}
fn decode_u16<R: Read>(rdr: &mut R) -> std::io::Result<u16> {
let mut buf = [0u8; 2];
rdr.read_exact(&mut buf)?;
Ok(u16::from_be_bytes(buf))
}
fn decode_kvs<R: Read>(rdr: &mut R) -> std::io::Result<KVs> {
let mut kvs = KVs::new();
let kvpcnt = decode_u16(rdr)?;
for _ in 0..kvpcnt {
let keylen = decode_u8(rdr)?;
let vallen = decode_u16(rdr)?;
let (mut key, mut val): (Vec<u8>, Vec<u8>) =
(vec![0; keylen.into()], vec![0; vallen.into()]);
rdr.read_exact(&mut key[..])?;
rdr.read_exact(&mut val[..])?;
if kvs.insert(key, val).is_some() {
return Err(IoError::new(
ErrorKind::InvalidData,
"key repeated in KV map",
));
}
}
Ok(kvs)
}
fn encode_kvs<W: std::io::Write>(kvs: &KVs, wtr: &mut W) -> std::io::Result<()> {
let kvpcnt: u16 = kvs
.len()
.try_into()
.map_err(|e| IoError::new(ErrorKind::InvalidData, e))?;
wtr.write_all(&kvpcnt.to_be_bytes())?;
for (key, val) in kvs {
let keylen: u8 = key
.len()
.try_into()
.map_err(|e| IoError::new(ErrorKind::InvalidData, e))?;
let vallen: u16 = val
.len()
.try_into()
.map_err(|e| IoError::new(ErrorKind::InvalidData, e))?;
let [vall0, vall1] = vallen.to_be_bytes();
// NOTE: if write_all_vectored becomes stable, use that instead
wtr.write_all(&[keylen, vall0, vall1])?;
wtr.write_all(&key[..])?;
wtr.write_all(&val[..])?;
}
Ok(())
}
impl Packet {
pub fn hash(&self) -> std::io::Result<PHash> {
let mut hasher = blake3::Hasher::new();
self.encode_to_wtr(&mut hasher)?;
Ok(hasher.finalize())
}
pub fn verify(&self) -> bool {
self.pubkey
.verify_strict(&self.inner[..], &self.signature)
.is_ok()
}
pub fn sign(&mut self, sk: &SigningKey) {
use ed25519_dalek::Signer;
self.signature = sk.sign(&self.inner[..]);
self.pubkey = sk.into();
}
pub fn decode_from_rdr<R: Read>(mut rdr: R) -> std::io::Result<Self> {
let ver = decode_u8(&mut rdr)?;
if ver != 0 {
return Err(IoError::new(
ErrorKind::InvalidData,
"unknown packet version",
));
}
let ttl = decode_u8(&mut rdr)?;
let markers = decode_kvs(&mut rdr)?;
let mut pubkey_tmp = [0u8; ed25519_dalek::PUBLIC_KEY_LENGTH];
rdr.read_exact(&mut pubkey_tmp)?;
let pubkey = VerifyingKey::from_bytes(&pubkey_tmp)
.map_err(|e| IoError::new(ErrorKind::InvalidData, e))?;
let mut sig_tmp = [0u8; ed25519_dalek::SIGNATURE_LENGTH];
rdr.read_exact(&mut sig_tmp)?;
let signature = Signature::from_bytes(&sig_tmp);
let mut inner = Vec::new();
rdr.read_to_end(&mut inner)?;
Ok(Self {
ttl,
markers,
pubkey,
signature,
inner,
})
}
pub fn encode_to_wtr<W: std::io::Write>(&self, mut wtr: W) -> std::io::Result<()> {
wtr.write_all(&[0, self.ttl])?;
encode_kvs(&self.markers, &mut wtr)?;
wtr.write_all(self.pubkey.as_bytes())?;
wtr.write_all(&self.signature.to_bytes())?;
wtr.write_all(&self.inner[..])?;
wtr.flush()?;
Ok(())
}
pub fn decode_inner(&self) -> Option<InnerPacket> {
let mut ret = InnerPacket {
attrs: Default::default(),
data: Vec::new(),
};
let mut cur = std::io::Cursor::new(&self.inner[..]);
ret.attrs = decode_kvs(&mut cur).ok()?;
cur.read_to_end(&mut ret.data).ok()?;
Some(ret)
}
}
impl InnerPacket {
pub fn encode(&self) -> Option<Vec<u8>> {
let mut ret = Vec::new();
encode_kvs(&self.attrs, &mut std::io::Cursor::new(&mut ret)).ok()?;
ret.extend_from_slice(&self.data[..]);
Some(ret)
}
}
pub fn collect_garbage(
sessmgr: &mut SessionManager,
pktspool: &PacketSpool,
) -> Result<std::collections::HashSet<PHash>, Error> {
let still_valid = sessmgr.collect_garbage()?;
pktspool.collect_garbage(&still_valid)?;
Ok(still_valid)
}
/// the main coordination structure
pub struct Constellation {
pub mangler: Mangler,
pub pktspool: PacketSpool,
pub sessmgr: SessionManager,
pub notifs: Event,
}
impl Constellation {
/// convenience wrapper around [`crate::collect_garbage`]
#[inline]
pub fn collect_garbage(&mut self) -> Result<std::collections::HashSet<PHash>, Error> {
collect_garbage(&mut self.sessmgr, &self.pktspool)
}
#[inline]
pub fn listen(&self) -> EventListener {
self.notifs.listen()
}
pub fn process_packet<F: FnOnce(&mut WrappedPacket) -> bool>(
&mut self,
pkt: WrappedPacket,
cb: F,
) -> Result<Option<WrappedPacket>, Error> {
let mut pkt = match self.mangler.process(pkt) {
Some(x) => x,
None => return Ok(None),
};
// allow the user to manipulate the packet if it passes the normal filters
if !cb(&mut pkt) {
return Ok(None);
}
if pkt.inner.ttl > 1 {
if self.sessmgr.set_for_all(pkt.hash.as_bytes())? {
// only store packets if we have any sessions
self.pktspool.store(false, Some(&pkt).into_iter())?;
// only send notifications after we stored the message
self.notifs.notify(usize::MAX);
}
}
// in the original implementation, every conn, after getting :fwdxfer
// which was only emitted in Distributor, called
// * SessionManager.set_soft_multi
// * PacketSpool.store_new
// we can safely omit that because we control the ordering.
// and thus no conn should have to "upgrade" messages to a session
// now, downstreams need to get the packet
// * non-session-based: get :fwdxfer, store packet, :requestpull
// * session-based: get :SessionPushed, peek queue, :requestpull
Ok(Some(pkt))
}
}

View file

@ -0,0 +1,125 @@
use crate::{KVFilters, KVs, PHash};
use core::num::NonZeroUsize;
#[derive(Clone)]
pub struct WrappedPacket {
pub hash: PHash,
pub inner: crate::Packet,
}
impl AsRef<WrappedPacket> for WrappedPacket {
#[inline(always)]
fn as_ref(&self) -> &Self {
self
}
}
impl WrappedPacket {
#[inline]
pub fn wrap(inner: crate::Packet) -> std::io::Result<Self> {
inner.hash().map(|hash| Self { hash, inner })
}
#[inline]
pub fn hash2str(&self) -> String {
crate::pktspool::enc_hash(&self.hash)
}
}
pub struct FConfig {
pub pos_markers: KVs,
pub neg_markers: KVFilters,
pub set_markers: KVs,
pub pos_attrs: KVs,
pub neg_attrs: KVFilters,
}
impl FConfig {
fn check_filters(&self, pkt: &WrappedPacket) -> bool {
let pktx = match pkt.inner.decode_inner() {
Some(x) => x,
None => return false,
};
let markers = &pkt.inner.markers;
let attrs = &pktx.attrs;
if self
.neg_markers
.iter()
.filter_map(|(k, v)| markers.get(k).map(|xv| v == xv))
.any(core::convert::identity)
{
return false;
}
if !self
.pos_markers
.iter()
.filter_map(|(k, v)| markers.get(k).map(|xv| v == xv))
.all(core::convert::identity)
{
return false;
}
if self
.neg_attrs
.iter()
.filter_map(|(k, v)| attrs.get(k).map(|xv| v == xv))
.any(core::convert::identity)
{
return false;
}
if !self
.pos_attrs
.iter()
.filter_map(|(k, v)| attrs.get(k).map(|xv| v == xv))
.all(core::convert::identity)
{
return false;
}
true
}
}
/// message filtering and processing
pub struct Mangler {
pub fconf: FConfig,
seen: lru::LruCache<PHash, ()>,
}
impl Mangler {
pub fn new(fconf: FConfig) -> Self {
Self {
fconf,
seen: lru::LruCache::new(NonZeroUsize::new(4096).unwrap()),
}
}
/// packet should only be forwarded further if it gets passed through (with modifications)
pub fn process(&mut self, mut pkt: WrappedPacket) -> Option<WrappedPacket> {
debug_assert_eq!(pkt.inner.hash().ok(), Some(pkt.hash));
if !self.seen.get(&pkt.hash).is_some() {
tracing::debug!("{}: packet discarded, already seen", pkt.hash2str());
return None;
}
if pkt.inner.ttl == 0 {
tracing::debug!(
"{}: packet expired in processing (out of hops)",
pkt.hash2str()
);
return None;
}
if !pkt.inner.verify() {
tracing::error!("{}: packet signature invalid", pkt.hash2str());
return None;
}
if !self.fconf.check_filters(&pkt) {
tracing::debug!("{}: packet discarded according to filters", pkt.hash2str());
return None;
}
self.seen.put(pkt.hash, ());
pkt.inner.ttl -= 1;
pkt.inner
.markers
.append(&mut self.fconf.set_markers.clone());
Some(pkt)
}
}

View file

@ -0,0 +1,119 @@
use crate::{mangler::WrappedPacket, PHash};
use cap_std::fs_utf8::{Dir, OpenOptions};
use std::collections::HashSet;
use std::io::{ErrorKind, Result};
use yzb64::{base64::Engine, B64_ENGINE};
pub struct PacketSpool(pub Dir);
#[inline]
pub(crate) fn enc_hash(h: &PHash) -> String {
B64_ENGINE.encode(h.as_bytes())
}
impl PacketSpool {
pub fn drop(&self, h: &PHash) -> Result<()> {
let henc = enc_hash(h);
if let Err(e) = self.0.remove_file(&henc) {
tracing::error!("unable to remove {}: {:?}", &henc, e);
Err(e)
} else {
Ok(())
}
}
pub fn fetch(&self, h: &PHash) -> Result<crate::Packet> {
let henc = enc_hash(h);
let fh = self.0.open(&henc)?;
let pkt = crate::Packet::decode_from_rdr(fh)?;
Ok(pkt)
}
pub fn store<W: AsRef<WrappedPacket>, I: Iterator<Item = W>>(
&self,
overwrite: bool,
wps: I,
) -> Result<()> {
let opts = {
let mut opts = OpenOptions::new();
opts.write(true);
if overwrite {
opts.create(true).truncate(true);
} else {
opts.create_new(true);
};
opts
};
for w in wps {
let w = w.as_ref();
let henc = enc_hash(&w.hash);
let mut fh = match self.0.open_with(&henc, &opts) {
Ok(fh) => fh,
Err(e) if e.kind() == ErrorKind::AlreadyExists => continue,
Err(e) => return Err(e),
};
// if this fails, bail, bc filesystem is probably full...
if let Err(e) = w.inner.encode_to_wtr(&mut fh) {
core::mem::drop(fh);
// make sure to invalidate the incomplete entry
let _ = self.0.remove_file(&henc);
return Err(e);
}
}
Ok(())
}
pub(crate) fn collect_garbage(&self, still_valid: &HashSet<PHash>) -> Result<()> {
let (mut cnt_rem, cnt_keep, mut cnt_present) = (0, still_valid.len(), 0);
for i in self.0.entries()? {
// decode entry metadata
let i = i?;
let ft = i.file_type()?;
if !ft.is_file() {
continue;
}
cnt_present += 1;
let name = match i.file_name() {
Ok(x) => x,
Err(e) => {
tracing::warn!("file without UTF-8 encodable filename in spool: {:?}", e);
continue;
}
};
let h = {
let mut x = [0u8; 33];
if let Err(e) = B64_ENGINE.decode_slice(&name, &mut x[..]) {
tracing::warn!(
"{:?}: file without base64 [32b] decodable filename in spool: {:?}",
name,
e
);
continue;
}
if x[32] != 0 {
continue;
}
PHash::from_bytes(x[..32].try_into().unwrap())
};
// handle entry
if !still_valid.contains(&h) {
cnt_rem += 1;
if let Err(e) = i.remove_file() {
tracing::error!("{:?}: unable to remove file: {:?}", name, e);
}
}
}
tracing::debug!(
"removed {} / kept {} / available {}",
cnt_rem,
cnt_keep,
cnt_present
);
Ok(())
}
}

View file

@ -0,0 +1,190 @@
use crate::PHash;
use rusqlite::{
params,
types::{ToSqlOutput, ValueRef},
Connection, Result as SResult,
};
use std::collections::{BTreeMap, HashSet};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Key(i64);
pub struct SessionManager(Connection);
fn inl_blob2sql(blb: &[u8]) -> ToSqlOutput<'_> {
ToSqlOutput::Borrowed(ValueRef::Blob(blb))
}
impl SessionManager {
pub fn new(conn: Connection) -> SResult<Self> {
conn.execute(
"CREATE TABLE IF NOT EXISTS keys (
kid integer primary key,
name blob not null unique,
pubkey blob not null
)",
params![],
)?;
conn.execute(
"CREATE TABLE IF NOT EXISTS ents (
eid integer primary key,
name blob not null unique
)",
params![],
)?;
conn.execute(
"CREATE TABLE IF NOT EXISTS sess (
id integer primary key,
kid integer not null references keys(kid),
eid integer not null references ents(eid)
)",
params![],
)?;
Ok(Self(conn))
}
pub fn resolve_key(&self, key: &[u8]) -> SResult<Option<(Key, Vec<u8>)>> {
let mut stmt = self.0
.prepare_cached("SELECT kid, pubkey FROM keys WHERE name = ?1 LIMIT 1")?;
let x = match stmt
.query_map([inl_blob2sql(key)], |row| {
Ok((Key(row.get(0)?), row.get(1)?))
})?
.next()
{
Some(Err(e)) => return Err(e),
Some(Ok(x)) => Some(x),
None => None,
};
Ok(x)
}
pub fn drop_key(&mut self, key: Key) -> SResult<()> {
let txn = self.0.transaction()?;
txn.execute("DELETE FROM sess WHERE kid = ?1", [key.0])?;
txn.execute("DELETE FROM keys WHERE kid = ?1", [key.0])?;
txn.commit()?;
Ok(())
}
fn resolve_entry_on(conn: &Connection, subkey: &[u8]) -> SResult<Option<i64>> {
let x = match conn
.prepare_cached("SELECT eid FROM ents WHERE name = ?1 LIMIT 1")?
.query_map([inl_blob2sql(subkey)], |row| row.get(0))?
.next()
{
Some(Err(e)) => Err(e),
Some(Ok(x)) => Ok(Some(x)),
None => Ok(None),
};
x
}
pub fn drop_entry(&mut self, subkey: &[u8]) -> SResult<()> {
let txn = self.0.transaction()?;
let eid = Self::resolve_entry_on(&*txn, subkey)?;
txn.execute("DELETE FROM sess WHERE eid = ?1", [eid])?;
txn.execute("DELETE FROM ents WHERE eid = ?1", [eid])?;
txn.commit()
}
pub fn register_key(&self, key: &[u8], pubkey: &[u8]) -> SResult<()> {
self.0.execute(
"INSERT INTO keys (name, pubkey) VALUES (?1, ?2)",
[inl_blob2sql(key), inl_blob2sql(pubkey)],
)?;
Ok(())
}
pub fn peek(&self, key: Key) -> SResult<Vec<PHash>> {
let mut stmt = self.0.prepare_cached(
"SELECT ents.name FROM ents INNER JOIN sess ON ents.eid = sess.eid WHERE sess.kid = ?1",
)?;
let ret = stmt
.query_map([key.0], |row| row.get(0).map(PHash::from_bytes))?
.collect::<SResult<Vec<_>>>()?;
Ok(ret)
}
pub fn set_for_all(&mut self, subkey: &[u8]) -> SResult<bool> {
let txn = self.0.transaction()?;
let eid = Self::resolve_entry_on(&*txn, subkey)?;
let chg = txn
.prepare_cached("INSERT INTO sess (kid, eid) SELECT keys.kid, ?1 FROM keys")?
.execute([eid])?;
txn.commit()?;
Ok(if chg > 0 {
true
} else {
false
})
}
pub fn set_soft_multi<'sk, SKI: Iterator<Item = &'sk [u8]>>(
&mut self,
key: Key,
subkeys: SKI,
) -> SResult<()> {
let txn = self.0.transaction()?;
{
let mut stmi_sess =
txn.prepare_cached("INSERT INTO sess (kid, eid) SELECT ?1, ents.eid FROM ents WHERE ents.name = ?2 LIMIT 1")?;
for subkey in subkeys {
stmi_sess.insert(params![key.0, inl_blob2sql(subkey)])?;
}
}
txn.commit()
}
pub fn unset_multi<'sk, SKI: Iterator<Item = &'sk [u8]>>(
&mut self,
key: Key,
subkeys: SKI,
) -> SResult<()> {
let txn = self.0.transaction()?;
{
let mut stmd_sess =
txn.prepare_cached("DELETE FROM sess WHERE sess.kid = ?1, sess.eid IN (SELECT ents.eid FROM ents WHERE ents.name = ?2 LIMIT 1)")?;
for subkey in subkeys {
stmd_sess.execute(params![key.0, inl_blob2sql(subkey)])?;
}
}
txn.commit()
}
/// runs garbage collection, returns set of still-valid entries
pub(crate) fn collect_garbage(&mut self) -> SResult<HashSet<PHash>> {
let txn = self.0.transaction()?;
let still_valid: BTreeMap<i64, PHash> = {
let mut stmt = txn.prepare_cached(
"SELECT ents.eid, ents.name FROM ents INNER JOIN sess ON ents.eid = sess.eid",
)?;
// such stuff is a work..around stmt-drop problems...
let x = stmt
.query_map([], |row| Ok((row.get(0)?, PHash::from_bytes(row.get(1)?))))?
.collect::<SResult<_>>()?;
x
};
{
let mut stmt_all = txn.prepare_cached("SELECT eid FROM ents")?;
let mut stmt_del = txn.prepare_cached("DELETE FROM ents WHERE eid = ?1")?;
// I hate this, but it is relatively clean, and we already have all the data already,
// so no need to allocate temporary tables or use some slow table-except to find all
// the entries to delete.
for eid in stmt_all.query_map([], |row| row.get(0))? {
let eid = eid?;
if !still_valid.contains_key(&eid) {
// we don't need to delete anything from sess because we already checked
// that it isn't there.
stmt_del.execute([eid])?;
}
}
}
txn.commit()?;
Ok(still_valid.into_iter().map(|(_, v)| v).collect())
}
}