huskies: merge 977

This commit is contained in:
dave
2026-05-13 15:07:11 +00:00
parent dcb43c465a
commit f268dca5bb
14 changed files with 59 additions and 758 deletions
+3 -8
View File
@@ -198,9 +198,8 @@ mod tests {
use super::super::write::write_item_str;
use super::*;
use bft_json_crdt::json_crdt::OpState;
use bft_json_crdt::keypair::make_keypair;
use bft_json_crdt::keypair::{Ed25519KeyPair, make_keypair};
use bft_json_crdt::op::ROOT_ID;
use fastcrypto::ed25519::Ed25519KeyPair;
use serde_json::json;
#[test]
@@ -438,8 +437,6 @@ mod tests {
#[test]
fn delta_sync_multi_author() {
use fastcrypto::traits::KeyPair;
let kp_a = make_keypair();
let kp_b = make_keypair();
let mut crdt_a = BaseCrdt::<PipelineDoc>::new(&kp_a);
@@ -454,7 +451,7 @@ mod tests {
// Peer has seen all of A's ops but none of B's.
let mut peer_clock = VectorClock::new();
let author_a_hex = hex::encode(&kp_a.public().0.to_bytes());
let author_a_hex = hex::encode(&kp_a.verifying_key().to_bytes());
peer_clock.insert(author_a_hex, 30);
let delta = local_ops_since(&all_ops, &peer_clock);
@@ -468,14 +465,12 @@ mod tests {
#[test]
fn build_vector_clock_from_ops() {
use fastcrypto::traits::KeyPair;
let kp = make_keypair();
let mut crdt = BaseCrdt::<PipelineDoc>::new(&kp);
let ops = make_ops(&kp, &mut crdt, 10, "631_vc");
let clock = build_clock(&ops);
let author_hex = hex::encode(&kp.public().0.to_bytes());
let author_hex = hex::encode(&kp.verifying_key().to_bytes());
assert_eq!(clock.len(), 1, "single author should produce 1 clock entry");
assert_eq!(clock[&author_hex], 10, "clock should show 10 ops");
-1
View File
@@ -6,7 +6,6 @@ use super::read::read_item;
use bft_json_crdt::json_crdt::*;
use bft_json_crdt::lww_crdt::LwwRegisterCrdt;
use bft_json_crdt::op::ROOT_ID;
use fastcrypto::traits::{Signer, ToFromBytes};
use serde_json::json;
use super::state::{apply_and_persist, get_crdt, rebuild_node_index};
+4 -6
View File
@@ -10,9 +10,7 @@ use std::path::Path;
use std::sync::Mutex;
use bft_json_crdt::json_crdt::{BaseCrdt, CrdtNode, JsonValue, SignedOp};
use bft_json_crdt::keypair::make_keypair;
use fastcrypto::ed25519::Ed25519KeyPair;
use fastcrypto::traits::ToFromBytes;
use bft_json_crdt::keypair::{Ed25519KeyPair, make_keypair};
use sqlx::SqlitePool;
use sqlx::sqlite::SqliteConnectOptions;
use tokio::sync::{broadcast, mpsc};
@@ -192,14 +190,14 @@ async fn load_or_create_keypair(pool: &SqlitePool) -> Result<Ed25519KeyPair, sql
if let Some((seed,)) = row {
// Reconstruct from stored seed. The seed is the 32-byte private key.
if let Ok(kp) = Ed25519KeyPair::from_bytes(&seed) {
return Ok(kp);
if let Ok(arr) = TryInto::<[u8; 32]>::try_into(seed) {
return Ok(Ed25519KeyPair::from_bytes(&arr));
}
slog!("[crdt] Stored keypair invalid, regenerating");
}
let kp = make_keypair();
let seed = kp.as_bytes().to_vec();
let seed = kp.to_bytes().to_vec();
sqlx::query("INSERT INTO crdt_node_identity (id, seed) VALUES (1, ?1) ON CONFLICT(id) DO UPDATE SET seed = excluded.seed")
.bind(&seed)
.execute(pool)
+1 -2
View File
@@ -10,8 +10,7 @@ use std::collections::{HashMap, HashSet};
use std::sync::{Mutex, OnceLock};
use bft_json_crdt::json_crdt::{BaseCrdt, SignedOp};
use bft_json_crdt::keypair::make_keypair;
use fastcrypto::ed25519::Ed25519KeyPair;
use bft_json_crdt::keypair::{Ed25519KeyPair, make_keypair};
use tokio::sync::{broadcast, mpsc};
use super::VectorClock;
+1 -2
View File
@@ -604,7 +604,6 @@ fn v2_delta_sync_via_clock_exchange() {
use bft_json_crdt::json_crdt::BaseCrdt;
use bft_json_crdt::keypair::make_keypair;
use bft_json_crdt::op::ROOT_ID;
use fastcrypto::traits::KeyPair;
use serde_json::json;
use crate::crdt_state::PipelineDoc;
@@ -641,7 +640,7 @@ fn v2_delta_sync_via_clock_exchange() {
assert_eq!(crdt_b.doc.items.view().len(), 3);
// Build B's clock.
let author_a_hex = crate::crdt_state::hex::encode(&kp_a.public().0.to_bytes());
let author_a_hex = crate::crdt_state::hex::encode(&kp_a.verifying_key().to_bytes());
let mut clock_b = std::collections::HashMap::new();
clock_b.insert(author_a_hex.clone(), 3u64);
+4 -6
View File
@@ -41,8 +41,6 @@
//! `verify_challenge` primitive but leaves the allow-list to story 480.
use bft_json_crdt::keypair::{Ed25519KeyPair, Ed25519Signature, sign};
use ed25519_dalek::SigningKey;
use fastcrypto::traits::{KeyPair, ToFromBytes};
use rand::RngCore;
use std::sync::OnceLock;
@@ -84,7 +82,7 @@ pub fn generate_challenge() -> ChallengeHex {
/// encoding steps.
pub fn sign_challenge(keypair: &Ed25519KeyPair, challenge: &str) -> SignatureHex {
let sig: Ed25519Signature = sign(keypair, challenge.as_bytes());
hex_encode(sig.as_bytes())
hex_encode(&sig.to_bytes())
}
// ── Verification ──────────────────────────────────────────────────────
@@ -143,7 +141,7 @@ pub fn verify_message_strict(pubkey_hex: &str, message: &[u8], signature_hex: &s
/// This is the same value written to the CRDT `claimed_by` and `node_id`
/// registers, so it is the canonical node identity across all subsystems.
pub fn public_key_hex(keypair: &Ed25519KeyPair) -> String {
hex_encode(keypair.public().as_bytes())
hex_encode(&keypair.verifying_key().to_bytes())
}
// ── File-based keypair persistence (ed25519-dalek) ────────────────────────
@@ -181,12 +179,12 @@ pub fn load_or_create_keypair_file(path: &std::path::Path) -> std::io::Result<No
"node identity key file must contain exactly 32 bytes",
)
})?;
SigningKey::from_bytes(&seed)
Ed25519KeyPair::from_bytes(&seed)
} else {
// Generate a fresh keypair and persist the seed.
let mut seed = [0u8; 32];
rand::rng().fill_bytes(&mut seed);
let sk = SigningKey::from_bytes(&seed);
let sk = Ed25519KeyPair::from_bytes(&seed);
// Create the file with mode 0600 at creation time (Unix) so the seed
// is never visible to other users even transiently.