Sequentia docs

4.5. Access-Control-List

Access-Control-Lists (ACLs) are specific limitations that can be enforced on transactions of a given token. ACLs make it possible to issue or update security tokens in compliance with company policies or other legal requirements: receiving addresses can be whitelisted or blacklisted, and in general, ACLs provide conditions on how tokens can be spent, determining how non-fungible the token is. For example, they can make it impossible to transfer a certain amount of tokens per transaction under a minimum or over a maximum threshold or enforce a time lock that limits the token’s transferability at a particular time.
ACL conditions can be implemented on RAS tokens, and the token issuer can update these conditions merely by creating a new transaction on Sequentia that contains the updated set of rules. Such centralized governance of the ACL rules is possible only if it is established in the set of rules originating from the token’s creation. In order to update the ACL, the token issuer could also make it necessary to execute a particular script or sign a transaction with a particular set of keys (such as n of m multi-sig).
Access-Control-Lists (ACLs) act as a filter dedicated to limiting the transferability properties of a token. By default, any address can transfer and use a token without limitations unless the token creator defined some ACL upon its launch. Among the rules to be defined, token issuers should decide on the possibility (or impossibility) of changing the ACL rules in the future, once the token is live on the mainnet, as well as whether some rules should be changeable while others are not, and to whom the rights to change the rules (if any) should be conferred.
One possible purpose of ACLs is to enable peer-to-peer trading and transfer of security tokens that need to comply with particular company policies or legislation. Different limits can be enforced on a transaction’s input or output.
On the input side:
  1. 1.
    It is possible to enforce an upper or lower bound on the amount transferred;
  2. 2.
    Time locks can be enforced (i.e., the UTXO cannot be spent until block x);
  3. 3.
    A particular address can be blocked so that all UTXOs from that address are frozen and cannot be transferred.
On the output side:
  1. 1.
    Only specific addresses can receive a transaction: in this case, the standard policy is to deny the transaction unless the requirement is met (the output address is whitelisted);
  2. 2.
    A specific address cannot receive a transaction: in this case, the standard policy is to allow any transaction unless the restriction is met (the output address is blacklisted);
  3. 3.
    Conditional whitelisting/blacklisting: a particular address can or cannot receive the transaction depending on the amount transferred (upper or lower bounds) or the lock time;
From a technical point of view, the rules are enforced through one or a series of filters and an action: allow, deny, or check:
  • If the action is ‘deny’, and at least one of the filters is met, then the transaction cannot be validated;
  • In the case of the ‘allow’ action, the transaction can be validated only if all the filters are met;
  • In the case of the ‘check’ action, the transaction is validated only if it meets another set of rules used for another token. The check action can be used in case of multiple tokens issued with the same policy conditions or if more tokens share a standard set of rules (recalled with check), on top of which other rules are enforced for each different token. For example, the token issuer can specify or inherit an ACL already defined by a trusted third party in charge of AML/KYC procedures.
An additional control parameter can be configured when there is a need for a particular entity to approve each transfer of the token. The entity is defined as a “controller” and shall “countersign” the transaction for validation. The difference with a simple 2-of-2 multi-signature is that this ACL control rule requiring the controller’s signature can be combined with other ACL rules or any other desired multi-signature scheme for the UTXO. For example, users might use a 3-of-5 multi-sig account to hold the tokens, which can only be transferred by providing at least 3 signatures together with the controller’s signature (so that it effectively becomes a 4-of-6 scheme) and whatever other ACL rules are configured for that token. The controller can be the token issuer, a service, an identity provider, or, more generically, an oracle.
In general, the required script contained in an ACL rule is relatively limited in size to be manageable for verifying nodes and does not require much space in terms of storage unless it is necessary to blacklist and whitelist multiple addresses. For this reason, there are three different possible implementations of ACL for blacklisting and whitelisting, which can be chosen depending on considerations regarding scalability, and based on the number of addresses to be blacklisted or whitelisted as well as the expected frequency of transactions in tokens complying with those ACL rules:
  1. 1.
    The list of addresses is held off-chain by a third party that will countersign any whitelisted (or not blacklisted) transaction, like in a traditional multi-signature scheme.
  2. 2.
    The list of addresses is written in one or more on-chain transactions. Each validator will check if the transaction is valid according to this set of addresses, checking all transactions and blocks and adding or deleting whitelisted or blacklisted addresses to a particular ACL rule.
  3. 3.
    The list of addresses is held off-chain by one or multiple third parties, possibly in a distributed hash table that users can freely sync. Not storing the list on-chain means the blockchain is not burdened with more data and may also help keep the list of addresses private. The list of addresses is a merkleized binary trie (12), whose root is the only piece saved in on-chain (13) transactions containing the ACL rule, and that can be updated in the future. Each user making a transaction needs to provide in that transaction proof that the address is in the merkleized binary trie, through a merkle audit proof (14). Therefore, the burden of the proof is with users sending transactions according to their respective ACL, rather than each validator node, without weighing on the blockchain.
The first solution (countersigning each transaction) grants more scalability but requires an always-online third-party node to sign transactions.
The second solution is feasible only if the list of addresses is small and changes infrequently. Assuming a public key is 256bit, 15 whitelisted public keys weigh around 3.8KB. If, instead, the list is made of 1,000 or 10,000 elements, the cost for on-chain transaction(s) to store and maintain this list on-chain goes against any reasonable principle of scalability.
The third solution can be chosen if the number of addresses is extensive, while the number of expected transactions in tokens complying with those rules is relatively infrequent and/or the transactions’ value will be high enough to afford a higher fee than average. With this solution, it is enough to store the merkle root on-chain rather than the entire list of addresses, which is very efficient in terms of storage. However, each transaction must carry the proof that it is valid, containing the Merkle audit path that proves the whitelisted address is in a leaf of the Merkle tree. The Merkle audit path is the shortest list of additional nodes in the tree required to compute the root hash for that tree. To verify that a leaf node belongs to a tree, it is necessary to only know the direct neighboring leaf node’s hash, if any, and the neighboring parent node hashes directly above the leaf nodes.
For example, to prove that leaf “7” is in the merkle tree (see the figure below), it is only necessary to know leaf 8, H(C), and H(A,B). For a list of only eight addresses like this (the leaves), the merkleized structure is inefficient: storing all addresses on-chain is better than requiring a proof that utilizes the Merkle audit path for each transaction.
However, a Merkle tree of 1 million addresses requires only 20 steps to reach the leaf from the root (15). Therefore, a high number of whitelisted addresses is feasible if transactions in that token are not that frequent and all have a relatively high value, for which it is reasonable to pay an above-average fee.
A proof that a particular element is in a tree takes O(n) time to construct where n is the number of elements in the merkle tree, but then takes only O(log n) space to store and O(log n) time to verify (16).