Getting started
The quickest useful integration is: import account authority once, clear the
caller-owned secret buffer, validate a peer key, and execute one bounded
operation. Android uses SoftchatAccount so Rust also commits protocol and
delivery state; lower-level protocol packages expose the equivalent immutable
cryptographic values.
The coordinates below are canonical, but public registry publication is not a completed release gate. Today, build and test the matching artifact from this repository before adding it to an application.
Add the packageโ
- Rust
- Android
- Swift
- TypeScript
[dependencies]
softchat = { path = "../softchat-sdk/crates/softchat" }
The crate currently depends on reviewed, unpublished Softrelay Git revisions,
so cargo package is intentionally not presented as a crates.io install.
dependencies {
implementation("com.softcose:softchat-android:0.1.0")
}
Build the AAR with bash scripts/build-android-package.sh. It contains
arm64-v8a and x86_64 native libraries and consumer R8 rules.
dependencies: [
.package(path: "../softchat-package")
]
Build the staged XCFramework/SwiftPM distribution on macOS with
bash scripts/build-swift-package.sh; import only SoftchatKit.
bash scripts/test-javascript-package.sh
npm install ./target/packages/javascript/softcose-softchat-0.1.0.tgz
Node supports CommonJS and ESM. Browser and Worker consumers use the explicit browser initializer described below.
Complete one trusted operationโ
The sample secret is deliberately omitted. Load 32 secret bytes from your platform authority, never from source code.
- Rust
- Android
- Swift
- TypeScript
use softchat::LocalIdentity;
let alice = LocalIdentity::from_secret_bytes(&alice_secret)?;
alice_secret.fill(0);
let bob = LocalIdentity::from_secret_bytes(&bob_secret)?;
bob_secret.fill(0);
let bob_public = bob.public_key();
let encrypted = alice.encrypt_utf8(&bob_public, "hello")?;
let plaintext = bob.decrypt_utf8(&encrypted)?;
assert_eq!(plaintext, "hello");
# Ok::<(), softchat::SoftchatError>(())
val account = SoftchatAccount.open(
secretKey = accountSecret,
databaseDirectory = context.noBackupFilesDir,
)
val recipient = PublicKey.parse(recipientInput)
val conversation = account.conversations.getOrCreate(listOf(recipient))
account.messages.send(
commandId = CommandId.random(),
conversationId = conversation.id,
content = MessageContent(text = "hello"),
)
open clears accountSecret. The command commits authenticated local state,
independent recipient copies, and delivery intent before either the SDK-managed
transport or a host-owned custom transport writes socket bytes. Keep the
account for the active session and close it before switch or deletion.
let alice = try SoftchatIdentity(secretKey: aliceSecret)
aliceSecret.resetBytes(in: aliceSecret.indices)
let bob = try SoftchatIdentity(secretKey: bobSecret)
bobSecret.resetBytes(in: bobSecret.indices)
let encrypted = try alice.encrypt("hello", for: bob.publicKey)
let plaintext = try bob.decrypt(encrypted)
precondition(plaintext == "hello")
import { SoftchatIdentity } from "@softcose/softchat";
const alice = SoftchatIdentity.import(aliceSecret);
aliceSecret.fill(0);
const bob = SoftchatIdentity.import(bobSecret);
bobSecret.fill(0);
const encrypted = alice.encrypt(bob.publicKey, "hello");
console.assert(bob.decrypt(encrypted) === "hello");
For a browser or Worker:
import { initializeSoftchat } from "@softcose/softchat/browser";
const { SoftchatIdentity } = await initializeSoftchat();
Nextโ
Learn the identity lifecycle, then choose the family you need: Nostr and cryptography, private messaging, chat and account events, Android account runtime, relay and persistence, Noise and synchronization, or media and HTTP plans.