# Secure Communication with User Keys

Canonical: https://docs.projectbabbage.com/docs/quickstarts/secure-communication-with-user-keys

Learn how to encrypt data securely between two users, protecting their privacy in BSV applications.

This guide is for developers wanting to *secure communications* between two BRC-100–compatible wallets (e.g., “Alice” and “Bob”) using the `encrypt` and `decrypt` methods defined by [BRC-2](https://github.com/bitcoin-sv/BRCs/blob/master/wallet/0002.md). These methods are exposed through the **WalletClient** interface in the BSV TypeScript SDK, letting your application handle data encryption and decryption with minimal overhead. We’ll also cover how to discover the correct public key (and thus confirm you’re truly encrypting for the right person) via the **IdentityClient**.

## Prerequisites

1. **A BSV Wallet**: Ensure the user is connected to a wallet implementing BRC-100—a standardized, vendor-neutral application-to-wallet interface within the BSV Blockchain ecosystem. If not, direct them over to the [Getting a Wallet](https://docs.projectbabbage.com/docs/quickstarts/getting-a-wallet) quickstart guide!
2. **WalletClient**: Your application code will interface with the wallet using this client to call `encrypt` and `decrypt`. Install `@bsv/sdk` and import it.
3. **Two User Setup**: In our example, *Alice* and *Bob* each have a BSV wallet/identity, which includes a **public identity key** for each.

## Understanding Encryption

When encrypting data (e.g., a message or file) using the wallet:
- Your app will specify:
  - The **plaintext** (as a byte array).
  - The **protocolID** and **keyID** (denoting the "context" in which the encryption is happening).
  - A **counterparty** (i.e., the recipient’s public key, or `'self'` if you’re just encrypting for yourself).
- Under the hood, the wallet calculates a **shared secret** between the user’s private key and the recipient’s public key.
- The data is encrypted using AES-256-GCM, with the resulting ciphertext returned to your application. Then you can send the encrypted version to them.

On the receiving side, the decrypt process reverses it:
- The wallet and your app supply the **ciphertext** plus the correct protocolID, keyID, and the recognized `counterparty` (which must be the sender’s public identity key).
- The wallet computes the same shared secret, then decrypts.

## Walkthrough: Alice Encrypting a Message for Bob

### Step 1: Acquire Bob’s Public Key
Before Alice can encrypt anything for Bob, she needs Bob’s identity key:
1. **Manual**: If Bob shares it directly, e.g., a hex-encoded public key string.
2. **IdentityClient**: Use an identity resolution call to fetch Bob’s public key *by a known handle or identity.*
   *This ensures we have confidence that `'bob@example.org'` truly maps to the public key we obtain.*
   In practice (in a React app) you could use the `IdentitySearchField` from `@bsv/identity-react` to [let Alice find Bob](https://github.com/bsv-blockchain/identity-react?tab=readme-ov-file#identity-search-field).

### Step 2: Call `walletClient.encrypt` with Bob’s Public Key
Alice’s application then does something like:
```ts
import { WalletClient } from '@bsv/sdk'
const walletClient = new WalletClient('auto'); // Connect to the BRC-100 wallet running on Alice's machine

const plaintextMsg = new TextEncoder().encode("Hi Bob, let's talk privately!");
const protocolID   = [2, 'private chat'];  // securityLevel=2, protocol name='private-chat'
const keyID        = 'session1';          // an arbitrary key ID

try {
  const { ciphertext } = await walletClient.encrypt({
    plaintext: [...plaintextMsg], // as an array of bytes
    protocolID,
    keyID,
    counterparty: bobsPubKeyHex   // Bob’s public key string
  });
  // Now you have ciphertext to send/store
} catch (err) {
  console.error("Encryption failed:", err);
}

// Bob will need to know Alice's public identity key. Let's get it for him.
const { publicKey } = await walletClient.getPublicKey({
  identityKey: true
})
```
- `protocolID` is `[ securityLevel, "protocolName" ]`, fulfilling BRC-43 semantics.  (Here, `2` indicates a “level-2” protocol that typically requires user permission for each new counterparty.)
- `keyID` is any unique string (e.g. `'session1'`) to differentiate the keys used for operations under the same protocol.

Alice can now pass the resulting ciphertext to Bob via any channel (websocket, stored on-chain, etc.). In practice, consider using the [Message Box Client](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/messaging/message-box-client) for P2P comms!

## Bob Decrypting Alice’s Message

Bob’s wallet likewise needs to handle the ciphertext:

```ts
const walletClient = new WalletClient('auto');

try {
  // Suppose you’ve received `ciphertext` bytes from Alice.
  const { plaintext } = await walletClient.decrypt({
    ciphertext,
    protocolID: [2, 'private chat'],
    keyID: 'session1',
    // Bob must name the 'counterparty' as Alice’s public key
    counterparty: alicesPubKeyIdentityKeyHex
  });

  // Convert plaintext bytes back to string
  const message = new TextDecoder().decode(new Uint8Array(plaintext));
  console.log("Alice said: ", message);
} catch (err) {
  console.error("Decryption failed:", err);
}
```

Matching the same `protocolID`, `keyID`, and specifying Alice’s public identity key as counterparty ensures Bob’s wallet uses the correct underlying keys to do the decryption.

## Identity Resolution / Public Key Discovery

As hinted above, you don’t want to just accept any string that calls itself “Bob’s public key.” [BRC-100 standard](https://brc.dev/100) wallets help facilitate using an **IdentityClient** or an analogous approach so you can do:
1. **Discover** a user’s public identity key by some kind of attributes, like a certified name, email, or social media handle trusted by the user.
2. **Support** the veracity of the returned key with certificates that link the user’s identity attributes to that key.

In many real apps, you might see something like:

```ts
import { IdentityClient } from '@bsv/sdk'

const fetchIdentities = async (query: string) => {
  let results
  const client = new IdentityClient()
  // Figure out if the query is by IdentityKey
  results = await client.resolveByAttributes({
    attributes: {
      any: query,
    }
  })
  return results
}
```

You’ll get the same BRC-2 encryption benefits, but with better confidence that the public key *genuinely belongs* to Bob. This avoids the risk of man-in-the-middle attacks where a malicious party tries to trick you into encrypting data for an incorrect key.

## Summary

- **Encryption**:
  1. Acquire the desired recipient’s public key.
  2. Use `walletClient.encrypt({plaintext, protocolID, keyID, counterparty})`.
  3. Share the resulting ciphertext with the recipient.

- **Decryption**:
  1. Retrieve the ciphertext.
  2. Call `walletClient.decrypt({ciphertext, protocolID, keyID, counterparty})`; the wallet verifies everything matches.
  3. Receive the resulting bytes as `plaintext`.

- **Identity**:
  - For *securely discovering* a user’s public key, rely on the [IdentityClient](https://bsv-blockchain.github.io/ts-sdk/reference/identity/#class-identityclient).

By weaving these steps together, you can create more private, user-friendly experiences in applications built on top of the BSV Blockchain. BRC-2 encryption helps keep messages secure, while standard methods for identity resolution (e.g., IdentityClient) ensure you’re using the right public key in the first place. Happy hacking!
