mirror of
https://github.com/logos-messaging/libchat.git
synced 2026-05-12 04:59:27 +00:00
Merge branch 'main' into feat/add-flake
This commit is contained in:
commit
6286611de7
54
Cargo.lock
generated
54
Cargo.lock
generated
@ -172,7 +172,7 @@ dependencies = [
|
||||
"ed25519-dalek",
|
||||
"generic-array 1.3.5",
|
||||
"hkdf",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
"sha2",
|
||||
"thiserror",
|
||||
"x25519-dalek",
|
||||
@ -187,7 +187,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
|
||||
dependencies = [
|
||||
"generic-array 0.14.7",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
@ -258,9 +258,8 @@ dependencies = [
|
||||
"chacha20poly1305",
|
||||
"chat-sqlite",
|
||||
"hkdf",
|
||||
"rand",
|
||||
"rand_core",
|
||||
"safer-ffi",
|
||||
"rand 0.9.3",
|
||||
"rand_core 0.6.4",
|
||||
"serde",
|
||||
"storage",
|
||||
"tempfile",
|
||||
@ -532,7 +531,7 @@ dependencies = [
|
||||
"double-ratchets",
|
||||
"hex",
|
||||
"prost",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
"safer-ffi",
|
||||
"storage",
|
||||
"tempfile",
|
||||
@ -729,8 +728,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
"rand_chacha 0.3.1",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ec095654a25171c2124e9e3393a930bddbffdc939556c914957a4c3e0a87166"
|
||||
dependencies = [
|
||||
"rand_chacha 0.9.0",
|
||||
"rand_core 0.9.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -740,7 +749,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core 0.9.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -752,6 +771,15 @@ dependencies = [
|
||||
"getrandom 0.2.17",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c"
|
||||
dependencies = [
|
||||
"getrandom 0.3.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rusqlite"
|
||||
version = "0.35.0"
|
||||
@ -897,7 +925,7 @@ version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
|
||||
dependencies = [
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -947,7 +975,7 @@ dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
@ -1171,7 +1199,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277"
|
||||
dependencies = [
|
||||
"curve25519-dalek",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
"serde",
|
||||
"zeroize",
|
||||
]
|
||||
@ -1186,7 +1214,7 @@ dependencies = [
|
||||
"derive_more",
|
||||
"ed25519",
|
||||
"ed25519-dalek",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"sha2",
|
||||
"x25519-dalek",
|
||||
"zeroize",
|
||||
|
||||
@ -6,26 +6,18 @@ edition = "2024"
|
||||
[lib]
|
||||
crate-type = ["rlib", "cdylib"]
|
||||
|
||||
[[bin]]
|
||||
name = "generate-headers"
|
||||
required-features = ["headers"]
|
||||
|
||||
[dependencies]
|
||||
x25519-dalek = { version="2.0.1", features=["static_secrets"] }
|
||||
chacha20poly1305 = "0.10.1"
|
||||
rand_core = "0.6.4"
|
||||
rand = "0.8.5"
|
||||
rand = "0.9.3"
|
||||
hkdf = "0.12.4"
|
||||
thiserror = "2"
|
||||
blake2 = "0.10.6"
|
||||
safer-ffi = "0.1.13"
|
||||
zeroize = "1.8.2"
|
||||
storage = { workspace = true }
|
||||
serde = "1.0"
|
||||
|
||||
[features]
|
||||
headers = ["safer-ffi/headers"]
|
||||
|
||||
[dev-dependencies]
|
||||
sqlite = { package = "chat-sqlite", path = "../sqlite" }
|
||||
tempfile = "3"
|
||||
|
||||
@ -23,12 +23,3 @@ cargo run --example double_ratchet_basic
|
||||
cargo run --example storage_demo --features storage
|
||||
cargo run --example storage_demo --features sqlcipher
|
||||
```
|
||||
|
||||
Run Nim FFI example,
|
||||
|
||||
```bash
|
||||
# In the root folder (libchat)
|
||||
cargo build --release
|
||||
# In ffi-nim-example folder
|
||||
nimble run
|
||||
```
|
||||
|
||||
@ -1,13 +0,0 @@
|
||||
# Package
|
||||
|
||||
version = "0.1.0"
|
||||
author = "kaichaosun"
|
||||
description = "A new awesome nimble package"
|
||||
license = "MIT"
|
||||
srcDir = "src"
|
||||
bin = @["ffi_nim_example"]
|
||||
|
||||
|
||||
# Dependencies
|
||||
|
||||
requires "nim >= 2.2.4"
|
||||
@ -1,144 +0,0 @@
|
||||
when defined(macosx):
|
||||
{.passL: "-Wl,-rpath,@executable_path/../../target/release".}
|
||||
when defined(linux):
|
||||
{.passL: "-Wl,-rpath,'$ORIGIN/../../target/release'".}
|
||||
|
||||
# Portable dynlib name with override capability (-d:RLN_LIB:"...")
|
||||
when defined(macosx):
|
||||
const DR_LIB* {.strdefine.} = "libdouble_ratchets.dylib"
|
||||
elif defined(linux):
|
||||
const DR_LIB* {.strdefine.} = "libdouble_ratchets.so"
|
||||
elif defined(windows):
|
||||
const DR_LIB* {.strdefine.} = "double_ratchets.dll"
|
||||
else:
|
||||
const DR_LIB* {.strdefine.} = "double_ratchets"
|
||||
|
||||
type FFIRatchetState* = object
|
||||
|
||||
type FFIEncryptResult* = object
|
||||
|
||||
type FFIInstallationKeyPair* = object
|
||||
|
||||
type CSize* = csize_t
|
||||
|
||||
type Vec_uint8* = object
|
||||
dataPtr*: ptr uint8
|
||||
len*: CSize
|
||||
cap*: CSize
|
||||
|
||||
type Array_uint8_32* {.bycopy.} = object
|
||||
idx*: array[32, uint8]
|
||||
|
||||
type CResult_Vec_uint8_Vec_uint8* {.bycopy.} = object ## <No documentation available>
|
||||
ok*: Vec_uint8
|
||||
err*: Vec_uint8
|
||||
|
||||
proc double_ratchet_init_receiver*(
|
||||
shared_secret: Array_uint8_32, keypair: ptr FFIInstallationKeyPair
|
||||
): ptr FFIRatchetState {.importc, dynlib: DR_LIB.}
|
||||
|
||||
proc double_ratchet_init_sender*(
|
||||
shared_secret: Array_uint8_32, remote_pub: Array_uint8_32
|
||||
): ptr FFIRatchetState {.importc, dynlib: DR_LIB.}
|
||||
|
||||
proc double_ratchet_encrypt_message*(
|
||||
state: ptr FFIRatchetState, plaintext: ptr Vec_uint8
|
||||
): ptr FFIEncryptResult {.importc, dynlib: DR_LIB.}
|
||||
|
||||
proc double_ratchet_descrypt_message*(
|
||||
state: ptr FFIRatchetState, encrypted: ptr FFIEncryptResult
|
||||
): CResult_Vec_uint8_Vec_uint8 {.importc, dynlib: DR_LIB.}
|
||||
|
||||
proc ratchet_state_destroy*(state: ptr FFIRatchetState) {.importc, dynlib: DR_LIB.}
|
||||
|
||||
proc encrypt_result_destroy*(result: ptr FFIEncryptResult) {.importc, dynlib: DR_LIB.}
|
||||
|
||||
proc installation_key_pair_generate*(): ptr FFIInstallationKeyPair {.
|
||||
importc, dynlib: DR_LIB
|
||||
.}
|
||||
|
||||
proc installation_key_pair_public*(
|
||||
keypair: ptr FFIInstallationKeyPair
|
||||
): Array_uint8_32 {.importc, dynlib: DR_LIB.}
|
||||
|
||||
proc installation_key_pair_destroy*(
|
||||
keypair: ptr FFIInstallationKeyPair
|
||||
) {.importc, dynlib: DR_LIB.}
|
||||
|
||||
proc ffi_c_string_free*(s: Vec_uint8) {.importc, cdecl, dynlib: DR_LIB.}
|
||||
|
||||
proc asString*(v: Vec_uint8): string =
|
||||
if v.dataPtr.isNil or v.len == 0:
|
||||
return ""
|
||||
result = newString(v.len.int)
|
||||
copyMem(addr result[0], v.dataPtr, v.len.int)
|
||||
|
||||
when isMainModule:
|
||||
echo("start run")
|
||||
|
||||
# === Shared secret (like X3DH) ===
|
||||
var sharedSecret: Array_uint8_32
|
||||
for i in 0 .. 31:
|
||||
sharedSecret.idx[i] = 42'u8
|
||||
|
||||
# === Bob generates DH keypair ===
|
||||
let bobKey = installation_key_pair_generate()
|
||||
let bobPub = installation_key_pair_public(bobKey)
|
||||
echo("bob public key:", bobPub)
|
||||
|
||||
# === Alice initializes as sender ===
|
||||
let alice = double_ratchet_init_sender(sharedSecret, bobPub)
|
||||
# # === Bob initializes as receiver ===
|
||||
let bob = double_ratchet_init_receiver(sharedSecret, bobKey)
|
||||
|
||||
# # === Alice sends message to Bob ===
|
||||
var msg1: array[3, uint8] = [11'u8, 12, 13]
|
||||
var msg1Vec = Vec_uint8(
|
||||
dataPtr: cast[ptr uint8](addr msg1[0]), len: CSize(msg1.len), cap: CSize(msg1.len)
|
||||
)
|
||||
|
||||
let enc1 = double_ratchet_encrypt_message(alice, addr msg1Vec)
|
||||
let dec1 = double_ratchet_descrypt_message(bob, enc1)
|
||||
|
||||
encrypt_result_destroy(enc1)
|
||||
|
||||
if dec1.err.dataPtr != nil:
|
||||
echo "Bob failed to decrypt: ", asString(dec1.err)
|
||||
ffi_c_string_free(dec1.err)
|
||||
ratchet_state_destroy(alice)
|
||||
ratchet_state_destroy(bob)
|
||||
installation_key_pair_destroy(bobKey)
|
||||
quit 1
|
||||
let res1 = dec1.ok
|
||||
var plaintext1: array[3, uint8]
|
||||
copyMem(addr plaintext1[0], res1.dataPtr, res1.len.int)
|
||||
echo "Bob received: ", plaintext1
|
||||
|
||||
# # === Bob replies (triggers DH ratchet) ===
|
||||
var msg2: array[3, uint8] = [1'u8, 2, 3]
|
||||
var msg2Vec = Vec_uint8(
|
||||
dataPtr: cast[ptr uint8](addr msg2[0]), len: CSize(msg1.len), cap: CSize(msg1.len)
|
||||
)
|
||||
let enc2 = double_ratchet_encrypt_message(bob, addr msg2Vec)
|
||||
let dec2 = double_ratchet_descrypt_message(alice, enc2)
|
||||
|
||||
encrypt_result_destroy(enc2)
|
||||
|
||||
if dec2.err.dataPtr != nil:
|
||||
echo "Alice failed to decrypt: ", asString(dec2.err)
|
||||
ffi_c_string_free(dec2.err)
|
||||
ratchet_state_destroy(alice)
|
||||
ratchet_state_destroy(bob)
|
||||
installation_key_pair_destroy(bobKey)
|
||||
quit 1
|
||||
let res2 = dec2.ok
|
||||
var plaintext2: array[3, uint8]
|
||||
copyMem(addr plaintext2[0], res2.dataPtr, res2.len.int)
|
||||
echo "Alice received: ", plaintext2
|
||||
|
||||
# # === Cleanup ===
|
||||
ratchet_state_destroy(alice)
|
||||
ratchet_state_destroy(bob)
|
||||
installation_key_pair_destroy(bobKey)
|
||||
|
||||
echo("==end==\n")
|
||||
@ -1,5 +0,0 @@
|
||||
use double_ratchets::ffi;
|
||||
|
||||
fn main() -> std::io::Result<()> {
|
||||
ffi::generate_headers()
|
||||
}
|
||||
@ -1,81 +0,0 @@
|
||||
use safer_ffi::prelude::*;
|
||||
use x25519_dalek::PublicKey;
|
||||
|
||||
use crate::{
|
||||
Header, RatchetState,
|
||||
ffi::{key::FFIInstallationKeyPair, utils::CResult},
|
||||
};
|
||||
|
||||
#[derive_ReprC]
|
||||
#[repr(opaque)]
|
||||
pub struct FFIRatchetState(pub(crate) RatchetState);
|
||||
|
||||
#[derive_ReprC]
|
||||
#[repr(opaque)]
|
||||
pub struct FFIEncryptResult {
|
||||
pub ciphertext: Vec<u8>,
|
||||
pub header: Header,
|
||||
}
|
||||
|
||||
#[ffi_export]
|
||||
fn double_ratchet_init_sender(
|
||||
shared_secret: [u8; 32],
|
||||
remote_pub: [u8; 32],
|
||||
) -> repr_c::Box<FFIRatchetState> {
|
||||
let state = RatchetState::init_sender(shared_secret, PublicKey::from(remote_pub));
|
||||
Box::new(FFIRatchetState(state)).into()
|
||||
}
|
||||
|
||||
#[ffi_export]
|
||||
fn double_ratchet_init_receiver(
|
||||
shared_secret: [u8; 32],
|
||||
keypair: &FFIInstallationKeyPair,
|
||||
) -> repr_c::Box<FFIRatchetState> {
|
||||
let state = RatchetState::init_receiver(shared_secret, keypair.0.clone());
|
||||
Box::new(FFIRatchetState(state)).into()
|
||||
}
|
||||
|
||||
#[ffi_export]
|
||||
fn double_ratchet_encrypt_message(
|
||||
state: &mut FFIRatchetState,
|
||||
plaintext: &repr_c::Vec<u8>,
|
||||
) -> repr_c::Box<FFIEncryptResult> {
|
||||
let encrypted = state.0.encrypt_message(plaintext);
|
||||
let result = FFIEncryptResult {
|
||||
ciphertext: encrypted.0,
|
||||
header: encrypted.1,
|
||||
};
|
||||
Box::new(result).into()
|
||||
}
|
||||
|
||||
//TODO rename decrypt
|
||||
#[ffi_export]
|
||||
fn double_ratchet_descrypt_message(
|
||||
state: &mut FFIRatchetState,
|
||||
encrypted: &FFIEncryptResult,
|
||||
) -> CResult<repr_c::Vec<u8>, repr_c::String> {
|
||||
let decrypted = state
|
||||
.0
|
||||
.decrypt_message(&encrypted.ciphertext, encrypted.header.clone());
|
||||
|
||||
match decrypted {
|
||||
Ok(plaintext) => CResult {
|
||||
ok: Some(plaintext.into()),
|
||||
err: None,
|
||||
},
|
||||
Err(err) => CResult {
|
||||
ok: None,
|
||||
err: Some(err.to_string().into()),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[ffi_export]
|
||||
fn ratchet_state_destroy(state: repr_c::Box<FFIRatchetState>) {
|
||||
drop(state)
|
||||
}
|
||||
|
||||
#[ffi_export]
|
||||
fn encrypt_result_destroy(result: repr_c::Box<FFIEncryptResult>) {
|
||||
drop(result)
|
||||
}
|
||||
@ -1,22 +0,0 @@
|
||||
use safer_ffi::prelude::*;
|
||||
|
||||
use crate::InstallationKeyPair;
|
||||
|
||||
#[derive_ReprC]
|
||||
#[repr(opaque)]
|
||||
pub struct FFIInstallationKeyPair(pub(crate) InstallationKeyPair);
|
||||
|
||||
#[ffi_export]
|
||||
fn installation_key_pair_generate() -> repr_c::Box<FFIInstallationKeyPair> {
|
||||
Box::new(FFIInstallationKeyPair(InstallationKeyPair::generate())).into()
|
||||
}
|
||||
|
||||
#[ffi_export]
|
||||
fn installation_key_pair_public(keypair: &FFIInstallationKeyPair) -> [u8; 32] {
|
||||
keypair.0.public().clone().to_bytes()
|
||||
}
|
||||
|
||||
#[ffi_export]
|
||||
fn installation_key_pair_destroy(keypair: repr_c::Box<FFIInstallationKeyPair>) {
|
||||
drop(keypair)
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
pub mod doubleratchet;
|
||||
pub mod key;
|
||||
pub mod utils;
|
||||
|
||||
#[cfg(feature = "headers")]
|
||||
pub fn generate_headers() -> std::io::Result<()> {
|
||||
safer_ffi::headers::builder()
|
||||
.to_file("double_ratchet.h")?
|
||||
.generate()
|
||||
}
|
||||
@ -1,13 +0,0 @@
|
||||
use safer_ffi::prelude::*;
|
||||
|
||||
#[derive_ReprC]
|
||||
#[repr(C)]
|
||||
pub struct CResult<T: ReprC, Err: ReprC> {
|
||||
pub ok: Option<T>,
|
||||
pub err: Option<Err>,
|
||||
}
|
||||
|
||||
#[ffi_export]
|
||||
pub fn ffi_c_string_free(s: repr_c::String) {
|
||||
drop(s);
|
||||
}
|
||||
@ -1,6 +1,5 @@
|
||||
pub mod aead;
|
||||
pub mod errors;
|
||||
pub mod ffi;
|
||||
pub mod hkdf;
|
||||
pub mod keypair;
|
||||
pub mod reader;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user