MAM, Masked Authenticated Message, is one of the most remarkable features of IOTA. Let us speculate the world full of small IoT devices, where their small jobs, flow of microscopic data, and nano-payments come and go all over the globe.

IOTA, whose goal is to become the very fundamental layer of such society, is the most provident project of the time that challenges looming paradigm shift. And MAM is its core driving force, which distinguishes IOTA from other distributed ledger by making data flow and transactions much cheaper, more secure and ubiquitous.

However, despite the fact that MAM is immensely important in IOTA and its future, since it is still under development stage, only limited amount of information is available to public with regard to its technical implementation.

This article reveals it in as comprehensible way as possible such that more people could wrap their head around this next technology.

MAM Channel

Like Youtube and other media, MAM also has Channel, where owner who publishes and viewers who subscribe meet. Viewers subscribe channel to get data that’s available. And channel owner publishes new data on their own channel. This ownership is implemented and secured in IOTA by Seed. If you tell others your seed, they can publish their whatever messages on your channel. Again, Seed holds all privacy and property right in its 81 trytes. Never, expose it and store securely.

Channel Mode

There are three options publishers can choose from when posting new message on their channel. Public: everyone can view, Private: only you (i.e. seed owner) can view, and Restricted: you can specify your viewers by telling them a key. This key is named as sideKey in source code. So, in this article, I’m also going to call this key sideKey . And, for any modes, root , which works as message identifier, is given to viewers so as to find message from tangle.

Public: Masked-message is decrypted using root . Private: address＝hash(root) . Masked message is decrypted using root . Restricted: address＝hash(root) . Masked message is decrypted using sideKey .

Message Chain

In IOTA protocol, like many other cryptos, people can attach arbitrary message to transactions. But, it’s feeless for IOTA! However, it limits sender to attach only one message at once and cannot publish consecutive related message with arbitrary context.

For example, if you want to post current temperature data every 15 minutes, without MAM, you have to post every message to same address. Because any distributed ledger including tangle is publicly accessible, it’s easy for attachers to identify such an address that updates every 15 minutes, and interfere it with spam transactions. Even though you decided to change address every time you post new data, you have to keep track of all address. And monitoring them is relatively costly in terms of just storing information online.

MAM, however, thanks to its design of Message Chain, we can protect our channel from any disturbing spam and let us free from managing cumulating addresses.

MAM posts every message to different address, but with verbose information that connects them. On this message chain, one generation to next generation, older message always lead to newer. Its flow is one way.

Basic Structure of MAM Bundle

Bundle of MAM has roughly two sections, Signature section and MAM section, each detail will be explained later in this article. Their data are stored as signatureFragment of transactions in the bundle. Signature is used to MAM’s ownership and thus its validity checking. MAM section stores an actual masked message.

Address: Where MAM is being stored

Address, where masked message is being stored, is hashed from root . Hashing is a complicated calculation in which one cannot guess what the input is by knowing output.

if (channel.mode !== 'public') {

// private, restricted mode

address = Crypto.converter.trytes(Encryption.hash(81, Crypto.converter.trits(mam.root.slice())));

} else {

address = mam.root;

}

Notice: Paul Handy’s article shows restricted mode address = hash(root+sideKey) . But, as seen in the source code above, address = hash(root) . So, in this article, I will explain as address = hash(root) for restricted mode. This may be different from fact, and so if anyone who’s acquainted with this in detail. Please, comment or contact me. I appreciate that.

Public Mode

root is address. root is encryption & decryption key.

nextRoot is a connecting pointer to next message. When masked message of one generation is decrypted, unmasked message contains nextRoot that is used for viewers to find the message of next generation of the channel. Simply put, it’s like you find the key to open second treasure chest, in the first treasure chest. Repeatedly, one could trace all messages on the chain from channel genesis. If you are given middle generation, you can start reading chain from that point. You can’t trace back to see past messages.

Restricted Mode

hash(root) is address. sideKey is encryption & decryption key.

Main idea is same as public mode. Only differences are sideKey is used to decrypt masked message. People without sideKey can find message’s location with root , but can’t understand what’s loaded there.

Ownership of Channel

Consider the following case:

Alice has just published her first message on her channel and want Bob to read her post. So, Alice gave him her root and sideKey . Bob visited her message by generating address(= hash(root) ) and decrypt it with sideKey . Bob enjoyed her post and thought "wanna read next!". And he has nextRoot in the decrypted current message, and can generate next address out of it. But, he realized that Alice hasn't published next message yet, at next address. Bob suddenly became evil. He has nextRoot and sideKey . He can post his message encrypted with sideKey to the address hash(nextRoot) . And he could hijack Alice's channel.

Do you think it would work? From information explained so far, there's no contradiction. ...However, that's MAM's failure. Don't worry, MAM is designed so people like Bob cannot jumble up the channel. Next topic to cover is how Alice keeps her message chain from being edited by anyone else.

Here we need signature in MAM.

Merkle tree based signature scheme

Merkle tree based signature scheme is the technique used in MAM. Go to link for those who are interested in more.

MAM Publish 101: root

root is the root of Merkle Tree. To get root ,one must firstly create Merkle Tree. And Seed is used to create Merkle Tree.

Merkle tree has integer parameters start and size . These represent index of address being generated from Seed. Recall that we take index as one of the parameters( seed,index,security ) when generating address. Recently explained here.

Following A, B, C, D are private keys generated with index = 0,1,2,3 respectively. And A', B', C', D' are corresponding address.

Then A”, B”, C”, D” are hash(address) . Up to root , narrow them down by hashing combined of each pair. Note that you cannot get previous from root .

Now, we got root . In public mode, this root is directly used as MAM address, in other modes, address = hash(root) .

MAM Publish 102: MAM Section

MAM section contains masked message that publisher is about to post, his/her raw message, ascii code string of arbitrary length. But, before being attached, it should be converted to tryte (Using library function toTrytes(ascii); // from asciiToTrytes.js ), and stored as message .

MAM Publish 102: MAM Section — nextRoot

To post masked message of one generation, one must generate TWO merkle trees. First tree is for the current generation and the other is for next generation.

For Genesis generation (i.e. 0-th generation), merkle tree, tree0 , has parameter start0 and count(= number of leaves) . For next generation(i.e. 1st generation), merkle tree, tree1 , is generated with start1 = start0+count and count .

By the way, each merkle tree can have a different size.

MAM Publish 102: MAM Section — Branch Index

Branch Index, branch_index , is chosen from any of leaves’ index of current generation’s merkle tree. In the example below, merkle tree has been made with start=0 and count=4 , so branch_index should be one of 0,1,2 and 3 .

MAM Publish 102: MAM Section — Siblings

Let’s say, leaf A' is given, to obtain root , you need to have all other leaves B'C'D' . But, if you cannot access to those, how do you get root ? Siblings are the set of complementary hashes, by being combined with given leaf, can generate root . Look at the figure below.

This figure exemplifies the case of branch_index=0 , where only A' is given. In this case, B" and Hash(C"D") are all what necessary to obtain root . You don’t have to have other leaves.

In this example, B" and Hash(C"D") are called Siblings of A' . In MAM, it’s referred to as Siblings of branch_index=0 . Different branch_index has different set of siblings.

MAM Publish 102: MAM Section — completed

In MAM section, compound of message , nextRoot , branch_index and Siblings , called messageTrytes are encrypted with root(Public mode) or sideKey(Restricted mode) . Following figure is the example of restricted mode encryption of MAM section.

MAM Publish 103: Signature Section

As I mentioned, for validity checking of MAM section, publishers add Signature in the bundle. Signature is stored in signatureFragment of the transactions, and those transactions are called Signature section in MAM bundle.

MAM Publish 103: Signature Section — signing

Signature of the masked message is created from Private Key =key(seed,branch_index,security) . Signed data is messageTrytes of MAM section. Signing scheme is explained here.

MAM Fetch

To fetch masked message, what’s needed are root and sideKey in the case of restricted mode.

First of all, calculate address from given root . And search bundle of the address. Then decrypt messageTryte of found bundle’s MAM section. Decryption key is root for public mode, sideKey for restricted mode. Now, from decrypted data, we have message , nextRoot , branch_index , Siblings .

Next step is checking validity of the unmasked message. Now, look at Signature section. Signature in the Signature section is used to validate messageTryte of MAM section of the bundle as signed data. Validation process is explained here.

After validation process, what you get is address, which is used as a leaf address of index= branch_index of merkle tree and combined with Siblings to calculate root of the tree, named as temp_root .

If temp_root equals to given root , then this unmasked message is valid message of the channel. If not, it is not published by channel owner(=seed owner).

Chainfork

MAM’s message chain can fork. And it is easy to fork. For the generation you chose to fork, you just have to publish message with different branch_index . But, limit of branches that can be forked in the generation is the size of merkle tree of the generation. If you forked more than that, new branch index spills over into branch_index of the next generation. You can set different sideKey and channel mode between subchains.

Snapshot

Masked message is stored in signatureFragment of transactions. Thus, after snapshot, which eliminates all transactions and address of zero balance, all MAM that preceded the snapshot are deleted.

To prevent this clearance from happening, MAM are stored in Permanode, which does not do snapshot. Although permanode requires large storage, bandwidth and high speed, currently it is running with no financial incentive. Our community has to discuss how IOTA’s infrastructure should be maintained and be rewarded to sustain its stabilization.

References