vault

package
v0.42.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 18, 2026 License: MIT Imports: 20 Imported by: 0

Documentation

Overview

Package vault provides per-user encrypted SQLite shards with CRDT sync and on-chain anchoring. This is the unified local-first data SDK.

Architecture:

Cloud HSM / K-Chain ML-KEM
  └── Master KEK (unwrapped via HSM or threshold decryption)
        └── Org KEK = HMAC-SHA256(master, "vault:org:" + orgID)
              └── User DEK = HMAC-SHA256(orgKEK, "vault:user:" + userID)
                    └── SQLite shard (AES-256-GCM encrypted)
                          └── CRDT sync via ZAP (conflict-free merge)
                                └── Merkle root anchored to chain

Usage:

vault.MustRegister(app, vault.Config{
    DataDir:    "/data/vaults",
    MasterKey:  masterKeyBytes, // from HSM or K-Chain
    OrgID:      "my-org",
    ChainRPC:   "http://localhost:9650/ext/bc/I", // optional anchoring
    SyncEnabled: true,
})

Each authenticated user gets their own encrypted SQLite file. Reads/writes are instant (local). CRDT syncs in background. Chain stores merkle roots, never row data.

SDK exposes the 5 primitives that any app needs:

  1. Identity — OpenUser, bind device, resolve DID
  2. KeyAccess — GetShardKey, unwrap DEK, rotation
  3. LocalDB — OpenShard, read/write encrypted SQLite
  4. Sync — PushOps, PullOps, Merge (CRDT over ZAP)
  5. Anchor — CommitAnchor, merkle root to chain, audit proof

Usage:

v, _ := vault.Open(vault.SDKConfig{
    DataDir:   "/data/vaults",
    MasterKEK: masterKey,     // from HSM or K-Chain
    OrgID:     "my-org",
})
defer v.Close()

session, _ := v.OpenUser("user-123")
session.Put("prefs", []byte(`{"theme":"dark"}`))
val, _ := session.Get("prefs")
session.Sync()
receipt, _ := session.Anchor()

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ExportVault

func ExportVault(session *Session) ([]byte, error)

ExportVault exports the session's encrypted state as a portable JSON bundle. The bundle contains ciphertext only — the DEK is NOT included. The caller must supply the DEK separately to import.

func GetWithToken

func GetWithToken(token *ShareToken, store map[string][]byte, key string) ([]byte, error)

GetWithToken retrieves and decrypts a value using a ShareToken. Only works for keys in the token's collection.

func MustRegister

func MustRegister(app core.App, config Config)

MustRegister registers the vault plugin and panics on error.

func RecoverFromShares

func RecoverFromShares(shares [][]byte) ([]byte, error)

RecoverFromShares reconstructs a DEK by XOR-ing all shares together. Requires all shares (threshold == total in v2).

func Register

func Register(app core.App, config Config) error

Register registers the vault plugin with a Base app.

Types

type AnchorReceipt

type AnchorReceipt struct {
	MerkleRoot string `json:"merkleRoot"`
	UserID     string `json:"userId"`
	OrgID      string `json:"orgId"`
	Timestamp  int64  `json:"timestamp"`
	ChainTxID  string `json:"chainTxId,omitempty"` // set after on-chain commit
	OpCount    int    `json:"opCount"`
}

AnchorReceipt is returned by Anchor() — proof of chain commitment.

type AuditEntry

type AuditEntry struct {
	Timestamp time.Time `json:"timestamp"`
	VaultID   string    `json:"vaultId"`  // org:user
	Actor     string    `json:"actor"`    // DID of who performed the action
	Action    string    `json:"action"`   // "put", "get", "delete", "sync", "anchor", "grant", "revoke"
	Resource  string    `json:"resource"` // key, capability ID, etc.
	Hash      string    `json:"hash"`     // SHA-256 of entry for chaining
	PrevHash  string    `json:"prevHash"` // hash of previous entry (chain link)
}

AuditEntry records a single vault operation.

type AuditLog

type AuditLog struct {
	// contains filtered or unexported fields
}

AuditLog is an append-only log of vault operations. Entries are hash-chained: each entry's PrevHash points to the previous entry's Hash. The last hash is the audit merkle root, suitable for chain anchoring.

func NewAuditLog

func NewAuditLog() *AuditLog

NewAuditLog creates an empty audit log.

func (*AuditLog) GetAuditLog

func (al *AuditLog) GetAuditLog(vaultID string, since time.Time) []AuditEntry

GetAuditLog returns entries for a vaultID since a given time. Pass time.Time{} (zero) to get all entries.

func (*AuditLog) Len

func (al *AuditLog) Len() int

Len returns the number of entries in the audit log.

func (*AuditLog) MerkleRoot

func (al *AuditLog) MerkleRoot() string

MerkleRoot returns the hash of the last entry, which is the root of the hash chain. This is the value anchored to chain. Returns empty string if the log is empty.

func (*AuditLog) Record

func (al *AuditLog) Record(vaultID, actor, action, resource string)

Record appends an entry to the audit log. The entry is hash-chained to the previous entry automatically.

func (*AuditLog) Verify

func (al *AuditLog) Verify() bool

Verify checks that the hash chain is consistent. Returns true if every entry's PrevHash matches the previous entry's Hash.

type Bundle

type Bundle struct {
	Version   int             `json:"version"`
	UserID    string          `json:"userId"`
	OrgID     string          `json:"orgId"`
	Timestamp int64           `json:"timestamp"`
	Snapshot  json.RawMessage `json:"snapshot"` // encrypted store entries
	Oplog     []Op            `json:"oplog"`
	Metadata  BundleMetadata  `json:"metadata"`
}

Bundle is a portable vault export: JSON envelope with encrypted data + oplog + metadata.

type BundleMetadata

type BundleMetadata struct {
	KeyCount int    `json:"keyCount"`
	OpCount  int    `json:"opCount"`
	Format   string `json:"format"` // "vault-bundle-v3"
}

BundleMetadata holds non-sensitive metadata about the bundle.

type Capability

type Capability struct {
	ID        string    // deterministic: SHA-256(issuer + subject + resource + actions)
	Issuer    string    // DID of the issuer
	Subject   string    // DID of the subject (who can use this)
	Resource  string    // vault ID, collection, or key pattern
	Actions   []string  // "read", "write", "sync", "anchor", "share"
	Expires   time.Time // zero value = never expires
	Signature []byte    // signed by issuer (verified externally)
	Revoked   bool      // set by Revoke()
}

Capability represents a delegated permission from one DID to another. Capabilities are signed by the issuer and scoped to specific resources/actions.

Example:

cap := &Capability{
    Issuer:   "did:lux:org:acme",
    Subject:  "did:lux:user:alice",
    Resource: "vault:acme:*",
    Actions:  []string{"read", "write"},
    Expires:  time.Now().Add(24 * time.Hour),
}

type ConfidentialEngine

type ConfidentialEngine interface {
	Execute(session *Session, query *ConfidentialQuery) (*ConfidentialResult, error)
	Verify(result *ConfidentialResult) (bool, error)
}

ConfidentialEngine processes queries on encrypted data. Implementations range from "decrypt locally and compute" (LocalConfidentialEngine) to full FHE/ZK backends. The interface is the same.

type ConfidentialQuery

type ConfidentialQuery struct {
	Operation string      // "sum", "count", "match", "policy_check"
	Target    string      // collection or key pattern
	Params    interface{} // query-specific parameters
}

ConfidentialQuery describes a computation to run on encrypted data.

type ConfidentialResult

type ConfidentialResult struct {
	Value     interface{} // result (may be encrypted or plaintext depending on engine)
	Proof     []byte      // hash-based proof of correct computation (optional)
	Encrypted bool        // whether Value is still encrypted
}

ConfidentialResult holds the output of a confidential computation.

type Config

type Config struct {
	Enabled     bool   `json:"enabled"`
	DataDir     string `json:"dataDir"`     // directory for per-user SQLite shards
	OrgID       string `json:"orgId"`       // organization identifier
	MasterKey   []byte `json:"-"`           // 32-byte master KEK (from HSM/K-Chain)
	ChainRPC    string `json:"chainRpc"`    // optional: I-Chain RPC for merkle anchoring
	SyncEnabled bool   `json:"syncEnabled"` // enable CRDT sync via ZAP
	ZAPPort     int    `json:"zapPort"`     // ZAP listen port for sync (default 9900)
}

Config configures the vault plugin.

type DeviceKey

type DeviceKey struct {
	UserID   string
	DeviceID string
	Key      []byte // 32-byte device wrapping key
}

DeviceKey is a device-specific wrapping key derived from the user DEK.

type LocalConfidentialEngine

type LocalConfidentialEngine struct{}

LocalConfidentialEngine is the baseline confidential compute engine. It decrypts data locally, runs the computation, and returns plaintext results with a hash-based proof of computation.

This is NOT FHE. It exists to exercise the ConfidentialEngine interface so callers are written correctly before a real FHE/ZK backend is plugged in. The proof is a SHA-256 hash binding the query + result — verifiable but not zero-knowledge.

func (*LocalConfidentialEngine) Execute

Execute runs a confidential query against a session's encrypted store. Supported operations:

  • "count" — count keys matching Target prefix
  • "sum" — sum numeric values for keys matching Target prefix
  • "match" — check if key Target equals Params (string)
  • "policy_check" — check if subject (Target) has action (Params) via PolicyEngine

func (*LocalConfidentialEngine) Verify

func (e *LocalConfidentialEngine) Verify(result *ConfidentialResult) (bool, error)

Verify checks that a result's proof matches its value. For the local engine, the proof is SHA-256(json(Value)).

type LocalRecoveryProvider

type LocalRecoveryProvider struct {
	// contains filtered or unexported fields
}

LocalRecoveryProvider stores threshold key shares in a local directory.

func NewLocalRecoveryProvider

func NewLocalRecoveryProvider(dir string) (*LocalRecoveryProvider, error)

NewLocalRecoveryProvider creates a recovery provider backed by a directory.

func (*LocalRecoveryProvider) FetchShares

func (p *LocalRecoveryProvider) FetchShares(userID string, indices []int) ([][]byte, error)

FetchShares retrieves encrypted shares for a user by index.

func (*LocalRecoveryProvider) StoreShare

func (p *LocalRecoveryProvider) StoreShare(userID string, shareIndex int, encryptedShare []byte) error

StoreShare stores an encrypted share for a user.

type LocalStorageProvider

type LocalStorageProvider struct {
	// contains filtered or unexported fields
}

LocalStorageProvider uses content-addressed file storage.

func NewLocalStorageProvider

func NewLocalStorageProvider(dir string) (*LocalStorageProvider, error)

NewLocalStorageProvider creates a storage provider backed by a directory.

func (*LocalStorageProvider) GetBlob

func (p *LocalStorageProvider) GetBlob(hash string) ([]byte, error)

GetBlob retrieves a blob by content hash.

func (*LocalStorageProvider) GetSnapshot

func (p *LocalStorageProvider) GetSnapshot(vaultID string, hash string) ([]byte, error)

GetSnapshot retrieves a snapshot by vault ID and content hash.

func (*LocalStorageProvider) PutBlob

func (p *LocalStorageProvider) PutBlob(key string, data []byte) (string, error)

PutBlob stores a blob and returns its content hash.

func (*LocalStorageProvider) PutSnapshot

func (p *LocalStorageProvider) PutSnapshot(vaultID string, data []byte) (string, error)

PutSnapshot stores a snapshot and returns its content hash.

type LocalSyncProvider

type LocalSyncProvider struct {
	// contains filtered or unexported fields
}

LocalSyncProvider uses filesystem + channels for local/self-hosted sync.

func NewLocalSyncProvider

func NewLocalSyncProvider(dir string) (*LocalSyncProvider, error)

NewLocalSyncProvider creates a sync provider backed by a directory.

func (*LocalSyncProvider) Pull

func (p *LocalSyncProvider) Pull(vaultID string, since uint64) ([]Op, error)

Pull returns ops with Seq > since for the given vault.

func (*LocalSyncProvider) Push

func (p *LocalSyncProvider) Push(vaultID string, ops []Op) error

Push appends ops and notifies subscribers.

func (*LocalSyncProvider) Subscribe

func (p *LocalSyncProvider) Subscribe(vaultID string, callback func([]Op)) error

Subscribe registers a callback for new ops.

type Meter

type Meter struct {
	// contains filtered or unexported fields
}

Meter tracks per-vault operation counts. Designed for pay-per-use billing but works locally too.

func NewMeter

func NewMeter() *Meter

NewMeter creates a new usage meter.

func (*Meter) GetUsage

func (m *Meter) GetUsage(vaultID string) *UsageReport

GetUsage returns the usage report for a vault.

func (*Meter) RecordAnchor

func (m *Meter) RecordAnchor(vaultID string)

RecordAnchor increments the anchor counter for a vault.

func (*Meter) RecordGet

func (m *Meter) RecordGet(vaultID string)

RecordGet increments the get counter for a vault.

func (*Meter) RecordPut

func (m *Meter) RecordPut(vaultID string)

RecordPut increments the put counter for a vault.

func (*Meter) RecordSync

func (m *Meter) RecordSync(vaultID string)

RecordSync increments the sync counter for a vault.

func (*Meter) Reset

func (m *Meter) Reset(vaultID string)

Reset zeroes all counters for a vault.

type Op

type Op struct {
	Seq    uint64 `json:"seq"`
	NodeID string `json:"nodeId"`
	Key    string `json:"key"`
	Value  []byte `json:"value"` // encrypted
	Time   int64  `json:"time"`
}

Op is a CRDT operation in the oplog.

type PolicyEngine

type PolicyEngine struct {
	// contains filtered or unexported fields
}

PolicyEngine manages capability-based access control for vaults. Thread-safe. All capabilities are held in memory (persisted to vault shard in production via Put/Get).

func NewPolicyEngine

func NewPolicyEngine() *PolicyEngine

NewPolicyEngine creates an empty policy engine.

func (*PolicyEngine) Check

func (pe *PolicyEngine) Check(subject, resource, action string) bool

Check returns true if subject has the given action on resource. Checks expiry and revocation.

func (*PolicyEngine) Grant

func (pe *PolicyEngine) Grant(cap *Capability) error

Grant issues a capability. The capability ID is computed deterministically. Returns an error if required fields are missing.

func (*PolicyEngine) List

func (pe *PolicyEngine) List(subject string) []*Capability

List returns all non-revoked capabilities for a subject.

func (*PolicyEngine) Revoke

func (pe *PolicyEngine) Revoke(capID string) error

Revoke revokes a capability by ID.

type ProviderRegistry

type ProviderRegistry struct {
	// contains filtered or unexported fields
}

ProviderRegistry discovers and manages providers.

func NewProviderRegistry

func NewProviderRegistry() *ProviderRegistry

NewProviderRegistry creates an empty registry.

func (*ProviderRegistry) GetRecovery

func (r *ProviderRegistry) GetRecovery(name string) (RecoveryProvider, error)

GetRecovery returns a recovery provider by name.

func (*ProviderRegistry) GetStorage

func (r *ProviderRegistry) GetStorage(name string) (StorageProvider, error)

GetStorage returns a storage provider by name.

func (*ProviderRegistry) GetSync

func (r *ProviderRegistry) GetSync(name string) (SyncProvider, error)

GetSync returns a sync provider by name.

func (*ProviderRegistry) RegisterRecovery

func (r *ProviderRegistry) RegisterRecovery(name string, p RecoveryProvider)

RegisterRecovery registers a named recovery provider.

func (*ProviderRegistry) RegisterStorage

func (r *ProviderRegistry) RegisterStorage(name string, p StorageProvider)

RegisterStorage registers a named storage provider.

func (*ProviderRegistry) RegisterSync

func (r *ProviderRegistry) RegisterSync(name string, p SyncProvider)

RegisterSync registers a named sync provider.

type RecoveryProvider

type RecoveryProvider interface {
	StoreShare(userID string, shareIndex int, encryptedShare []byte) error
	FetchShares(userID string, indices []int) ([][]byte, error)
}

RecoveryProvider assists with key recovery via threshold shares.

type SDKConfig

type SDKConfig struct {
	DataDir   string // directory for per-user SQLite shards
	MasterKEK []byte // 32-byte master key (from HSM or K-Chain)
	OrgID     string // organization identifier

	// Optional: chain anchoring
	ChainRPC string // I-Chain RPC for merkle root commits

	// Optional: sync
	SyncPeers []string // ZAP peer addresses for CRDT sync
}

SDKConfig configures a Vault instance (standalone, no Base app required).

type Session

type Session struct {
	// contains filtered or unexported fields
}

Session is a per-user encrypted data context. It holds the user's DEK and provides all 5 SDK primitives.

func ImportVault

func ImportVault(data []byte, dek []byte) (*Session, error)

ImportVault imports a vault from a portable bundle. The caller must provide the correct DEK to decrypt values.

func (*Session) Anchor

func (s *Session) Anchor() (*AnchorReceipt, error)

Anchor computes a merkle root over the current state and returns a receipt suitable for on-chain commitment. The chain stores ONLY the root hash — never row data, never keys.

func (*Session) CreateRecoveryShares

func (s *Session) CreateRecoveryShares(threshold, total int) ([][]byte, error)

CreateRecoveryShares splits the user DEK into `total` shares using XOR-based secret sharing. Any `threshold` shares can reconstruct the DEK when threshold == total (all shares needed). Proper Shamir SSS in v3.

func (*Session) Delete

func (s *Session) Delete(key string)

Delete removes a key.

func (*Session) Get

func (s *Session) Get(key string) ([]byte, error)

Get retrieves and decrypts a value by key.

func (*Session) GetCollection

func (s *Session) GetCollection(collection, key string) ([]byte, error)

GetCollection retrieves a value encrypted with the collection-scoped DEK.

func (*Session) Merge

func (s *Session) Merge(remoteOps []Op)

Merge applies remote ops into local state. Each op carries encrypted values — merge does not require DEK.

func (*Session) Put

func (s *Session) Put(key string, value []byte) error

Put stores an encrypted key-value pair. Value is encrypted with the user's DEK before storage.

func (*Session) PutCollection

func (s *Session) PutCollection(collection, key string, value []byte) error

PutCollection stores a value encrypted with the collection-scoped DEK.

func (*Session) ShareCollection

func (s *Session) ShareCollection(collection, recipientID string) *ShareToken

ShareCollection creates a ShareToken that lets recipientID decrypt only the named collection. Collection DEK = HMAC-SHA256(userDEK, "collection:" + collectionName).

func (*Session) Sync

func (s *Session) Sync() error

Sync pushes local ops to peers and pulls remote ops. CRDT merge is conflict-free — concurrent writes to the same key resolve by last-writer-wins (Lamport timestamp + nodeID). Ops carry ciphertext — peers relay opaque bytes without decrypting.

type ShareToken

type ShareToken struct {
	Collection    string
	RecipientID   string
	CollectionDEK []byte // 32-byte collection-scoped key
}

ShareToken carries a re-encrypted DEK scoped to a single collection.

type SharedSession

type SharedSession struct {
	Session
	// contains filtered or unexported fields
}

SharedSession is a multi-member vault derived from the org KEK + vaultID. Members list controls who can access. Each member decrypts with the shared DEK.

func (*SharedSession) GetAs

func (ss *SharedSession) GetAs(userID, key string) ([]byte, error)

GetAs retrieves a value only if the caller is a member.

func (*SharedSession) IsMember

func (ss *SharedSession) IsMember(userID string) bool

IsMember returns true if the given userID is in the members list.

func (*SharedSession) PutAs

func (ss *SharedSession) PutAs(userID, key string, value []byte) error

PutAs stores a value only if the caller is a member.

type StorageProvider

type StorageProvider interface {
	PutSnapshot(vaultID string, data []byte) (string, error) // returns content hash
	GetSnapshot(vaultID string, hash string) ([]byte, error)
	PutBlob(key string, data []byte) (string, error)
	GetBlob(hash string) ([]byte, error)
}

StorageProvider stores encrypted snapshots and blobs.

type SyncProvider

type SyncProvider interface {
	Push(vaultID string, ops []Op) error
	Pull(vaultID string, since uint64) ([]Op, error)
	Subscribe(vaultID string, callback func([]Op)) error
}

SyncProvider relays encrypted CRDT ops between devices/users.

type UsageReport

type UsageReport struct {
	VaultID string `json:"vaultId"`
	Puts    int64  `json:"puts"`
	Gets    int64  `json:"gets"`
	Syncs   int64  `json:"syncs"`
	Anchors int64  `json:"anchors"`
}

UsageReport holds operation counts for a vault.

type UserShard

type UserShard struct {
	UserID string
	Path   string // filesystem path to the .db file
	DEK    []byte // 32-byte data encryption key for this user
}

UserShard is an encrypted per-user SQLite database.

func (*UserShard) Decrypt

func (s *UserShard) Decrypt(ciphertext []byte) ([]byte, error)

Decrypt decrypts ciphertext (nonce-prepended) with the user's DEK.

func (*UserShard) Encrypt

func (s *UserShard) Encrypt(plaintext []byte) ([]byte, error)

Encrypt encrypts plaintext with the user's DEK using AES-256-GCM.

type Vault

type Vault struct {
	// contains filtered or unexported fields
}

Vault is the top-level SDK handle. One per app process.

func Open

func Open(cfg SDKConfig) (*Vault, error)

Open creates a new Vault instance.

func (*Vault) Close

func (v *Vault) Close()

Close releases all resources and zeroes key material.

func (*Vault) EnrollDevice

func (v *Vault) EnrollDevice(userID, deviceID string) (*DeviceKey, error)

EnrollDevice creates a device-specific wrapping key for the given user. Device key = HMAC-SHA256(userDEK, "device:" + deviceID). The device key wraps the user DEK for local storage on that device.

func (*Vault) OpenSharedVault

func (v *Vault) OpenSharedVault(vaultID string, members []string) (*SharedSession, error)

OpenSharedVault creates a shared vault accessible by the listed members. The DEK is derived from orgKEK + vaultID (not any single user).

func (*Vault) OpenUser

func (v *Vault) OpenUser(userID string) (*Session, error)

OpenUser opens (or creates) a session for a user. Derives the per-user DEK and opens the encrypted SQLite shard.

func (*Vault) RevokeDevice

func (v *Vault) RevokeDevice(userID, deviceID string) error

RevokeDevice removes a device key. The user DEK is unaffected — other devices continue to work. In production, the revoked device's wrapped DEK copy becomes useless because its wrapping key is discarded.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL