// Package privacy provides privacy-enhancing cryptographic features. package privacy import ( "bytes" "context" "encoding/json" "fmt" "io" "net/http" "sync/atomic" "time" ) const DefaultEndpoint = "https://privacy.synor.cc/api/v1" // Config is the privacy client configuration. type Config struct { APIKey string Endpoint string Timeout time.Duration Retries int Debug bool } // KeyType represents the type of cryptographic key. type KeyType string const ( KeyTypeEd25519 KeyType = "ed25519" KeyTypeSecp256k1 KeyType = "secp256k1" ) // GeneratorType represents the generator used for commitments. type GeneratorType string const ( GeneratorDefault GeneratorType = "default" GeneratorAlternate GeneratorType = "alternate" ) // PublicKey represents a public key. type PublicKey struct { Key string `json:"key"` Type KeyType `json:"type"` } // PrivateKey represents a private key. type PrivateKey struct { Key string `json:"key"` Type KeyType `json:"type"` } // ConfidentialUTXO is a UTXO for confidential transactions. type ConfidentialUTXO struct { TxID string `json:"txid"` Vout int `json:"vout"` Commitment string `json:"commitment"` RangeProof string `json:"rangeProof"` Blinding string `json:"blinding,omitempty"` Amount string `json:"amount,omitempty"` } // ConfidentialOutput is an output for confidential transactions. type ConfidentialOutput struct { Recipient string `json:"recipient"` Amount string `json:"amount"` Blinding string `json:"blinding,omitempty"` } // OutputFeatures contains output feature flags. type OutputFeatures struct { Flags int `json:"flags"` LockHeight int `json:"lockHeight,omitempty"` } // ConfidentialTxInput is a confidential transaction input. type ConfidentialTxInput struct { OutputRef string `json:"outputRef"` Commitment string `json:"commitment"` } // ConfidentialTxOutput is a confidential transaction output. type ConfidentialTxOutput struct { Commitment string `json:"commitment"` RangeProof string `json:"rangeProof"` Features OutputFeatures `json:"features"` } // TransactionKernel is the kernel for confidential transactions. type TransactionKernel struct { Features int `json:"features"` Fee string `json:"fee"` LockHeight int `json:"lockHeight"` Excess string `json:"excess"` ExcessSignature string `json:"excessSignature"` } // ConfidentialTransaction is a confidential transaction. type ConfidentialTransaction struct { TxID string `json:"txid"` Version int `json:"version"` Inputs []ConfidentialTxInput `json:"inputs"` Outputs []ConfidentialTxOutput `json:"outputs"` Kernel TransactionKernel `json:"kernel"` Offset string `json:"offset"` Raw string `json:"raw"` } // VerifyConfidentialTxDetails contains verification details. type VerifyConfidentialTxDetails struct { CommitmentsBalance bool `json:"commitmentsBalance"` RangeProofsValid bool `json:"rangeProofsValid"` SignatureValid bool `json:"signatureValid"` NoDuplicateInputs bool `json:"noDuplicateInputs"` } // VerifyConfidentialTxResult is the result of verifying a confidential transaction. type VerifyConfidentialTxResult struct { Valid bool `json:"valid"` Details VerifyConfidentialTxDetails `json:"details"` Error string `json:"error,omitempty"` } // RingSignatureComponents contains the signature components. type RingSignatureComponents struct { C []string `json:"c"` R []string `json:"r"` } // RingSignature is a ring signature. type RingSignature struct { ID string `json:"id"` MessageHash string `json:"messageHash"` Ring []string `json:"ring"` KeyImage string `json:"keyImage"` Signature RingSignatureComponents `json:"signature"` RingSize int `json:"ringSize"` } // VerifyRingSignatureResult is the result of verifying a ring signature. type VerifyRingSignatureResult struct { Valid bool `json:"valid"` KeyImage string `json:"keyImage"` } // StealthAddress is a stealth address. type StealthAddress struct { Address string `json:"address"` ScanPublicKey string `json:"scanPublicKey"` SpendPublicKey string `json:"spendPublicKey"` } // StealthKeypair is a stealth address keypair. type StealthKeypair struct { Address StealthAddress `json:"address"` ScanPrivateKey string `json:"scanPrivateKey"` SpendPrivateKey string `json:"spendPrivateKey"` } // OneTimeAddress is a one-time address derived from a stealth address. type OneTimeAddress struct { Address string `json:"address"` EphemeralPublicKey string `json:"ephemeralPublicKey"` SharedSecret string `json:"sharedSecret,omitempty"` } // SharedSecret is the result of deriving a shared secret. type SharedSecret struct { Secret string `json:"secret"` OneTimePrivateKey string `json:"oneTimePrivateKey"` OneTimeAddress string `json:"oneTimeAddress"` } // Commitment is a Pedersen commitment. type Commitment struct { Commitment string `json:"commitment"` Generator GeneratorType `json:"generator"` } // CommitmentWithBlinding is a commitment with its blinding factor. type CommitmentWithBlinding struct { Commitment Commitment `json:"commitment"` Blinding string `json:"blinding"` } // RangeProof is a Bulletproof range proof. type RangeProof struct { Proof string `json:"proof"` Commitment string `json:"commitment"` BitLength int `json:"bitLength"` } // VerifyRangeProofResult is the result of verifying a range proof. type VerifyRangeProofResult struct { Valid bool `json:"valid"` MinValue string `json:"minValue"` MaxValue string `json:"maxValue"` } // Error is a privacy error. type Error struct { Message string Code string StatusCode int } func (e *Error) Error() string { return e.Message } // Client is a Synor Privacy client. type Client struct { config Config httpClient *http.Client closed atomic.Bool } // NewClient creates a new privacy client. func NewClient(config Config) *Client { if config.Endpoint == "" { config.Endpoint = DefaultEndpoint } if config.Timeout == 0 { config.Timeout = 30 * time.Second } if config.Retries == 0 { config.Retries = 3 } return &Client{ config: config, httpClient: &http.Client{ Timeout: config.Timeout, }, } } // ==================== Confidential Transactions ==================== // CreateConfidentialTxOptions are options for creating a confidential transaction. type CreateConfidentialTxOptions struct { Inputs []ConfidentialUTXO Outputs []ConfidentialOutput Fee string LockHeight int } // CreateConfidentialTransaction creates a confidential transaction. func (c *Client) CreateConfidentialTransaction(ctx context.Context, opts CreateConfidentialTxOptions) (*ConfidentialTransaction, error) { body := map[string]interface{}{ "inputs": opts.Inputs, "outputs": opts.Outputs, } if opts.Fee != "" { body["fee"] = opts.Fee } if opts.LockHeight > 0 { body["lockHeight"] = opts.LockHeight } var resp struct { Transaction ConfidentialTransaction `json:"transaction"` } if err := c.request(ctx, "POST", "/transactions/confidential", body, &resp); err != nil { return nil, err } return &resp.Transaction, nil } // VerifyConfidentialTransaction verifies a confidential transaction. func (c *Client) VerifyConfidentialTransaction(ctx context.Context, tx *ConfidentialTransaction) (*VerifyConfidentialTxResult, error) { body := map[string]interface{}{ "transaction": tx.Raw, } var result VerifyConfidentialTxResult if err := c.request(ctx, "POST", "/transactions/confidential/verify", body, &result); err != nil { return nil, err } return &result, nil } // DecodeConfidentialOutput decodes a confidential output. func (c *Client) DecodeConfidentialOutput(ctx context.Context, commitment, blinding string) (string, error) { body := map[string]interface{}{ "commitment": commitment, "blinding": blinding, } var resp struct { Amount string `json:"amount"` } if err := c.request(ctx, "POST", "/transactions/confidential/decode", body, &resp); err != nil { return "", err } return resp.Amount, nil } // ==================== Ring Signatures ==================== // CreateRingSignatureOptions are options for creating a ring signature. type CreateRingSignatureOptions struct { Message string Ring []string PrivateKey string SignerIndex *int } // CreateRingSignature creates a ring signature. func (c *Client) CreateRingSignature(ctx context.Context, opts CreateRingSignatureOptions) (*RingSignature, error) { body := map[string]interface{}{ "message": opts.Message, "ring": opts.Ring, "privateKey": opts.PrivateKey, } if opts.SignerIndex != nil { body["signerIndex"] = *opts.SignerIndex } var resp struct { Signature RingSignature `json:"signature"` } if err := c.request(ctx, "POST", "/ring-signatures/create", body, &resp); err != nil { return nil, err } return &resp.Signature, nil } // VerifyRingSignature verifies a ring signature. func (c *Client) VerifyRingSignature(ctx context.Context, signature *RingSignature, message string) (*VerifyRingSignatureResult, error) { body := map[string]interface{}{ "signature": signature, "message": message, } var result VerifyRingSignatureResult if err := c.request(ctx, "POST", "/ring-signatures/verify", body, &result); err != nil { return nil, err } return &result, nil } // IsKeyImageUsed checks if a key image has been used. func (c *Client) IsKeyImageUsed(ctx context.Context, keyImage string) (bool, error) { var resp struct { Used bool `json:"used"` } if err := c.request(ctx, "GET", fmt.Sprintf("/ring-signatures/key-images/%s", keyImage), nil, &resp); err != nil { return false, err } return resp.Used, nil } // GenerateRandomRing generates a random ring of public keys. func (c *Client) GenerateRandomRing(ctx context.Context, size int, exclude []string) ([]string, error) { body := map[string]interface{}{ "size": size, } if len(exclude) > 0 { body["exclude"] = exclude } var resp struct { Ring []string `json:"ring"` } if err := c.request(ctx, "POST", "/ring-signatures/random-ring", body, &resp); err != nil { return nil, err } return resp.Ring, nil } // ==================== Stealth Addresses ==================== // GenerateStealthKeypair generates a new stealth address keypair. func (c *Client) GenerateStealthKeypair(ctx context.Context) (*StealthKeypair, error) { var resp struct { Keypair StealthKeypair `json:"keypair"` } if err := c.request(ctx, "POST", "/stealth/generate", nil, &resp); err != nil { return nil, err } return &resp.Keypair, nil } // CreateOneTimeAddress creates a one-time address for a stealth address. func (c *Client) CreateOneTimeAddress(ctx context.Context, stealthAddress *StealthAddress) (*OneTimeAddress, error) { body := map[string]interface{}{ "scanPublicKey": stealthAddress.ScanPublicKey, "spendPublicKey": stealthAddress.SpendPublicKey, } var resp struct { OneTimeAddress OneTimeAddress `json:"oneTimeAddress"` } if err := c.request(ctx, "POST", "/stealth/one-time-address", body, &resp); err != nil { return nil, err } return &resp.OneTimeAddress, nil } // DeriveSharedSecret derives the shared secret for a stealth payment. func (c *Client) DeriveSharedSecret(ctx context.Context, stealthAddress *StealthAddress, privateKey, ephemeralPublicKey string) (*SharedSecret, error) { body := map[string]interface{}{ "scanPublicKey": stealthAddress.ScanPublicKey, "spendPublicKey": stealthAddress.SpendPublicKey, "privateKey": privateKey, "ephemeralPublicKey": ephemeralPublicKey, } var secret SharedSecret if err := c.request(ctx, "POST", "/stealth/derive-secret", body, &secret); err != nil { return nil, err } return &secret, nil } // ScanForPayments scans transactions for stealth payments. func (c *Client) ScanForPayments(ctx context.Context, scanPrivateKey, spendPublicKey string, transactions []string) ([]OneTimeAddress, error) { body := map[string]interface{}{ "scanPrivateKey": scanPrivateKey, "spendPublicKey": spendPublicKey, "transactions": transactions, } var resp struct { Payments []OneTimeAddress `json:"payments"` } if err := c.request(ctx, "POST", "/stealth/scan", body, &resp); err != nil { return nil, err } return resp.Payments, nil } // ==================== Commitments ==================== // CreateCommitment creates a Pedersen commitment. func (c *Client) CreateCommitment(ctx context.Context, value string, blinding string) (*CommitmentWithBlinding, error) { body := map[string]interface{}{ "value": value, } if blinding != "" { body["blinding"] = blinding } var result CommitmentWithBlinding if err := c.request(ctx, "POST", "/commitments/create", body, &result); err != nil { return nil, err } return &result, nil } // OpenCommitment verifies a Pedersen commitment. func (c *Client) OpenCommitment(ctx context.Context, commitment, value, blinding string) (bool, error) { body := map[string]interface{}{ "commitment": commitment, "value": value, "blinding": blinding, } var resp struct { Valid bool `json:"valid"` } if err := c.request(ctx, "POST", "/commitments/open", body, &resp); err != nil { return false, err } return resp.Valid, nil } // AddCommitments adds two commitments. func (c *Client) AddCommitments(ctx context.Context, commitment1, commitment2 string) (string, error) { body := map[string]interface{}{ "commitment1": commitment1, "commitment2": commitment2, } var resp struct { Commitment string `json:"commitment"` } if err := c.request(ctx, "POST", "/commitments/add", body, &resp); err != nil { return "", err } return resp.Commitment, nil } // SubtractCommitments subtracts two commitments. func (c *Client) SubtractCommitments(ctx context.Context, commitment1, commitment2 string) (string, error) { body := map[string]interface{}{ "commitment1": commitment1, "commitment2": commitment2, } var resp struct { Commitment string `json:"commitment"` } if err := c.request(ctx, "POST", "/commitments/subtract", body, &resp); err != nil { return "", err } return resp.Commitment, nil } // ComputeBlindingSum computes the sum of blinding factors. func (c *Client) ComputeBlindingSum(ctx context.Context, positive, negative []string) (string, error) { body := map[string]interface{}{ "positive": positive, "negative": negative, } var resp struct { Sum string `json:"sum"` } if err := c.request(ctx, "POST", "/commitments/blinding-sum", body, &resp); err != nil { return "", err } return resp.Sum, nil } // GenerateBlinding generates a random blinding factor. func (c *Client) GenerateBlinding(ctx context.Context) (string, error) { var resp struct { Blinding string `json:"blinding"` } if err := c.request(ctx, "POST", "/commitments/random-blinding", nil, &resp); err != nil { return "", err } return resp.Blinding, nil } // ==================== Range Proofs ==================== // CreateRangeProofOptions are options for creating a range proof. type CreateRangeProofOptions struct { Value string Blinding string Message string BitLength int } // CreateRangeProof creates a Bulletproof range proof. func (c *Client) CreateRangeProof(ctx context.Context, opts CreateRangeProofOptions) (*RangeProof, error) { body := map[string]interface{}{ "value": opts.Value, "blinding": opts.Blinding, } if opts.Message != "" { body["message"] = opts.Message } if opts.BitLength > 0 { body["bitLength"] = opts.BitLength } else { body["bitLength"] = 64 } var resp struct { Proof RangeProof `json:"proof"` } if err := c.request(ctx, "POST", "/range-proofs/create", body, &resp); err != nil { return nil, err } return &resp.Proof, nil } // VerifyRangeProof verifies a Bulletproof range proof. func (c *Client) VerifyRangeProof(ctx context.Context, commitment, proof string) (*VerifyRangeProofResult, error) { body := map[string]interface{}{ "commitment": commitment, "proof": proof, } var result VerifyRangeProofResult if err := c.request(ctx, "POST", "/range-proofs/verify", body, &result); err != nil { return nil, err } return &result, nil } // CreateAggregatedRangeProof creates an aggregated range proof. func (c *Client) CreateAggregatedRangeProof(ctx context.Context, outputs []map[string]string) (string, error) { body := map[string]interface{}{ "outputs": outputs, } var resp struct { Proof string `json:"proof"` } if err := c.request(ctx, "POST", "/range-proofs/aggregate", body, &resp); err != nil { return "", err } return resp.Proof, nil } // ==================== Lifecycle ==================== // HealthCheck checks if the service is healthy. func (c *Client) HealthCheck(ctx context.Context) bool { var resp struct { Status string `json:"status"` } if err := c.request(ctx, "GET", "/health", nil, &resp); err != nil { return false } return resp.Status == "healthy" } // Close closes the client. func (c *Client) Close() { c.closed.Store(true) } // IsClosed returns whether the client is closed. func (c *Client) IsClosed() bool { return c.closed.Load() } // ==================== Private ==================== func (c *Client) request(ctx context.Context, method, path string, body interface{}, result interface{}) error { if c.closed.Load() { return &Error{Message: "client has been closed"} } var lastErr error for attempt := 0; attempt < c.config.Retries; attempt++ { err := c.doRequest(ctx, method, path, body, result) if err == nil { return nil } lastErr = err if attempt < c.config.Retries-1 { time.Sleep(time.Duration(1<= 400 { var errResp struct { Message string `json:"message"` Error string `json:"error"` Code string `json:"code"` } json.Unmarshal(respBody, &errResp) msg := errResp.Message if msg == "" { msg = errResp.Error } if msg == "" { msg = fmt.Sprintf("HTTP %d", resp.StatusCode) } return &Error{ Message: msg, Code: errResp.Code, StatusCode: resp.StatusCode, } } if result != nil { if err := json.Unmarshal(respBody, result); err != nil { return &Error{Message: fmt.Sprintf("failed to parse response: %v", err)} } } return nil }