Return-Path: Received: from smtp4.osuosl.org (smtp4.osuosl.org [IPv6:2605:bc80:3010::137]) by lists.linuxfoundation.org (Postfix) with ESMTP id 58ECFC000E for ; Mon, 2 Aug 2021 09:32:50 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 47A49403D9 for ; Mon, 2 Aug 2021 09:32:50 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org X-Spam-Flag: NO X-Spam-Score: -2.098 X-Spam-Level: X-Spam-Status: No, score=-2.098 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, HTML_MESSAGE=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001] autolearn=ham autolearn_force=no Authentication-Results: smtp4.osuosl.org (amavisd-new); dkim=pass (2048-bit key) header.d=gmail.com Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id KAIVHlMOo_Gt for ; Mon, 2 Aug 2021 09:32:48 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.8.0 Received: from mail-io1-xd32.google.com (mail-io1-xd32.google.com [IPv6:2607:f8b0:4864:20::d32]) by smtp4.osuosl.org (Postfix) with ESMTPS id AFDB6403C3 for ; Mon, 2 Aug 2021 09:32:48 +0000 (UTC) Received: by mail-io1-xd32.google.com with SMTP id m13so19496738iol.7 for ; Mon, 02 Aug 2021 02:32:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=vqG1Fsl6diFhd2o8p5KRXRpYpGecisUhEdVYj0NBomM=; b=j4lyVtX0Vzzylj0cjc5YcV7ir7+zmHD3NHGBV7rpcn/5bvUCQBwed/kHW9MlSlPHSF 4LwK8zR6Kumq+yvrH8de/RDjwnDmiMN2lvvwPOqa7YcerWiXynFEcGBbr63x8MUeeNGz Rlx2eQwzIZun8YNRJjBEpZ/W1am/mhBTEtt1QZtVqVbAFaLhKrfJpfiQ6FTz81sYnbfW SSU8mQi7LJOBu3Wiii6pDtpkcsVu1iIpPW8eH9LRP8CDMGjNHmQ1na4HaMJ5WQgpU93r GAVb7HnUoZeOIw4r8Owb/4iOH6IZc6FUbwaD7fiCkEHD6rcdLdaFvaWde3gJOR/wdAP7 R6LA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=vqG1Fsl6diFhd2o8p5KRXRpYpGecisUhEdVYj0NBomM=; b=sOPzkKQlMBOVA8ctqmnPTli/8uvVCE3mkwO6mGKyFbit4hN/o3ddaAjA/7tOjFdQ+k 3kZlKDd22RtlMH0Cwc1FRSOdjZ94y/R4dRJPAj8Jj3Pb77B4x9vGn+mmrAtvT76BrEAz 5/E7xkiCVhR4uc0riM9ZI4xxMP8ccKZfh6LK92MUPScAUASIESjGMYJ+2YOSNhNKZM+v 6UOEVrynlRgoZBOX9AUkySga4vVpaOb7k6EYiGbkh/LepkyoTwVhDPAZfVTAARMNXBkE 23Pdh4EeS+hfhFcVGCXFXmSYLjuuJOkKUXqkownRJZ5YzEUUNFCKiBXNmXEQ8abpH/Xa kyEw== X-Gm-Message-State: AOAM5308AIH9vY7Tc86wCAq801AV8rW9s+pBbqBL82PcRNYumoFVfAjA M58Tx1mw8STOJsm5Y9mJtoSd3XaR+cWt76ynVbQ= X-Google-Smtp-Source: ABdhPJzUpB4dcUSMIlz/7N9AtBRW/Lhu5mZNMZsZi6JN2RHFL3Md9qeGHYlMdqWTqTpFCtm8ilJ5a9latYr3QaI3Rf0= X-Received: by 2002:a6b:b287:: with SMTP id b129mr517264iof.209.1627896767845; Mon, 02 Aug 2021 02:32:47 -0700 (PDT) MIME-Version: 1.0 References: In-Reply-To: From: Zac Greenwood Date: Mon, 2 Aug 2021 11:32:36 +0200 Message-ID: To: Billy Tetrud Content-Type: multipart/alternative; boundary="0000000000009418aa05c89040a3" X-Mailman-Approved-At: Mon, 02 Aug 2021 10:26:44 +0000 Cc: Bitcoin Protocol Discussion Subject: Re: [bitcoin-dev] Exploring: limiting transaction output amount as a function of total input value X-BeenThere: bitcoin-dev@lists.linuxfoundation.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: Bitcoin Protocol Discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 02 Aug 2021 09:32:50 -0000 --0000000000009418aa05c89040a3 Content-Type: text/plain; charset="UTF-8" [Note: I've moved your reply to the newly started thread] Hi Billy, Thank you for your kind and encouraging feedback. I don't quite understand why you'd want to define a specific span of blocks > for the rate limit. Why not just specify the size of the window (in blocks) > to rate limit within, and the limit? To enable more straightforward validation logic. You mentioned change addresses, however, with the parameters you defined, > there would be no way to connect together the change address with the > original address, meaning they would have completely separate rate limits, > which wouldn't work since the change output would ignore the previous rate > limit. The rate-limiting parameters must be re-specified for each rate-limited input. So, a transaction that has a rate-limited input is only valid if its output is itself rate-limited such that it does not violate the rate-limiting constraints of its input. In my thread-starter, I gave the below example of a rate-limited address a2 that serves as input for transaction t2: a2: 99.8 sats at height 800100; Rate-limit params: h0=800000, h1=800143, a=500k, a_remaining=300k; Transaction t2: Included at block height 800200 Spend: 400k + fees. Rate-limiting params: h0=800144, h1=800287, a=500k, a_remaining=100k. Note how transaction t2 re-specifies the rate-limiting parameters. Validation must ensure that the re-specified parameters are within bounds, i.e., do not allow more spending per epoch than the rate-limiting parameters of its input address a2. Re-specifying the rate-limiting parameters offers the flexibility to further restrict spending, or to disable any additional spending within the current epoch by setting a_remaining to zero. Result: Value at destination address: 400k sats; Rate limiting params at destination address: none; Value at change address a3: 99.4m sats; Rate limiting params at change address a3: h0=800144, h1=800287, a=500k, a_remaining=100k. As a design principle I believe it makes sense if the system is able to verify the validity of a transaction without having to consider any transactions that precede its inputs. As a side-note, doing away with this design principle would however enable more sophisticated rate-limiting (such as rate-limiting per sliding window instead of rate-limiting per epoch having a fixed start and end block), but while at the same time reducing the size of per rate-limiting transaction (because it would enable specifying the rate-limiting parameters more space-efficiently). To test the waters and to keep things relatively simple, I chose not to go into this enhanced form of rate-limiting. I haven't gone into how to process a transaction having multiple rate-limited inputs. The easiest way to handle this case is to not allow any transaction having more than one rate-limited input. One could imagine complex logic to handle transactions having multiple rate-limited inputs by creating multiple rate-limited change addresses. However at first glance I don't believe that the marginal added functionality would justify the increased implementation complexity. I'd be interested in seeing you write a BIP for this. Thank you, but sadly my understanding of Bitcoin is way too low to be able to write a BIP and do the implementation. However I see tremendous value in this functionality. Favorable feedback of the list regarding the usefulness and the technical feasibility of rate-limiting functionality would of course be an encouragement for me to descend further down the rabbit hole. Zac On Sun, Aug 1, 2021 at 10:09 AM Zac Greenwood wrote: > [Resubmitting to list with minor edits. My previous submission ended up > inside an existing thread, apologies.] > > Hi list, > > I'd like to explore whether it is feasible to implement new scripting > capabilities in Bitcoin that enable limiting the output amount of a > transaction based on the total value of its inputs. In other words, to > implement the ability to limit the maximum amount that can be sent from an > address. > > Two use cases come to mind: > > UC1: enable a user to add additional protection their funds by > rate-limiting the amount that they are allowed to send during a certain > period (measured in blocks). A typical use case might be a user that > intends to hodl their bitcoin, but still wishes to occasionally send small > amounts. Rate-limiting avoids an attacker from sweeping all the users' > funds in a single transaction, allowing the user to become aware of the > theft and intervene to prevent further thefts. > > UC2: exchanges may wish to rate-limit addresses containing large amounts > of bitcoin, adding warm- or hot-wallet functionality to a cold-storage > address. This would enable an exchange to drastically reduce the number of > times a cold wallet must be accessed with private keys that give access to > the full amount. > > In a typical setup, I'd envision using multisig such that the user has two > sets of private keys to their encumbered address (with a "set" of keys > meaning "one or more" keys). One set of private keys allows only for > sending with rate-limiting restrictions in place, and a second set of > private keys allowing for sending any amount without rate-limiting, > effectively overriding such restriction. > > The parameters that define in what way an output is rate-limited might be > defined as follows: > > Param 1: a block height "h0" indicating the first block height of an epoch; > Param 2: a block height "h1" indicating the last block height of an epoch; > Param 3: an amount "a" in satoshi indicating the maximum amount that is > allowed to be sent in any epoch; > Param 4: an amount "a_remaining" (in satoshi) indicating the maximum > amount that is allowed to be sent within the current epoch. > > For example, consider an input containing 100m sats (1 BTC) which has been > rate-limited with parameters (h0, h1, a, a_remaining) of (800000, 800143, > 500k, 500k). These parameters define that the address is rate-limited to > sending a maximum of 500k sats in the current epoch that starts at block > height 800000 and ends at height 800143 (or about one day ignoring block > time variance) and that the full amount of 500k is still sendable. These > rate-limiting parameters ensure that it takes at minimum 100m / 500k = 200 > transactions and 200 x 144 blocks or about 200 days to spend the full 100m > sats. As noted earlier, in a typical setup a user should retain the option > to transact the entire amount using a second (set of) private key(s). > > For rate-limiting to work, any change output created by a transaction from > a rate-limited address must itself be rate-limited as well. For instance, > expanding on the above example, assume that the user spends 200k sats from > a rate-limited address a1 containing 100m sats: > > Start situation: > At block height 800000: rate-limited address a1 is created; > Value of a1: 100.0m sats; > Rate limiting params of a1: h0=800000, h1=800143, a=500k, a_remaining=500k; > > Transaction t1: > Included at block height 800100; > Spend: 200k + fee; > Rate limiting params: h0=800000, h1=800143, a=500k, a_remaining=300k. > > Result: > Value at destination address: 200k sats; > Rate limiting params at destination address: none; > Value at change address a2: 99.8m sats; > Rate limiting params at change address a2: h0=800000, h1=800143, a=500k, > a_remaining=300k. > > In order to properly enforce rate limiting, the change address must be > rate-limited such that the original rate limit of 500k sats per 144 blocks > cannot be exceeded. In this example, the change address a2 were given the > same rate limiting parameters as the transaction that served as its input. > As a result, from block 800100 up until and including block 800143, a > maximum amount of 300k sats is allowed to be spent from the change address. > > Example continued: > a2: 99.8 sats at height 800100; > Rate-limit params: h0=800000, h1=800143, a=500k, a_remaining=300k; > > Transaction t2: > Included at block height 800200 > Spend: 400k + fees. > Rate-limiting params: h0=800144, h1=800287, a=500k, a_remaining=100k. > > Result: > Value at destination address: 400k sats; > Rate limiting params at destination address: none; > Value at change address a3: 99.4m sats; > Rate limiting params at change address a3: h0=800144, h1=800287, a=500k, > a_remaining=100k. > > Transaction t2 is allowed because it falls within the next epoch (running > from 800144 to 800287) so a spend of 400k does not violate the constraint > of 500k per epoch. > > As could be seen, the rate limiting parameters are part of the transaction > and chosen by the user (or their wallet). This means that the parameters > must be validated to ensure that they do not violate the intended > constraints. > > For instance, this transaction should not be allowed: > a2: 99.8 sats at height 800100; > Rate-limit params of a2: h0=800000, h1=800143, a=500k, a_remaining=300k; > > Transaction t2a: > Included at block height 800200; > Spend: 400k + fees; > Rate-limit params: h0=800124, h1=800267, a=500k, a_remaining=100k. > > This transaction t2a attempts to shift the epoch forward by 20 blocks such > that it starts at 800124 instead of 800144. Shifting the epoch forward like > this must not be allowed because it enables spending more that the rate > limit allows, which is 500k in any epoch of 144 blocks. It would enable > overspending: > > t1: spend 200k at 800100 (epoch 1: total: 200k); > t2a: spend 400k at 800200 (epoch 2: total: 400k); > t3a: spend 100k at 800201 (epoch 2: total: 500k); > t4a: spend 500k at 800268 (epoch 2: total: 1000k, overspending for epoch > 2). > > Specifying the rate-limiting parameters explicitly at every transaction > allows the user to tighten the spending limit by setting tighter limits or > for instance by setting a_remainder to 0 if they wish to enforce not > spending more during an epoch. A second advantage of explicitly specifying > the four rate-limiting parameters with each transaction is that it allows > the system to fully validate the transaction without having to consider any > previous transactions within an epoch. > > I will stop here because I would like to gauge interest in this idea first > before continuing work on other aspects. Two main pieces of work jump to > mind: > > Define all validations; > Describe aggregate behaviour of multiple (rate-limited) inputs, proof that > two rate-limited addresses cannot spend more than the sum of their > individual limits. > > Zac > --0000000000009418aa05c89040a3 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
[Note: I've moved your reply to the newly started thre= ad]

Hi Billy,

Thank you for your kind= and encouraging feedback.

I don't quite understand why you'd want to de= fine a specific span of blocks for the rate limit. Why not just specify the= size of the window (in blocks) to rate limit within, and the limit?

To enable more straightforward validation logic.<= /div>

You m= entioned change addresses, however, with the parameters you defined, there = would be no way to connect together the change address with the original ad= dress, meaning they would have completely separate rate limits, which would= n't work since the change output would ignore the previous rate limit.<= /blockquote>

The rate-limiting parameters must be re-spe= cified for each rate-limited input. So, a transaction that has a rate-limit= ed input is only valid if its output is itself rate-limited such that it do= es not violate the rate-limiting constraints of its input.

In my thread-starter, I gave the below example of a rate-limited a= ddress a2 that serves as input for transaction t2:

a2: 99.8 sats at height=C2=A0800100;
Rate-limit params: h0= =3D800000, h1=3D800143, a=3D500k, a_remaining=3D300k;

<= div>Transaction t2:
Included at block height 800200
Spe= nd: 400k=C2=A0+ fees.
Rate-limiting params: h0=3D800144, h1=3D800= 287, a=3D500k, a_remaining=3D100k.

Note how tr= ansaction t2 re-specifies the rate-limiting parameters. Validation must ens= ure that the re-specified parameters are within bounds, i.e., do not allow = more spending per epoch than the rate-limiting parameters of its input addr= ess a2. Re-specifying the rate-limiting parameters offers the flexibility t= o further restrict spending, or to disable any additional spending within t= he current epoch by setting a_remaining to zero.

<= div>Result:
Value at destination address: 400k sats;
Ra= te limiting params at destination address: none;
Value at change = address a3: 99.4m sats;
Rate limiting params at change address a3= : h0=3D800144, h1=3D800287, a=3D500k, a_remaining=3D100k.
=

As a design principle I believe it makes sense if the s= ystem is able to verify the validity of a transaction without having to con= sider any transactions that precede its inputs. As a side-note, doing away = with this design principle would however enable more sophisticated rate-lim= iting (such as rate-limiting per sliding window instead of rate-limiting pe= r epoch having a fixed start and end block), but while at the same time red= ucing the size of per rate-limiting transaction (because it would enable sp= ecifying the rate-limiting parameters more space-efficiently). To test the = waters and to keep things relatively simple, I chose not to go into this en= hanced form of rate-limiting.

I haven't gone i= nto how to process a transaction having multiple rate-limited inputs. The e= asiest way to handle this case is to not allow any transaction having more = than one rate-limited input. One could imagine complex logic to handle tran= sactions having multiple rate-limited inputs by creating multiple rate-limi= ted change addresses. However at first glance I don't believe that the = marginal added functionality would justify the increased implementation com= plexity.

=C2=A0I'd be interested in seeing you write a BIP for this.

Thank you, but sadly my understanding of Bitcoin i= s way too low to be able to write a BIP and do the implementation. However = I see tremendous value in this functionality. Favorable feedback of the lis= t regarding the usefulness and the technical feasibility of rate-limiting f= unctionality would of course be an encouragement for me to descend further = down the rabbit hole.

Zac


On Sun, Aug 1, 2021 at 10:09 AM Zac Greenwood <zachgrw@gmail.com> wrote:
[Resubmitting to lis= t with minor edits. My previous submission ended up inside an existing thre= ad, apologies.]

Hi list,

= I'd like to explore whether it is feasible to implement new scripting c= apabilities in Bitcoin that enable limiting the output amount of a transact= ion based on the total value of its inputs. In other words, to implement th= e ability to limit the maximum amount that can be sent from an address.

Two use cases come to mind:

= UC1: enable a user to add additional protection their funds by rate-limitin= g the amount that they are allowed to send during a certain period (measure= d in blocks). A typical use case might be a user that intends to hodl their= bitcoin, but still wishes to occasionally send small amounts. Rate-limitin= g avoids an attacker from sweeping all the users' funds in a single tra= nsaction, allowing the user to become aware of the theft and intervene to p= revent further thefts.

UC2: exchanges may wish to = rate-limit addresses containing large amounts of bitcoin, adding warm- or h= ot-wallet functionality to a cold-storage address. This would enable an exc= hange to drastically reduce the number of times a cold wallet must be acces= sed with private keys that give access to the full amount.

In a typical setup, I'd envision using multisig such that the = user has two sets of private keys to their encumbered address (with a "= ;set" of keys meaning "one or more" keys). One set of privat= e keys allows only for sending with rate-limiting restrictions in place, an= d a second set of private keys allowing for sending any amount without rate= -limiting, effectively overriding such restriction.

The parameters that define in what way an output is rate-limited might be= defined as follows:

Param 1: a block height "= ;h0" indicating the first block height of an epoch;
Par= am 2: a block height "h1" indicating the last block height of an = epoch;
Param 3: an amount "a" in satoshi indicating the= maximum amount that is allowed to be sent in any epoch;
Para= m 4: an amount "a_remaining" (in satoshi) indicating the maximum = amount that is allowed to be sent within the current epoch.

For example, consider an input containing 100m sats (1 BTC)= which has been rate-limited with parameters (h0, h1, a, a_remaining) of (8= 00000, 800143, 500k, 500k). These parameters define that the address is rat= e-limited to sending a maximum of 500k sats in the current epoch that start= s at block height 800000 and ends at height 800143 (or about one day ignori= ng block time variance) and that the full amount of 500k is still sendable.= These rate-limiting parameters ensure that it takes at minimum 100m / 500k= =3D 200 transactions and 200 x 144 blocks or about 200 days to spend the f= ull 100m sats. As noted earlier, in a typical setup a user should retain th= e option to transact the entire amount using a second (set of) private key(= s).

For rate-limiting to work, any change output c= reated by a transaction from a rate-limited address must itself be rate-lim= ited as well. For instance, expanding on the above example, assume that the= user spends 200k sats from a rate-limited address a1 containing 100m sats:=

Start situation:
At block height 800000= : rate-limited address a1 is created;
Value of a1: 100.0m sats;
Rate limiting params of a1: h0=3D800000, h1=3D800143, a=3D500k, a_= remaining=3D500k;

Transaction t1:
Includ= ed at block height 800100;
Spend: 200k + fee;
Rate limi= ting params: h0=3D800000, h1=3D800143, a=3D500k, a_remaining=3D300k.
<= div>
Result:
Value at destination address: 200k sat= s;
Rate limiting params at destination address: none;
V= alue at change address a2: 99.8m sats;
Rate limiting params at ch= ange address a2: h0=3D800000, h1=3D800143, a=3D500k, a_remaining=3D300k.

In order to properly enforce rate limiting, the chan= ge address must be rate-limited such that the original rate limit of 500k s= ats per 144 blocks cannot be exceeded. In this example, the change address = a2 were given the same rate limiting parameters as the transaction that ser= ved as its input. As a result, from block 800100 up until and including blo= ck 800143, a maximum amount of 300k sats is allowed to be spent from the ch= ange address.

Example continued:
a2: 99.= 8 sats at height=C2=A0800100;
Rate-limit params: h0=3D800000, h1= =3D800143, a=3D500k, a_remaining=3D300k;

Transacti= on t2:
Included at block height 800200
Spend: 400k=C2= =A0+ fees.
Rate-limiting params: h0=3D800144, h1=3D800287, a=3D50= 0k, a_remaining=3D100k.

Result:
Value at destination address: 400k sats;
Rate limiting params at= destination address: none;
Value at change address a3: 99.4m sat= s;
Rate limiting params at change address a3: h0=3D800144, h1=3D8= 00287, a=3D500k, a_remaining=3D100k.

Transaction t= 2 is allowed because it falls within the next epoch (running from 800144 to= 800287) so a spend of 400k does not violate the constraint of 500k per epo= ch.

As could be seen, the rate limiting parameters= are part of the transaction and chosen by the user (or their wallet). This= means that the parameters must be validated to ensure that they do not vio= late the intended constraints.

For instance, this = transaction should not be allowed:
a2: 99.8 sats at height= =C2=A0800100;
Rate-limit params of a2: h0=3D800000, h1=3D800143, = a=3D500k, a_remaining=3D300k;

Transaction t2a:
Included at block height 800200;
Spend: 400k=C2=A0+ fees;<= /div>
Rate-limit params: h0=3D800124, h1=3D800267, a=3D500k, a_rem= aining=3D100k.

This transaction t2a attempts= to shift the epoch forward by 20 blocks such that it starts at 800124 inst= ead of 800144. Shifting the epoch forward like this must not be allowed bec= ause it enables spending more that the rate limit allows, which is 500k in = any epoch of 144 blocks. It would enable overspending:

=
t1: spend 200k at 800100 (epoch 1: total: 200k);
t2a: = spend 400k at 800200 (epoch 2: total: 400k);
t3a: spend 100k at 8= 00201 (epoch 2: total: 500k);
t4a: spend 500k at 800268 (epoch 2:= total: 1000k, overspending for epoch 2).

Specifyi= ng the rate-limiting parameters explicitly at every transaction allows the = user to tighten the spending limit by setting tighter limits or for instanc= e by setting a_remainder to 0 if they wish to enforce not spending more dur= ing an epoch. A second advantage of explicitly specifying the four rate-lim= iting parameters with each transaction is that it allows the system to full= y validate the transaction without having to consider any previous transact= ions within an epoch.

I will stop here because I w= ould like to gauge interest in this idea first before continuing work on ot= her aspects. Two main pieces of work jump to mind:

Define all validations;
Describe aggregate behaviour of multiple= (rate-limited) inputs, proof that two rate-limited addresses cannot spend = more than the sum of their individual limits.
=

Zac
--0000000000009418aa05c89040a3--