[Discussion] - (optional) native support of secp256k1 for new accounts


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?

  1. Ammer Card needs to obtain the secp256k1 public key from the card (hardware wallet)
  2. 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
  3. Ammer Card will then for each new transaction
    1. create a SpendTx based on the input provided in the app with nonce=0 (required for GaMetaTx)
    2. compute the tx-hash for the prepared SpendTx in a specific way which is required for the inner tx used in a GaMetaTx
    3. 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
    4. pass the hash to be signed to the hardware wallet
    5. receive the signed hash from the hardware wallet
    6. encode the calldata for the authorize entrypoint (authData) which needs to be provided in the GaMetaTx
    7. create the actual GaMetaTx providing the required details (GA address, authData, spendTx)
    8. 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 :sweat_smile:

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 :slight_smile:

If such integration is a huge pain for potential partners we should seriously discuss that topic.

With regards of the work flow, I don’t see how it can be simplified but I see an obvious way of improving it.

I believe the Ammer team is using this entrypoint:

  entrypoint to_sign(h : hash, n : int) : hash =
    Crypto.blake2b((h, n))

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.

Those are my thoughts, now I drag @hanssv.chain or @hanssv2 into this :smiley:


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 :sweat_smile:

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 :smiley:

should have been more a sidenote about the current state :stuck_out_tongue:

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.

1 Like

well, that’s one of the questions that would have to be answered in case there is a strong need to support secp256k1 natively.

I am actually not sure if it’s really worth the effort.

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…

I think that would be one (viable) implementation - basically instead of a contract (GA) you “attach” a secp256k1 key-pair.

1 Like

…and still keep the nonce

mhh, I think I need to invite devs from Ammer Card to judge if this would have helped them.

@hanssv.chain could we provide an easy way then to resolve the AE address then based on the private key of the secp256k1 keypair?

Yes, just send the private key to me and I can find it :stuck_out_tongue:

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 :thinking:

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 :sweat_smile:.

I don’t see any reason to disallow the same secp256k1 keypair from being reused on protocol level.

1 Like

true, we could provide an endpoint to return all secp256k1 accounts based on the provided secp256k1 public key.

I will try to figure out if this proposal would be beneficial over the “generic” GA. very interesting discussion :slight_smile:

just to be aligned → nonce-handling for secp256k1 accounts would then be handled by the protocol again, right?

1 Like

Yes, that would be the natural way, I think…

1 Like

maybe a solution for the future but not for now. crypto is about to go mainstream and these cards too. should not miss the moment.

next hf material? Governance vote would be needed.

1 Like

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

1 Like

This one I agree with both hands