Replay Attacks and possible mitigations

True, you do not need personally to have a contract with everyone, but all the intermediary nodes have also smart contracts with each other on chain. So I think in the end they al use 2 of 2 inputs, so they can only steal from themselves. Basically you can make any hops in the LN network, you can use even multiple branches, but they all play by the same rules. As least if I understand LN correctly

Yeah, it is entirely possible that NRD replays are not an issue at all. I dont understand it well enough

True, same here. In the end only an expert can give a definite answer. I do know an expert on LN but he is not into Grin nor close enough to ask for favours.

Another, possibly orthogonal issue to the restore. We need to think about child wallets in the context of replays and its handling. If I’m a parent and I derive a child wallet for my son and give him some utxos, if he receives some outputs, I’ll also see these UTXOs in my wallet. It’s hard to judge whether this should be labeled as unsafe or not and if I decide to self spend these UTXOs, I took money away from my son.

Is it possible to detect it is an output of a child wallet and hence mark it as safe?

Definetly possible. Just treat it as any HD wallet,. A parrent always owns everything from it children wallets as it can proof ownership by regenerating child keys from the extended privatekey. Now if you would make it multiple accounts with one key as in BIP44, this becomes slightly different although you still have one Extendedkey that can regenerate all accounts children keys.

-> So any transactions between children should be marked as safe which the wallet can do since it has a list of all children.

Here’s an idea: as soon as a previously-spent output appears either in the mempool or on-chain, a wallet will spend it entirely as fees. That is, aggregate it with a 1-input, 0-output tx with fees equal to its value.

This also minimizes the odds that a wallet, after restore, finds any spendable outputs on chain that it previously spent.

After a wallet restore, the wallet could show the user the last few outputs and query the user which ones they recognize as definitely having received before. According to the above “dupe-burning” behaviour, such an output as well as all earlier ones should not be dupes. For the remaining ones, the user should let the wallet refresh them one by one, over a long enough period to minimize correlations. It would be best if these 1-input 1-output refreshes were employed for aggregation in the dandelion stem phase, in which case they actually enhance privacy.

How would the wallet identify previously spent outputs? Particularly in the case of multiple wallet instances and/or on restore? The issue is bigger than just the current UTXOs the wallet has access to, it is ALL previously spent TXOs.

Just so it is here (I am pretty sure Valdo explained it in Keybase once, but I cant find it).

Beam has decided that duplicated kernels/replay attacks were too much of a risk and they chose to address the concern with a consensus change.

Some of what I could find is below:

To mitigate this threat, starting from Fork2 duplicating kernels will be forbidden. Technically this is achieved by the following:

  • There will be a new consensus parameter, MaxKernelLifespan , probably equivalent to ~ 1 month.
  • Starting from Fork2, kernels with HeightLock.Min (minimum height) lower than Fork2 will be rejected.
  • Each kernel, in addition to the optional HeightLock.Max (maximum height) will have implicit max height lock as HeightLock.Min + MaxKernelLifespan . This (and the previous restriction) will make repeating old kernels impossible.
  • Each node will have to keep track of all the recent kernels, down to current height minus MaxKernelLifespan . Kernels below this height may be forgotten (for the sake of blockchain verification).
  • Side effect: Kernels with relative height lock (already available on the mainnet) will not be able to reference a kernel older than MaxKernelLifespan . But this is ok, practically relative locks are needed for much shorter duration.

By such we will make kernel replaying illegal, whereas nodes will have to keep track only of the most recent kernels.

1 Like

When a wallet identifies a new on-chain output as its own,
it should be able to tell approximately when it created that output.

In what cases would it make sense to accept an output created over a week ago as valid?

In what cases would it make sense to accept an output created prior to the last wallet restore as valid?

All unspent outputs that a wallet has control of are valid.

I don’t know how much more time we want to discuss this, but it would be good to take a decision at some point, or to put a deadline to take one, so that the people that have been irrationally claiming that a wallet fix exists have a bit of a deadline to finally show us one.
Otherwise it never ends. Been a few months already.

Not putting a fix for replay attacks ready for last hard fork would be irresponsible in my opinion, and the result of way too much prolonged mental jerking. User should come first. No fix means that the replay vulnerabilities exist and they do currently.

Suppose all wallets observe the following rules:

  1. The wallet keeps track of what outputs it created, and which ones it spent.

  2. When a previously-spent output re-appears anywhere, it is burned as fees.

  3. When an output not known to have been created appears, it is in limbo, and the user is given the choice to accept it (e.g. when known to be created by a child wallet), or refresh it (e.g. sweep).

[EDIT] 3.5) When the wallet signs for some outputs to be spent (i.e. used as inputs), they are also considered in limbo (currently shown as "Awaiting finalization), until spent on-chain.

  1. The wallet reports clean status if no coins are being burned or in limbo.

  2. Upon restore, the user is asked for the last known date with clean status. All prior identified utxo are considered created and never-spent. All later ones are considered in limbo.

What would then be a realistic attack scenario?

I think @joltz and others are right. Give time to work out other options. Smarter people than myself are thinking about other options and they may find something. Worry about the arguments in this message when the time comes that a decision HAS to be made.

I am not particularly fond of burning solutions, they only work if it is 100% certain that the replay was malicious. Also, for the same reason as the possibility of non-malicious replay, I am not a fan of assuming all wallets will follow unenforced rules. Users are just going to use and it is inevitable mistakes will happen if they are allowed to happen. If replaying kernels is an accidental side effect instead of a huge added value feature, then they are only posing a risk.

And I fear that the wallet solutions will continue to come with the caveats of multiple instances of a wallet running and restores destroying the ideas. For example, point 5 ignores important information that is mentioned in point 1. The restored wallet will never know what previous spent outputs exist and will always be at risk of replay of these txs.

I would see (and it is a very personal opinion) the deployment of such a user experience, together with all the borderline security properties it implies, as a direct attack on Grin

It knows that none exist whenever clean status is reported.

I’ll try to think more in depth about this later, but I’d like to add that we need to keep in mind that replays don’t need to happen on chain. A failure to publish a tx could expose a kernel which is the secret to a replay. I hope we also talk about this in the scope of replay attacks as these scenarios definitely can’t be saved by the kernel uniqueness property. Rather you’d have to keep track of created kernels, but this assumes you have a history of these in your wallet.

Failure to publish a tx can be fully fixed by:

  1. sender checks balance before sending
  2. Having non-flawed tx propogation and mempool mechanisms.

the item 1. has been checked.
checking 2. in more depth is needed.

Let’s not confused everything and be honest intellectually.

Kernel uniqueness fixes a whole category of attacks including those which we haven’t thought of yet and may never find out until an attacker does it.

Expiring kernels potentially introduce problems we haven’t even thought of yet.