client

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Mar 16, 2026 License: MIT Imports: 25 Imported by: 0

Documentation

Overview

Package client provides the Opaque SDK for privacy-preserving search.

Hierarchical Private Search Client

This implements a three-level privacy-preserving vector search:

Level 1: HE on super-bucket centroids
  - Encrypt query with HE
  - Compute HE scores for ALL centroids (server does this)
  - Client decrypts privately, selects top-K super-buckets
  - Server NEVER knows which super-buckets were selected

Level 2: Decoy-based sub-bucket fetch
  - Fetch real sub-buckets + decoy sub-buckets
  - Shuffle all requests - server can't tell real from decoy

Level 3: Local AES decrypt + scoring
  - Decrypt vectors with AES
  - Score locally with plaintext dot products

Privacy guarantees:

  • Query: hidden from server (HE)
  • Super-bucket selection: hidden from server (client-side decrypt)
  • Sub-bucket interest: hidden from server (decoys)
  • Vectors: hidden from storage (AES)
  • Scores: hidden from everyone (local)

Index

Constants

View Source
const DefaultPoolSize = 4

DefaultPoolSize is the default number of HE engines in the worker pool. Each engine has independent evaluators but shared keys, enabling true parallelism.

Variables

This section is empty.

Functions

This section is empty.

Types

type Client

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

Client is the main SDK entry point for privacy-preserving search.

func NewClient

func NewClient(cfg Config) (*Client, error)

NewClient creates a new Opaque client.

func (*Client) ComputeLSHHash

func (c *Client) ComputeLSHHash(vector []float64) ([]byte, error)

ComputeLSHHash computes the LSH hash for a query vector.

func (*Client) ComputeMaskedLSHHash

func (c *Client) ComputeMaskedLSHHash(vector []float64) ([]byte, error)

ComputeMaskedLSHHash computes the LSH hash with session key masking. The masked hash hides the exact bucket from the server.

func (*Client) DecryptScores

func (c *Client) DecryptScores(encryptedScores [][]byte) ([]float64, error)

DecryptScores decrypts a list of encrypted scores.

func (*Client) DecryptScoresSequential

func (c *Client) DecryptScoresSequential(encryptedScores [][]byte) ([]float64, error)

DecryptScoresSequential decrypts scores sequentially (for debugging).

func (*Client) EncryptAndComputeLocal

func (c *Client) EncryptAndComputeLocal(query, vector []float64) (float64, float64, error)

EncryptAndComputeLocal tests the full homomorphic pipeline locally.

func (*Client) EncryptQuery

func (c *Client) EncryptQuery(vector []float64) ([]byte, error)

EncryptQuery encrypts a query vector.

func (*Client) GetEngine

func (c *Client) GetEngine() *crypto.Engine

GetEngine returns the crypto engine (for testing).

func (*Client) GetPublicKey

func (c *Client) GetPublicKey() ([]byte, error)

GetPublicKey returns the serialized public key for registration.

func (*Client) GetSessionKey

func (c *Client) GetSessionKey() []byte

GetSessionKey returns the current session key (for server coordination).

func (*Client) RotateSessionKey

func (c *Client) RotateSessionKey()

RotateSessionKey generates a new session key for hash masking. Call this periodically to prevent query correlation.

func (*Client) SearchLocal

func (c *Client) SearchLocal(ctx context.Context, query []float64, index *lsh.Index, vectors map[string][]float64, topK int) ([]Result, error)

SearchLocal performs a complete local search (for testing without server). This simulates the full protocol locally.

func (*Client) SetLSHPlanes

func (c *Client) SetLSHPlanes(planes []float64, numPlanes, dimension int) error

SetLSHPlanes sets the LSH hyperplanes from the server.

func (*Client) TopKResults

func (c *Client) TopKResults(ids []string, scores []float64, k int) []Result

TopKResults sorts results by score and returns top-k.

func (*Client) TwoStageSearchLocal

func (c *Client) TwoStageSearchLocal(ctx context.Context, query []float64, index *lsh.Index, vectors map[string][]float64) ([]Result, error)

TwoStageSearchLocal performs optimized two-stage search locally. Stage 1: LSH retrieves many candidates (cheap, ~0.1ms) Stage 2: Rank by Hamming distance, HE score only top N (expensive but fewer) This provides better accuracy with faster execution.

type Config

type Config struct {
	// Vector dimension
	Dimension int

	// Number of LSH bits
	LSHBits int

	// Maximum candidates to retrieve from LSH (Stage 1)
	MaxCandidates int

	// Number to score with HE after Hamming ranking (Stage 2)
	HECandidates int

	// Number of final results to return
	TopK int

	// Enable hash masking for privacy
	EnableHashMasking bool
}

Config holds client configuration.

func DefaultConfig

func DefaultConfig() Config

DefaultConfig returns a default configuration.

type DummyQueryRunner

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

DummyQueryRunner sends periodic dummy queries to create noise.

func NewDummyQueryRunner

func NewDummyQueryRunner(client *Tier2Client, interval time.Duration) *DummyQueryRunner

NewDummyQueryRunner creates a runner that sends periodic dummy queries.

func (*DummyQueryRunner) Start

func (d *DummyQueryRunner) Start()

Start begins sending dummy queries in the background.

func (*DummyQueryRunner) Stop

func (d *DummyQueryRunner) Stop()

Stop stops sending dummy queries.

type EnterpriseHierarchicalClient

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

EnterpriseHierarchicalClient performs privacy-preserving vector search using enterprise-specific credentials received from the auth service.

Architecture (no sub-buckets - simplified for better accuracy):

  • Level 1: HE scoring on centroids (k-means clusters)
  • Level 2: Fetch ALL vectors from selected super-buckets + decoys
  • Level 3: Local AES decrypt + scoring

Key security properties:

  • Uses enterprise-specific AES key for decryption
  • HE scoring on centroids (server never sees query or selection)
  • Decoy buckets hide real bucket access patterns

func NewEnterpriseHierarchicalClient

func NewEnterpriseHierarchicalClient(
	cfg hierarchical.Config,
	credentials *auth.ClientCredentials,
	store blob.Store,
) (*EnterpriseHierarchicalClient, error)

NewEnterpriseHierarchicalClient creates a client from authenticated credentials using the default HE engine pool size of 4.

The credentials contain:

  • AES key for vector decryption
  • Centroids for HE scoring

For control over the pool size, use NewEnterpriseHierarchicalClientWithPoolSize.

func NewEnterpriseHierarchicalClientWithPoolSize

func NewEnterpriseHierarchicalClientWithPoolSize(
	cfg hierarchical.Config,
	credentials *auth.ClientCredentials,
	store blob.Store,
	poolSize int,
) (*EnterpriseHierarchicalClient, error)

NewEnterpriseHierarchicalClientWithPoolSize creates a client with a configurable number of HE engines in the worker pool.

Each HE engine consumes significant memory (~50MB for CKKS parameters with LogN=14) but enables parallel homomorphic dot product computations during search. A higher pool size improves search latency when many centroids need scoring.

Recommended: poolSize = runtime.NumCPU(), capped at 8. Minimum: 1. Values < 1 are clamped to 1.

func (*EnterpriseHierarchicalClient) GetCredentials

GetCredentials returns the current credentials.

func (*EnterpriseHierarchicalClient) GetEnterpriseID

func (c *EnterpriseHierarchicalClient) GetEnterpriseID() string

GetEnterpriseID returns the enterprise ID from credentials.

func (*EnterpriseHierarchicalClient) IsTokenExpired

func (c *EnterpriseHierarchicalClient) IsTokenExpired() bool

IsTokenExpired checks if the token needs refresh.

func (*EnterpriseHierarchicalClient) Search

Search performs the full hierarchical private search. Returns search results with timing breakdown and statistics.

func (*EnterpriseHierarchicalClient) SearchBatch

func (c *EnterpriseHierarchicalClient) SearchBatch(ctx context.Context, query []float64, topK int) (*hierarchical.SearchResult, error)

SearchBatch performs hierarchical search using SIMD batch HE operations. This is significantly faster than Search() as it reduces 64 HE ops to just 1-2.

For 64 centroids with 128-dim vectors:

  • Standard: 64 HE multiply+sum operations (~2s)
  • Batch: 1 HE multiply + partial sum (~100ms)

The results are mathematically equivalent to Search().

func (*EnterpriseHierarchicalClient) TimeUntilTokenExpiry

func (c *EnterpriseHierarchicalClient) TimeUntilTokenExpiry() time.Duration

TimeUntilTokenExpiry returns the duration until the token expires.

func (*EnterpriseHierarchicalClient) UpdateCredentials

func (c *EnterpriseHierarchicalClient) UpdateCredentials(creds *auth.ClientCredentials) error

UpdateCredentials updates the client with refreshed credentials. Call this after refreshing the token with the auth service. Also reloads centroid cache if centroids changed.

type HierarchicalClient

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

HierarchicalClient performs hierarchical private search.

func NewHierarchicalClient

func NewHierarchicalClient(index *hierarchical.Index) (*HierarchicalClient, error)

NewHierarchicalClient creates a new hierarchical search client.

func (*HierarchicalClient) Search

func (c *HierarchicalClient) Search(ctx context.Context, query []float64, topK int) (*hierarchical.SearchResult, error)

Search performs the full hierarchical private search.

type HybridClient

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

HybridClient provides the Tier 2.5 hybrid search.

func NewHybridClient

func NewHybridClient(cfg HybridConfig, aesKey []byte, store blob.Store) (*HybridClient, error)

NewHybridClient creates a new hybrid client.

func (*HybridClient) Close

func (c *HybridClient) Close() error

Close cleans up resources.

func (*HybridClient) DecryptScoreHE

func (c *HybridClient) DecryptScoreHE(encScore *rlwe.Ciphertext) (float64, error)

DecryptScoreHE decrypts an HE-encrypted score.

func (*HybridClient) EncryptQueryHE

func (c *HybridClient) EncryptQueryHE(query []float64) (*rlwe.Ciphertext, error)

EncryptQueryHE encrypts a query with HE (for sending to compute server).

func (*HybridClient) GetHEPublicKey

func (c *HybridClient) GetHEPublicKey() ([]byte, error)

GetHEPublicKey returns the HE public key for a compute server.

func (*HybridClient) GetStats

func (c *HybridClient) GetStats(ctx context.Context) (*blob.StoreStats, error)

GetStats returns storage statistics.

func (*HybridClient) Insert

func (c *HybridClient) Insert(ctx context.Context, id string, vector []float64, metadata map[string]any) error

Insert encrypts and stores a vector.

func (*HybridClient) InsertBatch

func (c *HybridClient) InsertBatch(ctx context.Context, ids []string, vectors [][]float64, metadata []map[string]any) error

InsertBatch encrypts and stores multiple vectors.

func (*HybridClient) Search

func (c *HybridClient) Search(ctx context.Context, query []float64, topK int) (*HybridSearchResult, error)

Search performs hybrid search with configurable privacy levels.

func (*HybridClient) SearchFast

func (c *HybridClient) SearchFast(ctx context.Context, query []float64, topK int) (*HybridSearchResult, error)

SearchFast performs search without HE (Tier 2 style, faster).

func (*HybridClient) SearchPrivate

func (c *HybridClient) SearchPrivate(ctx context.Context, query []float64, topK int) (*HybridSearchResult, error)

SearchPrivate performs search with HE (maximum privacy, slower).

type HybridConfig

type HybridConfig struct {
	Dimension int
	LSHBits   int
	LSHSeed   int64

	// Two-stage filtering
	CoarseCandidates int // Number of candidates from LSH (e.g., 200)
	FineCandidates   int // Number to score with HE (e.g., 20)

	// Privacy modes
	UseHEForFinalScoring bool // If true, use HE for final scoring (slower but more private)
}

HybridConfig holds configuration for the hybrid client.

func DefaultHybridConfig

func DefaultHybridConfig() HybridConfig

DefaultHybridConfig returns sensible defaults.

type HybridSearchResult

type HybridSearchResult struct {
	Results []Result

	// Timing breakdown
	LSHTime     time.Duration
	FetchTime   time.Duration
	DecryptTime time.Duration
	CoarseTime  time.Duration // Time for initial scoring (plaintext)
	HEScoreTime time.Duration // Time for HE scoring (if enabled)
	TotalTime   time.Duration

	// Stats
	BlobsFetched     int
	CoarseCandidates int
	HEOperations     int
}

HybridSearchResult contains search results with timing breakdown.

type LoginCredentials

type LoginCredentials struct {
	Token       string
	ExpiresAt   time.Time
	AESKey      []byte
	Centroids   [][]float64
	Dimension   int
	NumClusters int
}

LoginCredentials holds the response from server login.

type PrivacyConfig

type PrivacyConfig struct {
	// Timing obfuscation
	MinLatency  time.Duration // Minimum response time (pad short queries)
	MaxLatency  time.Duration // Maximum latency cap
	JitterRange time.Duration // Random jitter added to responses

	// Query obfuscation
	DecoyBuckets int  // Number of random buckets to fetch
	PadResults   bool // Pad results to fixed size

	// Background noise
	EnableDummyQueries bool          // Send periodic dummy queries
	DummyQueryInterval time.Duration // How often to send dummy queries

	// Result handling
	ShuffleBeforeProcess bool // Randomize blob order before decryption
}

PrivacyConfig holds privacy-related configuration.

func DefaultPrivacyConfig

func DefaultPrivacyConfig() PrivacyConfig

DefaultPrivacyConfig returns privacy settings optimized for security.

func HighPrivacyConfig

func HighPrivacyConfig() PrivacyConfig

HighPrivacyConfig returns settings for maximum privacy (slower).

func LowLatencyConfig

func LowLatencyConfig() PrivacyConfig

LowLatencyConfig returns settings optimized for speed (less private).

type PrivacyMetrics

type PrivacyMetrics struct {
	TotalQueries        int64
	DummyQueries        int64
	DecoyBucketsFetched int64
	AvgObfuscationDelay time.Duration
	// contains filtered or unexported fields
}

PrivacyMetrics tracks privacy-related statistics.

func (*PrivacyMetrics) GetMetrics

func (m *PrivacyMetrics) GetMetrics() PrivacyMetrics

GetMetrics returns a copy of the current metrics.

func (*PrivacyMetrics) RecordQuery

func (m *PrivacyMetrics) RecordQuery(isDummy bool, decoyCount int, obfuscationDelay time.Duration)

RecordQuery records a query for metrics.

type RemoteClient

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

RemoteClient performs privacy-preserving vector search via REST API.

Architecture:

  • Client encrypts query with HE (server never sees plaintext query)
  • Server computes HE scores on centroids
  • Client decrypts scores, selects clusters (server never sees selection)
  • Client fetches blobs from selected clusters + decoys
  • Client decrypts vectors and scores locally

This maintains query privacy because:

  • HE-encrypted query is sent to server
  • Score decryption happens client-side
  • Cluster selection is client-side (server doesn't know which are real)
  • Final scoring is client-side

func NewRemoteClient

func NewRemoteClient(cfg RemoteClientConfig, enterpriseID, userID, password string) (*RemoteClient, error)

NewRemoteClient creates a remote client and authenticates with the server.

func (*RemoteClient) IsTokenExpired

func (c *RemoteClient) IsTokenExpired() bool

IsTokenExpired checks if the token needs refresh.

func (*RemoteClient) RefreshToken

func (c *RemoteClient) RefreshToken(ctx context.Context) error

RefreshToken refreshes the authentication token.

func (*RemoteClient) Search

func (c *RemoteClient) Search(ctx context.Context, query []float64, topK int) (*hierarchical.SearchResult, error)

Search performs privacy-preserving vector search via the server.

type RemoteClientConfig

type RemoteClientConfig struct {
	ServerURL        string
	HTTPTimeout      time.Duration
	TopSelect        int
	NumDecoys        int
	ProbeThreshold   float64
	MaxProbeClusters int
}

RemoteClientConfig holds configuration for the remote client.

func DefaultRemoteClientConfig

func DefaultRemoteClientConfig() RemoteClientConfig

DefaultRemoteClientConfig returns sensible defaults.

type Result

type Result struct {
	ID    string
	Score float64
}

Result represents a search result.

type SearchOptions

type SearchOptions struct {
	// TopK is the number of results to return.
	TopK int

	// NumBuckets is how many buckets to search (more = better recall, slower).
	NumBuckets int

	// DecoyBuckets is how many random buckets to fetch (for privacy).
	// Storage can't tell which buckets you're actually interested in.
	DecoyBuckets int

	// UseMultiProbe enables multi-probe LSH (searches neighboring buckets).
	UseMultiProbe bool
}

SearchOptions controls search behavior.

type Tier2Client

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

Tier2Client provides data-private vector search. Vectors are encrypted client-side; storage never sees plaintext.

func NewTier2Client

func NewTier2Client(cfg Tier2Config, encryptor *encrypt.AESGCM, store blob.Store) (*Tier2Client, error)

NewTier2Client creates a new Tier 2 client.

func (*Tier2Client) Close

func (c *Tier2Client) Close() error

Close closes the underlying store.

func (*Tier2Client) Delete

func (c *Tier2Client) Delete(ctx context.Context, id string) error

Delete removes a vector by ID.

func (*Tier2Client) DeleteBatch

func (c *Tier2Client) DeleteBatch(ctx context.Context, ids []string) error

DeleteBatch removes multiple vectors by ID.

func (*Tier2Client) GetKeyFingerprint

func (c *Tier2Client) GetKeyFingerprint() string

GetKeyFingerprint returns the encryption key fingerprint. Useful for verifying the correct key is being used.

func (*Tier2Client) GetLSHPlanes

func (c *Tier2Client) GetLSHPlanes() [][]float64

GetLSHPlanes returns the LSH hyperplanes. Other clients need these to compute compatible LSH hashes.

func (*Tier2Client) GetPrivacyMetrics

func (c *Tier2Client) GetPrivacyMetrics() *PrivacyMetrics

GetPrivacyMetrics returns privacy-related metrics.

func (*Tier2Client) GetStats

func (c *Tier2Client) GetStats(ctx context.Context) (*blob.StoreStats, error)

GetStats returns storage statistics.

func (*Tier2Client) Insert

func (c *Tier2Client) Insert(ctx context.Context, id string, vector []float64, metadata map[string]any) error

Insert encrypts and stores a single vector.

func (*Tier2Client) InsertBatch

func (c *Tier2Client) InsertBatch(ctx context.Context, ids []string, vectors [][]float64, metadata []map[string]any) error

InsertBatch encrypts and stores multiple vectors.

func (*Tier2Client) Search

func (c *Tier2Client) Search(ctx context.Context, query []float64, topK int) ([]Result, error)

Search performs a privacy-preserving search. 1. Compute LSH hash locally 2. Fetch matching bucket(s) from storage 3. Decrypt vectors locally 4. Compute similarity locally 5. Return top-K results

func (*Tier2Client) SearchWithOptions

func (c *Tier2Client) SearchWithOptions(ctx context.Context, query []float64, opts SearchOptions) ([]Result, error)

SearchWithOptions performs a search with custom options.

func (*Tier2Client) SearchWithPrivacy

func (c *Tier2Client) SearchWithPrivacy(ctx context.Context, query []float64, topK int) ([]Result, error)

SearchWithPrivacy performs a search with full privacy enhancements. Uses timing obfuscation, decoy buckets, and shuffling based on PrivacyConfig.

func (*Tier2Client) SetPrivacyConfig

func (c *Tier2Client) SetPrivacyConfig(cfg PrivacyConfig)

SetPrivacyConfig configures privacy features.

func (*Tier2Client) StartDummyQueries

func (c *Tier2Client) StartDummyQueries()

StartDummyQueries starts sending background dummy queries.

func (*Tier2Client) StopDummyQueries

func (c *Tier2Client) StopDummyQueries()

StopDummyQueries stops sending background dummy queries.

type Tier2Config

type Tier2Config struct {
	// Dimension is the vector dimension.
	Dimension int

	// LSHBits is the number of LSH hash bits.
	// Fewer bits = larger buckets = more privacy but less precision.
	LSHBits int

	// LSHSeed is the random seed for LSH planes (must match across clients).
	LSHSeed int64

	// MaxBucketsToFetch limits how many buckets to download per search.
	MaxBucketsToFetch int

	// MaxResultsPerBucket limits results from each bucket (0 = unlimited).
	MaxResultsPerBucket int
}

Tier2Config holds configuration for the Tier 2 client.

func DefaultTier2Config

func DefaultTier2Config() Tier2Config

DefaultTier2Config returns sensible defaults.

type TimingObfuscator

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

TimingObfuscator adds random delays to hide query timing patterns.

func NewTimingObfuscator

func NewTimingObfuscator(minLatency, jitterRange time.Duration) *TimingObfuscator

NewTimingObfuscator creates a new timing obfuscator.

func (*TimingObfuscator) Obfuscate

func (t *TimingObfuscator) Obfuscate() func()

Obfuscate ensures the operation takes at least minLatency + random jitter. Call at the start of an operation, defer the returned function.

func (*TimingObfuscator) ObfuscateContext

func (t *TimingObfuscator) ObfuscateContext(ctx context.Context) func()

ObfuscateContext is like Obfuscate but respects context cancellation.

Jump to

Keyboard shortcuts

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