Skip to content

shakesco/shakesco-private

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

29 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

@shakesco/private

JavaScript SDK for building privacy-preserving Ethereum transfers using stealth addresses.

Special credit to Umbra Cash for pioneering stealth payment infrastructure.

What It Does

The @shakesco/private SDK lets you implement truly private crypto transactions. No one except the sender and receiver can link the payment to the recipient's known address.

Learn more:

Installation

npm i @shakesco/private

Quick Start

const shakesco = require("@shakesco/private");
const { KeyPair, RandomNumber, StealthKeyRegistry, utils } = shakesco;
const { IsUsersFunds, generateKeyPair, prepareSend } = shakesco;

Security Note: This implementation assumes a single private key secures your wallet and that you're signing the same message hash.

Basic Workflow

1. Check if User Has Stealth Keys

const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
const registry = new StealthKeyRegistry(provider);

const { spendingPublicKey, viewingPublicKey } =
  await registry.getStealthKeys(recipientId);

if (!spendingPublicKey) {
  console.log("User needs to register stealth keys first");
}

2. Register Stealth Keys

For Smart Wallets (ERC-4337):

const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
const signer = new ethers.Wallet(process.env.PRIV_KEY, provider);
const signature = await signer.signMessage(messageHash);

const { spendingKeyPair, viewingKeyPair } = await generateKeyPair(signature);
const registry = new StealthKeyRegistry(provider);

const { spendingPrefix, spendingPubKeyX, viewingPrefix, viewingPubKeyX } =
  await registry.setSmartStealthKeys(
    spendingKeyPair.publicKeyHex,
    viewingKeyPair.publicKeyHex
  );

// Use these values to call the registry contract via your smart wallet

For EOAs (Regular Wallets):

const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
const { spendingKeyPair, viewingKeyPair } = await generateKeyPair(setupSig);
const registry = new StealthKeyRegistry(provider);

const { spendingPrefix, spendingPubKeyX, viewingPrefix, viewingPubKeyX } =
  await registry.SetEOAStealthKeys(
    spendingKeyPair.publicKeyHex,
    viewingKeyPair.publicKeyHex
  );

3. Generate Stealth Address

const payee = "0x..."; // Recipient's address
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);

const { stealthKeyPair, pubKeyXCoordinate, encrypted } = await prepareSend(
  payee,
  provider
);

console.log(stealthKeyPair.address); // Send funds HERE
console.log(pubKeyXCoordinate); // Share with recipient
console.log(encrypted.ciphertext); // Share with recipient

Important: You must share pubKeyXCoordinate and encrypted.ciphertext with the recipient so they can prove ownership and spend the funds.

4. Announce the Payment

Emit this event from your contract so recipients can discover their payments:

event Announcement(
  address indexed receiver,
  uint256 amount,
  address indexed tokenAddress,
  bytes32 pkx,
  bytes32 ciphertext
);

Use indexing services like The Graph or Moralis to help recipients scan for announcements efficiently.

5. Check if Funds Belong to User

IsUsersFunds(announcement, provider, viewingPrivateKey, sender).then((data) => {
  if (data.isForUser) {
    console.log("Amount:", data.amount);
    console.log("Token:", data.tokenAddress);
    console.log("Stealth address:", data.stealthAddress);
  }
});

6. Spend Private Funds

const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
const signer = new ethers.Wallet(process.env.PRIV_KEY, provider);
const signature = await signer.signMessage(messageHash);

const { spendingKeyPair, viewingKeyPair } = await generateKeyPair(signature);

const payload = {
  ephemeralPublicKey: uncompressedPubKey,
  ciphertext: ciphertext,
};

const random = await viewingKeyPair.decrypt(payload);

const stealthPrivateKey = KeyPair.computeStealthPrivateKey(
  spendingKeyPair.privateKeyHex,
  random
);

const wallet = new ethers.Wallet(stealthPrivateKey, provider);
const txResponse = await wallet.sendTransaction({
  value: ethers.parseEther(value),
  to: destinationAddress,
});

await txResponse.wait();
console.log("Private funds successfully transferred!");

Documentation

For complete integration guides and examples, visit: docs.shakesco.com/stealth-payments

About Stealth Addresses

What are spending and viewing keys?

  • Spending Keys - Used to generate stealth addresses and spend from them
  • Viewing Keys - Allow scanning for incoming transactions without spending ability

This separation means you can monitor for payments without risking your funds.

Note: Storing viewingKeyPair.privateKeyHex for users is acceptable - it only enables transaction scanning, not spending.

Resources

Future

While stealth addresses provide strong privacy today, zero-knowledge proofs will eventually offer even better solutions. Until then, stealth payments are the best way to bring privacy to Ethereum transactions.

We aim to help expand the adoption of stealth payments and make Ethereum more private!

Packages

 
 
 

Contributors