Iagon's solution to the Cardano Proof of Burn Challenge
Introduction
Iagon took on the recent Challenge to introduce a proof-of-burn protocol for the Cardano Ecosystem as proposed by Mr. Charles Hoskinson[1]. This short essay aims to give insights in the solution developed by the Iagon team and will adhere to the following structure:
- General explanation of the proof-of-burn mechanism and its applications;
- Smart contract implementation and action mechanism of Iagon’s proof-of-burn solution on the Cardano network;
- The deployment and testing of the smart contract (on testnet);
- Implementation of the proof-of-burn protocol by sending tokens to a “black hole”-address (wallet transaction).
1. Proof-of-burn and its applications
Nowadays, the burning of cryptographic tokens has been widely implemented and essentially comes down to sending tokens to a “black hole”-address. Such address isn’t accessible and there are no access keys to retrieve any of the burned tokens. Simultaneously, the public can verify that the burn took place, but only by knowing a “secret”: the commitment value. This mechanism was introduced to assure the burn of funds isn’t censorable by a middleman[2].
A burning mechanism serves different functions and may serve to boost the valuation of the remaining tokens, or it may be used as a proof of commitment in blockchain protocols[3]. Burning in large amounts may cause deflationary pressure since it decreases the total amount of the token in circulation. Although burn mechanisms are common blockchain transaction, they need to be accepted by the miner. Despite the benefits of such mechanisms, some people are opposed to burning tokens. To prevent any opposition, Iagon aims to introduce a protocol that allows people to burn the tokens without having the possibility to censor them. It is such particular implementation, without any censorship possibility, that captured the attention of Mr. Charles Hoskinson[4].
Security of proof-of-burn is based on the same mechanisms as security of token transfer transactions, namely “cryptographic hash functions”. Such Cryptographic hash function are easy to compute, but very difficult to reverse. In essence, it’s so difficult to reverse that a change in a single bit of input will change each bit of the output result randomly. That means that when a single bit of the output of a cryptographic hash function is changed, reversing the computation starting from the output would take extremely long. In short, flipping the lowest bit in a cryptographic hash function creates a black hole address. Whatever is sent to this address becomes very hard or impossible to recover.
The former shows that security of crypto transactions can be based solely on the public key cryptography and cryptographic hash functions: “Whenever money sent, a new unspent transaction output is created”. This UTxO records both the amount of money, and a cryptographic hash of the public key of the receiver. For a receiver to use the money, one must sign a new transaction that spends it with the same public key.
But why flipping the lowest bit in an output of a hash function instead of just using a hash of 0x0? Well, using a known value would make the burns immediately visible. However, the idea of the protocol is to first burn the money and prove it was burned afterwards (in a separate step). For this to work, a hash derived from a commitment value is created first. Afterwards the commitment value shows that a black hole address was created.
2. Smart Contract for Proof-of-Burn on Cardano Network
In this section, the mechanics of a Proof-of-Burn on a Cardano smart contract are explained. Cardano smart contracts are programs that run on the Cardano network and allow the contract developer to execute (financial) transactions in accordance with a set of given rules. Smart contracts [5] aim to establish transactions between multiple parties that are transparent and verifiable. Recent Driving factors for the parabolic rise in adoption are decentralized financial services and decentralized organizations[6].
Traditional Ethereum-style smart contracts consist of state recorded on the ledger and program that is called asynchronously by applications to change this state. Since the state of the ledger belonging to a smart contract can only be changed through the program, all permissible state manipulations can be deduced from the program code and recorded on the blockchain.
Circling back to the Cardano Ecosystem, it has implemented a different architecture, which aims to make attacks harder by allowing users to first simulate each transaction locally within their wallets. The resulting change is then validated by the blockchain node, and this very change is recorded. For this purpose, Cardano smart contracts are described by three components:
- redeemer scripts that permit or forbid the spending of eUTxOs;
- wallet scripts that are run on behalf of the user in order to redeem funds and create new eUTxOs;
- eUTxOs, each holding funds and a datum that can be used for redeemers to confirm under which conditions these funds may be used again.
That means that Cardano smart contracts don’t have a central state on the ledger. Each eUTxO has a separate state (datum) that is inseparable from the funds in this eUTxOs. This results in four possible actions:
- burn – which sends the funds to a black hole address with a secret hashed commitment value;
- burned – which validates that a burn with the given commitment value took place;
- lock – which sends the funds to an address with a key;
- redeem – which redeems the funds locked by the lock;
Please note that endpoints run within the wallet of a user. After the endpoint script runs in the wallet, the resulting transactions moves to the blockchain. In our case, the transaction will move money to the Redeemer script. This script verifies that money is only available to the target address whose hash it holds.
type HashOfTargetAddr = BuiltinByteString
newtype MyDatum = MyDatum { fromMyDatum :: HashOfTargetAddr }
validateSpend :: ValidatorType Burner validateSpend (MyDatum addrHash) _myRedeemerValue
ScriptContext { scriptContextTxInfo = txinfo } =
traceIfFalse "owner has not signed"
(addrHash 'elem' fmap (sha3_256 . getPubKeyHash) (txInfoSignatories txinfo))
In the case of lock, the hash may be of our own address. In the case of burn, the hash points to a black hole. We achieve it by hashing a secret commitment value and then flipping a bit in it. Since we use the cryptographic hash function, it is almost impossible to find a value that would match the resulting hash.
burn' :: AsContractError e => (BuiltinByteString, Value) -> Contract w Schema e ()
burn' (aCommitment, burnedFunds) = do
let hash = flipCommitment $ sha3_256 aCommitment
let tx = Constraints.mustPayToTheScript (MyDatum hash) burnedFunds
void $ submitTxConstraints burnerTypedValidator tx
Note that flipCommitment just flips the least significant bit of a hash:
flipCommitment :: BuiltinByteString -> BuiltinByteString
flipCommitment (BuiltinByteString bs) = BuiltinByteString $ do
case unsnoc bs of
Just (seq, lastElt) -> snoc seq
$ lastElt 'xor' 1
The middlemen accepting the transactions will not know whether the transaction is a burn or a lock. By leveraging this script, the middlemen cannot selectively censor any burn transactions. Both burn and lock use the same Redeemer format, and only the transaction submitter knows whether the action was a burn or a lock. The burn value could be checked by calling the burned endpoint with the given commitment. Until the commitment value is revealed, nobody knows that the funds were burned. If you are interested in the code, the repository is described under section 3.
3. Deployment of the smart contract (on testnet)[7]
To start a testnet node with a wallet, a mnemonic phrase and a random password is needed. The smart contract can be deployed be executing the following steps:
1. Install Haskell toolchain
curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh
source ~/.ghcup/env
2. Build the Plutus script
cabal run plutus-burner
3. Start the containers with cardano node and cardano wallet
mkdir out/
export NETWORK=testnet
export BLOCKFROST_API_TOKEN=<token>
docker-compose up --build -d
docker-compose run cardano-wallet \
sh -c 'chmod 777 /ipc/node.socket'
4. To restore the wallet and output the wallet ID (which is needed for the following steps) the following code could be run (in order to generate a random mnemonic phrase for testing)
scripts/cardano-cli.sh 'cardano-address recovery-phrase generate'
scripts/cardano-cli.sh 'wallet.sh bootstrap_wallet out/ “<mnemonic sentence phrase>” “<password>”'
5. Burn tokens by running
scripts/cardano-cli.sh 'wallet.sh burn_funds out/ <wallet-id> <commitment> <amount>'
6. To verify the burn, run
scripts/cardano-cli.sh 'wallet.sh validate_burn <commitment> $(cat out/burn.addr)'
By running these steps, the outside world wouldn’t be able to know whether the transactions are a burn or a lock. However, after publishing this script, people might try to compile denying Redeemers that correspond to the proposed Redeemer script hash. Such actions would require serious effort but could eventually lead to the censoring of certain burns. In order to prevent this and make any breaches even harder, Iagon aims to make the solution even more secure as set apart hereinafter under section 4.
4. From a smart contract to wallet script
By leveraging the fact that most actions in a smart contract happen in the user’s wallet, the creation of an implementation that only uses the wallet might make the smart contract unnecessary. However, such implementation would have a practical implication, namely that selectively preventing smart contract transactions that correspond to burns would be impossible. But a censor wanting to prevent all burns could just block all scripts that try to burn anything.[8] By only ever using a wallet, the only way to censor the burns is to censor all Cardano transactions. That would be an ultimate resistance to censorship.
For this to work, we need to replace the public key hash with the hash of the commitment value and flip the lowest bit of this commitment. But this is not all. Cardano prevents typos in addresses by verifying its structure and CRC code. The easiest way to generate the address from the commitment is using the following script and Cardano API library:
burnAddress = do
commitment <- flipCommitment . sha3_256 $ arg
return $ serialiseAddress
$ makeShelleyAddress
network
(fromShelleyPaymentCredential (Shelley.KeyHashObj (mkKeyHash commitment))) NoStakeAddress
To see how it works, you can generate the burn address with:
export NETWORK=testnet
cabal run generate-burn-address -- "mySecretCommitment"
Afterwards you can submit the transaction to the Cardano blockchain with:
scripts/cardano-cli.sh 'wallet.sh send_funds out/ <wallet-id> <burn-address> <amount>'
In order to verify the burn, you need to check the transactions sent to the burn address by using the following:
scripts/cardano-cli.sh 'wallet.sh get_utxo <burn-address> | jq .'
Conclusion
This essay has set apart the implementation of a proof-of-burn protocol either as a smart contract or as a wallet transaction. However, Alonzo smart contracts don’t have the necessary infrastructure, like the PAB library, in place yet. Due to this, a wallet script is recommended. Nevertheless, once the PAB library, which will facilitate the development of Cardano-based applications in the near future, a complex smart contract solution with a combined wallet script might be more feasible in order to create an environment that could withstand potential scrutiny.[9] For those willing to do a deep dive on the solution, all info is available at Github.
⭐️ Download the PDF version of the 'Iagon's solution to the Cardano Proof of Burn Challenge' file 👉 here
P.S:
We just want to clarify to our community that we know Cardano is not going to burn tokens, and that the challenge was announced to the Cardano community as humour. We think it is important to clarify this, as to not lead to any misunderstandings as to our intention or the intention of Cardano.
Iagon saw the challenge as a good opportunity to explore and play with the Plutus playground, to better understand Cardano, and published our model for Proof-of-burn to answer the challenge and open up to peer review of our understanding of Plutus.
References
- C. Hoskinson. “Proof of Burn Challenge”, IOHK. August 2021, https://youtu.be/KaLZJs5Y_rE.; K. Karantias, K. Aggelos & Z. Dionysis, “Proof-of-Burn”,In 523–40, 2020. https://doi.org/10.1007/978-3-030-51280-
4_28. - K. Karantias, K. Aggelos & Z. Dionysis, “Proof-of-Burn”,In 523–40, 2020. https://doi.org/10.1007/978-3-030-51280-4_28.
- K. Karantias, K. Aggelos & Z. Dionysis, “Proof-of-Burn”,In 523–40, 2020. https://doi.org/10.1007/978-3-030-51280-4_28.
- C. Hoskinson. “Proof of Burn Challenge”, IOHK. August 2021, https://youtu.be/KaLZJs5Y_rE.
- Adams, Hayden, Noah Zinsmeister, and Dan Robinson. 2020. “Uniswap V2 Core.” Uniswap.org. 2020. https://uniswap.org/whitepaper.pdf.
Ismail, Leila, and Huned Materwala. 2019. “A Review of Blockchain Architectureand Consensus Protocols: Use Cases, Challenges, and Solutions.” Symmetry 11 (10). https://doi.org/10.3390/sym11101198. - Y. El Faqir, A. Javier and H. Samer, “An Overview of Decentralized Autonomous Organizations on the Blockchain.” In Proceedingsof the 16th International Symposium on Open Collaboration, OpenSym 2020, New York, NY, USA, Association for Computing Machinery, https://doi.org/10.1145/3412569.3412579. ; K. Fanning and D.P. Centers, “Blockchain and Its Coming Impact on Financial Services.” Journal of Corporate Accounting & Finance 27 (5), 2016,53–57. https://doi.org/https://doi.org/10.1002/jcaf.22179.
- The interface uses command line scripts. Once the PAB library is live, signing wallet transactions from web applications will be available.
- Since each new GHC version generates slightly different Plutus code, it would require some effort by the means of static analysis or CI/CD setup that checks script hashes. But it is theoretically possible.
- Cfr.: Infra
by Michał J. Gajda & Julian Ospald