Using proof-of-work and hexadecimal to improve the verifiability of Web3 actions
Computers talk in bits (or bytes), humans prefer actual letters and languages. It's hard for humans to see what's going on inside a computer.
When a user Alice makes a blockchain transaction, she is traditionally shown a transaction hash. Alice can then use this transaction identifier to check on a block explorer that her action was correctly performed on the blockchain.
Important note: Alice, in this case, has to trust the block explorer because a malicious block explorer could show a fake action that never occurred and Alice would believe that it actually happened as a block explorer is just a website just with data and no way to quickly check its correctness for a human.
An alternative way to think about this is a phone infected with malware: The phone could display a message stating that an action “A” occurred, when indeed a malicious action “B” occurred.
This lack of visibility and verifiability opens up a whole can of worms of attacks. What if your phone is telling you that you voted for candidate Bob in an election, but it’s malicious and cast a vote for candidate Charlie instead?
To make this type of checking easier (along with other reasons), blockchain apps use the hexadecimal number system that allows humans to have a more compact and visual (i.e., easier to read) representation of wallet addresses, transaction hashes, etc…
Hexadecimal?
Hexadecimal is a type of number system, that has a base value equal to 16. What does this actually mean? It means that each digit is encoded in 5 bits and it can be represented by a total of 16 possibilities. Concretely: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, and f.
The main takeaway from this post is the following: We can leverage the fact that we have these letters and numbers and use them as an alphabet to denote specific actions performed on a blockchain. Let’s look at what this could look like below!
Human Readable Map
We have the regular letters from hexadecimal, so we’ll keep those:
a → a
b → b
c → c
d → d
e → e
f → f
We have some numbers that can be used for other purposes as they can visually look like letters. This was used a lot back in the day to make ‘Leet’ usernames and words. This is what it could look like:
0 → O
1 → I
2 → Z (this one may be a stretch)
3→ E(we already have this letter)4→ A(we already have this letter)5 → S
6 → G
7 → T
8→ B(we already have this letter)9 → ?
How to use these values?
For example, the words “good”, “bad”, and “bid” fall under this alphabet. The first two words can be used to encode a positive/negative vote on a block explorer. Meanwhile, the last one is enough to be used in specific bidding smart contracts.
How to generate these values?
Traditionally, in a blockchain setting, the user has some flexibility regarding what to submit as an input. For example, users create an ECDSA signature to perform a transaction. Moreover, such a signature uses a random nonce. Client code can be tweaked to allow for such an encoding while preserving the same security levels. This can be considered a client-side “proof-of-work” (PoW).
What to do with this?
Honestly, this was just a realisation I had recently while I was trying to make actions on a blockchain more readable (e.g., online voting). There may be more interesting use cases or interesting words that can be encoded. Do, however, keep in mind that the longer the word, the more work has to be done on the client-side, thus affecting the usability.
Would this kind of approach be vulnerable to the same kinds of attacks we've seen against vanity address generators? I am assuming that in order to make this work, whatever function is generating the hash would have to keep at work until it generates the *right kind of hash*. I imagine this isn't something you'd want to do with every transaction (but it could be I'm just misundersatnding).