Late last year, two excellent articles were published on implementing Colored Coins in Bitcoin Cash using a new proposed opcode called OP_GROUP. Thank you Andrew Stone for the initial concept, and Chris Pacia for building upon this.

The OP_GROUP approach is elegant, powerful and secure. It is not a fully-blown smart contract system, but does provide very powerful functionality that is sufficient for most use cases. I’m very enthusiastic about its possibilities. I think it needs one small addition to make it even more useful and powerful, and that is the capability to safely transfer the token generation abilities between parties and improve token generation transparency / accountability when multiple groups are involved in token generation.

In a nutshell, the current OP_GROUP token minting and burning processes requires the use of a single set of static private keys. I.e., one or more ‘keys’ are used to issue the tokens, and the locks can never be changed. The keys can thus be given (copied) from one person to another person, but it is not certain whether the first person has retained a copy of his key. In this article, I shall demonstrate how we can use one administrative token as a key to issue other tokens. Since administrative tokens can be moved from one address to another, these administrative tokens can be transferred from one party to another, where the first party no longer has access.

First, a small recap of how OP_GROUP tokens work.

How does OP_GROUP work?

In Bitcoin Cash, a standard Pay to Public Key hash transaction looks like this:

OP_DUP, OP_HASH160, <pubkeyHash>, OP_EQUAL_VERIFY, OP_CHECKSIG

For colored coins , a group identifier is added. Andrew Stone suggested using a 160 bit hash, in which case the transaction looks like this:

<colored_hash>, OP_GROUP, OP_DUP, OP_HASH160, <pubkeyHash>, OP_EQUALVERIFY, OP_CHECKSIG

The only difference with a standard transaction, is the addition of the <colored_hash> and the OP_GROUP opcode. Andrew Stone describes the operation of OP_GROUP as follows:

When the OP_GROUP instruction is encountered, it uses the data on the top of the stack as a group identifier, and adds/subtracts the value of this input/output to an integer (initialized to zero) that is associated with the group. This integer is called the “group balance”. If there is no OP_GROUP, the input/output is assumed to be in a default “bitcoin cash” group. At the end of transaction processing, every group balance must be zero except for the “bitcoin cash” group whose inputs may exceed its outputs to form the transaction fee (as occurs today). In other words, within every colored-coin group the satoshis input balance the satoshis spent.

In the articles referenced above, the <colored_hash> is the hash that essentially defines a Bitcoin Cash address. That address alone is able to create new tokens, or to destroy existing tokens. All other transactions are able to transfer tokens, as long as the sum of tokens of each type is the same for the input and output parts of each transaction.

What’s missing?

OP_GROUP allows extremely powerful centralized management of tokens, as is desired for this use case. However, there exists a scenario that isn’t fully covered by this approach - there is no key revocation or transfer process.

Imagine Bob is responsible for issuing the colored tokens on behalf of Widget Inc.. Bob, by the nature of his job, has access to the private key of his <colored_hash> address. We will never know for sure if he made any copies of that key. Then, Bob changes jobs and is replaced by Dave. Bob must now give the private key associated with <colored_hash> to Dave. Then, 1000 new colored Widget Inc. coins are created, and Dave denies having issued them. How can we know who issued them, and how could it have been prevented?

Or, imagine a country decides to issue their national currency on the Bitcoin Cash blockchain. Anyone who was involved in issuing the currency in the past, but is no longer in that role, cannot have, or be suspected of having, (partial) access to the keys that control currency issuance. Their access must be able to be fully revoked, as re-issuing a national currency every time someone changes their job is not an option.

Of course, token generation could be (and probably should be) implemented as a multisig address, and preferably using multiple hardware wallets. Still, even if creating colored coins requires signatures from Bob and Charles, who have both been replaced by Dave and Evan, then we still have the same situation where we cannot rule out that Bob and Charles both copied their keys and are now colluding to create more tokens.

A simple solution to this problem

We can fix this issue, by introducing administrative tokens that are able to create tokens.

As designed by Andrew Stone, the group is identified as follows:

<colored_hash> = HASH160(<pub_key>);

In other words, it is a Bitcoin Cash address in byte format.

Let’s redefine the group identifier to include an indicator of whether it is based on an address, or based on another token.

We can instead define the colored_hash as follows:

<colored_hash> = HASH160(SHA256(CONCAT(<type>,<identifier>)));

In this case, <type> can be any unique byte (or byte array) that identifies what kind of colored hash is created. In this case, only two types are needed, but any number of additional types can be added in the future, should there be a shared desire to do so.

In the case the colored_hash is based on a public key, the colored_hash becomes:

<colored_hash> = HASH160(SHA256(CONCAT(TYPE_ADDRESS,<pub_key>)));

TYPE_ADDRESS could be any unique “type” byte, such as 0x00;

In the case the colored_hash is based on another token (i.e., <other_colored_hash>), the new colored_hash becomes:

<colored_hash> = HASH160(SHA256(CONCAT(TYPE_TOKEN,<other_colored_hash>)));

TYPE_TOKEN could be any unique “type” byte, such as 0x01;

This would require no further changes to the transfer logic of colored coins, as defined by Andrew Stone. It would require only a change to the minting and melting of colored coins.

Let’s have a look at how coins are minted using Andrew Stones’s OP_GROUP proposal:

... we must make “mint” and “burn” operations that essentially are exceptions to the rule that the input and output within a group must always sum to zero. Luckily, we have also not yet defined a format for the data is that defines a group. So let us define a group identifier to be the hash160 of a ECDSA public key (in other words, a Bitcoin address). This will allow us to create an elegant mechanism to add and remove satoshis to the group.

To “mint” new coins into a group, if a transaction has an input that is signed by the same Bitcoin address as the OP_GROUP identifier, then the value of that input MAY be placed either in the group or in the bitcoin group (or part in each) in the outputs. Additionally, the first “mint” transaction could contain an optional OP_RETURN that contains a short human readable name for the group (a stock symbol, for example) and the hash of a document/contract that describes the group in detail. For example, a valid transaction could have an input of 200 BCH satoshis located at address ABC, and an output of 200 ABC.

To “melt” coins (remove them from the group), we use the same strategy. If a transaction input is grouped and signed by the same Bitcoin address as the OP_GROUP identifier, then the value of that input MAY be placed either in the group or in the bitcoin group (or part in each). For example if a transaction has an input worth 200 TOK on address TOK and 2 outputs: 100 TOK paying to any address and 100 BCH satoshis paying to another address, then this transaction balances.

In this way, only the owner of a group address can mint new colored coins or melt them back into BCH.

Let’s expand on this logic, and make some additions.

We must make “mint” and “melt” operations that essentially are exceptions to the rule that the input and output within a group must always sum to zero. Let us define a group identifier to be the colored_hash identifier as described above. This will allow us to create an elegant mechanism to add and remove satoshis to the group.

We “mint” new colored coins, when we have the regular Bitcoin Cash tokens as input, and <colored_hash> tokens as output. Transactions that are permitted to “mint” the colored coins are limited and enforced by the Bitcoin Cash nodes and miners. To “mint” new coins into a group with identifier “colored_hash”, a transaction has to:

Either, have an input that is signed using a public key used to create a TYPE_ADDRESS token, i.e.

HASH160 ( SHA256 ( CONCAT ( TYPE_ADDRESS, <pub_key>))) == <colored_hash>

Or, have an input that contains an administrative token (i.e. <token_admin>). So that

HASH160 ( SHA256 ( CONCAT ( TYPE_TOKEN, <token_admin>))) == <colored_hash>

The <colored_hash> would be the OP_GROUP identifier.

We “melt” colored coins, when we have <colored_hash> tokens as an input, and regular Bitcoin Cash tokens as an output. Again, the transactions that are allowed to do this are limited. The transactions would have to be:

Either, Colored Coins are first sent back to the address that created them (for TYPE_ADDRESS). When spent from this address, the colored coins can be input as a token, and be output as regular Bitcoin Cash.

Or, Colored Coins are spent in a transaction that also transfers the associated administrative token of the type <token_hash> as described above. In other words, the administrative token is part of the transaction (both as input and output). When the administrative token is transferred, the token associated with this administrative token may be minted or melted.

An identifier could be added to the transaction (i.e. in an OP_RETURN) that specifies what TYPE field is used. This allows the number of types to increase unbounded in the future, should that be desired.

For TYPE_ADDRESS mint transactions:

And melt transactions:

The mint and melt transactions must originate from an address that is related to the <colored_hash> group with the function:

<colored_hash> = HASH160 ( SHA256 ( CONCAT ( TYPE_ADDRESS, <pub_key> ) ) );

For TYPE_TOKEN mint transactions (where colored_admin is the token capable of creating the colored_hash token), the transaction contains the administrative token both as an input and as an output. Because the creator of this transaction obviously has the ability to spend the administrative token, he/she has the power to mint or melt TYPE_TOKEN colored coins:

The “mint” transaction could look like this:

And the “melt” transaction:

The colored_admin token can stay in the same address, it will just be moved from one utxo to another utxo, but still spendable by the same person(s) that control these keys.

In Andrew Stone’s proposal, because the token_hash is the same as the pubkey_hash, it is possible to embed data about the token in an OP_RETURN linked to that pubkey_hash address. In this case, this shortcut is broken, and you cannot determine the source of the tokens directly.

However, each token is a chain of digital signatures. Just as is the case with the Bitcoin Cash tokens, you can trace it back on the blockchain, until you reach the minting transaction. The minting transaction knows exactly how it was created (either by another token, or by a private key). In the case of a private key, the root has been found. In the case of another token, this same backtracking strategy can be applied.

It is thus a little more work, requires going back through spend transactions, and is slightly less efficient. Wallets could be created that optimize this process (i.e., caching tokens and original issuing addresses). It is also possible to provide all this information off-chain, as verification is much more efficient than tracing back a token through numerous transactions back to its creation. Yet it is possible without difficulty, and would only be done by clients that need this information. It is not relevant to the miners or fully verifying nodes.

Therefore, the first “mint” transaction could contain an OP_RETURN that contains a short human readable name for the group (a stock symbol, for example) and the hash of a document/contract that describes the group in detail. For example, a valid transaction could have an input of 1000 BCH satoshis located at address ABC, and an output of 1000 ABC tokens. The ABC tokens could be identified in the OP_RETURN as Widget Inc. tokens.

Issuing a token is thus a multi step process.

First, an administrative token is created, and it is of type TYPE_ADDRESS. If desired, these tokens can be created through a signing ceremony, where care is taken that the private key that created this token is destroyed. This allows for certainty that no additional administrative tokens can ever be made. Of course, if Chris Pacia’s OP_CHAINHEIGHT is implemented, this opcode could be used to enforce this mathematically, and provide irrefutable proof to third parties that no more administrative tokens can be created. In any case, safeguarding this token is critical, and (depending on its future market cap) it should never be created or used on an online PC.

One administrative token is created per person or group of persons that will be able to issue the tokens. Because each token is unique, and traceable, it is immediately obvious what administrative token created which tokens.

Let’s assume that two people need to collaborate to create tokens. They share one administrative token, locked away in a multisig addresses, i.e. a 3 out of 5 address. One key is stored with a trusted third party (i.e., a lawyer). One key is stored with a completely different trusted third party (i.e. another lawyer). One key is stored in an auto-sign server. The two remaining keys are owned by the two people creating tokens.

Let’s call these two people Bob and Charlie. Bob and Charlie want to create 1000 Widget Inc. tokens. The administrative token is safely stored in the 3/5 address, of which they both hold one key. They create their mint transaction, and both sign it. It now has 2 out of the 3 necessary signatures. They send their partially signed transaction to an auto-sign service. The only job of this service, is to ensure that the administrative token’s input address is the same as the output address. In other words, the token is not allowed to be moved outside of the control of the 3/5 address, even if Bob and Charlie collude.

When Bob and Charlie leave the company, they sign one more transaction to transfer the administrative token to another address. Without access to a third private key, they cannot steal the token for themselves. In the event that Bob and Charlie are both fired simultaneously, and they both refuse to sign a transaction, the two lawyers can be contacted to assist in transferring the administrative token to another address. In no event can Bob and Charlie collude.

A hacker could still penetrate Widget Inc.’s security, and steal the keys owned by Bob and Charlie. However, this would only appear to be possible if they are held on an online computer. A hardware device, such as a Trezor or Ledger, could be used to manage the private keys and transaction signing.

The “auto-sign” server could have a configurable delay, i.e. it will send out an alert if a request to sign a transaction has been received. The recipients of this alert would then have one week, for example, to cancel the transaction. If it is not cancelled, then the auto-sign service adds the third private key. This eliminates the effect of a hacker stealing two keys, and using it to generate tokens.

In theory, a hacker could still obtain all three keys, and create tokens at will. At this point, it may be acceptable to say that Widget Inc. had poor security. Just like how Bitcoin Cash tokens are lost if the security is poor, Widget Inc. tokens can be lost if the security is poor.

Once tokens have been issued, these tokens are “valid”, even if they have been issued by hackers. Being able to remotely destroy or freeze tokens is highly undesirable, as it destroys the very concept of “he who has the private keys owns the token”. Widget Inc. could, in this case, broadcast a special transaction (i.e. a transaction with a ‘killcode’ OP_RETURN). That would indicate to all wallets that the token will no longer be accepted, but it won’t prevent transfer of ownership of said token. It is up to the wallets to check whether this ‘killcode’ has been broadcasted or embedded in the blockchain. Widget Inc. will then have to create a new token. They can scan the blockchain to find each address that had their tokens, and know the exact amount. They can create a Widget Inc2 Token, and send the same amount of Widget Inc2 tokens to each address. This should be a client-side implementation, not a core protocol implementation.

However, tokens are based on the Bitcoin Cash scripting language. It is conceivable that, in the future, smart contracts will exist that enable the following logic: when minting transactions, the newly created tokens are first sent to a predefined ‘waiting’ address. This address can either be spent directly, where the colored tokens lose their coloring. Or this address can be spent after a certain amount of time, where the colored tokens retain their coloring.

It is also conceivable that, should one administrative token be fully compromised, that the token configuration can somehow be updated to require two tokens to be transferred. I.e., not changing the lock, but adding a second lock. Administrative tokens cannot be “revoked”, just as tokens cannot be moved without a corresponding private key of the address that holds it. Let’s imagine we have a fully compromised administrative token. We can take a second administrative token that we control, and send it to the bitcoin address where the public key is the same as the token identifier. We will never be able to spend that administrative token. But now, we only would need to do a lookup for that address and count the number of administrative tokens. If there are no tokens, 1 administrative token can be used for mint and burn operations. If there is one token, 2 administrative tokens are required for mint and burn operations. And so on and so forth. Of course, this needs to be a more efficient approach to the one described here, as spamming this address with useless tokens would slow down transaction verification - thus a better approach (or caching) is needed. But the general idea is that, if we cannot revoke administrative tokens, maybe we can require more of them, thus rendering stolen administrative tokens useless.



