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
- type Client
- func (c *Client) ComputeLSHHash(vector []float64) ([]byte, error)
- func (c *Client) ComputeMaskedLSHHash(vector []float64) ([]byte, error)
- func (c *Client) DecryptScores(encryptedScores [][]byte) ([]float64, error)
- func (c *Client) DecryptScoresSequential(encryptedScores [][]byte) ([]float64, error)
- func (c *Client) EncryptAndComputeLocal(query, vector []float64) (float64, float64, error)
- func (c *Client) EncryptQuery(vector []float64) ([]byte, error)
- func (c *Client) GetEngine() *crypto.Engine
- func (c *Client) GetPublicKey() ([]byte, error)
- func (c *Client) GetSessionKey() []byte
- func (c *Client) RotateSessionKey()
- func (c *Client) SearchLocal(ctx context.Context, query []float64, index *lsh.Index, ...) ([]Result, error)
- func (c *Client) SetLSHPlanes(planes []float64, numPlanes, dimension int) error
- func (c *Client) TopKResults(ids []string, scores []float64, k int) []Result
- func (c *Client) TwoStageSearchLocal(ctx context.Context, query []float64, index *lsh.Index, ...) ([]Result, error)
- type Config
- type DummyQueryRunner
- type EnterpriseHierarchicalClient
- func NewEnterpriseHierarchicalClient(cfg hierarchical.Config, credentials *auth.ClientCredentials, store blob.Store) (*EnterpriseHierarchicalClient, error)
- func NewEnterpriseHierarchicalClientWithPoolSize(cfg hierarchical.Config, credentials *auth.ClientCredentials, store blob.Store, ...) (*EnterpriseHierarchicalClient, error)
- func (c *EnterpriseHierarchicalClient) GetCredentials() *auth.ClientCredentials
- func (c *EnterpriseHierarchicalClient) GetEnterpriseID() string
- func (c *EnterpriseHierarchicalClient) IsTokenExpired() bool
- func (c *EnterpriseHierarchicalClient) Search(ctx context.Context, query []float64, topK int) (*hierarchical.SearchResult, error)
- func (c *EnterpriseHierarchicalClient) SearchBatch(ctx context.Context, query []float64, topK int) (*hierarchical.SearchResult, error)
- func (c *EnterpriseHierarchicalClient) TimeUntilTokenExpiry() time.Duration
- func (c *EnterpriseHierarchicalClient) UpdateCredentials(creds *auth.ClientCredentials) error
- type HierarchicalClient
- type HybridClient
- func (c *HybridClient) Close() error
- func (c *HybridClient) DecryptScoreHE(encScore *rlwe.Ciphertext) (float64, error)
- func (c *HybridClient) EncryptQueryHE(query []float64) (*rlwe.Ciphertext, error)
- func (c *HybridClient) GetHEPublicKey() ([]byte, error)
- func (c *HybridClient) GetStats(ctx context.Context) (*blob.StoreStats, error)
- func (c *HybridClient) Insert(ctx context.Context, id string, vector []float64, metadata map[string]any) error
- func (c *HybridClient) InsertBatch(ctx context.Context, ids []string, vectors [][]float64, ...) error
- func (c *HybridClient) Search(ctx context.Context, query []float64, topK int) (*HybridSearchResult, error)
- func (c *HybridClient) SearchFast(ctx context.Context, query []float64, topK int) (*HybridSearchResult, error)
- func (c *HybridClient) SearchPrivate(ctx context.Context, query []float64, topK int) (*HybridSearchResult, error)
- type HybridConfig
- type HybridSearchResult
- type LoginCredentials
- type PrivacyConfig
- type PrivacyMetrics
- type RemoteClient
- type RemoteClientConfig
- type Result
- type SearchOptions
- type Tier2Client
- func (c *Tier2Client) Close() error
- func (c *Tier2Client) Delete(ctx context.Context, id string) error
- func (c *Tier2Client) DeleteBatch(ctx context.Context, ids []string) error
- func (c *Tier2Client) GetKeyFingerprint() string
- func (c *Tier2Client) GetLSHPlanes() [][]float64
- func (c *Tier2Client) GetPrivacyMetrics() *PrivacyMetrics
- func (c *Tier2Client) GetStats(ctx context.Context) (*blob.StoreStats, error)
- func (c *Tier2Client) Insert(ctx context.Context, id string, vector []float64, metadata map[string]any) error
- func (c *Tier2Client) InsertBatch(ctx context.Context, ids []string, vectors [][]float64, ...) error
- func (c *Tier2Client) Search(ctx context.Context, query []float64, topK int) ([]Result, error)
- func (c *Tier2Client) SearchWithOptions(ctx context.Context, query []float64, opts SearchOptions) ([]Result, error)
- func (c *Tier2Client) SearchWithPrivacy(ctx context.Context, query []float64, topK int) ([]Result, error)
- func (c *Tier2Client) SetPrivacyConfig(cfg PrivacyConfig)
- func (c *Tier2Client) StartDummyQueries()
- func (c *Tier2Client) StopDummyQueries()
- type Tier2Config
- type TimingObfuscator
Constants ¶
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 (*Client) ComputeLSHHash ¶
ComputeLSHHash computes the LSH hash for a query vector.
func (*Client) ComputeMaskedLSHHash ¶
ComputeMaskedLSHHash computes the LSH hash with session key masking. The masked hash hides the exact bucket from the server.
func (*Client) DecryptScores ¶
DecryptScores decrypts a list of encrypted scores.
func (*Client) DecryptScoresSequential ¶
DecryptScoresSequential decrypts scores sequentially (for debugging).
func (*Client) EncryptAndComputeLocal ¶
EncryptAndComputeLocal tests the full homomorphic pipeline locally.
func (*Client) EncryptQuery ¶
EncryptQuery encrypts a query vector.
func (*Client) GetPublicKey ¶
GetPublicKey returns the serialized public key for registration.
func (*Client) GetSessionKey ¶
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 ¶
SetLSHPlanes sets the LSH hyperplanes from the server.
func (*Client) TopKResults ¶
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.
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.
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 ¶
func (c *EnterpriseHierarchicalClient) GetCredentials() *auth.ClientCredentials
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 ¶
func (c *EnterpriseHierarchicalClient) Search(ctx context.Context, query []float64, topK int) (*hierarchical.SearchResult, error)
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) 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 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) 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 ¶
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.