Files
dchain/relay/keypair.go
vsecoder 7e7393e4f8 chore: initial commit for v0.0.1
DChain single-node blockchain + React Native messenger client.

Core:
- PBFT consensus with multi-sig validator admission + equivocation slashing
- BadgerDB + schema migration scaffold (CurrentSchemaVersion=0)
- libp2p gossipsub (tx/v1, blocks/v1, relay/v1, version/v1)
- Native Go contracts (username_registry) alongside WASM (wazero)
- WebSocket gateway with topic-based fanout + Ed25519-nonce auth
- Relay mailbox with NaCl envelope encryption (X25519 + Ed25519)
- Prometheus /metrics, per-IP rate limit, body-size cap

Deployment:
- Single-node compose (deploy/single/) with Caddy TLS + optional Prometheus
- 3-node dev compose (docker-compose.yml) with mocked internet topology
- 3-validator prod compose (deploy/prod/) for federation
- Auto-update from Gitea via /api/update-check + systemd timer
- Build-time version injection (ldflags → node --version)
- UI / Swagger toggle flags (DCHAIN_DISABLE_UI, DCHAIN_DISABLE_SWAGGER)

Client (client-app/):
- Expo / React Native / NativeWind
- E2E NaCl encryption, typing indicator, contact requests
- Auto-discovery of canonical contracts, chain_id aware, WS reconnect on node switch

Documentation:
- README.md, CHANGELOG.md, CONTEXT.md
- deploy/single/README.md with 6 operator scenarios
- deploy/UPDATE_STRATEGY.md with 4-layer forward-compat design
- docs/contracts/*.md per contract
2026-04-17 14:16:44 +03:00

55 lines
1.3 KiB
Go

package relay
import (
"encoding/hex"
"encoding/json"
"fmt"
"os"
)
type keypairFile struct {
Pub string `json:"pub"`
Priv string `json:"priv"`
}
// LoadOrCreateKeyPair loads an X25519 relay keypair from path, creating it if absent.
func LoadOrCreateKeyPair(path string) (*KeyPair, error) {
data, err := os.ReadFile(path)
if err == nil {
var f keypairFile
if err := json.Unmarshal(data, &f); err != nil {
return nil, fmt.Errorf("parse relay key file: %w", err)
}
pubBytes, err := hex.DecodeString(f.Pub)
if err != nil || len(pubBytes) != 32 {
return nil, fmt.Errorf("invalid relay pub key in %s", path)
}
privBytes, err := hex.DecodeString(f.Priv)
if err != nil || len(privBytes) != 32 {
return nil, fmt.Errorf("invalid relay priv key in %s", path)
}
kp := &KeyPair{}
copy(kp.Pub[:], pubBytes)
copy(kp.Priv[:], privBytes)
return kp, nil
}
if !os.IsNotExist(err) {
return nil, fmt.Errorf("read relay key file: %w", err)
}
// Generate new keypair and persist.
kp, err := GenerateKeyPair()
if err != nil {
return nil, err
}
f := keypairFile{
Pub: kp.PubHex(),
Priv: hex.EncodeToString(kp.Priv[:]),
}
out, _ := json.MarshalIndent(f, "", " ")
if err := os.WriteFile(path, out, 0600); err != nil {
return nil, fmt.Errorf("write relay key file: %w", err)
}
return kp, nil
}