This topic popped up recently when the team of https://ammer.cards started working on the integration of æternity into their hardware wallet which we just recently showcased at the Token Summit in Liechtenstein where æternity was Platinum Sponsor.
Currently, due to the lack of native support for secp256k1 for accounts & signature verification, the integration MUST be handled using the Generalized Account feature of æternity. This in general works very good and this is definitely a good showcase to highlight this protocol feature. However, this scenario isn’t really convenient right now.
How does it work currently?
Ammer Card needs to obtain the secp256k1 public key from the card (hardware wallet)
Ammer Card will convert a regular, plain-old account into a Generalized Account which means a contract is being attached to account which now handles the authorize logic for this account
this is handled via the GaAttachTx type where also the secp256k1 public key needs to be provided because the contract needs to be able to verify valid signatures based on this curve
the contract uses the Crypto namespace provided in the standard library of Sophia to verify a valid transaction
Ammer Card will then for each new transaction
create a SpendTx based on the input provided in the app with nonce=0 (required for GaMetaTx)
compute the tx-hash for the prepared SpendTx in a specific way which is required for the inner tx used in a GaMetaTx
call a specific entrypoint of the contract behind the GA to obtain the actual hash which is quite hard to do without going that route
pass the hash to be signed to the hardware wallet
receive the signed hash from the hardware wallet
encode the calldata for the authorize entrypoint (authData) which needs to be provided in the GaMetaTx
create the actual GaMetaTx providing the required details (GA address, authData, spendTx)
broadcast the GaMetaTx to the network
A complete example how this process looks like using the Java SDK can be observed here:
the Java SDK (which is used by the Ammer Card team) currently does still rely on a http compiler to compile contracts and to encode/decode calldata
of course this can also be achieved with the recommended and actively maintained JavaScript/TypeScript SDK, there is just no usage guide written down for this specific example right now
It works, so what’s the problem?
If you follow the steps and the example highlighted above there is a lot of overhead required to achieve a quite simple goal. The team of Ammer Card anyway integrated this into their application and thus we can now happily use a cool hardware wallet to send and receive Æ as well as other cryptos.
However, supporting secp256k1 natively would have made it much easier for the Ammer Card team to integrate æternity into their system.
Personally I think there is one issue in this specific case when you made a backup of the private key of the wallet and you lose the card. You would definitely want to recover your account and get somehow access to it, right? Following things need to be considered:
the address of the GA cannot easily be recovered just by knowing the private key (because it’s based on secp256k1)
the address of the GA must be known or fetched in some way from the Ammer Card app on your smartphone OR the Ammer Card support team can provide you the correct address OR you can remember/lookup the GA address based on some activity you know that the account perfomed (e.g. a claim of a specific name) OR you try to obtain that information via an indexer like e.g. the ae_mdw where you could try to find the information about the secp256k1 public key through looking into the params provided in a GaAttachTx
Feedback / Opinions
Personally I don’t really have a strong opinion on that one. I know and see that this procedure is quite an overhead. I am actually very interested in the opinion of the core developers about this. I remember discussing it shortly with @dimitar.chain before the Æternity Universe Two conference
I think we have a lot of other important topics on the plate and this would definitely be another and probably also big one.
Independent of that I absolutely LOVE æternity being integrated into Ammer Card and I am happy to support their team in any way
If such integration is a huge pain for potential partners we should seriously discuss that topic.
Since they are calling an external compiler and maybe after that dry-running the call itself, I can see how this could be slow. It would be great if this could be implemented in Java so there would be zero overhead. What would be missing though is the correct nonce. This now has two different trains of thought - if the wallet is the source of truth - it could keep the nonce locally and happily use it. I would consider this approach to be wrong as the source of truth should be the blockchain itself. Even if the only producer of transactions for this address would be this particular wallet, still transactions could be posted on the network and still not make it in a block so we can not rely on the wallet’s cached value. Please note that this is the case not only for GAs but also for basic accounts. The difference with native support would be that there would be no encoding of call data (currently done via a network call, something that could be improved as you said), and no production of a MetaTx.
I think having GAs had the goal of exactly that - supporting various authentication methods.
thanks for your feedback @dimitar.chain. I know there is definitely room for improvement on SDK side. it’s not only the hash function but also the encoding/decoding of the calldata.
the setup-workflow in general is quite complex and thus the question is raised if it makes sense (and is worth the effort) to support secp256k1 natively.
for the actual GaMetaTx you are absolutely right. if the SDK or the Java application can handle the blake2b hash function and knows about the nonce of the account a call to the contract to obtain the current nonce wouldn’t be required. so this could improve the process. actually the wallet should be the source of truth, so nonce handling could be done locally. only if you detach and (re-)attach the hardware wallet the app would probably have to obtain the current nonce once.
as we see and as you pointed out it can be achieved to use secp256k1 for signing valid transactions using GA.
the question remains if it’s needed and worth the effort to introduce native support for secp256k1.
I strongly disagree with this. Imagine the following example: Alice creates a tx and puts low gas price, so no miner pickes it up and includes in the blockchain. Or there is a TTL set and the transaction is not included in a block till the height it is reached. In those cases the wallet thinks the nonce had been used while the transaction is not yet on-chain and the nonce is actually not yet used. The wallet should not be the source of truth regarding the nonce, the blockchain should be. So even if the process is greatly improved, a wallet shall check with the blockchain which nonce is to be used, no matter if GA or a basic account.
Let’s not dwell on the topic of HTTP compiler and slowness, any serious programmer can do the native implementation for a particular hash/calldata in a couple of hours… I agree the GA use case is a bit complex, but not unreasonably so.
For the question/idea about native support for secp256k1 - what would be the native way? secp256k1 is different from ed25519 when it comes to key size, etc. How would you identify if an account is secp256k1 or ed25519, etc?! Once you decide on these details you can start thinking about the cost of implementation
Also another option would be to lobby for an implementation of ed25519 in hardware wallets… I think secp256k1 happens to be some de-facto standard, but I don’t know if there are any fundamental blockers (apart from the normal incompetence/unwillingness to change)…
true, forgot that it cannot really stay in a pool of tx in this case
that’s definitely not part of the secp256k1 discussion and should not be discussed here
should have been more a sidenote about the current state
that would be the ideal solution, sure. I think most industry standard cryptographic chips are just not able to handle ed25519 curve right now. didn’t dig too deep into that topic yet.
anyway, I brought the topic up for discussion. as already mentioned I don’t have a strong opinion here.
The key size is a really big topic, as this will touch literally every code piece in the node itself. This would be an enormous refactoring and I don’t really see the added benefit.
@hanssv.chain maybe if we have another GA-like transaction saying “this account will be a secp256k1 account” so we would have basic, GA and secp256k1 authentication methods. I still don’t see how this would be providing any additional functionality for the blockchain opposed to what GAs already provide. A shortcut - yes, new functionality - not really…
Yes, just send the private key to me and I can find it
On a more serious note, No, there wouldn’t be a quick way to lookup in that direction without something extra. But it sounds like a job for the middleware to index all the “attach secp256k1” calls?! Then you could lookup address from secp256k1 pub-key.
we could actually already do that “somehow” by parsing the existing GaAttachTx with the middleware. but would be cool to have a more streamlined way to achieve this.
also one question would be if we’d allow the same keypair to be used in different accounts
I doesn’t get more streamlined than having an API in the mdw to do this?? The node itself should not keep this kind of information I think, not part of core .
I don’t see any reason to disallow the same secp256k1 keypair from being reused on protocol level.
I think we should also discuss with Ammer Card team on this one of that would be a better solution. but in general I think it makes sense to have a specific type of GA for the secp256k1 keypair.
still somebody would have to execute the AttachSecp256k1Tx (or however we would call it). of course this could be done by some service in the backend using the PayingForTx which we already tested successfully with the ga-multisig contracts. works pretty well.
a huge benefit over the current approach would be the nonce-handling on protocol level IMO