Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Lesson 3.md #34

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 24 additions & 13 deletions Chapter 2/Lesson 3.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
# Chapter 2, lesson 3

### Authorization of external messages in contracts
We'll talk about different ways to authorize messages and, you know, make sure that they're coming from the authentic senders and how, like what kind of patterns that emerge in Tanaka system to work with authorization. So first of all, let's start with two styles of messages, you have internal messages and external messages. And external messages are the least capable, they're just plain byte strings. So there are really two authorization strategies that one could use. One is checking the signature, meaning that the contract receives those bytes, some part of this bicycle the cell part of the cell contains the 64 byte signature and the contract checks that the signature is valid according to his public key that is somewhere inside the contract, still stored already in the contract. And, if the signature matches the public key, then the rest of the message is processes very simple and this authentication by the signature is used to bridge the external world to the internal world of blockchain. And you most often use it for individual wallets. And the other, the other strategy with external messages is actually quite interesting. It's not to authorize messages at all. Imagine you have a system that should be censorship resistant, like you have a contract that operates some kind of like financial pool that needs to be triggered from outside to perform some actions. And you may want to make it not tied to any operator. So that anyone like normally there would be operator, of course, but in case this operator goes down, anyone else could run their script, or have the Crunchyroll server to, to trigger some actions on this contract, let's say like, distribution of dividends or something like that. And in this case, you want to implement something that does not require authorization at all. And this could be done by external messages that are not authenticated. So instead of just checking the signature, the contract would check its own internal state and see if it's in a good state, if there is some dividends accumulated or some other something else should be happening. And then when it receives this command, from this external message, now does it and it doesn't care where this message comes from. So this is also one important consideration, maybe in your contract, in some cases, you don't want to check who sends the message. And, if that operation is, like, quite cheap, or can be, you know, paid by, by the contract itself, then it could be done as an external message, just to blame on authorized command that comes into the contract. And this is basically all about it about the external messages, either signatures or unauthorized ones.
### Authorization of internal messages in contracts
And the really fun part happens in the internal message. Internal messages, they are at the low level they're authenticated by so called message sender, this is what the network guarantees you the address of the contract that emitted this internal message. And you can do some fun things with it. So, first of all, your wallet is normally your gateway to the tone network of contracts. So, you will typically send external message to Wallet contract and then this whole contract will route the the internal messages to other contracts. And then those other contracts may no longer worry about checking signatures, they could implement the message sender as an address that has been checked. And this is this allows quite nice composition. So for instance, you have a contract that is that implements a token. It has an owner field and this owner field is a simple 32 byte or like actually slightly slower, like longer but anyway, it's kind of like a short contract address that stored in inside the contract. And anytime you want to own or do something with this token, like change its owner or change his parameters, it will check if the internal message has the same message sender that's, the owner field inside this contract. So it's a simple check, without any, you know, cryptographic operations just to equality comparison, and the network guarantees that this center is correct. And this is quite powerful way to implement authorization because it's composable. This means that not only the wallet contract can be the sender, it means that this token can be owned by some other contract. And the token doesn't really have to worry about what kind of contract is controlling this token, because this only interfaces, you know, some kind of message signature like message format, and the address of the center. So it could be the wallet, it could be the decks, it could be, it could be some other, like tokens could be owned by you know, collections, or could be owned by some multisig contracts or anything like that. This is very flexible thing. And the simplest way to authorize by the message center is to just check it against the list of senators or if you, for instance, have a list of parties in the contract, you can, go through this list and see if the Message Center is one of the members of that of that list and authorize this way. So it's very cheap composable and this is like, if you can, this should be your default choice of authorizing participants. And this is how you can also do different roles like administrative role operator role, by just having separate slots for contract addresses.
### DNA check
Now, there are some more interesting ways to use the message center. It's when you want to check if if you're interacting with the sibling contract. So for instance, if you look at the shutdown, like token standard, then every user has their own token balance.
So the simplest way is to just check it to be equal to whatever, like contract address that you're storing, for whatever purpose like a role of owner, administrator operator like backdoor, whatever you're doing. The more interesting ways that you should remember that your contract address is a deterministic function of the code and initial state of the contract. And this means that you could check that the incoming message is not just from some predetermined address, but it's from some contracts that implements certain code. So for instance, in zetten, standard that implements the fungible tokens, the scalability is achieved by having each user holding their own contract with a balance, that's called your total wallet, while the name is not ideal, because it's not really a wallet, but it's a separate contract that has an owner, it can attach to this owner. So it's not like NFT, that switches the owner, it's just kind of bound to it forever. And it has, it has a counter that contains the balance of this, of the shirt on for that particular user. And every user has the same code for this digital wallet, but with a different owner. And the interesting thing is that how to transfer the tokens between those instances, from the perspective of each instance, one is sending out a message saying, Hey, I just decremented my balance, you should receive one unit of this token, and the other instance, receives an incoming message saying, Hey, could you please increment your balance by one token? And how does this instance trust that, on the other side that decrement was correctly applied. So this is done by transmitting unnecessary information in the message such as, who was the owner, and what are like other, you know, parameters of this asset on wall so that the recipient instance could reconstruct that the contract address that should match with a message sender. So what does it mean is that they, let's say, I'm an instance of this digital wallet, and I received the message, supposedly, from the other instance of digital wallet that says, Please increment your balance by one, what I'm going to do, I'm going to receive the necessary data that's on the other side, like who was the owner of that instance. And I would construct an instance of a contract, it's called state in it, I would take my own code, take the initial data, like the the owners address, maybe like some initial state or whatever, whatever is important to store in this digital wallet. And I would put it all together and hash it, and compute the address of a contract that I would trust to receive the message from. And once I copied this address, then I would compare this address with the actual message center. And if the message sender matches that it means that the message was sent by the contract with the same code as mine, kind of sharing the same DNA, and therefore I can trust it. If the address doesn't match, then it means that either it's a sibling, but with the wrong parameters that they send, and then I just, you know, reject this message and ignore it. Or it's completely unrelated contract that tries to trick me into increasing my balance. And to protect the issuer. And all the users of this token, I'm going to reject this message as Donavon. So, effectively, like this kind of DNA check is implemented through message center, because we compute the sender's address deterministically from the code and data it at the at the point of receiving the message and this is quite a common pattern anytime you have contracts that kind of split the state among themselves in each authenticate messages in between themselves because for instance, you have a per user storage, like the balance or collection of balances are some other information. And that's the pattern that you would likely see in some other applications and Ton. Also, like, when we talked about unauthorized messages, we talked about external messages. But it's also possible to implement unauthorized messages that are internal ones. And why why would you want to do that? This is because internal messages can have the coins attached to them. So imagine you have a contract that should be for censorship resistance reasons, or be triggered by anyone to do the payouts or something like that. But there is no non trivial cost that is associated with doing this operation, and you don't want to be attacked by unauthorized messages that exhausts your balance by incurring the small gas costs. So what you would do, he would say, I want to be triggered by anyone, but this should be done through internal message, and this internal message should pay for the gas. And this means that your, whatever external system is set up, that would do the operational work, they would have to set up the wallet and pay a little bit for, you know, the gas fees, to operate those messages. And if the system goes down, and anyone wants to operate this contract, by themselves, they would also have to incur some gas fees. And that would be kind of a safe way to design your contract, like sounds like anyone can trigger it, but they should be the transaction fees.
### Signatures in data signal
Finally, by the data signal, like you bother signatures, there is another use case for signatures, you may sign not just the external message. But you could also imagine a system where you are transporting the signed piece of data through internal message. This is the situation where the user pre authorized certain action like signed off on some parameters. But this piece of data is not going to be used right away, this probably stored in some off Chain system somewhere. And then when time comes, and the need, like the contract needs to be resolved or some action should be performed, then this piece of data could be transported through the series of like internal messages. And it may happen that the contract receives the internal message and tax data and also sees that there is this approval by some public key with a signature that must be checked. And this allows you to kind of bury the authentication by a human somewhere inside the network of your contracts. So that's another possibility for authorizing some actions through the scan to interrupt like indirect data signatures, and there is like pull requests number 100 four data signatures, that proposals, the standard for this kind of like off chain, sign data, and this data could be used completely off chain, or it could be an account packed and verified by the contracts, where it's like transmitted within the cells in between the contracts.
### Conclusion
So to summarize, what are the guidelines for contract developers? First, try to minimize the use of signatures. And because they compose kind of poorly, you would have much more flexibility if you just check the message center and use the user's wallet as a way to interact with the system. So even if you for instance, create a multisig contract, don't put the list of public keys there. Instead, you could just put a list of wallet addresses. And then every person may choose what kind of word they use, and maybe some of them would not even words and it would be much easier to check the conditions you would just keep track of like who which message sender sent which vote into this multisig contract. And compose your contracts through internal messages, right. So your system would likely be composed have multiple contracts and they will all route messages between themselves and authenticate each other through this message senders either by DNA or directly by just checking their contract address.
# Authorization of messages in contracts

###### tags: `Chapter 2`

This lesson discusses various authorization methods for messages.


## Overview of all authentication types

1. **Authentication with a signature.**
> :exclamation: Any event in the TON blockchain should start with an external message.
*Whenever the external message comes in wallet, it reads off 64 bytes of data :six::four:, <u>that is the signature for the rest of the message</u>, verifies the signature with its public key, and then treats the rest of the message as the instructions to send other messages to other contracts internally inside the blockchain.*

2. **Authentication of a message sender.**

> *All the internal messages in TON are identified by a message sender that is guaranteed to be correct and secure :unlock: by the TON protocol. Every time a contract receives an internal message, it knows for sure from which other contract the message was received. And this is immensely more cheap and powerful than checking the signatures.*

3. **DNA check for trusted code.** :raised_hands:

> *Since the addresses in the TON ecosystem are not simply unique identifiers of the contracts, but they're also cryptographically secure hashes of the contract code and data, they don't change when the data changes. Since those addresses are cryptographic commitments to this code, you could verify what kind of code is talking on the other end by checking the message sender.*

4. **Lack of authentication for censorship resistance.**

> :question: *Isn't it insecure to not authenticate the messages? In certain situations, this is where the security actually lies. You can deal with a system that must be censorship resistant like decentralized staking pool*