The blockchain has seen a boom in popularity in the last couple of years and has introduced three fundamental concepts: Safety, Transparency and Scalability. But, how exactly does blockchain provide more security than traditional transaction processes? What keeps your transaction data safe? A big part of trust involves reliable authentication, improved security, scalability and reliability in online data authentication — and these are some of our tech devs biggest challenges.
Let’s take a look at how AppCoins improves security, reliability and scalability by using authentication frameworks, Merkle Tree-based structures and Address Proxy Contracts.
Authentication on Back-End: Immutable, Reliable and Secure
With increased cases of data leaks, fraud and phishing, authentication is a major concern of ours. How can we protect ourselves and users from such threats? The answer is blockchain technology, which is immutable, reliable and secure. At AppCoins, our tech dev team focuses on using the blockchain to authenticate in our backend.
There are two main flows on the AppCoins Protocol: Proof-of-Attention (PoA) and In-App Purchase (IAP). The first allows the user to receive APPC Credits, the latter allows the user to purchase items with either the APPC Credits that the user has earned before, AppCoins, Credit Card or PayPal. In these flows we have to identify and authenticate the user somehow, and to do so we use the user’s public ethereum wallet address and a message signed by that wallet.The wallet address identifies the user, and the signed message is used to authenticate. In our backend we check if the wallet that the user claims as his, is the wallet that signed the message. This proves he is the owner of the wallet — and that he is who he says he is.
The public ethereum wallet address is made of the last 40 hex characters from the public key prefixed by “0x”.
When the communication with our backend involves sensitive data, we need an extra layer of security: an authentication. In order to perform the authentication we follow a standard where the user signs a pre-established message with his private key.
The message is composed by 3 elements:
Ex: \x19Ethereum Signed Message:\n420x20286E1865b26dbC18393322D94cCaEB1A5983B6
- \x19Ethereum Signed Message:\n: predefined message by the standard
- 42: length of the message (the wallet address in our case)
- 0x20286E1865b26dbC18393322D94cCaEB1A5983B6: the message (the wallet address in our case)
From the signed message, we can calculate the user’s public key using the following function:
So, on the backend we end up with the user’s public ethereum wallet address and his signed message. From the signed message, we can get the public key using the previous algorithm. From the public key, we can get the wallet address, which we then check to make sure it matches the wallet address we got from the signed message, if it does, the user is authenticated.
Merkle Tree: How Transaction Verification Works
One of the benefits of using the AppCoins protocol is transparency. To do so, we register everything on Ethereum blockchain, including the transactions processed by our backend (off-chain transactions, for example). The problem is that storing data on the blockchain is very expensive so we have to store a summary of that data via what is called Merkle Tree based structures.
To create this summary we use a very important concept: Hash. A Hash function is a mathematical function that takes any input string (data) and outputs fixed sized alphanumeric strings called a unique digital fingerprint. The hash cannot be reversed to get the input data and therefore, it can be used to check the integrity of data.
As a general rule, the same input data has always the same output hash. In this case we have a collision where “John Smith” and “Sandra Dee” produce the same output. There are many different functions to calculate hashes with different characteristics, and here at AppCoins we are using one that ensures that there are no collisions. In order to explain the logic behind the algorithm we use to generate the summary of the data we store on the blockchain, we focus on an off-chain IAP flow.
The bottom line is, we select the important data from the payment, compile an hash using that data, put a bunch of hashes together, generate a new hash and register it on the blockchain.
The data we consider relevant is:
- Amount in Wei — the purchase value in Wei (ethereum unit)
- Address — buyer
- Dev — owner of the app where the purchase was made
- Store — android app store associated with the app that made the purchase
- Oem — the android device manufacturer
- Package_name — application identifier
- Sku — purchased item identifier
- Timestamp as %Y-%m-%dT%H:%M:%S.%f — purchase time stamp
- Country — where the purchase was made
Then we carefully generate the hashes between that data in the following order:
It’s important to keep this order, as any change in data will produce a completely different hash. The resultant hash, also known as transaction id, represents all the data in the transaction in 128 bits.
The python code used to reproduce the transaction id is the following:
The next step is to gather all the transactions for each involved Ethereum address, order them by time stamp, and create a new hash with those transactions.
In our case, the Data blocks are the transactions made by an app, the Top Hash is what we register on blockchain. So, no matter how many transactions per app we need to store on the blockchain, we will always register 128bits (the size of the final hash also known as root hash). In the end, all these hashes generate a merkle tree.
Address Proxy: Reliability and Updatability in One Contract
As you know, we use the ethereum blockchain and its smart contracts in order to build trust and transparency on the protocol. The only way to identify and call a smart contract is by using its address. The problem is that everything in the blockchain is immutable so, every time we need to update our contracts, we actually need to deploy a new one. In the past, every time we deployed a new smart contract, we had to update every other product in order to use this new smart contract. This is very time consuming!
To solve this issue, we’ve created an address proxy contract where all the smart contracts addresses are stored, just like you’d do to a DNS server. Then all we had to do was to change our products once to get the contract addresses from this contract instead of having it hard coded. This simple implementation saved us a lot of time.
Let’s say our front end needs to access our advertising contract, all it has to do is to use the following code:
If we need to deploy a new version of a specific contract, all we have to do is to update our contract proxy. This way our products are always up to date with our latest smart contracts since.
You can check this and more information on our documentation here.
As always, you’re invited to follow our work regarding all of the products we’re working on: