The following example is a simple way to mix coins without the need for a complex coinjoin coordination. Of course it has its limits but is extremely easy to impliment.
The basic idea is to emulate lightning channel opening and closing. A channel open is creating a 2-of-2 multisig address. So you could use existing simple techniques for key derivation to create such an address.
By doing so, when Alice create an address with this scheme, and receives coins from Bob, a casual observer will not know if Bob is paying Alice, or Bob is opening a lightning channel with Carol.
When Alice spends from this address, it is not known if Alice is spending x coins and y change or is Bob closing a channel with x to him and y to Carol
Derive 2 public keys from an extended public or private key, one at
[xpub]/0/n
and and [xpub]/2/n
, reserving as is convention [xpub]/1/n
for your change addresses
const bitcoin = require("bitcoinjs-lib");
const bip32 = require("bip32");
const assert = require("assert");
const TESTNET = bitcoin.networks.testnet;
const xpub =
"tpubDDuXvjq5jan28BS18ex3hmHwm6MtdtAqP55iXDxeLKpMoW1yMxPQAq1QyNsAihZHZq3Bpie962os125g2qsQ5tEsyUF3Q1kTJcXPbWe7WpN";
const root = bip32.fromBase58(xpub, TESTNET);
const child1 = root.derivePath("m/0/1");
const child2 = root.derivePath("m/2/1");
const pubkeys = [child1.publicKey, child2.publicKey];
const { address } = bitcoin.payments.p2wsh({
redeem: bitcoin.payments.p2ms({ m: 2, pubkeys, network: TESTNET }),
network: TESTNET
});
assert.strictEqual(
address,
"tb1qgjsscqk36m6rqc58u0n5sfak89a7jk2kxx22s02f7chslxn7z0gspeupac"
);
Now Alice can preset tb1qwtfch5z7ru4gkgrfem8u33mwskz8yf5u5mwetmemrrmr27ytnxsqxwhu7p
to Bob for
payment.