s = k + e*r
, where:
k
is a secret noncee
is a schnorr challenger
is the private key
For multisig:
ss + sr = ks + kr + H(M | Ks + Kr | Rs + Rr)*(rs + rr)
where s
and r
define whether this variable is from sender or receiver,
so Ks
is sender's public nonce while rr
is receiver's private sum of his blinding factors.
In this document we introduce a new transaction building flow that keeps the same Schnorr challenge, but allows the sender to construct the partial signature right away from the receiver's slatepack address and obtain a payment proof for it. This allows the receiver to finalize the transaction in the next step. The same flow also works for the receiver->sender flow.
Currently the Slatepack address contains:
- receiver_pubkey (ed25519 public key)
- hrp (human readable prefix, usually "grin")
Along with receiver_pubkey
and hrp
we also send enc_T
. We introduce new curve points T1 = t*G
and T2 = t*G
which are randomly chosen by the receiver. Receiver creates enc_T
like this: enc_T = encrypt({T1, T2}, receiver_privatekey)
.
Whoever has the address can compute T1, T2 = decrypt(enc_T, receiver_pubkey)
. T1
and T2
are encrypted in enc_T
with the receiver_privatekey
so that nobody can change them. This way it guarantees that T1
and T2
were picked by the owner of receiver_pubkey
. The address is for one-time use.
-
Receiver shares his address with the sender through some communication channel (directly with him or make it public).
-
Sender
- calculates
T1, T2 = decrypt(enc_T, receiver_pubkey)
andRr = T1
. We useT1
so that the sender doesn't know the private key ofRr
. - randomly chooses his private nonce
ks
and calculates hisrs
. - calculates
R = Rs + Rr
- calculates
Kr = H(amount | sender_pub | receiver_pub | enc_T | R | Ks) * T2
where:- we need
amount
andsender_pub
to know who sent how much - we need
receiver_pub
, andenc_T
to prove we had the right info from the receiver (we also needT2
but that's already a point with which we multiply the hash) - we need
R
to link hash with some kernel on the chain - we need
Ks
to assure the sender can't fakeKs
when proving his payment - explained later - we multiply it by
T2
so that the sender doesn't know private key ofKr
, becauseKr = (H(...)*t2) * G
and he doesn't knowt2
.T2
must be the one from theenc_T
(and that's not T1!).
- we need
- calculates
ss = ks + e*rs
wheree = H(M | Ks + Kr | Rs + Rr)
- sends
{ ss, amount, Ks, Rs, sender_pub, enc_T }
to the receiver. Note thatKr
andRr
are not sent.
- calculates
-
Receiver
- wallet keeps track of used
enc_T
's, so they must be unique to avoid nonce and excess reuse. - calculates
Rr
,R
andKr
- calculates
sr = kr + e*rr
- finalizes the transactions and broadcasts it
- wallet keeps track of used
Note: the sender can't lie about the amount because the receiver computes Kr
from the amount variable that he received. If
the sender constructed Kr
for a different amount then they would get a different schnorr challenge and the transaction
would not be valid.
If the sender doesn't directly receive anything from the receiver then he must somehow create the payment proof.
Sender needs to prove that he knows how to calculate K = Ks + Kr
where:
Kr = H(amount | sender_pub | receiver_pub | enc_T | R | Ks) * T2
K
is public nonce of the kernel with excessR
which is on chain
You need Ks
in the hash because otherwise the sender could fake his Ks
by defining it as Ks = K - Kr
.
I think the receiver can prove it in the same way since he also can't fake Ks
.
So the proof is a set { amount, sender_pub, receiver_pub, enc_T, R, Ks }
.
The flow should be very similar. Sender shares his slatepack address, which contains T1
and T2
, to the receiver.
Receiver calculates Rs = T1
, picks his rr
and kr
and then calculates
Ks = H(U | amount | sender_pub | receiver_pub | enc_T | R | Kr) * T2
.
The payment proof should be similar as when the sender initiates except that here you prove the knowledge of Ks
instead of
Kr
. Therefore the proof is a set { amount, sender_pub, receiver_pub, enc_T, R, Kr }
.
- does not require a consensus change
- both parties end up with a payment proof so it can be done in any direction
- not proven secure
- wallets need to keep distinct slatepack addresses - they can't be reused through wallets because wallets keep track of
enc_T
values for per address to avoidT1
andT2
reuse - wallets need to store
enc_T
values per each address they generate - wallet restore invalidates previous unused addresses
- with the current version you can't have parties pay for their own fees because the sender commits to fee in the first phase (unless the fee amount was sent with the address by the receiver)
- can we somehow make it possible to generate a permanent address?
- missing solution for different fee payment strategies (eg. each his own, all finalizer)
Looks insecure. What unknowns (to sender) does equation sr = kr + e*rr have, other than t ?