diff --git a/Bitmessage.uml b/Bitmessage.uml new file mode 100644 index 0000000..592faa7 --- /dev/null +++ b/Bitmessage.uml @@ -0,0 +1,92 @@ + + + JAVA + + + ch.dissem.bitmessage.entity.VerAck + ch.dissem.bitmessage.entity.Streamable + ch.dissem.bitmessage.ports.Inventory + ch.dissem.bitmessage.entity.Version + ch.dissem.bitmessage.entity.MessagePayload + ch.dissem.bitmessage.ports.NetworkMessageReceiver + ch.dissem.bitmessage.entity.NetworkMessage + ch.dissem.bitmessage.entity.Addr + ch.dissem.bitmessage.ports.NetworkMessageSender + ch.dissem.bitmessage.entity.valueobject.InventoryVector + ch.dissem.bitmessage.entity.ObjectPayload + ch.dissem.bitmessage.entity.valueobject.NetworkAddress + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Fields + Methods + Properties + + All + private + + diff --git a/docs/diagram.svg b/docs/diagram.svg new file mode 100644 index 0000000..5ef0521 --- /dev/null +++ b/docs/diagram.svg @@ -0,0 +1,5844 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + List<InventoryVector> + + + + + + getInventory(long...) + + + + + + List<InventoryVector> + + + + + + getMissing(List<InventoryVector>, long...) + + + + + + ObjectMessage + + + + + + getObject(InventoryVector) + + + + + + List<ObjectMessage> + + + + + + getObjects(long, long, ObjectType) + + + + + + void + + + + + + storeObject(ObjectMessage) + + + + + + void + + + + + + cleanup() + + + + + + + + + + Inventory + + + + + + + + + + + + + + + + + + + + + + + + + void + + + + + + write(OutputStream) + + + + + + + + + Command + + + + + + command + + + + + + List<NetworkAddress> + + + + + + addresses + + + + + + + + + + Addr + + + + + + + + + + + + + + + + + + + + + + InetAddress + + + + + toInetAddress() + + + + + + boolean + + + + + equals(Object) + + + + + + int + + + + + hashCode() + + + + + + String + + + + + toString() + + + + + + void + + + + + write(OutputStream) + + + + + + void + + + + + write(OutputStream, boolean) + + + + + + + + + long + + + + + + services + + + + + + int + + + + + + port + + + + + + long + + + + + + time + + + + + + long + + + + + + stream + + + + + + byte[] + + + + + + IPv6 + + + + + + + + + NetworkAddress + + + + + + + + + + + + + + + + + + + + + + + + + Command + + + + + + command + + + + + + + + + MessagePayload + + + + + + + + + + + + + + + + + + + + + + + + + int + + + + + + + + MAGIC + + + + + + byte[] + + + + + + + + MAGIC_BYTES + + + + + + + + + void + + + + + + write(OutputStream) + + + + + + + + + MessagePayload + + + + + + payload + + + + + + + + + + NetworkMessage + + + + + + + + + + + + + + + + + + + + + + + + + void + + + + + + write(OutputStream) + + + + + + + + + Command + + + + + + command + + + + + + long + + + + + + nonce + + + + + + long + + + + + + services + + + + + + String + + + + + + userAgent + + + + + + NetworkAddress + + + + + + addrFrom + + + + + + NetworkAddress + + + + + + addrRecv + + + + + + long[] + + + + + + streams + + + + + + long + + + + + + timestamp + + + + + + int + + + + + + version + + + + + + + + + + Version + + + + + + + + + + + + + + + + + + + + + + boolean + + + + + + equals(Object) + + + + + + int + + + + + + hashCode() + + + + + + void + + + + + + write(OutputStream) + + + + + + String + + + + + + toString() + + + + + + + + + byte[] + + + + + + hash + + + + + + + + + + InventoryVector + + + + + + + + + + + + + + + + + + + + + + + + + void + + + + + write(OutputStream) + + + + + + + + + Streamable + + + + + + + + + + + + + + + + + + + + + + + + + void + + + + + + write(OutputStream) + + + + + + + + + Command + + + + + + command + + + + + + + + + + VerAck + + + + + + + + + + + + + + + + + + + + + + + + + int + + + + + + + + CURRENT_VERSION + + + + + + + + + void + + + + + + send(long, long, ObjectPayload, long, long, long) + + + + + + void + + + + + + addStream(long) + + + + + + void + + + + + + removeStream(long) + + + + + + + + + long + + + + + + networkNonceTrialsPerByte + + + + + + NodeRegistry + + + + + + addressRepository + + + + + + int + + + + + + port + + + + + + NetworkHandler + + + + + + networkHandler + + + + + + long + + + + + + networkExtraBytes + + + + + + Inventory + + + + + + inventory + + + + + + long[] + + + + + + streams + + + + + + + + + + BitmessageContext + + + + + + + + + + + + + + + + + + + + + + + + + List<BitmessageAddress> + + + + + + findIdentities() + + + + + + List<BitmessageAddress> + + + + + + findContacts() + + + + + + void + + + + + + save(BitmessageAddress) + + + + + + void + + + + + + remove(BitmessageAddress) + + + + + + + + + + AddressRepository + + + + + + + + + + + + + + + + + + + + + + + + + byte[] + + + + + calculateNonce(byte[], byte[]) + + + + + + + + + ProofOfWorkEngine + + + + + + + + + + + + + + + + + + + + + + byte[] + + + + + calculateNonce(byte[], byte[]) + + + + + + + + + MultiThreadedPOWEngine + + + + + + + + + + + + + + + + + + + + + + + + + void + + + + + + start(MessageListener) + + + + + + void + + + + + + stop() + + + + + + void + + + + + + offer(InventoryVector) + + + + + + + + + + NetworkHandler + + + + + + + + + + + + + + + + + + + + + + + + + List<NetworkAddress> + + + + + + getKnownAddresses(int, long...) + + + + + + void + + + + + + offerAddresses(List<NetworkAddress>) + + + + + + + + + + NodeRegistry + + + + + + + + + + + + + + + + + + + + + + Logger + + + + + + + + LOG + + + + + + + + + NetworkMessage + + + + + + + getNetworkMessage(int, InputStream) + + + + + + ObjectMessage + + + + + + + getObjectMessage(int, InputStream, int) + + + + + + Pubkey + + + + + + + createPubkey(long, long, byte[], byte[], long, long, Feature...) + + + + + + BitmessageAddress + + + + + + + generatePrivateAddress(long, Feature...) + + + + + + ObjectPayload + + + + + + + getObjectPayload(long, long, long, InputStream, int) + + + + + + Pubkey + + + + + + + readPubkey(long, long, InputStream, int) + + + + + + + + + + Factory + + + + + + + + + + + + + + + + + + + + + + NetworkMessage + + + + + + + read(InputStream) + + + + + + ObjectMessage + + + + + + + readObject(InputStream, int) + + + + + + + + + + V3MessageFactory + + + + + + + + + + + + + + + + + + + + + + byte[] + + + + + + + calculateTag(long, long, byte[]) + + + + + + String + + + + + + toString() + + + + + + + + + byte[] + + + + + + ripe + + + + + + String + + + + + + address + + + + + + byte[] + + + + + + tag + + + + + + PrivateKey + + + + + + privateKey + + + + + + long + + + + + + version + + + + + + Pubkey + + + + + + pubkey + + + + + + long + + + + + + stream + + + + + + String + + + + + + alias + + + + + + + + + + BitmessageAddress + + + + + + + + + + + + + + + + + + + + + + void + + + + + + encrypt(byte[]) + + + + + + void + + + + + + decrypt(byte[]) + + + + + + + + + + Encrypted + + + + + + + + + + + + + + + + + + + + + + + + + void + + + + + + write(OutputStream) + + + + + + + + + Command + + + + + + command + + + + + + List<InventoryVector> + + + + + + inventory + + + + + + + + + + Inv + + + + + + + + + + + + + + + + + + + + + + + + + void + + + + + + sign(PrivateKey) + + + + + + boolean + + + + + + isSignatureValid(Pubkey) + + + + + + void + + + + + + write(OutputStream) + + + + + + + + + Command + + + + + + command + + + + + + byte[] + + + + + + payloadBytesWithoutNonce + + + + + + InventoryVector + + + + + + inventoryVector + + + + + + long + + + + + + expiresTime + + + + + + boolean + + + + + + signed + + + + + + long + + + + + + version + + + + + + ObjectPayload + + + + + + payload + + + + + + byte[] + + + + + + nonce + + + + + + long + + + + + + type + + + + + + long + + + + + + stream + + + + + + + + + + ObjectMessage + + + + + + + + + + + + + + + + + + + + + + + + + void + + + + + + write(OutputStream) + + + + + + + + + Command + + + + + + command + + + + + + List<InventoryVector> + + + + + + inventory + + + + + + + + + + GetData + + + + + + + + + + + + + + + + + + + + + + + + + PrivateKey + + + + + + + read(InputStream) + + + + + + void + + + + + + write(OutputStream) + + + + + + + + + byte[] + + + + + + privateEncryptionKey + + + + + + byte[] + + + + + + privateSigningKey + + + + + + Pubkey + + + + + + pubkey + + + + + + + + + + PrivateKey + + + + + + + + + + + + + + + + + + + + + + byte[] + + + + + + encrypted + + + + + + + + + Broadcast + + + + + + + + + + + + + + + + + + + + + + V4Pubkey + + + + + + + read(InputStream, long, int) + + + + + + void + + + + + + encrypt(byte[]) + + + + + + void + + + + + + decrypt(byte[]) + + + + + + void + + + + + + write(OutputStream) + + + + + + + + + byte[] + + + + + + signingKey + + + + + + ObjectType + + + + + + type + + + + + + byte[] + + + + + + tag + + + + + + long + + + + + + version + + + + + + byte[] + + + + + + signature + + + + + + byte[] + + + + + + encryptionKey + + + + + + long + + + + + + stream + + + + + + + + + + V4Pubkey + + + + + + + + + + + + + + + + + + + + + + int + + + + + + behaviorBitfield + + + + + + + + + V2Pubkey + + + + + + + read(InputStream, long) + + + + + + void + + + + + + write(OutputStream) + + + + + + + + + byte[] + + + + + + signingKey + + + + + + ObjectType + + + + + + type + + + + + + long + + + + + + version + + + + + + byte[] + + + + + + encryptionKey + + + + + + long + + + + + + stream + + + + + + + + + + V2Pubkey + + + + + + + + + + + + + + + + + + + + + + long + + + + + + nonceTrialsPerByte + + + + + + long + + + + + + extraBytes + + + + + + + + + V3Pubkey + + + + + + + read(InputStream, long) + + + + + + void + + + + + + write(OutputStream) + + + + + + void + + + + + + writeBytesToSign(OutputStream) + + + + + + + + + boolean + + + + + + signed + + + + + + long + + + + + + version + + + + + + byte[] + + + + + + signature + + + + + + + + + + V3Pubkey + + + + + + + + + + + + + + + + + + + + + + void + + + + + writeBytesToSign(OutputStream) + + + + + + + + + ObjectType + + + + + + type + + + + + + boolean + + + + + + signed + + + + + + byte[] + + + + + + signature + + + + + + long + + + + + + stream + + + + + + + + + ObjectPayload + + + + + + + + + + + + + + + + + + + + + + UnencryptedMessage + + + + + read(InputStream) + + + + + + void + + + + + write(OutputStream, boolean) + + + + + + void + + + + + write(OutputStream) + + + + + + + + + byte[] + + + + + + signature + + + + + + long + + + + + + stream + + + + + + + + + UnencryptedMessage + + + + + + + + + + + + + + + + + + + + + + + + + CryptoBox + + + + + + + read(InputStream, int) + + + + + + InputStream + + + + + + decrypt(byte[]) + + + + + + void + + + + + + write(OutputStream) + + + + + + + + + + CryptoBox + + + + + + + + + + + + + + + + + + + + + + V5Broadcast + + + + + read(InputStream, long, int) + + + + + + void + + + + + write(OutputStream) + + + + + + + + + byte[] + + + + + + tag + + + + + + + + + V5Broadcast + + + + + + + + + + + + + + + + + + + + + + long + + + + + + + + LATEST_VERSION + + + + + + + + + byte[] + + + + + + add0x04(byte[]) + + + + + + + + + byte[] + + + + + + signingKey + + + + + + byte[] + + + + + + ripe + + + + + + long + + + + + + version + + + + + + byte[] + + + + + + encryptionKey + + + + + + + + + + Pubkey + + + + + + + + + + + + + + + + + + + + + + GetPubkey + + + + + read(InputStream, long, int, long) + + + + + + void + + + + + write(OutputStream) + + + + + + + + + ObjectType + + + + + + type + + + + + + long + + + + + + stream + + + + + + + + + + GetPubkey + + + + + + + + + + + + + + + + + + + + + + + + + + GET_PUBKEY + + + + + + + PUBKEY + + + + + + + MSG + + + + + + + BROADCAST + + + + + + + + + ObjectType + + + + + + + fromNumber(long) + + + + + + + + + long + + + + + + number + + + + + + + + + ObjectType + + + + + + + + + + + + + + + + + + + + + + + + + GenericPayload + + + + + + + read(InputStream, long, int) + + + + + + void + + + + + + write(OutputStream) + + + + + + boolean + + + + + + equals(Object) + + + + + + int + + + + + + hashCode() + + + + + + + + + ObjectType + + + + + + type + + + + + + long + + + + + + stream + + + + + + + + + + GenericPayload + + + + + + + + + + + + + + + + + + + + + + Msg + + + + + + + read(InputStream, long, int) + + + + + + void + + + + + + writeBytesToSign(OutputStream) + + + + + + void + + + + + decrypt(byte[]) + + + + + + void + + + + + + write(OutputStream) + + + + + + + + + ObjectType + + + + + + type + + + + + + boolean + + + + + + signed + + + + + + byte[] + + + + + + signature + + + + + + long + + + + + + stream + + + + + + + + + + Msg + + + + + + + + + + + + + + + + + + + + + + V4Broadcast + + + + + read(InputStream, long, int) + + + + + + void + + + + + writeBytesToSign(OutputStream) + + + + + + void + + + + + write(OutputStream) + + + + + + + + + byte[] + + + + + + encrypted + + + + + + ObjectType + + + + + + type + + + + + + byte[] + + + + + + signature + + + + + + long + + + + + + stream + + + + + + + + + V4Broadcast + + + + + + + + + + + + + + + 1 + 1 + + + + + + + + + 1 + 1 + + + + + + + + + 1 + 1 + + + + + + + + + 1 + 1 + + + + + + + + + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + «create» + + + + + + + + + + + 1 + 1 + + + + + + + + + 1 + 1 + + + + + + + + + 1 + 1 + + + + + + + + + 1 + 1 + + + + + + + + + 1 + 1 + + + + + + + + + 1 + 1 + + + + + + + + + + «create» + + + + + + + + + + + 1 + 1 + + + + + + + + + + «create» + + + + + + + + + + + + «create» + + + + + + + + + + + + «create» + + + + + + + + + + + + «create» + + + + + + + + + + + * + 1 + + + + + + + + + * + 1 + + + + + + + + + + «create» + + + + + + + + + + + + «create» + + + + + + + + + + + * + 1 + + + + + + + + + + «create» + + + + + + + + + + + 1 + 1 + + + + + + + + + 1 + 1 + + + + + + + + + 1 + 1 + + + + + + + + + 1 + 1 + + + + + + + + + + «create» + + + diff --git a/docs/seminar.pdf b/docs/seminar.pdf index 57e28b8..f01bb70 100644 Binary files a/docs/seminar.pdf and b/docs/seminar.pdf differ diff --git a/docs/seminar.tex b/docs/seminar.tex index 826ec37..5134281 100644 --- a/docs/seminar.tex +++ b/docs/seminar.tex @@ -11,6 +11,7 @@ \newcommand{\msg}[1]{\textit{#1}} \newcommand{\obj}[1]{\textbf{#1}} \newcommand{\node}[1]{\textbf{#1}} +\newcommand{\key}[1]{\textbf{#1}} \begin{document} \maketitle @@ -76,7 +77,7 @@ \subsection{Addresses} \label{subsec:addr} - \textit{BM-2cXxfcSetKnbHJX2Y85rSkaVpsdNUZ5q9h}: Addresses start with "BM-" and are, like Bitcoin addresses, Base58 encoded\footnote{Which avoids the easily confused characters I, l, 0 and O.}. + \textit{BM-2cXxfcSetKnbHJX2Y85rSkaVpsdNUZ5q9h}: Addresses start with "BM-" and are, like Bitcoin addresses, Base58 encoded\footnote{Which uses characters 1-9, A-Z and a-z without the easily confused characters I, l, 0 and O.}. \listinginfo{}{version}{Address version.}{} \listinginfo{}{stream}{Stream number.}{} @@ -84,7 +85,32 @@ \listinginfo{}{checksum}{First four bytes of a double SHA-512 hash of the above.}{sha512(sha512(version + stream + ripe))} \subsection{Encryption} - TODO + + Bitcoin uses Elliptic Curve Cryptography for both signing and encryption. While the mathematics behind elliptic curves is even harder to understand than the usual prime-and-modulo-until-your-brain-explodes approach, it's based on the same principle that factorizing large numbers is very hard to do. Instead of two very large primes, we multiply a point on the elliptic curve by a very large number\footnote{Please don't ask me how to do it. If your're crazy enough, start at \url{http://en.wikipedia.org/wiki/Elliptic_curve_cryptography}. If you're not that crazy, use a library like Bouncy Casle.}. + + The user, let's call her Alice, needs a key pair, consisting of a private key +$$k$$ +which represents a huge random number, and a public key +$$K = G k$$ +which represents a point on the agreed on curve\footnote{Bitmessage uses a curve called \textit{secp256k1}.}. Please note that this is not a simple multiplication, but the multiplication of a point along an elliptic curve. $G$ is the starting point for all operations on a specific curve. + + Another user, Bob, knows the public key. To encrypt a message, Bob creates a temporary key pair +$$r$$ +and +$$R = G r$$ +He then calculates +$$K r$$ +uses the resulting Point to encrypt the message\footnote{A double SHA-512 hash over the x-coordinate is used to create the actual key.} and sends $K$ along with the message. + + When Alice receives the message, she uses the fact that +$$K r = G k r = G r k = R k$$ +so she just uses $R k$ to decrypt the message. + + The exact method used in Bitmessage is called Elliptic Curve Integrated Encryption Scheme or ECIES\footnote{See \url{http://en.wikipedia.org/wiki/Integrated_Encryption_Scheme}}. + + \subsection{Signature} + +ECDSA \section{Issues} @@ -93,7 +119,7 @@ Bitmessage doen't really scale. If there are very few users, anonymity isn't given anymore, and with many users traffic and storage use grows quadratically. \subsubsection{Streams} - The intended solution for this problem is splitting traffic\footnote{Addresses, actualy} into streams. When all active streams are full, a new one is created which should be used for new addresses. All users can send messages to any stream, but only listen to the streams belonging to their addresses. The unsolved problem is to determine when a stream is full. The other issue is the fact that, as the overall network grows, traffic on full streams still grows, as there are more users who might wanto to write someone on the full stream. + The intended solution for this problem is splitting traffic\footnote{Addresses, actualy.} into streams. When all active streams are full, a new one is created which should be used for new addresses. All users can send messages to any stream, but only listen to the streams belonging to their addresses. The unsolved problem is to determine when a stream is full. The other issue is the fact that, as the overall network grows, traffic on full streams still grows, as there are more users who might wanto to write someone on the full stream. \subsubsection{Prefix Filtering} TODO