Skip to content

Commit

Permalink
Merge pull request #28 from tolya-yanot/main
Browse files Browse the repository at this point in the history
Ton Core Team updates
  • Loading branch information
KuznetsovNikita authored Jul 3, 2024
2 parents d373fb0 + 5962103 commit c5465be
Show file tree
Hide file tree
Showing 29 changed files with 5,208 additions and 1,784 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
node_modules
temp
build
.idea
.env
72 changes: 2 additions & 70 deletions Specification.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ Authentication:

Operations:
* standard "send message" action (up to 255 messages at once),
* enable/disable signature authentication,
* enable/disable signature authentication (can be invoked only by extension),
* install/remove extension.

Signed messages can be delivered both by external and internal messages.
Expand Down Expand Up @@ -111,77 +111,9 @@ When wallet contract is being deployed, original code hash is being used as the
Library contract itself data and code are empty cells. That leads to the inability to change the library code, delete the contract, or withdraw funds from it.
Therefore, any Wallet V5 user can top up the library contract balance if they are afraid that the library code of their wallet will be frozen.

## Wallet ID

Wallet ID disambiguates requests signed with the same public key to different wallet versions (V3/V4/V5) or wallets deployed on different chains.

For Wallet V5 we suggest using the following wallet ID:

```
wallet_id$_ global_id:int32 wc:int8 version:(## 8) subwallet_number:(## 32) = WalletID;
```

- `global_id` is a TON chain identifier. TON Mainnet `global_id = -239` and TON Testnet `global_id = -3`.
- `wc` is a Workchain. -1 for Masterchain and 0 for Basechain.
- `version`: current version of wallet v5 is `0`.
- `subwallet_number` can be used to get multiple wallet contracts bound to the single keypair.

## Packed address

To make authorize extensions efficiently we compress 260-bit address (workchain + sha256 of stateinit) into a 256-bit integer:

```
int addr = addr_hash ^ (wc + 1)
```

Previously deployed wallet v4 was packing the address into a cell which costs ≈500 gas, while access to dictionary costs approximately `120*lg2(N)` in gas, that is serialization occupies more than half of the access cost for wallets with up to 16 extensions. This design makes packing cost around 50 gas and allows cutting the authentication cost 2-3x for reasonably sized wallets.

As of 2023 TON network consists of two workchains: -1 (master) and 0 (base). This means that the proposed address packing reduces second-preimage resistance of sha256 by 1 bit which we consider negligible. Even if the network is expanded with 254 more workchains in a distant future, our scheme would reduce security of extension authentication by only 8 bits down to 248 bits. Note that birthday attack is irrelevant in our setting as the user agent is not installing random extensions, although the security margin is plenty anyway (124 bits).



## TL-B definitions

Action types:

```tl-b
// Standard actions from block.tlb:
out_list_empty$_ = OutList 0;
out_list$_ {n:#} prev:^(OutList n) action:OutAction = OutList (n + 1);
action_send_msg#0ec3c86d mode:(## 8) out_msg:^(MessageRelaxed Any) = OutAction;
// Extended actions in W5:
action_list_basic$0 {n:#} actions:^(OutList n) = ActionList n 0;
action_list_extended$1 {m:#} {n:#} action:ExtendedAction prev:^(ActionList n m) = ActionList n (m+1);
action_add_ext#1c40db9f addr:MsgAddressInt = ExtendedAction;
action_delete_ext#5eaef4a4 addr:MsgAddressInt = ExtendedAction;
action_set_signature_auth_allowed#20cbb95a allowed:(## 1) = ExtendedAction;
```

Authentication modes:

```tl-b
signed_request$_ // 32 (opcode from outer)
wallet_id: WalletID // 80
valid_until: # // 32
msg_seqno: # // 32
inner: InnerRequest // 1 .. (1 + 32 + 256) + ^Cell
signature: bits512 // 512
= SignedRequest; // Total: 688 .. 976 + ^Cell
internal_signed#73696e74 signed:SignedRequest = InternalMsgBody;
internal_extension#6578746e inner:InnerRequest = InternalMsgBody;
external_signed#7369676e signed:SignedRequest = ExternalMsgBody;
actions$_ {m:#} {n:#} actions:(ActionList n m) = InnerRequest;
```

Contract state:
```tl-b
wallet_id$_ global_id:# wc:int8 version:(## 8) subwallet_number:# = WalletID;
contract_state$_ seqno:int33 wallet_id:WalletID public_key:(## 256) extensions_dict:(HashmapE 256 int8) = ContractState;
```
See `types.tlb`.

## Source code

Expand Down
1 change: 1 addition & 0 deletions build/library-deployer.compiled.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"hash":"7b886902938fda7f8ee72fe31ee250744bf82489579c0b8e502105a49cb72e2a","hashBase64":"e4hpApOP2n+O5y/jHuJQdEv4JIlXnAuOUCEFpJy3Lio=","hex":"b5ee9c72410106010030000114ff00f4a413f4bcf2c80b0102012002050202d1030400053c006000193b511cbec1b232483ec13b55200006f2f0014136d496"}
1 change: 1 addition & 0 deletions build/wallet_v5.compiled.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"hash":"20834b7b72b112147e1b2fb457b84e74d1a30f04f737d4f62a668e9552d2b72f","hashBase64":"IINLe3KxEhR+Gy+0V7hOdNGjDwT3N9T2KmaOlVLSty8=","hex":"b5ee9c7241021401000281000114ff00f4a413f4bcf2c80b01020120020d020148030402dcd020d749c120915b8f6320d70b1f2082106578746ebd21821073696e74bdb0925f03e082106578746eba8eb48020d72101d074d721fa4030fa44f828fa443058bd915be0ed44d0810141d721f4058307f40e6fa1319130e18040d721707fdb3ce03120d749810280b99130e070e2100f020120050c020120060902016e07080019adce76a2684020eb90eb85ffc00019af1df6a2684010eb90eb858fc00201480a0b0017b325fb51341c75c875c2c7e00011b262fb513435c280200019be5f0f6a2684080a0eb90fa02c0102f20e011e20d70b1f82107369676ebaf2e08a7f0f01e68ef0eda2edfb218308d722028308d723208020d721d31fd31fd31fed44d0d200d31f20d31fd3ffd70a000af90140ccf9109a28945f0adb31e1f2c087df02b35007b0f2d0845125baf2e0855036baf2e086f823bbf2d0882292f800de01a47fc8ca00cb1f01cf16c9ed542092f80fde70db3cd81003f6eda2edfb02f404216e926c218e4c0221d73930709421c700b38e2d01d72820761e436c20d749c008f2e09320d74ac002f2e09320d71d06c712c2005230b0f2d089d74cd7393001a4e86c128407bbf2e093d74ac000f2e093ed55e2d20001c000915be0ebd72c08142091709601d72c081c12e25210b1e30f20d74a111213009601fa4001fa44f828fa443058baf2e091ed44d0810141d718f405049d7fc8ca0040048307f453f2e08b8e14038307f45bf2e08c22d70a00216e01b3b0f2d090e2c85003cf1612f400c9ed54007230d72c08248e2d21f2e092d200ed44d0d2005113baf2d08f54503091319c01810140d721d70a00f2e08ee2c8ca0058cf16c9ed5493f2c08de20010935bdb31e1d74cd0b4d6c35e"}
41 changes: 26 additions & 15 deletions contracts/imports/stdlib.fc
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
;; Standard library for funC
;;

{-
This file is part of TON FunC Standard Library.

FunC Standard Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.

FunC Standard Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

-}

{-
# Tuple manipulation primitives
The names and the types are mostly self-explaining.
Expand All @@ -26,7 +41,7 @@ forall X -> tuple cons(X head, tuple tail) asm "CONS";
forall X -> (X, tuple) uncons(tuple list) asm "UNCONS";

;;; Extracts the tail and the head of lisp-style list.
forall X -> (tuple, X) list_next(tuple list) asm( -> 1 0) "UNCONS";
forall X -> (tuple, X) list_next(tuple list) asm(-> 1 0) "UNCONS";

;;; Returns the head of lisp-style list.
forall X -> X car(tuple list) asm "CAR";
Expand Down Expand Up @@ -244,11 +259,9 @@ cont bless(slice s) impure asm "BLESS";
() commit() impure asm "COMMIT";

;;; Not implemented
;;() buy_gas(int gram) impure asm "BUYGAS";

;;; Computes the amount of gas that can be bought for `amount` nanoTONs,
;;; and sets `gl` accordingly in the same way as [set_gas_limit].
() buy_gas(int amount) impure asm "BUYGAS";
;;() buy_gas(int amount) impure asm "BUYGAS";

;;; Computes the minimum of two integers [x] and [y].
int min(int x, int y) asm "MIN";
Expand Down Expand Up @@ -285,12 +298,12 @@ slice begin_parse(cell c) asm "CTOS";
() end_parse(slice s) impure asm "ENDS";

;;; Loads the first reference from the slice.
(slice, cell) load_ref(slice s) asm( -> 1 0) "LDREF";
(slice, cell) load_ref(slice s) asm(-> 1 0) "LDREF";

;;; Preloads the first reference from the slice.
cell preload_ref(slice s) asm "PLDREF";

{- Functions below are commented because are implemented on compilator level for optimisation -}
{- Functions below are commented because are implemented on compilator level for optimisation -}

;;; Loads a signed [len]-bit integer from a slice [s].
;; (slice, int) ~load_int(slice s, int len) asm(s len -> 1 0) "LDIX";
Expand All @@ -311,8 +324,8 @@ cell preload_ref(slice s) asm "PLDREF";
;; slice preload_bits(slice s, int len) asm "PLDSLICEX";

;;; Loads serialized amount of TonCoins (any unsigned integer up to `2^128 - 1`).
(slice, int) load_grams(slice s) asm( -> 1 0) "LDGRAMS";
(slice, int) load_coins(slice s) asm( -> 1 0) "LDGRAMS";
(slice, int) load_grams(slice s) asm(-> 1 0) "LDGRAMS";
(slice, int) load_coins(slice s) asm(-> 1 0) "LDVARUINT16";

;;; Returns all but the first `0 ≤ len ≤ 1023` bits of `slice` [s].
slice skip_bits(slice s, int len) asm "SDSKIPFIRST";
Expand All @@ -330,7 +343,7 @@ slice slice_last(slice s, int len) asm "SDCUTLAST";

;;; Loads a dictionary `D` (HashMapE) from `slice` [s].
;;; (returns `null` if `nothing` constructor is used).
(slice, cell) load_dict(slice s) asm( -> 1 0) "LDDICT";
(slice, cell) load_dict(slice s) asm(-> 1 0) "LDDICT";

;;; Preloads a dictionary `D` from `slice` [s].
cell preload_dict(slice s) asm "PLDDICT";
Expand All @@ -342,7 +355,7 @@ slice skip_dict(slice s) asm "SKIPDICT";
;;; In other words loads 1 bit and if it is true
;;; loads first ref and return it with slice remainder
;;; otherwise returns `null` and slice remainder
(slice, cell) load_maybe_ref(slice s) asm( -> 1 0) "LDOPTREF";
(slice, cell) load_maybe_ref(slice s) asm(-> 1 0) "LDOPTREF";

;;; Preloads (Maybe ^Cell) from `slice` [s].
cell preload_maybe_ref(slice s) asm "PLDOPTREF";
Expand Down Expand Up @@ -434,7 +447,7 @@ builder store_slice(builder b, slice s) asm "STSLICER";
;;;
;;; Store amounts of TonCoins to the builder as VarUInteger 16
builder store_grams(builder b, int x) asm "STGRAMS";
builder store_coins(builder b, int x) asm "STGRAMS";
builder store_coins(builder b, int x) asm "STVARUINT16";

;;; Stores dictionary `D` represented by `cell` [c] or `null` into `builder` [b].
;;; In other words, stores a `1`-bit and a reference to [c] if [c] is not `null` and `0`-bit otherwise.
Expand Down Expand Up @@ -485,7 +498,7 @@ builder store_maybe_ref(builder b, cell c) asm(c b) "STOPTREF";

;;; Loads from slice [s] the only prefix that is a valid `MsgAddress`,
;;; and returns both this prefix `s'` and the remainder `s''` of [s] as slices.
(slice, slice) load_msg_addr(slice s) asm( -> 1 0) "LDMSGADDR";
(slice, slice) load_msg_addr(slice s) asm(-> 1 0) "LDMSGADDR";

;;; Decomposes slice [s] containing a valid `MsgAddress` into a `tuple t` with separate fields of this `MsgAddress`.
;;; If [s] is not a valid `MsgAddress`, a cell deserialization exception is thrown.
Expand Down Expand Up @@ -618,8 +631,6 @@ int get_seed() impure asm "RANDSEED";
() randomize_lt() impure asm "LTIME" "ADDRAND";

;;; Checks whether the data parts of two slices coinside
int equal_slice_bits(slice a, slice b) asm "SDEQ";
int equal_slices(slice a, slice b) asm "SDEQ";

int equal_slices_bits(slice a, slice b) asm "SDEQ";
;;; Concatenates two builders
builder store_builder(builder to, builder from) asm "STBR";
Loading

0 comments on commit c5465be

Please sign in to comment.