Skip to content

Instantly share code, notes, and snippets.

Last active October 13, 2023 09:27
Show Gist options
  • Save norwnd/890ad642985f4e9e9f7b1dd243b21f9e to your computer and use it in GitHub Desktop.
Save norwnd/890ad642985f4e9e9f7b1dd243b21f9e to your computer and use it in GitHub Desktop.
Decrediton 2FA, hoddle safely!

I have an idea I want to discuss (and maybe turn it into a proposal I'm willing to work on), apologize for the long text ahead but, I've been thinking about implementing 2FA for Decrediton lately (as nicely outlined here - - it doesn't help to make your Decrediton funds more secure) but rather simple 2 of 2 multisig based one (it's also better than your typical 2FA security-wise).

There's even an old ticket about it - decred/decrediton#2147, the gist of it is: having significant portion of your wealth tied to single secret if far from ideal (and in case of Decrediton, while many might not realize it, your seed is almost as good as your password - meaning if you pick small length password you don't want somebody to get hold of your encrypted dcrwallet data, which can happen if your laptop gets stolen). Hardware wallets help a bit, but you have to trust the device and staking is not supported yet. Ideally for cold storage somebody would use multisig solutions (maybe Casa or something similar), but it's hard/expensive to set up and I haven't seen anybody in Decred community mention anything like that (probably none support Decred so far). So, considering all that, multisig-based 2 Factor transaction signing might be a nice middle-ground (easy to set up and use, and much safer than what you currently have with Decrediton).

Note, I'm using the following terms: "key", "seed", "seed phrase", "secret" pretty much interchangeably (hope the meaning is clear from context).

How I see 2FA should work

Decredtion will adopt new concept of 2FA account = "cold storage", just like it currently has default/unmixed/mixed accounts = "hot storage" (if you aren't familiar with cold/hot wallet terminology you probably should be - google it, or see FAQ below). 2FA account will be controlled by 2 signers: Decrediton signer (a separate account on your Decrediton seed basically) and Android signer (it could be any other external signer device, Android phone is probably the best one to start with). Ideally user will learn about 2FA account during Decrediton setup, and will be suggested to do create it in the following way:

  • he clicks Create 2FA account button in Decredtion
  • he'll be asked to install Decrediton2FA app from PlayStore to set up 2nd Android-based signer
  • Android app will generate 2nd key for the user independent of Decrediton key; user can also import his previously used Decrediton2FA app key in case he already has 2FA account and is just restoring it; user will backup his Android private key as seed-phrase ofc (just like he stores his Decrediton key backup)
  • user needs to type in his Android pub key into Decredtion app, or even simpler, he can scan QR code Android app displays if he has web-cam on Decrediton machine, and then user will confirm that he indeed typed in pub key correctly by scanning QR code Decrediton shows with his Android device
  • (maybe optional) Decrediton will display a QR code to share it's 2FA account pub key with Android Decrediton2FA app, user scans it and so the 2FA account setup i Now we can generate our multisig 2FA address to receive funds into it and sign multisig send/ticket-buy transactions
  • to sign a transaction user needs to initiate it in Decrediton and then scan QR code with his Android app, Android app will add 2nd signature and publish transaction
  • for maximum security user needs to receive/send small amount of funds to/from his 2FA account, before doing larger sums

The user could be educated/encouraged to store the bulk of his funds in 2FA account (instead of mixed account) because it is strictly better security-wise and it has almost same ease of use it has a different set of trade-offs actually (for trully secure custody you'd need a 2 of 3 multisig at a minimun with different signer implementations: Trezor/Ledger/Decrediton/AndroidApp/whatever). There are some privacy-related considerations but I think these are addressable (e.g. to continue encourage mixing user will only be permitted to transfer funds into his 2FA account from mixed account; buing mixed tickets directly from mixed account is not compatible with 2FA account though, user can continue doing this at his own risk).

Implementation details for techies

Reiterating 2FA account setup flow again, from engineering standpoint.

  • user clicks Create 2FA account button in Decredtion
  • he'll be asked to install Decrediton2FA app from PlayStore to set up 2nd Android-based signer
  • Android app will generate 2nd key for the user independent of Decrediton key (which is where security comes from; the key will be encrypted with password similar to how dcrwallet stores keys); user can also import his previously used Decrediton2FA app key in case he already has 2FA account and is just restoring it; user will backup his Android private key as seed-phrase ofc (just like he stores his Decrediton key backup)
  • user needs to type in his Android pub key into Decredtion app, or even simpler, you can scan QR code Android app displays if you have web-cam on Decrediton machine (probably better to encode it as some word-phrase so he'll just type in 12 words or something like that), and then user will confirm that he indeed typed in pub key correctly by scanning QR code Decrediton shows with his Android device (thus fetching the pub key value Decrediton decyphered from those 12 words, and comparing against his pub key)
  • (this step can disappear if we pass 2FA account pub key along with partially-signed-tranasction-QR-code; although, that means Android app won't know Decrediton pub key until very first 2FA-account-send and I'm not sure just yet whether it's a dealbreaker or not) Decrediton will display a QR code to share it's 2FA account pub key with Android Decrediton2FA app (because Android app will need it to sign transactions later, I think), user scans it and so the 2FA account setup is done! Now we can generate our multisig 2FA address to receive funds into it and sign multisig send/ticket-buy transactions
  • to sign a transaction user needs to initiate it in Decrediton and then scan QR code with his Android app (QR code will contain partially signed transaction, aka 1 of 2 signed), Android app will add 2nd signature and publish transaction (currently I'm thinking about publishing transaction through dcrdata, but better-privacy alternatives are also possible eg. 2 of 2 signed transaction can be encrypted to Decrediton pub key and copied to clip-board or presented as QR code for user to move it to his laptop where Decrediton is running, decrypt and publish from there)
  • for maximum security user needs to receive/send small amount of funds to/from his 2FA account, before doing larger sums; this is because 1 of the signers might have already been compromized all along, and while hacker can't steal the funds he might interfere with 2FA account setup such that neither him (because he won't be able to produce 2nd signature form uncomprozed signer) nor you won't be able to access funds sent into 2 of 2 multisig, unless you cooperate ;D

I've done some experiments with Decred multisig transactions, and at this point I feel pretty confident that it's doable:

  • dcrwallet has most multisig-related functionality working already (allows to generate and import 1 multisig address, tracks its balance, allows for signing multisig transactions and so on); sending arbitraty-amount transactions needs to be implemented, ticket buying needs to be extended/adjusted (but I managed to buy a ticket with multisig funds, and it should redeem back into that same multisig address (so effectively funds never leave user multisig 2FA account when user is staking!) -, and perhaps some other functionality added to dcrwallet (Decrediton interface will need to accommodate all the UI-related changes too, but given it already has the concept of multiple accounts it should be more-or-less a natural extension)
  • QR code based data passing is chosen for convenience (many people have access to Android device, or can purchase one), it should fit these requirements (I think it can store enough data for simple transactions / ticket-buys, the only potential issue would be laptop screen resolution/brightness & Android camera precision, we need to test QR code scanning on more devices - on mine I managed to scan 512 bytes of hex data encoded to QR as text quite easily); you have to bring devices to the same place, but you don't need to connect them through internet or cables (Android device could even be offline signer, once the app has been installed)
  • the user will need to store an additional seed (for Android signer app), Android app will have typical secure-seed-storing-instructions for this just like any other crypto-wallet app does, securely storing 2 seeds shouldn't be much harder than storing 1 ... and if the user is lazy he can store 2 seeds together (I don't advise) and still benefit in many ways
  • I'm not 100% sure how well tested Decred/dcrwallet multisig functionality is to "put your life savings into it", but since receive/send/buy-ticket functionality is pretty simple there shouldn't be edge-cases that show up after common scenarios have been tested (but I'd appreciate feedback on that), and some straightforward sanity checks can be put in place on dcrwallet side (e.g. for ticket buys from 2FA account dcrwallet must make sure that source address always matches receive address, since you always want your funds back in your "safe" multisig account); on Android app side, everything should be opensource of course (potentially with a separate command-line tool implementation in case Android app gets censored or something), but doesn't have to since your Android device holds only 1 of 2 secrets; and we'll probably want to use gomobile to compile decred signing libs so we don't have to rewrite it in another language, which is error-prone (I've had some experience with compiling Golang for execution on Android in the past, so it should be reasonably simple)
  • I think it will be possible to use this 2FA account with your hardware wallet based Decrediton setup (but current limitations of hardware wallet not yet supporting ticket purchasing probably apply until resolved on hardware wallet side)

In summary

Leaving aside ad-hoc home-grown multisig solutions (available to few skilled devs only, if they even bother to implement it for themselves) this one has all the potential to become The safest way to hoddle/grow your DCR position, assuming it is supposed to be a store of value.


Hot wallet, cold wallet ? give me a real world analogy

Suppose we'd have a perfect bank in our world.

If you store all your money in that bank - it is your "cold" storage (2FA account). It isn't convenient to go to your bank and withdraw some cash every time you need to buy some milk or whatever, you'll visit your bank every once in a while and withdraw a sum of money that'll get your through a month or two - that's your "hot" storage (non-2FA accounts in Decrediton), it's easily accessible and you can loose quite easily too.

Next to ticket-buying, ... you also can visit your bank every once in a while and sign some paper with the pen that's sitting in your cabinet there which helps the bank running and rewards you (= buy a ticket); you don't need to take that pen out of the bank and sign with it at some other place, you don't want to loose this pen while carrying it because this is the pen they'll ask you to sign with when you need to withdraw any funds from that bank.

Compare that to what you currently have with Decrediton - which would be similar to you storing all your money in cash at home, or maybe in your pockets.

Will my 2FA account work with auto-ticket-buyer, auto-mixing or with dex orders

What I've described in this proposal is offline signing solution, you essentially combine your signatures offline in asynchronous manner,

it won't work with mixing or automatic ticket buyer because those need your private key (the 1 key responsible for your funds) to stay in memory unencrypted while those ticket-buyer/mixer programs run ... which is their weak point. It also wouldn't work with Dcrdex orders that need your wallet to stay unlocked in just the same manner while order is in the book (so that automatic code could react to the match if/when it happens).

So this offline signing solution requires manual ticket purchasing (if you are managing many tickets perhaps you'd want to buy them in batches), and will work with mixed account in a sense that you'll have to choose what funds you want to mix manually (I think the following funds flow between your accounts should be private enough: unmixed -> mixed -> 2FA -> unmixed; if you follow these transfer rules and enforce it through Decrediton UI you'll get roughly same privacy gurantees you currently have there, but you'll have to choose how much of your funds you want to keep in 2FA="cold wallet" and how much to temporarily place in other accounts="hot wallet" at any single time)

I think potentially one can come up with online synchronous signing solution (your signers will be online all the time, and start communicate online once something matched and they all need to sign) later on, but it's much harder to implement, set up and make sure they can communicate in robust manner - so I guess better start with simpler one, see how it works, and maybe then think about online signing.

How will my ticket-buying behavior change with 2FA account ?

For me personally ticket buying would work exactly as it does now, except for that additional 1 minute approve step with Android device, but if you are a whale ... you'll have to do a lot of manual ticket-signing, true ... but you do it for additional security not for fun,

and you still can fall back to auto-ticket buyer if that's your style.

Compare it to something like SeedSigner

I personally didn't use SeedSigner, but there is a youtube vid that was brought to my attention -, I'll point out couple differences with 2FA account setup I'm suggesting

  • in that vid SeedSigner funds are still tied to single seed (or so it seems, cause he doesn't mention anything about sparrow-wallet seed/setup), you show that backup piece of paper to somebody and funds are gone, so in terms of security gurantees it's more like Trezor, I believe 2 of 2 multisig setup is much safer (and you could, potentially, use Trezor-backed Decrediton signer in the future)
  • using Android device would provide for better UX and it's much more accessible; in far future, potentially, you could use a SeedSigner-like device as your 2nd signer

Should you keep your Android signer and Decrediton machine in two separate locations ?

It depends on whether you want more security, or better UX,

if you have both your Decrediton machine and mobile signer stolen - then using this 2FA setup only marginally helps you (attacker will need to hack both, you'll have more time), but in practice you'll probably either:

  • carry your phone with you, while Decrediton machine will stay at home (or some other place)
  • or you'll purchase a separate cheap phone specifically for using with this setup (which would also probably provide better privacy) and store it far from your Decrediton machine

Do any other coins have anything like this already ?

I personally haven't seen crpyto wallet with such a simple multisig setup as would be possible with this feature (haven't used many Bitcoin wallet, but I think is considered to be a gold standard there - and it's quite a bit more involved and even more secure solution),

but I expect many will appear in the following couple of years, secure custody is one of the biggest pain-points in crypto - so, many people are working on it, and I presume smart-contract based platforms will have an advantage long term - there you can encode quite complex smart contract logic (e.g. to implement inheritance and so on),

although the quite important goal of what I'm suggesting is to get a decent balance between security and ease of use (such that even non-tech users will benefit from defaults).

If one or both of the devices (Decrediton machine, Android phone) are lost, can everything be automatically recovered just using the two seeds?

Yes, that's the point of it, exactly 2 seeds are needed and sufficient to recover,

  • the Decrediton seed - imported as it's currently is with Decrediton
  • and Android app seed - imported with same Android signer app

even if 1 of your "paper" seeds is compromized, the funds are still safe, but you better move your funds out into newly setup 2FA account (since you don't want to keep it in 2FA account with 1 seed being compromized for too long).

Wouldn't it be better to have a separate wallet managing cold storage (2FA account) ?

Having a separate wallet is probably higher maintenance for most users. User can set up standalone 2FA-account-only wallet if he wants, I'm not sure if there are any benefits though (and he'll need to take extra care when sending funds between his 2FA wallet and other wallets he has if he wants to preserve privacy).

What about multiple Android signers for same 2FA account ?

If having a "readily available 2nd signer backup (instead of having to restore it from your Android app seed)" is what you are after, you'll be able to easily import the Android app seed generated for you by your 1st phone and put it into your 2nd phone (right at 2FA account setup stage, or even later - since you'll have a "paper" backup you can use it any time) with the design outlined in my doc.

If you want to have a completely separate 2nd Android signer (with a separate seed that's not same as your 1st Android signer seed) then I think it's possible to extend my design to have this as an additional feature (that'll probably be 2 of 3 multisig instead of 2 of 2):

  • it's a bit harder to use, and harder to implement, but
  • it could actually somewhat help with the 2nd issue outlined below (somewhat - because ideally you'd wanna run a separate 2nd signer implementation and not just another Android signer, because Google Play Store might deliver hacked apk to both your 2nd signer Android devices)

So, are there ANY issues with 2FA account ?

  1. Since you now have a 2nd device you could leak your privacy with - there is that. Care needs to be taken implementing this feature to avoid privacy leaks, as long as implemented correctly there shouldn't be any data leaking from Android signer app. If you are worried that somebody might "hack/read" into your app you can (and should) buy a separate phone that doesn't have your personal info on it to link to and use that (but to use Google App Store you'll still need to have/create fake Google account, or you can install .apk directly yourself).

  2. Even if you are successfully receiving/sending from your 2FA account it doesn't truly mean that 2 seeds you wrote down are indeed encoding those private keys that sit in your 2 apps and sign transactions for you. The hacker could have comrpomized 1 of the apps before the app displayed your seed, hacker can screw you by showing you a different seed than the one encoding your private key (while stealing away the real one for himself), thus when you'll try to recover from seed phrase you'll won't get that same private key that's controling your funds (hacker might contact you and try to pursuade you to cooperate and unlock the funds to, say, split it with you half and half ... so there is a motivation to hack like that too). I think this isssue is unaddressed by almost all the wallets out there, including Decrediton and hardware wallets. 2FA account simply makes it worse by expanding the attack surface from just one to two software pieces. The way you can protect your 2FA account from shit like that is to restore your Android app seed with a separate command-line singer implementation (just make sure to run it on macnihe different from machine running Decrediton), if resulting pub key matches with the pub key controlling your multisig address (matches one of pub keys present in redeem script for that multisig address) your Android seed backup is good (if it doesn't match - you've been hacked!). This is a hell of a check to pull of for an average user (even if we design for it), but it can be done, and it's somewhat similar to "manually verifying the binary you are running". It would probably be harder to check Decrediton app itself in the same manner since there isn't a 2nd implementation (you might try restoring Decredtion seed with another/earlier Decrediton build, if you trust it more than, say, the latest one; but you'll need to do it on yet another machine, not the one running Decrediton or the one you've checked Android seed with), so verifying Decrediton binaries is probably the best you can do for Decrediton - which is the current standard.

Thus, to get the ultimate security/privacy out of 2FA account you'll need to:

  • have/buy an Android phone pretty much dedicated to serve as 2nd signer device
  • download .apk and verify it (similar to how you'd verify Decrediton binary), manually install it on your dedicated Android phone
  • (perhaps doesn't really do much, if you isntalled .apk manually) download command-line signer utility, verify it, run it on machine different from Decrediton machine to check Android-generated seed recovery is working as expected

This ^ is probably not what an average user would do, but the fact that you can do it and it's not too difficuilt gives me hope. I'm not entirely sure though that default 2FA account setup an average user will go for (with his everyday phone, installing app from Google Play without additional verification) is better than just using Decrediton as is, or with hardware wallet. Perhaps if we deem Google Play delivery method too risky we can force the user to intall .apk manually, making this feature advanced-only.

Long-term we need Decrediton with generic multisig support, right ?

Right, ideally you'd have a multisig across many different wallets (typically hardware wallets) and spread them apart in physical space too, and touch those only rarely. But Decred ticketing PoS system is still an obstacle.

While I'm pro-PoS overall, it seems the way it currently works (with ticket buying) would still be significantly prohibitive for truly secure custody, you can't spread signers apart and keep buying tickets ... but then again you might look at ticket-buying similar to what PoW is - which is a business of securing, say, Bitcoin network with certain risks and rewards. So you'll have to choose whether you want to risk staking or not. That's not how mainstream looks at PoS right now though - the "norm" seems to be you don't really bear the risk of loosing funds when staking (you might have a risk of slashing, but that's a different thing), eg. decred/decrediton#1491 (comment) pretty much summarises my initial impression of Decred with respect to secure self-custody (and probably still does with ~7% inflation).

Or maybe Decred protocol can change to facilitate voting with multisig, I see couple of ways to go about it:

  • for example, there would exist special on-chain protocol-embedded smart contract that serves as multisig wallet that can also buy tickets for you, similar to how ticket auto-buyer works, with it you can receive funds, change ticket-buying settings, send funds somewhere else, all of these actions requiring M of N signatures and are really needed only once per action; plus there would be a single voting-key (which you can also provide to VSP) responsible for the voting side of things - while single key for voting isn't perfect, if you loose it (or somebody steals it) you still have the control of all of your funds, and can just move them to another wallet (or maybe rotate voting key, if multisig smart contract supports it)
  • or it might be even better to reconsider whole ticket-buying approach, even for a simple single-private-key wallet (while it's an interesting way to gamify PoS, and it's fun for people buing their 1st or 2nd ticket) it is still an additional, unnecessary effort on user-side; plus, for hardware wallets (Trezor, Ledger) ticket-buying is more cumbersome process compared to using software wallet (because you unlock seed with software wallet just once, unlike with hardware wallet where pretty much every operation needs a separate physical confirmation on device)

Note, compatible with the way current ticket-based Decred PoS system works, 2 of 3 Decrediton+AndroidApp+Trezor/Ledger multisig setup seems like a viable option too (you can do daily operations in Decrediton with the help of AndroidApp, yet still have Trezor/Ledger device in case Decrediton/AndroidApp fails in any way - eg. as outlined in 2nd clause here). Compared to 2FA approach described above it's quite a bit more complex to implement, and from user perspective it's more burdensome to setup/recover such a wallet, but otherwise it has all the same benefits of secure and simple daily use (although, if you go for 2 of 3 multisig setup, using Decrediton+Trezor+Ledger would probably be even better, there is no need for AndroidApp signer as long as at least 1 of Trezor/Ledger supports ticket-buying and has a screen to show the user what he is signing). Still, one has to sign up to 3 transactions when buying ticket (split_tx+ticket_buy_tx+fee_to_vsp_tx, but perhaps can be done in 2) which is far from ideal UX, with AndroidApp being 2nd signer in 2 of 3 setup that can be easily hidden away from the user since we can write Android software, with hardware wallets I'm not so sure.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment