In-game Private Key Management: Risks and Considerations
Authored by Colin Adams
At present, nearly 50% of active cryptocurrency wallets connected to decentralized applications are gaming-related. With GameFi kicking into high gear, ChainSafe is building out our Gaming SDK so that developers can connect to any EVM-compatible blockchain and use on-chain data to power their games.
While the new possibilities are unquestionably exciting, blockchain gaming brings new challenges around user keys and global admin keys. This article will touch on both of these related problems.
The first challenge is how to let users securely send transactions on various kinds of devices. Wallets often lack support on devices like mobile and desktop, raising questions around how users manage their private keys and sign transactions without them.
The second issue is that as more and more games get spun up, it's worth highlighting just how unsafe it is for developers to hard-code their keys into game binaries to authorize rewards for players.
This holds true despite how convenient it is when compared to alternatives. This is because it is not hard to compromise these private keys, which anyone can use to generate fraudulent digital signatures. Here is a quick example to emphasize this point:
The bottom line is for anything that's running inside a user's browser or local machine, an attacker can gain absolute control over it. Even if normal players have to abide by the rules of the game, players with special tooling can effectively alter any parts of the memory of the game. And if there is some signing logic embedded in the game, they can convince it to sign any transaction they like.
The above is important to keep in mind, but it should be noted that our signing tool is focused on the first challenge - user key management. Let's run through an example of how a conventional gaming developer might approach in-game private key management with the ChainSafe Gaming SDK.
⚠️ Note that this is a naive way of managing private keys. That is, DO NOT DO THIS⚠️. If you do, you risk user funds, you risk your reputation, and overall, you do more harm than good because if you or your user gets hacked, you can damage the reputation of the entire ecosystem.
-
An NFT is minted with metadata that refers to its stats, level info, and other traits (i.e., inventory or features) stored on-chain.
-
A player performs an action that necessitates a metadata update. For example: leveling up or stat redistribution.
-
A transaction is signed and sent by the key in the game binary to update the metadata. And in order to avoid player exploitation of a level-up system, on-chain metadata can only be updated through the onlyOwner method in Solidity.
-
The transaction is sent from the account associated with a private key stored within the game binary.
Why might a developer want to do this?
-
This methodology abstracts things away from players. In other words, players no longer have to validate and sign for every interaction themselves. (Imagine having players sign for every interaction that happens in an RPG where a player levels up or distributes a stat point to their dexterity category 😱 . It would aggressively violate the time-to-fun principle.)
-
It's fast to implement. Interest is intensifying for in-game signing and sending, and this would be one of the fastest routes to doing it.
Easy peasy, right? Those pros might make it seem worth taking this risky approach. Not so fast.
Let's look at why you should definitely not do this.
-
Adversarial users have access to the private key. When we ask ourselves where we should be storing private keys, it should always be in a system that is as secure as possible and has been secured such that there are fewer possible points of failure. By having the private key (in some format, somewhere) stored on a user machine, you are in effect giving them the key -> as it is impossible for us to secure a client's machine.
-
Adversarial users have control over the game state. In this specific context, as the key we are storing in the client presumably has onlyOwner style permissions for the contract containing associations with NFT tokenIDs and their metadata, it is essentially giving each user the potential to control the entire game state. Recall the video example above.
Again, it's worth highlighting that a developer that's not thought deeply about key management might consider the previous approach acceptable. We're here to warn you of the potential risks in doing so. There's a reason why conventional game devs working on MMOs still have to jump through hoops - such as requiring a server or centralized service to hold the admin keys and conduct fraud detection.
An aside: are there blockchain games without game servers?
Therein lies the paradox of blockchain games - decentralization is a worthy ideal, but centralized servers still have the advantage of being able to deal with signing and anti-cheat without the need for complicated proof systems.
As we see it now, a blockchain is not a replacement for a game server, although it may complement it. If we want to create fully decentralized p2p games, we need sophisticated tools to ensure people are playing with each other and earning rewards fairly. That is why zero-knowledge technology like zkSNARKS is relevant; they prove fair play in a fully p2p context.
There are only a few very special cases where developers have developed a truly decentralized game on a blockchain without reliance on central game servers. One such example is Dark Forest, a decentralized turn-based MMO strategy game built on Ethereum with zkSNARKs.
It's worth noting that the game wasn't built from the ground up with conventional "fun" in mind. To this day, Dark Forest continues to be an experimentation in what one can make as a game to exist exclusively on a blockchain using zero-knowledge methodologies.
Announcing the experimental in-game key signing branch of the Gaming SDK repo and a call to action.
Edit: An earlier version of this blog post mentioned an experimental branch for direct signing with a private key. This branch has since been deprecated.
We're releasing an experimental branch of our repo as a security research tool and asking our community to work with the lower-level utilities to develop a forward-thinking wallet solution that can be used across platforms.
By installing this version of web3.unitypackage, you will find under the Prefabs → Wallet folder a "Send Transaction" prefab that will allow devs to sign in-game transactions with a user's private key.
Check out this demo:
Our developers would like to issue a call to action for our passionate gaming community to show us - if it's at all possible - how to allow for in-game private key signing that's secure and robust.
Try out the utility, share your ideas in our Discord's #web3unity-gaming-general channel, and make pull requests to our repo with secure signing logic by leveraging what we've shared in this article. Go get ‘em.
About ChainSafe
ChainSafe is a leading blockchain research and development firm specializing in infrastructure solutions for the decentralized web. Alongside client implementations for Ethereum, Polkadot, Filecoin, and Mina, we're building a portfolio of web3 products - Files, Storage, web3.unity, and more. As part of our mission to build innovative products for users and better tooling for developers, ChainSafe embodies an open source and community-oriented ethos. To learn more, click here.
Website |Twitter |Linkedin |GitHub |Discord |YouTube
Acknowledgments
Thanks to Stephanie Zhang, Alessandro Voto, Willem Olding, and Tim Ho for their help in writing this article.