Complete API reference for all privacy-related functions in @syncro/sdk.
- Stealth Addresses
- Metadata Encryption
- Pedersen Commitments
- Key Derivation
- Payment Commitments
- Types & Interfaces
Generate a new stealth meta-address (viewing and spending keys).
import { generateStealthMetaAddress } from '@syncro/sdk';
const meta = generateStealthMetaAddress();
// {
// viewPublicKey: "02a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5",
// spendPublicKey: "03f6e5d4c3b2a1f6e5d4c3b2a1f6e5d4c3b2a1f6e5d4c3b2a1f6e5d4c3b2a1",
// encoded: "syncro:stealth:v1:02a1b2c3...:03f6e5d4..."
// }Returns:
interface StealthMetaAddress {
viewPublicKey: string; // Compressed secp256k1 point (hex, 66 chars)
spendPublicKey: string; // Compressed secp256k1 point (hex, 66 chars)
encoded: string; // Versioned encoding for sharing
}Use case: Generate once per user identity, share encoded format publicly
Security:
- Private keys generated using
crypto.getRandomValues() - Each key pair is unique
- Suitable for long-term stealth address
Generate one-time stealth address from a meta-address using ECDH.
import { deriveEphemeralStealthAddress } from '@syncro/sdk';
const result = deriveEphemeralStealthAddress(
{
viewPublicKey: meta.viewPublicKey,
spendPublicKey: meta.spendPublicKey
},
`subscription-${subscriptionId}:payment-${index}`
);
// {
// ephemeralPubkey: "02r1r2r3r4...", // Publish in transaction memo
// stealthAddress: "02s1s2s3s4..." // Send payment here
// }Parameters:
metaAddress(object): Must haveviewPublicKeyandspendPublicKeyentropy(string): Unique per payment (e.g.,${subscriptionId}:${index})
Returns:
interface EphemeralStealthResult {
ephemeralPubkey: string; // Compressed secp256k1 point (hex, 66 chars)
stealthAddress: string; // Compressed secp256k1 point (hex, 66 chars)
}Use case: Generate unique address per payment without revealing payment history
Security:
- Deterministic given same entropy (reproducible)
- Different entropy produces completely different addresses
- ephemeralPubkey must be published in transaction memo for recipient discovery
Throws:
Errorif entropy produces scalar zero (probability: ~2^-256, negligible)
Derive deterministic stealth address for a specific subscription cycle.
import { deriveStealthAddress } from '@syncro/sdk';
const address = deriveStealthAddress(
meta,
'netflix-sub-2024-unique-id',
0 // First payment
);
// Returns: "02d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9"Parameters:
metaAddress(StealthMetaAddress): Viewing and spending keyssubscriptionId(string): Unique subscription identifierindex(number): Payment number (0 = first, 1 = second, etc.)
Returns:
string: One-time stealth address (hex-encoded Ristretto point)
Use case: Derive deterministic addresses for recurring payments
Security:
- Same subscriptionId + index = same address (reproducible)
- Different index = different address (unlinkable)
Encrypt subscription metadata (name, price, cycle, provider).
import { encryptSubscriptionMetadata } from '@syncro/sdk';
const encrypted = await encryptSubscriptionMetadata(
'aabbccddeeff00112233445566778899aabbccddeeff00112233445566778899', // 64-char hex key
{
name: 'Netflix',
price: 15.99,
cycle: 'monthly',
provider: 'netflix.com'
}
);
// {
// iv: "a1b2c3d4e5f6a1b2c3d4e5f6",
// authTag: "f1e2d3c4b5a6f1e2d3c4b5a6",
// ciphertext: "7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d..."
// }Parameters:
key(string): 64-character hex string (32 bytes). Must be exactly 64 chars.metadata(SubscriptionMetadata): Must containname,price,cycle,provider
Returns:
interface EncryptedData {
iv: string; // Hex-encoded initialization vector (24 hex chars = 12 bytes)
authTag: string; // Hex-encoded authentication tag (32 hex chars = 16 bytes)
ciphertext: string; // Hex-encoded encrypted data
}Use case: Store subscription details encrypted on server
Security:
- Generates random 12-byte IV each time
- AES-256-GCM authenticated encryption
- Different IV each call (same key safe to reuse)
- Authentication tag detects tampering
Throws:
Errorif metadata doesn't match schemaErrorif key is not 64 hex characters
Decrypt subscription metadata.
import { decryptSubscriptionMetadata } from '@syncro/sdk';
const metadata = await decryptSubscriptionMetadata(
'aabbccddeeff00112233445566778899aabbccddeeff00112233445566778899',
encrypted
);
// {
// name: "Netflix",
// price: 15.99,
// cycle: "monthly",
// provider: "netflix.com"
// }Parameters:
key(string): Same key used for encryptionencrypted(EncryptedData): FromencryptSubscriptionMetadata()
Returns:
Promise<SubscriptionMetadata>: Decrypted metadata
Use case: Retrieve encrypted subscription details
Security:
- Verifies authentication tag (detects tampering)
- Fails if key is wrong
- Fails if data corrupted
Throws:
Errorif key is wrongErrorif authentication tag verification failsErrorif decrypted data is not valid JSONErrorif JSON doesn't match SubscriptionMetadata schema
Low-level encrypt/decrypt for any string data.
import { encryptMetadata, decryptMetadata } from '@syncro/sdk';
// Encrypt any string
const encrypted = await encryptMetadata(
'my secret note about this subscription',
keyHex
);
// Decrypt
const plaintext = await decryptMetadata(encrypted, keyHex);Use case: Encrypt arbitrary string data (not just subscriptions)
Create a commitment to a value (amount).
import { commit } from '@syncro/sdk';
// With auto-generated random blinding factor
const commitment1 = commit(1500n); // $15.00
// {
// commitment: "4a8f2e1d9c...", // Ristretto point (hex)
// blindingFactor: "9e3f1a2b7c..." // Scalar (hex)
// }
// With specified blinding factor
const blindingFactor = 12345678901234567890n;
const commitment2 = commit(1500n, blindingFactor);Parameters:
value(bigint): Amount to commit (must be >= 0)blindingFactor(bigint, optional): If omitted, generates random
Returns:
interface PedersenCommitment {
commitment: string; // Hex-encoded Ristretto point
blindingFactor: string; // Hex-encoded blinding factor scalar
}Use case: Hide payment amount while proving you know it
Security:
- Mathematically binding: Can't prove different amount
- Computationally hiding: Commitment reveals nothing about amount
- Homomorphic: Commitments are additive
Note: For payment amounts in cents, use commit(BigInt(price * 100))
Verify a commitment matches a value.
import { verify } from '@syncro/sdk';
const isValid = verify(1500n, blindingFactor, commitment);
if (isValid) {
console.log('Payment amount verified!');
} else {
console.log('Amount does not match commitment');
}Parameters:
value(bigint): Claimed amountblindingFactor(string): Original blinding factor (hex)commitment(string): Original commitment (hex)
Returns:
boolean: true if valid, false otherwise
Use case: Verify commitment without revealing blinding factor
Security:
- Detects if amount or blinding factor was changed
- Blinding factor should not be revealed except when verifying
Create commitment to an event (subscription, payment, etc).
import { createEventCommitment } from '@syncro/sdk';
const commitment = createEventCommitment(
'subscription_payment',
'{"amount": 1500, "subscription": "netflix", "date": "2024-01-01"}'
);
// {
// commitment: "4a8f2e1d9c...",
// blindingFactor: "9e3f1a2b7c..."
// }Use case: Create commitment to specific event for later proof
Verify an event commitment.
import { verifyEventCommitment } from '@syncro/sdk';
const isValid = verifyEventCommitment(
'subscription_payment',
'{"amount": 1500, "subscription": "netflix", "date": "2024-01-01"}',
commitment
);Derive deterministic encryption key from password and subscription ID.
import { deriveSubscriptionEncryptionKey } from '@syncro/sdk';
const key = await deriveSubscriptionEncryptionKey(
'my-secure-password',
'netflix-subscription-id'
);
// Returns: 32-byte encryption key (hex string)
// Same password + subscription = same key (deterministic)Parameters:
password(string): User password (any length)subscriptionId(string): Subscription identifier
Returns:
Promise<string>: 64-character hex string (32 bytes)
Use case: Derive keys from user password without storing them
Security:
- Uses PBKDF2 with 100,000 iterations
- Brute-force resistant: ~50ms per attempt
- Deterministic: Same inputs = same key
- Unique per subscription: Different subscription = different key
Throws:
Errorif password or subscriptionId is empty
Create commitment to a payment with range proof.
import { createPaymentCommitment } from '@syncro/sdk';
const commitment = await createPaymentCommitment(
1500, // Amount in cents
'USD' // Currency
);
// {
// commitment: "...", // Pedersen commitment
// rangeProof: "...", // Proof amount is in valid range
// blindingFactor: "...",
// metadata: {
// amount: 1500,
// currency: 'USD',
// createdAt: '2024-01-01T...'
// }
// }Returns:
interface PaymentCommitment {
commitment: string; // Pedersen commitment
rangeProof: string; // Bulletproof (amount in range)
blindingFactor: string; // Scalar
metadata: {
amount: number;
currency: string;
createdAt: string;
}
}Use case: Prove payment amount without revealing it, with range verification
Verify payment commitment.
import { verifyPaymentCommitment } from '@syncro/sdk';
const isValid = await verifyPaymentCommitment(
paymentCommitment.commitment,
1500,
paymentCommitment.blindingFactor
);interface SubscriptionMetadata {
name: string; // Service name (non-empty)
price: number; // Price in dollars (>= 0, finite)
cycle: 'weekly' | 'monthly' | 'quarterly' | 'yearly';
provider: string; // Service provider domain (non-empty)
}interface StealthMetaAddress {
viewPublicKey: string; // Compressed secp256k1 point (66 hex chars)
spendPublicKey: string; // Compressed secp256k1 point (66 hex chars)
encoded: string; // Versioned format: "syncro:stealth:v1:..."
}interface EphemeralStealthResult {
ephemeralPubkey: string; // Publish in transaction memo
stealthAddress: string; // Recipient address for payment
}interface EncryptedData {
iv: string; // Initialization vector (24 hex chars)
authTag: string; // Authentication tag (32 hex chars)
ciphertext: string; // Encrypted data (hex)
}interface PedersenCommitment {
commitment: string; // Commitment point (hex)
blindingFactor: string; // Secret blinding factor (hex)
}All functions throw descriptive errors:
try {
const result = await decryptSubscriptionMetadata(key, encrypted);
} catch (error) {
if (error instanceof Error) {
if (error.message.includes('Invalid subscription metadata schema')) {
// Corrupted or tampered data
} else if (error.message.includes('Decrypted data is not valid JSON')) {
// Decryption succeeded but result is not JSON
} else if (error.message.includes('auth tag')) {
// Tampering detected or wrong key
}
}
throw error;
}// Stealth Addresses
import {
generateStealthMetaAddress,
deriveEphemeralStealthAddress,
deriveStealthAddress,
StealthMetaAddress,
EphemeralStealthResult
} from '@syncro/sdk';
// Metadata Encryption
import {
encryptSubscriptionMetadata,
decryptSubscriptionMetadata,
encryptMetadata,
decryptMetadata,
SubscriptionMetadata,
EncryptedData
} from '@syncro/sdk';
// Pedersen Commitments
import {
commit,
verify,
createEventCommitment,
verifyEventCommitment,
PedersenCommitment
} from '@syncro/sdk';
// Key Derivation
import {
deriveSubscriptionEncryptionKey
} from '@syncro/sdk';
// Payment Commitments
import {
createPaymentCommitment,
verifyPaymentCommitment
} from '@syncro/sdk';| Operation | Time | Notes |
|---|---|---|
| Generate stealth meta-address | <1ms | secp256k1 key generation |
| Derive ephemeral address | <1ms | ECDH computation |
| Encrypt metadata | <1ms | AES-256-GCM |
| Decrypt metadata | <1ms | AES-256-GCM |
| Create commitment | <1ms | Ristretto point multiplication |
| Verify commitment | <1ms | Point addition |
| Derive key from password | ~50ms | PBKDF2 100k iterations |
See sdk/examples/ for complete working examples:
stealth-addresses/— One-time payment addressesmetadata-encryption/— Encrypt subscription detailspedersen-commitments/— Hide payment amountskey-derivation/— Derive keys from passwordscomplete-privacy-stack/— Combine all features
- ✅ Stealth Addresses (ECDH)
- ✅ Metadata Encryption (AES-256-GCM)
- ✅ Pedersen Commitments (Ristretto)
- ✅ Key Derivation (PBKDF2-SHA256)
- ✅ Payment Commitments (with range proofs)
- ⏳ Zero-Knowledge Proofs (General circuit support)
- ⏳ Payment Channels (Layer 2 off-chain)
- ⏳ Multi-signature Support (Threshold encryption)
- ⏳ Key Recovery Procedures
- Documentation: See guides in
sdk/docs/privacy/ - Issues: github.com/Calebux/SYNCRO/issues
- Security: security@syncro.app