Skip to content

Commit 37add0b

Browse files
refactor: rename crates for crates.io publishing
heartwood-core → nsec-tree-rs heartwood-nip46 → nip46-signer Package names now describe what they do, not which appliance they came from. Directory names unchanged (internal concern).
1 parent fcf7139 commit 37add0b

19 files changed

Lines changed: 81 additions & 68 deletions

bunker/index.mjs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -769,6 +769,19 @@ async function writeRelayStatus() {
769769
setTimeout(writeRelayStatus, 3000)
770770
setInterval(writeRelayStatus, 15000)
771771

772+
// --- 8b. Periodic subscription refresh ---
773+
// Relays may silently drop subscriptions (idle timeout, restart) while keeping
774+
// the WebSocket open. SimplePool's status check sees connected=true but the
775+
// NIP-46 event filter is gone. Cycling the subscription every 5 minutes
776+
// ensures we stay reachable overnight.
777+
778+
const SUBSCRIPTION_REFRESH_MS = 5 * 60 * 1000
779+
780+
setInterval(() => {
781+
connectRelays(relays)
782+
console.log('Subscription refreshed')
783+
}, SUBSCRIPTION_REFRESH_MS)
784+
772785
// --- 9. Clean shutdown ---
773786

774787
function shutdown() {

crates/heartwood-core/Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
[package]
2-
name = "heartwood-core"
2+
name = "nsec-tree-rs"
33
version = "0.1.0"
44
edition.workspace = true
55
license.workspace = true
66
repository.workspace = true
7-
description = "nsec-tree deterministic identity derivation — Rust port"
8-
keywords = ["nostr", "nsec-tree", "signing", "identity", "cryptography"]
7+
description = "Deterministic Nostr sub-identity derivation — Rust port of nsec-tree. HMAC-based one-way key hierarchy with Schnorr linkage proofs."
8+
keywords = ["nostr", "nsec-tree", "signing", "identity", "secp256k1"]
99
categories = ["cryptography", "authentication"]
1010

1111
[dependencies]

crates/heartwood-core/examples/basic_usage.rs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//!
33
//! Run with: `cargo run -p heartwood-core --example basic_usage`
44
5-
fn main() -> Result<(), heartwood_core::HeartwoodError> {
5+
fn main() -> Result<(), nsec_tree_rs::HeartwoodError> {
66
// --- 1. Create a tree root from a BIP-39 mnemonic ---
77
//
88
// The mnemonic is the master secret. Everything derives from it.
@@ -11,52 +11,52 @@ fn main() -> Result<(), heartwood_core::HeartwoodError> {
1111
let mnemonic = "abandon abandon abandon abandon abandon abandon \
1212
abandon abandon abandon abandon abandon about";
1313

14-
let root = heartwood_core::from_mnemonic(mnemonic, None)?;
14+
let root = nsec_tree_rs::from_mnemonic(mnemonic, None)?;
1515
println!("Master pubkey: {}", root.master_pubkey);
1616

1717
// --- 2. Derive child identities by purpose and index ---
1818
//
1919
// Each (purpose, index) pair produces a deterministic, unique keypair.
2020
// Different purposes create unlinkable identity sets.
21-
let social = heartwood_core::derive(&root, "social", 0)?;
21+
let social = nsec_tree_rs::derive(&root, "social", 0)?;
2222
println!("\nSocial identity:");
2323
println!(" npub: {}", social.npub);
2424
println!(" purpose: {}, index: {}", social.purpose, social.index);
2525

26-
let commerce = heartwood_core::derive(&root, "commerce", 0)?;
26+
let commerce = nsec_tree_rs::derive(&root, "commerce", 0)?;
2727
println!("\nCommerce identity:");
2828
println!(" npub: {}", commerce.npub);
2929

3030
// Same purpose + different index = different identity, same category
31-
let social_alt = heartwood_core::derive(&root, "social", 1)?;
31+
let social_alt = nsec_tree_rs::derive(&root, "social", 1)?;
3232
assert_ne!(social.npub, social_alt.npub);
3333
println!("\nSocial alt (index 1): {}", social_alt.npub);
3434

3535
// --- 3. Named personas ---
3636
//
3737
// Personas are a convenience wrapper: derive_persona("work") is
3838
// equivalent to derive("nostr:persona:work", 0).
39-
let work = heartwood_core::derive_persona(&root, "work", None)?;
39+
let work = nsec_tree_rs::derive_persona(&root, "work", None)?;
4040
println!("\nWork persona: {}", work.identity.npub);
4141

4242
// Sub-identities from a persona (two-level hierarchy)
43-
let work_dms = heartwood_core::derive_from_persona(&work, "dms", None)?;
43+
let work_dms = nsec_tree_rs::derive_from_persona(&work, "dms", None)?;
4444
println!(" Work DMs sub-identity: {}", work_dms.npub);
4545

4646
// --- 4. Linkage proofs ---
4747
//
4848
// Prove that a child key belongs to the master, without revealing
4949
// the derivation path (blind) or with it (full).
50-
let blind_proof = heartwood_core::create_blind_proof(&root, &social)?;
51-
assert!(heartwood_core::verify_proof(&blind_proof)?);
50+
let blind_proof = nsec_tree_rs::create_blind_proof(&root, &social)?;
51+
assert!(nsec_tree_rs::verify_proof(&blind_proof)?);
5252
println!(
5353
"\nBlind proof verified: master {} owns child {}",
5454
&blind_proof.master_pubkey[..12],
5555
&blind_proof.child_pubkey[..12]
5656
);
5757

58-
let full_proof = heartwood_core::create_full_proof(&root, &social)?;
59-
assert!(heartwood_core::verify_proof(&full_proof)?);
58+
let full_proof = nsec_tree_rs::create_full_proof(&root, &social)?;
59+
assert!(nsec_tree_rs::verify_proof(&full_proof)?);
6060
println!(
6161
"Full proof: purpose={}, index={}",
6262
full_proof.purpose.as_deref().unwrap_or("?"),
@@ -67,7 +67,7 @@ fn main() -> Result<(), heartwood_core::HeartwoodError> {
6767
//
6868
// Scan a set of purposes to rediscover all derived identities.
6969
// Useful after restoring from mnemonic backup.
70-
let found = heartwood_core::recover(
70+
let found = nsec_tree_rs::recover(
7171
&root,
7272
&["social".to_string(), "commerce".to_string()],
7373
None, // default scan range (20 indices per purpose)

crates/heartwood-core/tests/derive_test.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
use heartwood_core::derive::{derive, derive_from_identity};
2-
use heartwood_core::root::from_nsec_bytes;
1+
use nsec_tree_rs::derive::{derive, derive_from_identity};
2+
use nsec_tree_rs::root::from_nsec_bytes;
33

44
/// Frozen test vectors — MUST match TypeScript nsec-tree byte-for-byte.
55
/// Root key: 0x01-fill (32 bytes of 0x01).
6-
fn root_01() -> heartwood_core::types::TreeRoot {
6+
fn root_01() -> nsec_tree_rs::types::TreeRoot {
77
let nsec_bytes = [0x01u8; 32];
88
from_nsec_bytes(&nsec_bytes).expect("root creation must succeed")
99
}

crates/heartwood-core/tests/encoding_test.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use heartwood_core::encoding::{decode_npub, decode_nsec, encode_npub, encode_nsec};
1+
use nsec_tree_rs::encoding::{decode_npub, decode_nsec, encode_npub, encode_nsec};
22

33
#[test]
44
fn round_trip_nsec() {

crates/heartwood-core/tests/full_vectors_test.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
//! These vectors MUST match the TypeScript nsec-tree implementation byte-for-byte.
44
//! If any of these tests break, a backwards-incompatible change has been introduced.
55
6-
use heartwood_core::*;
6+
use nsec_tree_rs::*;
77

88
const MNEMONIC: &str =
99
"abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";

crates/heartwood-core/tests/generate_test.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use heartwood_core::generate_mnemonic;
1+
use nsec_tree_rs::generate_mnemonic;
22

33
#[test]
44
fn generate_mnemonic_returns_24_words() {

crates/heartwood-core/tests/mnemonic_test.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
use heartwood_core::derive::derive;
2-
use heartwood_core::root::{from_mnemonic, from_nsec_bytes};
1+
use nsec_tree_rs::derive::derive;
2+
use nsec_tree_rs::root::{from_mnemonic, from_nsec_bytes};
33

44
const MNEMONIC: &str =
55
"abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";

crates/heartwood-core/tests/persona_test.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
use heartwood_core::persona::{derive_from_persona, derive_persona};
2-
use heartwood_core::root::from_nsec_bytes;
1+
use nsec_tree_rs::persona::{derive_from_persona, derive_persona};
2+
use nsec_tree_rs::root::from_nsec_bytes;
33

4-
fn root_01() -> heartwood_core::types::TreeRoot {
4+
fn root_01() -> nsec_tree_rs::types::TreeRoot {
55
let nsec_bytes = [0x01u8; 32];
66
from_nsec_bytes(&nsec_bytes).expect("root creation must succeed")
77
}

crates/heartwood-core/tests/proof_test.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
use heartwood_core::derive::derive;
2-
use heartwood_core::proof::{create_blind_proof, create_full_proof, verify_proof};
3-
use heartwood_core::root::from_nsec_bytes;
1+
use nsec_tree_rs::derive::derive;
2+
use nsec_tree_rs::proof::{create_blind_proof, create_full_proof, verify_proof};
3+
use nsec_tree_rs::root::from_nsec_bytes;
44

5-
fn root_01() -> heartwood_core::types::TreeRoot {
5+
fn root_01() -> nsec_tree_rs::types::TreeRoot {
66
let nsec_bytes = [0x01u8; 32];
77
from_nsec_bytes(&nsec_bytes).expect("root creation must succeed")
88
}

0 commit comments

Comments
 (0)