[Lightning-dev] BOLT11 In the World of Scriptless Scripts

Anthony Towns aj at erisian.com.au
Sun Nov 4 04:26:13 UTC 2018

On Sun, Nov 04, 2018 at 01:30:48PM +1030, Rusty Russell wrote:
> I'm not sure.  Jonas Nick proposed a scheme, which very much assumes
> Schnorr AFAICT:
> Jonas Nick wrote:
> > How I thought it would work is that the invoice would contain a
> > Schnorr nonce R.

(Note this means the "invoice" must be unique for each payment)

> > Then the payer would construct s*G = R +
> > H(payee_pubkey,R,"I've bought 5 shirts shipped to Germany")*G. Then
> > the payer builds the scriptless script payment path such that when the
> > payee claims, the payer learns s and thus has a complete
> > signature. However, that doesn’t work with recurrent payments because
> > the payee can use the nonce only once.

So that's totally fine to do however you receive the "s" value -- the
message that's getting the Schnorr signature isn't a valid bitcoin
transaction, so it's something that only needs to be validated by
BOLT-aware courts.

I also think you can get recurrent payments easily by extending the
verification algorithm. Basically instead of Verify(m,P,sig) have
Verify(m,P,n,sig) to verify you've made n payments of the invoice "m".

Construct "m" to include the postimage X = H(pre,1000) which indicates
"pre" has been hashed 1000 times, so X = H(H(pre,1000-n),n).

Calculate the original signature as:

   s = r + H(P,R,m+X)*p

and verify that n payments have been made by checking:

   Verify(m,P,n,(s,R,rcpt)) :: s*G = R + H(P,R,m+H(rcpt,n))*P

You'd provide s,R,X when setting up the subscription, then reveal the
preimage to X, the preimage to the preimage of X etc on each payment.
(Maybe shachain would work here?)

I think that approach is independent of using sha256/secp256k1 for
preimages over lightning too.

> I would probably enhance this to include a nonce, which allows for AMP
> (you have to xor the AMP payments to get the nonce):
> R + H(payee_pubkey,R,"I've bought 5 shirts shipped to Germany",NONCE)*G

R is already a unique nonce under the hash here, so I don't think a
second one adds any value fwiw.

> > I think it makes sense to think of proof-of-payment in terms of a
> > verification algorithm (that a third party court could use), that takes:
> >
> >   m - the invoice details, eg
> >       "aj paid $11 for stickers to be delivered to Australia"
> >   P - the pubkey of the vendor
> >   sig - some signature
> >
> > With the current SHA256 preimages, you can make sig=(R,s,pre)
> > where the sig is valid if:
> >
> >   s*G = R + H(P,R,m+SHA256(pre))*P
> >
> > If you share R,s,SHA256(pre) beforehand, the payer can tell they'll have
> > a valid signature if they pay to SHA256(pre). That's a 96B signature,
> > and it requires "pre" be different for each sale, and needs pre-payment
> > interactivity to agree on m and communicate R,s back to the payer.
> For current-style invoices (no payer-supplied data), the payee knows
> 'm', so no interactivity needed, which is nice.

I'm looking at it as needing interactivity to determine m prior to
the payment going through -- the payer needs to send through "aj" and
"Australia" in the example above, before the payee can generate s,R to
send back, at which point the payer can make the payment knowing they'll
either get a cryptographic proof of payment or a refund.

> In the payer-supplied data case, I think 'm' should include a signature
> for a key only the payer knows: this lets them prove *they* made the
> payment.

I don't object to that, but I think it's unnecessary; as long as there
was a payment for delivery of the widget to "aj" in "Australia" does it
matter if the payment was technically made by "aj" by "Visa on behalf
of aj" or by "Bank of America on behalf of Mastercard on behalf of aj's
friend who owed him some money" ?

> How does this interact with AMP, however?

The way I see it is they're separate: you have a way of getting the
preimage back over lightning (which is affected by AMP), and you have a
way of turning a preimage into a third-party-verifiable PoP (with
Schnorr or whatever).

(That might not be true if there's a clever way of safely feeding the
nonce R back, so that you can go straight from a generic offer to an
accepted payment with proof of payment)

> > With seckp256k1 preimages, it's easy to reduce that to sig=(R,s),
> > and needing to communicate an R to the payer initially, who can then
> > calculate S and send "m" along with the payment.
> OK, I buy that.

Crap, do I need to give you proof of payment for it now? :)

> > Maybe it makes sense to disambiguate the term "invoice" -- when you don't
> > know who you might be giving the goods/service to, call it an "offer",
> > which can be a write-once/accept-by-anyone deal that you just leave on
> > a webpage or your email signature; but an "invoice" should be specific
> > to each individual payment, with a "receipt" provided once an invoice
> > is paid.
> "offer" is a good name, since I landed on the same one while thinking
> about this too :)


> > It seems to me like there are three levels that could be implemented:
> >
> >  - laolu/conner: ("low AMP" ?)
> >     works with sha256
> >     some privacy improvement
> >     loses proof-of-payment
> >     can't claim unless all payments arrive
> Yep.
> >  - just send multiple payments with the same hash:
> >     works with sha256
> >     privacy not improved much (some intermediary nodes no longer know
> >       full invoice value)
> >     can claim partial payments as soon as they arrive
> >     accepting any partial payment provides proof-of-payment
> Interestingly, if vendor takes part payment, rest can be stolen by
> intermediaries.

Or you could just see a $5 bill, send $0.50 through, and wait to see
if the take the partial payment immediately before even trying the
remaining $4.50.

> >  - secp256k1: ("high AMP" ?)
> >     needs secp256k1 preimages
> >     works fine with decorrelation improving privacy at every step
> >     can set it up so can only claim once all partial payments arrive
> >     accepting partial payment provides proof-of-payment
> Yes.  Though I'm not sure exactly how this works with your scheme
> above...

 Vendor -> *:        "I sell widgets for 0.01 BTC, my pubkey is P"
 Customer -> Vendor: "I want to buy a widget"
 Vendor -> Customer: "Here's an R value"
 Customer: calculates S = R + H(P,R,"send $me a widget at $address")*P
 Customer -> Vendor: "here's 0.01 BTC for s corresponding to S, my
                      details are R, $me, $address"
 Vendor: looks up r for R=r*G, calculates s = r + H(P,R,"send $me a
         widget at $address")*p, checks S=s*G
 Vendor -> Customer: <accepts payment, revealing s>

 Customer -> Court: reveals the invoice ("send $me a widget...") and the
                    signature by Vendor's pubkey P, (s,R)

I think the way to do secp256k1 AMP with that is that when sending
through the payment is for the customer to send three payments to the
Vendor conditional on preimages for A,B,C calculated as:

   A = S + H(1,secret)*G
   B = S + H(2,secret)*G
   C = S + H(3,secret)*G

where "secret" is your xor of info from each of the three message hashes.

> > In theory, both "just send multiple payments" and "secp256k1" could have
> > splitting and joining at any hop, if we could encode the instructions
> > on how to do that in the onion message; joining is probably easy, but
> > splitting seems like it might be hard?
> I don't think so.  If you can join two payments, it wasn't private?

Sorry, I mean "source-directed splits and joins", so rather than
your source routing being a linear "me -> A -> B -> C -> D -> you",
you specify a graph: "me -> A -> B,E ; B -> C ; E -> F -> G ; C,G ->
D -> you" so you tell "A" how to split the payment into two new routes,
and tell "D" to join two payments and continue it on. The ECC part works
fine for that, but the onion routed messages seem difficult and probably
not worth considering for spec v1.1.

> Note: if we need an interaction message for BOLT11 features we want in
> future[1], then it has the advantage that it decouples the bolt11
> features from changing preimages to secp256k1.  That makes this question
> *critical* for the Summit next week.
> Thanks!
> Rusty.
> [1] If we're not careful we're going to implement HORNET so we can pass
> arbitrary messages around, which means we want to start charging for
> them to prevent spam, which means we reopen the pre-payment debate, and
> need reliable error messages...

Could leave the interactivity to the "web store" layer, eg have a BOLT
11 v1.1 "offer" include a url for the website where you go an enter your
name and address and whatever other info they need, and get a personalised
BOLT 11 v1.1 "invoice" back with payment-hash/nonce/signature/whatever?


More information about the Lightning-dev mailing list