Eliminating finalize step

It seems you were first mentioning that in case of no change output, the tx output becomes a 1-2 output. This one is not true since the sender never learns receiver’s blinding factors with David’s construction, even when there is no change output.

In your post above, you are mentioning something different, which is a play attack vulnerability in case the receiver doesn’t broadcast the tx. This is the same threat model as other play attacks (that can be achieved differently) that were discussed before.

No, you misunderstood. It is the sender’s output that becomes 1-of-2 by providing a partial signature for spending it.

Ok. But the receiver never learns sender’s blinding factors at all, in all cases.

So you were saying that it is vulnerable to a play attack, which is true (mentioned it in my post), and is the same threat as other play attacks. It has nothing to do with change outputs or no change outputs.

1 Like

Am I right in understanding your proposal effectively makes private nonces deterministic, through the sender choosing a derivation path for the public nonce?

My (limited) understanding of Schnorr is that the private nonces must be generated randomly.
It would seem that allowing the sender to “force” the recipient to choose a particular nonce based on the derivation path for the public nonce potentially changes the security model here.

Edit: The catastrophic case would presumably be if the sender somehow forced the recipient to reuse a nonce that had been previously used in a signature. But there may be other more nuanced issues here with deterministic nonce generation.

You can do a similar construction using a Diffie Hellman key exchange, and use it similarly to what is done in stealth addresses protocols. This provides “true” randomness for the nonce computation since the sender can generate fully randomnly an ephemeral key (sent to the sender in the slatepack) from which to derive (together with receiver secp256k1 key) the Diffie Hellman secret.

1 Like

How to do Payment proofs following the original proposal (not the “reverse” one, which has easier payment proofs):

Due to the fact that it is the receiver that finally broadcasts the transaction, the traditional payment proof cannot be performed in this proposal. Here is a proposed solition:

Set up:

  • Grin users have a base secp256k1 public key that is used when they receive transactions, call it B. Call the associate private key b
  • Grin’s senders of transactions generate an ephemeral secp256k1 key when they send a transaction: call it S, and let s be the associated private key. S is to be sent by the sender in the slatepack for the receiver to gain knowledge of it to finalize the transaction.


Let’s call c the Diffie-Hellman secret, which can be computed by the sender and the receiver only:
c = Hash(s.B) = Hash(b.S).

Now, the receiver’s partial nonce R_b could be derived by the following formula:
R_b = c.G + B. That would work well for building the transaction, but we will modify this a bit in order to enable payment proofs.

Let’s define x = Hash(c||B||tx_amount||timestamp). And we actually define R_b by the following formula instead:
R_b = x.G + B.

Only the receiver knows the private key of R_b since only him knows the private key of B.
Define by R_a being the sender’s partial nonce, and by R being the total nonce: R = R_a + R_b.
R is going to be onchain data. The receiver, in David’s scheme, cannot trick everyone and use a different partial nonce since the sender has committed to R when creating his partial signature already.

How can the sender prove payment?

He can do that by doing the three following things:

  1. Prove knowledge of the secret key to R_a
  2. Show that R - R_a = x.G + B
  3. Provide the preimage to x (and to c).

The sender has successfully proven that he sent tx_amount coins at time t = timestamp to the owner of the public key B.


This is much better than my idea for payment proofs. Great job @Kurt. And if we generate the sender’s nonce deterministically from the kernel commitment, you can rebuild the proof by knowing only the kernel, tx_amount, and receiver’s address (I’m ignoring timestamp, since that may not actually be necessary). So payment proofs are very lightweight.


What specific form would the receiver’s nonce and excess take?

Sorry, I’m not quite sure what you’re asking. Can you elaborate?

How do you define the receiver’s nonce and excess as a function of receiver public key and sender public keys?

1 Like

I like @Kurt’s idea above for generating the nonce. The excess can be generated in a similar way, or just pure BIP32 (https://en.bitcoin.it/wiki/BIP_0032#Public_parent_key_.E2.86.92_public_child_key) using a keychain path derived from something deterministic, like the has of the inputs.

One cannot have both R_b and P_b linear in B (with coefficients known to sender) though, as the receiver signature would allow solving for their private key.

Right, I guess we would require having 2 public keys - one for nonce and one for excess. Unless you’ve got a better idea?

It is not necessary to derive excess for receiver anyway if you dont put total excess in signature’s message, which doesnt hurt security. Then receiver chooses whatever partial excess he likes when finalizing the tx. If you absolutely want, you can use two addresses as David suggests, yep.

Tromp is only referring to receiver’s excess & nonce - not sender’s

right, typo, i meant receiver. i edited to correct

I suspect that two public keys are necessary.

Note that if you make these the receiver public excess and public nonce, then it’s just the extra round that you were trying to avoid.

Instead you plan for these keys to be used as a base key pair from which to derive many (excess, nonce) key pairs.

The major worry here is that the derivation method somehow leaks information about the base key pair, particularly when the sender has the ability to grind over the derived nonce key and introduce subtle biases there.

1 Like

Actually, can’t you just multiply their pubkey by some factor for nonce, and add some amount to it for excess?

I think it does not solve. The problem is that the sender knows all the data in the signature’s scalar, and he can always solve for b whatever trick you do. The only way would be to be the receiver has two secrets, aka two public keys, i think.

If you do your suggestion:
s_b (the partial signature of the receiver) verifies:
s_b = alpha.b + Hash(m).(beta + b),
which the sender can solve for b since he knows everything but b.
(solution is b = (s_b - Hash(m).beta).(alpha + Hash(m))^(-1))

1 Like

You are correct. My mistake.