From de59950d90f4bac12dccda075d0583c00cc67cb2 Mon Sep 17 00:00:00 2001 From: Oleg Andreev Date: Wed, 14 Dec 2022 09:46:05 +0100 Subject: [PATCH 01/14] Data signatures proposal --- text/0000-data-signatures.md | 227 +++++++++++++++++++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 text/0000-data-signatures.md diff --git a/text/0000-data-signatures.md b/text/0000-data-signatures.md new file mode 100644 index 00000000..49f35f68 --- /dev/null +++ b/text/0000-data-signatures.md @@ -0,0 +1,227 @@ +- **TEP**: [0](https://github.com/ton-blockchain/TEPs/pull/0) *(don't change)* +- **title**: Data Signatures +- **status**: Draft +- **type**: Core +- **authors**: [Steve Korshakov](https://github.com/ex3ndr), [Oleg Andreev](https://github.com/oleganza), [Sergey Andreev](https://github.com/siandreev) +- **created**: 13.12.2022 +- **replaces**: [TEP-0](https://github.com/ton-blockchain/TEPs/blob/master/0000-template.md) +- **replaced by**: - + +# Summary + +Safe signing for non-transaction data by the wallet’s key. + +# Motivation + +User’s wallet in TON ecosystem is not only used to perform asset transfers, but also plays a role of a universal identifier for on-chain and off-chain application. + +Most commonly, the wallet is used to send TON messages that transfer coins, change ownership of tokens and interact with other smart contracts. In all these cases the client app signs a well-formed transaction that can be verified by the wallet’s public key. + +The proposed protocol addresses scenarios where the wallet’s public key verifies arbitrary data used within contracts other than the user’s wallet (that is, non-transaction data) or offchain applications. + +# Examples + +1. Proving ownership of an address for off-chain services. +2. Signing a structured message to be verified in a TON smart contract (inside TVM). + +# Safe hashing + +To sign a transaction (or just a cell) for TON it is required to create **Cell Representation**, hash it and then sign. Our goal is to create a signature scheme that guarantees to never collide with the signed cells, and therefore guarantee that this scheme cannot be abused to send transaction on behalf of the wallet. + +From the TON whitepaper: + +>3.1.4. Standard cell representation. +> +>When a cell needs to be transferred by a network protocol or stored in a disk file, it must be serialized. +> +>The standard representation `CellRepr(c) = CellRepr∞(c)` of a cell `c` as an octet (byte) sequence is constructed as follows: +>1. Two descriptor bytes `d1` and `d2` are serialized first. Byte `d1` equals `r+8s+32l`, where `0 ≤ r ≤ 4` is the quantity of cell references contained in the cell, `0 ≤ l ≤ 3` is the level of the cell, and `0 ≤ s ≤ 1` is 1 for exotic cells and 0 for ordinary cells. Byte `d2` equals ``⌊b/8⌋+⌈b/8⌉``, where `0 ≤ b ≤ 1023` is the quantity of data bits in `c`. +>2. Then the data bits are serialized as `⌈b/8⌉` 8-bit octets (bytes). If `b` is not a multiple of eight, a binary 1 and up to six binary 0s are appended to the data bits. After that, the data is split into `⌈b/8⌉` eight-bit groups, and each group is interpreted as +>an unsigned big-endian integer 0 . . . 255 and stored into an octet. +>3. Finally, each of the `r` cell references is represented by 32 bytes containing the 256-bit representation hash `Hash(ci)`, explained below in 3.1.5, of the cell `ci` referred to. +> +>In this way, `2 + ⌈b/8⌉ + 32r` bytes of `CellRepr(c)` are obtained. + + +From the documentation follows that if we want to sign a cell with a single reference it will have a form ``. Now we need to construct such `prefix` that the cell representation became invalid. It is obvious that values `5 ≤ r ≤ 7`, `2 ≤ s ≤ 3` and `4 ≤ l ≤ 7` are all invalid. We will pick the maximum values for each of these parameters making the byte `d1` equal `0xff`. + +While this is enough to make the cell representation invalid, we will strengthen it further in case the cell representation is expanded in the future. Second byte `d2` does not have invalid values by itself, so let's just pick the same maximum value `0xff`. This value would indicate `1023` bits of data in the cell. We make that value invalid if we write a bit string that is less than 127 bytes long. + +# Specification + +Let `X` be the arbitrary payload cell. + +Let `timestamp` be the UNIX timestamp in seconds (since 00:00:00 UTC on 1 January 1970) on signer’s device at the moment on creating the signature. + +Let `schema_version` be the 4-byte number indicating the layout and semantics of payload `X`. + +To sign an arbitrary cell that couldn't be used as a transaction in blockchain we compute data for signing in the following way: + +``` +ed25519( + sha256( + 0xffff ++ + uint32be(schema_version) ++ + uint64be(timestamp) ++ + cell_hash(X) + ), + privkey +) +``` + +In JS: + +```js +let X: Cell; // Payload cell +let prefix = Buffer.alloc(2 + 4 + 8); // d1 + d2 + version + timestamp +prefix.writeUInt8(0xff); +prefix.writeUInt8(0xff); +prefix.writeUint32BE(schema_version); +prefix.writeUint64BE(timestamp); +let sighash = sha256(Buffer.concat([prefix, X.hash()])); +let signature = Ed25519Sign(sighash, privkey); +``` + +In FunC: + +``` +cell X; ;; Payload cell +var b = begin_cell() + .store_uint(0xff, 8) + .store_uint(0xff, 8) + .store_uint(schema_version, 32) + .store_uint(timestamp, 64) + .store_uint(cell_hash(x), 256) + .end_cell(); +var target_hash = string_hash(b); +var is_valid = check_signature(target_hash, sig, pk); +``` + +## Transporting signed data into smart contracts + +This specification recommends the following packaging of the signed data: + +``` +Cell { + bits: signature (512 bits) ++ schema_version (32 bits) ++ timestamp (64 bits) + refs: [ X ] +} +``` + + +## Payload verification + +For users’ safety every signature should be bound to a specific *place* and *time*. Note that all the signatures are produced by the same wallet’s key and each app, service or smart contract must enforce domain separation for itself. + +**Schema version** is used to specify the layout of payload cell that in turn defines domain separation. The app should verify the schema version value and reject signatures with unsupported schema version. + +This specification reserves all schema versions with high bit set to 0 (i.e. in the interval `[0, 2**31)`). Applications may use non-standard schemas in the range `[2**31, 2**32)`. + +**Payload cell** contains arbitrary data. + +**Timestamp** binds the signature to the moment of time. Applications must reject expired signatures per their TTL parameter. + + +## Standard schema versions + +### Version 0: plain text message + +Version 0 schema defines the _bits_ portion of the payload cell as UTF-8 text string that should be displayed to the user. + +Binary parameters (not visible to the user) are placed in the cell references. + +Wallets MUST display the text string to the user. + +Applications MUST verify the contents of the signed string to enforce the domain separation. + + +``` +var X_version0 = begin_cell() + .store_slice("utf8 text") + .store_ref(begin_cell().store_slice("data...").end_cell()) + .end_cell(); +``` + +### Version 1: binding to a contract + +Version 1 binds the message to a contract address. + +Wallets MUST display the contract address to the user. + +TON contract MUST verify that the signed contract address matches its own. + +``` +var X_version1 = begin_cell() + .store_slice() + .store_ref(begin_cell().store_slice("data...").end_cell()) + .end_cell(); +``` + +### Version 2: binding to a TON.DNS name + +Version 2 binds the message to a TON.DNS name. + +Wallets MUST display the TON.DNS name and verify that the request came from the current owner of that DNS record. +Verification of the request origin is outside the scope of this specification. + +Applications MUST verify that the signed name matches the name of their application. + +``` +var X_version1 = begin_cell() + .store_slice() + .store_ref(begin_cell().store_slice("data...").end_cell()) + .end_cell(); +``` + + + + +# Drawbacks + +None + + +# Rationale and alternatives + +## Encoding data in cells + +Offchain applications do not generally need to work with TON cells, however we propose a single encoding that is also usable inside TVM to keep the specification simple. + + +## Binding signatures to a current timestamp + +Schnorr signatures (e.g. Ed25519) are non-repudiable and replayable by design. To avoid long-range vulnerabilities, e.g. when a secret key becomes known, all signatures must be bound to the shortest time window that is reasonable in a given application. For instance, a few minutes for a real-time use by a single party, or several hours or days for collecting signatures from multiple parties. + + +## Schema version and payload verification + +User’s security depends on cooperation between the wallets and the applications to enforce *domain separation*. + +Applications enforce domain separation to reject signatures from other domains. + +Wallets enforce domain separation to protect users from inadvertently signing for another app. + +The role of schema version is to coordinate wallets and apps. + +**Version 1** offers the most relaxed guarantees with no built-in verification on the wallet’s part. User needs to check the text they are signing and apps must embed domain separation in that text. + +**Version 2** offers strong binding to a specific smart contract. Wallets may display a name and an icon for the well-known contracts and even interpret parameters as specific actions. + +**Version 3** offers strong binding to a TON.DNS record. This is allows wallets perform a real-time verification that the request is signed by the named service and eliminate virtually any possibility for phishing since the service controls the entire authentication flow: even if the user does not pay attention to the text in the confirmation window. + + +# Prior art + +This proposal is a simplified variation of [Ethereum EIP-1271](https://eips.ethereum.org/EIPS/eip-1271). + +This is based on [Steve Korshakov’s](https://github.com/ex3ndr) [safe signing proposal](https://github.com/ton-blockchain/TEPs/pull/93). + +# Unresolved questions + +None + +# Future possibilities + +In the future more schema versions could be added that specify the contents of the payload data along with the protocol for verifying that data. + + From 0f20993140719594e680782656961c25f73072c9 Mon Sep 17 00:00:00 2001 From: Oleg Andreev Date: Wed, 14 Dec 2022 15:28:38 +0100 Subject: [PATCH 02/14] removed hidden data from plaintext msg; all texts are chunked; address+domain could be used together --- text/0000-data-signatures.md | 124 +++++++++++++++++++++-------------- 1 file changed, 73 insertions(+), 51 deletions(-) diff --git a/text/0000-data-signatures.md b/text/0000-data-signatures.md index 49f35f68..06c895b5 100644 --- a/text/0000-data-signatures.md +++ b/text/0000-data-signatures.md @@ -17,7 +17,7 @@ User’s wallet in TON ecosystem is not only used to perform asset transfers, bu Most commonly, the wallet is used to send TON messages that transfer coins, change ownership of tokens and interact with other smart contracts. In all these cases the client app signs a well-formed transaction that can be verified by the wallet’s public key. -The proposed protocol addresses scenarios where the wallet’s public key verifies arbitrary data used within contracts other than the user’s wallet (that is, non-transaction data) or offchain applications. +The proposed protocol addresses scenarios where the wallet’s public key verifies arbitrary data used within offchain applications and also on-chain contracts other than the user’s wallet (that is, non-transaction data). # Examples @@ -49,21 +49,21 @@ While this is enough to make the cell representation invalid, we will strengthen # Specification -Let `X` be the arbitrary payload cell. +Let `X` be the arbitrary payload cell. The layout of the payload cell is specified using TL-B. Let `timestamp` be the UNIX timestamp in seconds (since 00:00:00 UTC on 1 January 1970) on signer’s device at the moment on creating the signature. -Let `schema_version` be the 4-byte number indicating the layout and semantics of payload `X`. +Let `schema_crc` be the 4-byte CRC32 of the TL-B scheme that specifies the layout and semantics of payload `X`. To sign an arbitrary cell that couldn't be used as a transaction in blockchain we compute data for signing in the following way: ``` ed25519( sha256( - 0xffff ++ - uint32be(schema_version) ++ - uint64be(timestamp) ++ - cell_hash(X) + 0xffff ++ + uint32be(schema_crc) ++ + uint64be(timestamp) ++ + cell_hash(X) ), privkey ) @@ -76,7 +76,7 @@ let X: Cell; // Payload cell let prefix = Buffer.alloc(2 + 4 + 8); // d1 + d2 + version + timestamp prefix.writeUInt8(0xff); prefix.writeUInt8(0xff); -prefix.writeUint32BE(schema_version); +prefix.writeUint32BE(schema_crc); prefix.writeUint64BE(timestamp); let sighash = sha256(Buffer.concat([prefix, X.hash()])); let signature = Ed25519Sign(sighash, privkey); @@ -85,11 +85,11 @@ let signature = Ed25519Sign(sighash, privkey); In FunC: ``` -cell X; ;; Payload cell +cell X; ;; Payload cell var b = begin_cell() .store_uint(0xff, 8) .store_uint(0xff, 8) - .store_uint(schema_version, 32) + .store_uint(schema_crc, 32) .store_uint(timestamp, 64) .store_uint(cell_hash(x), 256) .end_cell(); @@ -103,7 +103,7 @@ This specification recommends the following packaging of the signed data: ``` Cell { - bits: signature (512 bits) ++ schema_version (32 bits) ++ timestamp (64 bits) + bits: signature (512 bits) ++ schema_crc (32 bits) ++ timestamp (64 bits) refs: [ X ] } ``` @@ -113,67 +113,83 @@ Cell { For users’ safety every signature should be bound to a specific *place* and *time*. Note that all the signatures are produced by the same wallet’s key and each app, service or smart contract must enforce domain separation for itself. -**Schema version** is used to specify the layout of payload cell that in turn defines domain separation. The app should verify the schema version value and reject signatures with unsupported schema version. +**Schema CRC** indicates the layout of payload cell that in turn defines domain separation. The app should verify the schema version value and reject signatures with unsupported schemas. -This specification reserves all schema versions with high bit set to 0 (i.e. in the interval `[0, 2**31)`). Applications may use non-standard schemas in the range `[2**31, 2**32)`. +**Payload cell** contains arbitrary data per its TL-B definition to be verified and interpreted by the app. -**Payload cell** contains arbitrary data. - -**Timestamp** binds the signature to the moment of time. Applications must reject expired signatures per their TTL parameter. +**Timestamp** binds the signature to the time of signing per user’s local clock. Applications must reject expired signatures per their internal TTL parameter. ## Standard schema versions -### Version 0: plain text message +### Short plain text message + +This schema is used to sign UTF-8 text messages using chunked encoding (same as in TON.DNS). + +TL-B: -Version 0 schema defines the _bits_ portion of the payload cell as UTF-8 text string that should be displayed to the user. +``` +plaintext text:ChunkedText = PayloadCell; + +// From block.tlb: +chunk_ref$_ {n:#} ref:^(TextChunks (n + 1)) = TextChunkRef (n + 1); +chunk_ref_empty$_ = TextChunkRef 0; +text_chunk$_ {n:#} len:(## 8) data:(bits (len * 8)) next:(TextChunkRef n) = TextChunks (n + 1); +text_chunk_empty$_ = TextChunks 0; +text$_ chunks:(## 8) rest:(TextChunks chunks) = ChunkedText; +``` -Binary parameters (not visible to the user) are placed in the cell references. +Schema: + +``` +crc32('plaintext text:ChunkedText = PayloadCell') = 0x5c9f9d40 +``` Wallets MUST display the text string to the user. Applications MUST verify the contents of the signed string to enforce the domain separation. +### Application binding -``` -var X_version0 = begin_cell() - .store_slice("utf8 text") - .store_ref(begin_cell().store_slice("data...").end_cell()) - .end_cell(); -``` +This schema allows signing binary data for a target application identified by the TON.DNS name, contract address or both. -### Version 1: binding to a contract +TL-B: -Version 1 binds the message to a contract address. +``` +app_data data:^Cell address:(Maybe MsgAddress) domain:(Maybe ChunkedText) = PayloadCell; + +// From block.tlb: +chunk_ref$_ {n:#} ref:^(TextChunks (n + 1)) = TextChunkRef (n + 1); +chunk_ref_empty$_ = TextChunkRef 0; +text_chunk$_ {n:#} len:(## 8) data:(bits (len * 8)) next:(TextChunkRef n) = TextChunks (n + 1); +text_chunk_empty$_ = TextChunks 0; +text$_ chunks:(## 8) rest:(TextChunks chunks) = ChunkedText; +``` -Wallets MUST display the contract address to the user. +where: +* `data` contains application-specific data; +* `address` is an optional contract address that receives the signed message; +* `domain` is a fully-qualified TON.DNS domain in a reversed zero-delimited format (e.g. `ton\0example\0myapp\0` for `myapp.example.ton`); -TON contract MUST verify that the signed contract address matches its own. +Schema: ``` -var X_version1 = begin_cell() - .store_slice() - .store_ref(begin_cell().store_slice("data...").end_cell()) - .end_cell(); +crc32('app_data payload:^Cell address:(Maybe MsgAddress) domain:(Maybe ChunkedText) = PayloadCell') + = 0x6d3c5436 ``` -### Version 2: binding to a TON.DNS name +Wallets MUST reject requests where neither domain, nor address are specified. -Version 2 binds the message to a TON.DNS name. +Wallets MUST display the contract address to the user if it is specified. -Wallets MUST display the TON.DNS name and verify that the request came from the current owner of that DNS record. +Wallets MUST display the TON.DNS name (if it is specified) and verify that the request came from the current owner of that DNS record. Verification of the request origin is outside the scope of this specification. -Applications MUST verify that the signed name matches the name of their application. - -``` -var X_version1 = begin_cell() - .store_slice() - .store_ref(begin_cell().store_slice("data...").end_cell()) - .end_cell(); -``` +TON contracts MUST verify that the message includes the address and it matches the target contract’s address. +Applications MUST verify that the signed name matches their name. Contracts MAY also perform the same check where applicable. +Application MAY display a human-readable meaning of the `data` field, if they are aware of its layout for a given smart contract `address` or the service indicated by the `domain`. # Drawbacks @@ -187,13 +203,15 @@ None Offchain applications do not generally need to work with TON cells, however we propose a single encoding that is also usable inside TVM to keep the specification simple. - ## Binding signatures to a current timestamp -Schnorr signatures (e.g. Ed25519) are non-repudiable and replayable by design. To avoid long-range vulnerabilities, e.g. when a secret key becomes known, all signatures must be bound to the shortest time window that is reasonable in a given application. For instance, a few minutes for a real-time use by a single party, or several hours or days for collecting signatures from multiple parties. +Schnorr signatures such as Ed25519 are non-repudiable and replayable by design. To avoid long-range vulnerabilities (e.g. when a secret key becomes known) all signatures must be bound to the shortest time window that is reasonable in a given application. For instance, a few minutes for a real-time use by a single party, or several hours or days for collecting signatures from multiple parties. + +## Why timestamp is not a part of the payload? +Timestamp binding is needed in almost every protocol, so it makes sense to save space for application-specific data in the payload cell. -## Schema version and payload verification +## Notes on domain separation User’s security depends on cooperation between the wallets and the applications to enforce *domain separation*. @@ -201,13 +219,17 @@ Applications enforce domain separation to reject signatures from other domains. Wallets enforce domain separation to protect users from inadvertently signing for another app. -The role of schema version is to coordinate wallets and apps. +## Why messages are limited to 127 bytes? + +Current proposal offers the simplest text encoding using 1023 contiguous bits available in the payload cell. More complex text encoding schemes (e.g. chunked) are possible to add to this protocol later if needed. + +## How to use contract address binding -**Version 1** offers the most relaxed guarantees with no built-in verification on the wallet’s part. User needs to check the text they are signing and apps must embed domain separation in that text. +Wallets may display a name and an icon for the well-known contracts and even interpret parameters as specific actions. -**Version 2** offers strong binding to a specific smart contract. Wallets may display a name and an icon for the well-known contracts and even interpret parameters as specific actions. +## How to use TON.DNS binding -**Version 3** offers strong binding to a TON.DNS record. This is allows wallets perform a real-time verification that the request is signed by the named service and eliminate virtually any possibility for phishing since the service controls the entire authentication flow: even if the user does not pay attention to the text in the confirmation window. +Binding the singature to the TON.DNS name allows wallets perform a real-time verification that the request is signed by the named service. This eliminates virtually any possibility for phishing since the service controls the entire authentication flow. Even if the user does not pay attention to the text in the confirmation window, it would not be possible to trick user confirm action on that service without hijacking their session. # Prior art From 01c39bdecc87f545da80f9a9130b8829e45596e0 Mon Sep 17 00:00:00 2001 From: Oleg Andreev Date: Wed, 14 Dec 2022 15:29:46 +0100 Subject: [PATCH 03/14] typo fix and CRC update --- text/0000-data-signatures.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/text/0000-data-signatures.md b/text/0000-data-signatures.md index 06c895b5..97e9cbcb 100644 --- a/text/0000-data-signatures.md +++ b/text/0000-data-signatures.md @@ -174,8 +174,8 @@ where: Schema: ``` -crc32('app_data payload:^Cell address:(Maybe MsgAddress) domain:(Maybe ChunkedText) = PayloadCell') - = 0x6d3c5436 +crc32('app_data data:^Cell address:(Maybe MsgAddress) domain:(Maybe ChunkedText) = PayloadCell') + = 0xd35aba23 ``` Wallets MUST reject requests where neither domain, nor address are specified. From 4cf3db5e77740d54122227b52d7a11f61b931234 Mon Sep 17 00:00:00 2001 From: Oleg Andreev Date: Wed, 14 Dec 2022 15:30:28 +0100 Subject: [PATCH 04/14] remove stale limit --- text/0000-data-signatures.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/text/0000-data-signatures.md b/text/0000-data-signatures.md index 97e9cbcb..06ca6966 100644 --- a/text/0000-data-signatures.md +++ b/text/0000-data-signatures.md @@ -219,10 +219,6 @@ Applications enforce domain separation to reject signatures from other domains. Wallets enforce domain separation to protect users from inadvertently signing for another app. -## Why messages are limited to 127 bytes? - -Current proposal offers the simplest text encoding using 1023 contiguous bits available in the payload cell. More complex text encoding schemes (e.g. chunked) are possible to add to this protocol later if needed. - ## How to use contract address binding Wallets may display a name and an icon for the well-known contracts and even interpret parameters as specific actions. From ddd53f4ab52b323d14460f1ee31ae5449d1803a8 Mon Sep 17 00:00:00 2001 From: Oleg Andreev Date: Wed, 14 Dec 2022 16:05:21 +0100 Subject: [PATCH 05/14] remove chunked encoding and use sha256 instead --- text/0000-data-signatures.md | 46 +++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/text/0000-data-signatures.md b/text/0000-data-signatures.md index 06ca6966..22d5fb5b 100644 --- a/text/0000-data-signatures.md +++ b/text/0000-data-signatures.md @@ -126,23 +126,18 @@ For users’ safety every signature should be bound to a specific *place* and *t This schema is used to sign UTF-8 text messages using chunked encoding (same as in TON.DNS). +Text string is embedded through its SHA-256 hash while the original string is transmitted separately. + TL-B: ``` -plaintext text:ChunkedText = PayloadCell; - -// From block.tlb: -chunk_ref$_ {n:#} ref:^(TextChunks (n + 1)) = TextChunkRef (n + 1); -chunk_ref_empty$_ = TextChunkRef 0; -text_chunk$_ {n:#} len:(## 8) data:(bits (len * 8)) next:(TextChunkRef n) = TextChunks (n + 1); -text_chunk_empty$_ = TextChunks 0; -text$_ chunks:(## 8) rest:(TextChunks chunks) = ChunkedText; +plaintext text_sha256:bits256 = PayloadCell; ``` Schema: ``` -crc32('plaintext text:ChunkedText = PayloadCell') = 0x5c9f9d40 +crc32('plaintext text_sha256:bits256 = PayloadCell') = 0x51d557b9 ``` Wallets MUST display the text string to the user. @@ -153,36 +148,31 @@ Applications MUST verify the contents of the signed string to enforce the domain This schema allows signing binary data for a target application identified by the TON.DNS name, contract address or both. +Domain name is transmitted separately within the request that is signed by the service operator. + TL-B: ``` -app_data data:^Cell address:(Maybe MsgAddress) domain:(Maybe ChunkedText) = PayloadCell; - -// From block.tlb: -chunk_ref$_ {n:#} ref:^(TextChunks (n + 1)) = TextChunkRef (n + 1); -chunk_ref_empty$_ = TextChunkRef 0; -text_chunk$_ {n:#} len:(## 8) data:(bits (len * 8)) next:(TextChunkRef n) = TextChunks (n + 1); -text_chunk_empty$_ = TextChunks 0; -text$_ chunks:(## 8) rest:(TextChunks chunks) = ChunkedText; +app_data data:^Cell address:(Maybe MsgAddress) domain_sha256:(Maybe bits256) = PayloadCell; ``` where: * `data` contains application-specific data; * `address` is an optional contract address that receives the signed message; -* `domain` is a fully-qualified TON.DNS domain in a reversed zero-delimited format (e.g. `ton\0example\0myapp\0` for `myapp.example.ton`); +* `domain_sha256` is a SHA-256 of the fully-qualified TON.DNS domain in a human-readable form (e.g. `sha256("myapp.example.ton")`); Schema: ``` -crc32('app_data data:^Cell address:(Maybe MsgAddress) domain:(Maybe ChunkedText) = PayloadCell') - = 0xd35aba23 +crc32('app_data data:^Cell address:(Maybe MsgAddress) domain_sha256:(Maybe bits256) = PayloadCell') + = 0xc175a7f6 ``` Wallets MUST reject requests where neither domain, nor address are specified. -Wallets MUST display the contract address to the user if it is specified. +Wallets MUST display the contract address to the user if it is included in the signature. -Wallets MUST display the TON.DNS name (if it is specified) and verify that the request came from the current owner of that DNS record. +Wallets MUST display the TON.DNS name (if it is included in the signature) and verify that the request came from the current owner of that DNS record. Verification of the request origin is outside the scope of this specification. TON contracts MUST verify that the message includes the address and it matches the target contract’s address. @@ -203,6 +193,18 @@ None Offchain applications do not generally need to work with TON cells, however we propose a single encoding that is also usable inside TVM to keep the specification simple. +## Why plaintext message is hashed separately? + +To avoid unnecessary length limits and conceptual overhead with chunked encoding, the plaintext message is included via its SHA-256 hash. + +Applications should transmit plaintext messages separately. The goal of this proposal is to offer a safe signature protocol, not the transport protocol. + +## Why domain name is hashed separately? + +As with the plaintext message, we are avoiding unnecessary limits and complexity. +This comes at virtually no cost since the domain name would be transmitted explicitly anyway within the request for signature. + + ## Binding signatures to a current timestamp Schnorr signatures such as Ed25519 are non-repudiable and replayable by design. To avoid long-range vulnerabilities (e.g. when a secret key becomes known) all signatures must be bound to the shortest time window that is reasonable in a given application. For instance, a few minutes for a real-time use by a single party, or several hours or days for collecting signatures from multiple parties. From b0a930b2d7e7e4ed3de5b8bc7eb0b515557acbac Mon Sep 17 00:00:00 2001 From: Oleg Andreev Date: Wed, 14 Dec 2022 16:07:22 +0100 Subject: [PATCH 06/14] order fix --- text/0000-data-signatures.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/text/0000-data-signatures.md b/text/0000-data-signatures.md index 22d5fb5b..a56c0097 100644 --- a/text/0000-data-signatures.md +++ b/text/0000-data-signatures.md @@ -153,19 +153,19 @@ Domain name is transmitted separately within the request that is signed by the s TL-B: ``` -app_data data:^Cell address:(Maybe MsgAddress) domain_sha256:(Maybe bits256) = PayloadCell; +app_data address:(Maybe MsgAddress) domain_sha256:(Maybe bits256) data:^Cell = PayloadCell; ``` where: -* `data` contains application-specific data; * `address` is an optional contract address that receives the signed message; * `domain_sha256` is a SHA-256 of the fully-qualified TON.DNS domain in a human-readable form (e.g. `sha256("myapp.example.ton")`); +* `data` contains application-specific data; Schema: ``` -crc32('app_data data:^Cell address:(Maybe MsgAddress) domain_sha256:(Maybe bits256) = PayloadCell') - = 0xc175a7f6 +crc32('app_data address:(Maybe MsgAddress) domain_sha256:(Maybe bits256) data:^Cell = PayloadCell') + = 0x9bb162af ``` Wallets MUST reject requests where neither domain, nor address are specified. From d88d55edd1044c32bd3f79cdd9e23a1ddaa96662 Mon Sep 17 00:00:00 2001 From: Oleg Andreev Date: Wed, 14 Dec 2022 19:38:07 +0100 Subject: [PATCH 07/14] Revert "order fix" This reverts commit b0a930b2d7e7e4ed3de5b8bc7eb0b515557acbac. --- text/0000-data-signatures.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/text/0000-data-signatures.md b/text/0000-data-signatures.md index a56c0097..22d5fb5b 100644 --- a/text/0000-data-signatures.md +++ b/text/0000-data-signatures.md @@ -153,19 +153,19 @@ Domain name is transmitted separately within the request that is signed by the s TL-B: ``` -app_data address:(Maybe MsgAddress) domain_sha256:(Maybe bits256) data:^Cell = PayloadCell; +app_data data:^Cell address:(Maybe MsgAddress) domain_sha256:(Maybe bits256) = PayloadCell; ``` where: +* `data` contains application-specific data; * `address` is an optional contract address that receives the signed message; * `domain_sha256` is a SHA-256 of the fully-qualified TON.DNS domain in a human-readable form (e.g. `sha256("myapp.example.ton")`); -* `data` contains application-specific data; Schema: ``` -crc32('app_data address:(Maybe MsgAddress) domain_sha256:(Maybe bits256) data:^Cell = PayloadCell') - = 0x9bb162af +crc32('app_data data:^Cell address:(Maybe MsgAddress) domain_sha256:(Maybe bits256) = PayloadCell') + = 0xc175a7f6 ``` Wallets MUST reject requests where neither domain, nor address are specified. From e32009d86a2e3b9ddc072ecc42eccb43ea9cc992 Mon Sep 17 00:00:00 2001 From: Oleg Andreev Date: Wed, 14 Dec 2022 19:38:17 +0100 Subject: [PATCH 08/14] Revert "remove chunked encoding and use sha256 instead" This reverts commit ddd53f4ab52b323d14460f1ee31ae5449d1803a8. --- text/0000-data-signatures.md | 46 +++++++++++++++++------------------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/text/0000-data-signatures.md b/text/0000-data-signatures.md index 22d5fb5b..06ca6966 100644 --- a/text/0000-data-signatures.md +++ b/text/0000-data-signatures.md @@ -126,18 +126,23 @@ For users’ safety every signature should be bound to a specific *place* and *t This schema is used to sign UTF-8 text messages using chunked encoding (same as in TON.DNS). -Text string is embedded through its SHA-256 hash while the original string is transmitted separately. - TL-B: ``` -plaintext text_sha256:bits256 = PayloadCell; +plaintext text:ChunkedText = PayloadCell; + +// From block.tlb: +chunk_ref$_ {n:#} ref:^(TextChunks (n + 1)) = TextChunkRef (n + 1); +chunk_ref_empty$_ = TextChunkRef 0; +text_chunk$_ {n:#} len:(## 8) data:(bits (len * 8)) next:(TextChunkRef n) = TextChunks (n + 1); +text_chunk_empty$_ = TextChunks 0; +text$_ chunks:(## 8) rest:(TextChunks chunks) = ChunkedText; ``` Schema: ``` -crc32('plaintext text_sha256:bits256 = PayloadCell') = 0x51d557b9 +crc32('plaintext text:ChunkedText = PayloadCell') = 0x5c9f9d40 ``` Wallets MUST display the text string to the user. @@ -148,31 +153,36 @@ Applications MUST verify the contents of the signed string to enforce the domain This schema allows signing binary data for a target application identified by the TON.DNS name, contract address or both. -Domain name is transmitted separately within the request that is signed by the service operator. - TL-B: ``` -app_data data:^Cell address:(Maybe MsgAddress) domain_sha256:(Maybe bits256) = PayloadCell; +app_data data:^Cell address:(Maybe MsgAddress) domain:(Maybe ChunkedText) = PayloadCell; + +// From block.tlb: +chunk_ref$_ {n:#} ref:^(TextChunks (n + 1)) = TextChunkRef (n + 1); +chunk_ref_empty$_ = TextChunkRef 0; +text_chunk$_ {n:#} len:(## 8) data:(bits (len * 8)) next:(TextChunkRef n) = TextChunks (n + 1); +text_chunk_empty$_ = TextChunks 0; +text$_ chunks:(## 8) rest:(TextChunks chunks) = ChunkedText; ``` where: * `data` contains application-specific data; * `address` is an optional contract address that receives the signed message; -* `domain_sha256` is a SHA-256 of the fully-qualified TON.DNS domain in a human-readable form (e.g. `sha256("myapp.example.ton")`); +* `domain` is a fully-qualified TON.DNS domain in a reversed zero-delimited format (e.g. `ton\0example\0myapp\0` for `myapp.example.ton`); Schema: ``` -crc32('app_data data:^Cell address:(Maybe MsgAddress) domain_sha256:(Maybe bits256) = PayloadCell') - = 0xc175a7f6 +crc32('app_data data:^Cell address:(Maybe MsgAddress) domain:(Maybe ChunkedText) = PayloadCell') + = 0xd35aba23 ``` Wallets MUST reject requests where neither domain, nor address are specified. -Wallets MUST display the contract address to the user if it is included in the signature. +Wallets MUST display the contract address to the user if it is specified. -Wallets MUST display the TON.DNS name (if it is included in the signature) and verify that the request came from the current owner of that DNS record. +Wallets MUST display the TON.DNS name (if it is specified) and verify that the request came from the current owner of that DNS record. Verification of the request origin is outside the scope of this specification. TON contracts MUST verify that the message includes the address and it matches the target contract’s address. @@ -193,18 +203,6 @@ None Offchain applications do not generally need to work with TON cells, however we propose a single encoding that is also usable inside TVM to keep the specification simple. -## Why plaintext message is hashed separately? - -To avoid unnecessary length limits and conceptual overhead with chunked encoding, the plaintext message is included via its SHA-256 hash. - -Applications should transmit plaintext messages separately. The goal of this proposal is to offer a safe signature protocol, not the transport protocol. - -## Why domain name is hashed separately? - -As with the plaintext message, we are avoiding unnecessary limits and complexity. -This comes at virtually no cost since the domain name would be transmitted explicitly anyway within the request for signature. - - ## Binding signatures to a current timestamp Schnorr signatures such as Ed25519 are non-repudiable and replayable by design. To avoid long-range vulnerabilities (e.g. when a secret key becomes known) all signatures must be bound to the shortest time window that is reasonable in a given application. For instance, a few minutes for a real-time use by a single party, or several hours or days for collecting signatures from multiple parties. From d2ade0b88412a1eb5b946922a38dbd101651fd8d Mon Sep 17 00:00:00 2001 From: Oleg Andreev Date: Wed, 14 Dec 2022 21:25:52 +0100 Subject: [PATCH 09/14] snake text encoding --- text/0000-data-signatures.md | 40 ++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/text/0000-data-signatures.md b/text/0000-data-signatures.md index 06ca6966..18da5a78 100644 --- a/text/0000-data-signatures.md +++ b/text/0000-data-signatures.md @@ -124,25 +124,23 @@ For users’ safety every signature should be bound to a specific *place* and *t ### Short plain text message -This schema is used to sign UTF-8 text messages using chunked encoding (same as in TON.DNS). +This schema is used to sign UTF-8 text messages using _snake format_ (per [TEP-64](https://github.com/ton-blockchain/TEPs/blob/master/text/0064-token-data-standard.md)). TL-B: ``` -plaintext text:ChunkedText = PayloadCell; - -// From block.tlb: -chunk_ref$_ {n:#} ref:^(TextChunks (n + 1)) = TextChunkRef (n + 1); -chunk_ref_empty$_ = TextChunkRef 0; -text_chunk$_ {n:#} len:(## 8) data:(bits (len * 8)) next:(TextChunkRef n) = TextChunks (n + 1); -text_chunk_empty$_ = TextChunks 0; -text$_ chunks:(## 8) rest:(TextChunks chunks) = ChunkedText; +plaintext text:Text = PayloadCell; + +// From TEP-64: +tail#_ {bn:#} b:(bits bn) = SnakeData ~0; +cons#_ {bn:#} {n:#} b:(bits bn) next:^(SnakeData ~n) = SnakeData ~(n + 1); +text#_ {n:#} data:(SnakeData ~n) = Text; ``` Schema: ``` -crc32('plaintext text:ChunkedText = PayloadCell') = 0x5c9f9d40 +crc32('plaintext text:Text = PayloadCell') = 0x754bf91b ``` Wallets MUST display the text string to the user. @@ -156,14 +154,12 @@ This schema allows signing binary data for a target application identified by th TL-B: ``` -app_data data:^Cell address:(Maybe MsgAddress) domain:(Maybe ChunkedText) = PayloadCell; - -// From block.tlb: -chunk_ref$_ {n:#} ref:^(TextChunks (n + 1)) = TextChunkRef (n + 1); -chunk_ref_empty$_ = TextChunkRef 0; -text_chunk$_ {n:#} len:(## 8) data:(bits (len * 8)) next:(TextChunkRef n) = TextChunks (n + 1); -text_chunk_empty$_ = TextChunks 0; -text$_ chunks:(## 8) rest:(TextChunks chunks) = ChunkedText; +app_data data:^Cell address:(Maybe MsgAddress) domain:(Maybe Text) = PayloadCell; + +// From TEP-64: +tail#_ {bn:#} b:(bits bn) = SnakeData ~0; +cons#_ {bn:#} {n:#} b:(bits bn) next:^(SnakeData ~n) = SnakeData ~(n + 1); +text#_ {n:#} data:(SnakeData ~n) = Text; ``` where: @@ -174,15 +170,15 @@ where: Schema: ``` -crc32('app_data data:^Cell address:(Maybe MsgAddress) domain:(Maybe ChunkedText) = PayloadCell') - = 0xd35aba23 +crc32('app_data data:^Cell address:(Maybe MsgAddress) domain:(Maybe Text) = PayloadCell') + = 0xee8c4d2d ``` Wallets MUST reject requests where neither domain, nor address are specified. -Wallets MUST display the contract address to the user if it is specified. +Wallets MUST display the contract address to the user if it is included in the signature. -Wallets MUST display the TON.DNS name (if it is specified) and verify that the request came from the current owner of that DNS record. +Wallets MUST display the TON.DNS name (if it is included under signature) and verify that the request came from the current owner of that DNS record. Verification of the request origin is outside the scope of this specification. TON contracts MUST verify that the message includes the address and it matches the target contract’s address. From 223ef072b1811d6fcc43f766fe2778ee42422c89 Mon Sep 17 00:00:00 2001 From: Oleg Andreev Date: Wed, 14 Dec 2022 21:42:22 +0100 Subject: [PATCH 10/14] remove invalid cell repr hack and sign 352-bit message instead --- text/0000-data-signatures.md | 60 ++++++++++++------------------------ 1 file changed, 20 insertions(+), 40 deletions(-) diff --git a/text/0000-data-signatures.md b/text/0000-data-signatures.md index 18da5a78..4ce2e7f6 100644 --- a/text/0000-data-signatures.md +++ b/text/0000-data-signatures.md @@ -2,7 +2,7 @@ - **title**: Data Signatures - **status**: Draft - **type**: Core -- **authors**: [Steve Korshakov](https://github.com/ex3ndr), [Oleg Andreev](https://github.com/oleganza), [Sergey Andreev](https://github.com/siandreev) +- **authors**: [Oleg Andreev](https://github.com/oleganza), [Sergey Andreev](https://github.com/siandreev), [Denis Subbotin](https://github.com/mr-tron) - **created**: 13.12.2022 - **replaces**: [TEP-0](https://github.com/ton-blockchain/TEPs/blob/master/0000-template.md) - **replaced by**: - @@ -26,26 +26,19 @@ The proposed protocol addresses scenarios where the wallet’s public key verifi # Safe hashing -To sign a transaction (or just a cell) for TON it is required to create **Cell Representation**, hash it and then sign. Our goal is to create a signature scheme that guarantees to never collide with the signed cells, and therefore guarantee that this scheme cannot be abused to send transaction on behalf of the wallet. +To sign a transaction (or just a cell) for TON it is required to create **Cell Representation**, hash it and then sign. Our goal is to create a signature scheme that guarantees to never collide with the signed cells so that signed data messages cannot be used as transactions made on behalf of the wallet. -From the TON whitepaper: +We observe the following implementation in wallet smart contracts (FunC) where signature is computed over 256-bit message equal to the SHA256 hash of an arbitrary cell: ->3.1.4. Standard cell representation. -> ->When a cell needs to be transferred by a network protocol or stored in a disk file, it must be serialized. -> ->The standard representation `CellRepr(c) = CellRepr∞(c)` of a cell `c` as an octet (byte) sequence is constructed as follows: ->1. Two descriptor bytes `d1` and `d2` are serialized first. Byte `d1` equals `r+8s+32l`, where `0 ≤ r ≤ 4` is the quantity of cell references contained in the cell, `0 ≤ l ≤ 3` is the level of the cell, and `0 ≤ s ≤ 1` is 1 for exotic cells and 0 for ordinary cells. Byte `d2` equals ``⌊b/8⌋+⌈b/8⌉``, where `0 ≤ b ≤ 1023` is the quantity of data bits in `c`. ->2. Then the data bits are serialized as `⌈b/8⌉` 8-bit octets (bytes). If `b` is not a multiple of eight, a binary 1 and up to six binary 0s are appended to the data bits. After that, the data is split into `⌈b/8⌉` eight-bit groups, and each group is interpreted as ->an unsigned big-endian integer 0 . . . 255 and stored into an octet. ->3. Finally, each of the `r` cell references is represented by 32 bytes containing the 256-bit representation hash `Hash(ci)`, explained below in 3.1.5, of the cell `ci` referred to. -> ->In this way, `2 + ⌈b/8⌉ + 32r` bytes of `CellRepr(c)` are obtained. +``` +check_signature(slice_hash(in_msg), signature, public_key) +``` +In this proposal we are going to compute signature over 352-bit message that consists of the schema identifier, timestamp and a hash of the payload cell X. -From the documentation follows that if we want to sign a cell with a single reference it will have a form ``. Now we need to construct such `prefix` that the cell representation became invalid. It is obvious that values `5 ≤ r ≤ 7`, `2 ≤ s ≤ 3` and `4 ≤ l ≤ 7` are all invalid. We will pick the maximum values for each of these parameters making the byte `d1` equal `0xff`. +This signature is domain-separated from wallet transactions by having a different length of the message. +Domain separation for the data messages is provided using the schema identifier and various layouts of the payload X. -While this is enough to make the cell representation invalid, we will strengthen it further in case the cell representation is expanded in the future. Second byte `d2` does not have invalid values by itself, so let's just pick the same maximum value `0xff`. This value would indicate `1023` bits of data in the cell. We make that value invalid if we write a bit string that is less than 127 bytes long. # Specification @@ -58,43 +51,29 @@ Let `schema_crc` be the 4-byte CRC32 of the TL-B scheme that specifies the layou To sign an arbitrary cell that couldn't be used as a transaction in blockchain we compute data for signing in the following way: ``` -ed25519( - sha256( - 0xffff ++ - uint32be(schema_crc) ++ - uint64be(timestamp) ++ - cell_hash(X) - ), - privkey -) +ed25519(uint32be(schema_crc) ++ uint64be(timestamp) ++ cell_hash(X), privkey) ``` In JS: ```js -let X: Cell; // Payload cell -let prefix = Buffer.alloc(2 + 4 + 8); // d1 + d2 + version + timestamp -prefix.writeUInt8(0xff); -prefix.writeUInt8(0xff); +let X: Cell; // Payload cell +let prefix = Buffer.alloc(4 + 8); // version + timestamp prefix.writeUint32BE(schema_crc); prefix.writeUint64BE(timestamp); -let sighash = sha256(Buffer.concat([prefix, X.hash()])); -let signature = Ed25519Sign(sighash, privkey); +let signature = Ed25519Sign(Buffer.concat([prefix, X.hash()]), privkey); ``` In FunC: ``` -cell X; ;; Payload cell -var b = begin_cell() - .store_uint(0xff, 8) - .store_uint(0xff, 8) +cell X; ;; Payload cell +var m = begin_cell() .store_uint(schema_crc, 32) .store_uint(timestamp, 64) .store_uint(cell_hash(x), 256) .end_cell(); -var target_hash = string_hash(b); -var is_valid = check_signature(target_hash, sig, pk); +var is_valid = check_data_signature(begin_parse(m), sig, pk) ``` ## Transporting signed data into smart contracts @@ -147,6 +126,7 @@ Wallets MUST display the text string to the user. Applications MUST verify the contents of the signed string to enforce the domain separation. + ### Application binding This schema allows signing binary data for a target application identified by the TON.DNS name, contract address or both. @@ -228,7 +208,9 @@ Binding the singature to the TON.DNS name allows wallets perform a real-time ver This proposal is a simplified variation of [Ethereum EIP-1271](https://eips.ethereum.org/EIPS/eip-1271). -This is based on [Steve Korshakov’s](https://github.com/ex3ndr) [safe signing proposal](https://github.com/ton-blockchain/TEPs/pull/93). +This is originally inspired by [Steve Korshakov’s](https://github.com/ex3ndr) [safe signing proposal](https://github.com/ton-blockchain/TEPs/pull/93), +but we observe that there is a possibility of avoiding unnecessary layer of hashing and constructing invalid cell representation +since TVM support signature checks over arbitrary-sized messages. # Unresolved questions @@ -237,5 +219,3 @@ None # Future possibilities In the future more schema versions could be added that specify the contents of the payload data along with the protocol for verifying that data. - - From 049c563e13744bf1563b02b1267d9ee60e568a7a Mon Sep 17 00:00:00 2001 From: Oleg Andreev Date: Thu, 15 Dec 2022 09:25:57 +0100 Subject: [PATCH 11/14] domain name in ^Text for pruning --- text/0000-data-signatures.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/text/0000-data-signatures.md b/text/0000-data-signatures.md index 4ce2e7f6..6889a899 100644 --- a/text/0000-data-signatures.md +++ b/text/0000-data-signatures.md @@ -134,7 +134,7 @@ This schema allows signing binary data for a target application identified by th TL-B: ``` -app_data data:^Cell address:(Maybe MsgAddress) domain:(Maybe Text) = PayloadCell; +app_data data:^Cell address:(Maybe MsgAddress) domain:(Maybe ^Text) = PayloadCell; // From TEP-64: tail#_ {bn:#} b:(bits bn) = SnakeData ~0; @@ -150,8 +150,8 @@ where: Schema: ``` -crc32('app_data data:^Cell address:(Maybe MsgAddress) domain:(Maybe Text) = PayloadCell') - = 0xee8c4d2d +crc32('app_data data:^Cell address:(Maybe MsgAddress) domain:(Maybe ^Text) = PayloadCell') + = 0xd38095a3 ``` Wallets MUST reject requests where neither domain, nor address are specified. @@ -187,6 +187,10 @@ Schnorr signatures such as Ed25519 are non-repudiable and replayable by design. Timestamp binding is needed in almost every protocol, so it makes sense to save space for application-specific data in the payload cell. +## Why domain name is in another cell? + +Domain name is declared as `^Text` to allow pruning and storing cell hash in its place. + ## Notes on domain separation User’s security depends on cooperation between the wallets and the applications to enforce *domain separation*. From 26dd089c34ce0cbc3e3e1d0568aa0beb028bb4a3 Mon Sep 17 00:00:00 2001 From: Oleg Andreev Date: Thu, 15 Dec 2022 09:36:25 +0100 Subject: [PATCH 12/14] domain:^Text --- text/0000-data-signatures.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/text/0000-data-signatures.md b/text/0000-data-signatures.md index 6889a899..92884c71 100644 --- a/text/0000-data-signatures.md +++ b/text/0000-data-signatures.md @@ -134,7 +134,7 @@ This schema allows signing binary data for a target application identified by th TL-B: ``` -app_data data:^Cell address:(Maybe MsgAddress) domain:(Maybe ^Text) = PayloadCell; +app_data address:(Maybe MsgAddress) domain:(Maybe ^Text) data:^Cell = PayloadCell; // From TEP-64: tail#_ {bn:#} b:(bits bn) = SnakeData ~0; @@ -150,8 +150,8 @@ where: Schema: ``` -crc32('app_data data:^Cell address:(Maybe MsgAddress) domain:(Maybe ^Text) = PayloadCell') - = 0xd38095a3 +crc32('app_data address:(Maybe MsgAddress) domain:(Maybe ^Text) data:^Cell = PayloadCell') + = 0xd6712a27 ``` Wallets MUST reject requests where neither domain, nor address are specified. @@ -222,4 +222,5 @@ None # Future possibilities -In the future more schema versions could be added that specify the contents of the payload data along with the protocol for verifying that data. +A future extension to the protocol may specify the layout and semantics of the payload data (e.g. attaching a TL-B scheme). +This would enable wallets display human-readable structure of the message to be signed. From 69cd1c060808246c3974e7ef7fc2b47c2d32e6f2 Mon Sep 17 00:00:00 2001 From: Oleg Andreev Date: Thu, 15 Dec 2022 09:50:41 +0100 Subject: [PATCH 13/14] add ext field --- text/0000-data-signatures.md | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/text/0000-data-signatures.md b/text/0000-data-signatures.md index 92884c71..91a3b16c 100644 --- a/text/0000-data-signatures.md +++ b/text/0000-data-signatures.md @@ -134,7 +134,7 @@ This schema allows signing binary data for a target application identified by th TL-B: ``` -app_data address:(Maybe MsgAddress) domain:(Maybe ^Text) data:^Cell = PayloadCell; +app_data address:(Maybe MsgAddress) domain:(Maybe ^Text) data:^Cell ext:(Maybe ^Cell) = PayloadCell; // From TEP-64: tail#_ {bn:#} b:(bits bn) = SnakeData ~0; @@ -143,15 +143,16 @@ text#_ {n:#} data:(SnakeData ~n) = Text; ``` where: -* `data` contains application-specific data; * `address` is an optional contract address that receives the signed message; * `domain` is a fully-qualified TON.DNS domain in a reversed zero-delimited format (e.g. `ton\0example\0myapp\0` for `myapp.example.ton`); +* `data` contains application-specific data; +* `ext` is a cell for future extensions; Schema: ``` -crc32('app_data address:(Maybe MsgAddress) domain:(Maybe ^Text) data:^Cell = PayloadCell') - = 0xd6712a27 +crc32('app_data address:(Maybe MsgAddress) domain:(Maybe ^Text) data:^Cell ext:(Maybe ^Cell) = PayloadCell') + = 0x54b58535 ``` Wallets MUST reject requests where neither domain, nor address are specified. @@ -161,6 +162,8 @@ Wallets MUST display the contract address to the user if it is included in the s Wallets MUST display the TON.DNS name (if it is included under signature) and verify that the request came from the current owner of that DNS record. Verification of the request origin is outside the scope of this specification. +Wallets MUST display the `data` and `ext` contents to the user before signing. + TON contracts MUST verify that the message includes the address and it matches the target contract’s address. Applications MUST verify that the signed name matches their name. Contracts MAY also perform the same check where applicable. @@ -207,6 +210,13 @@ Wallets may display a name and an icon for the well-known contracts and even int Binding the singature to the TON.DNS name allows wallets perform a real-time verification that the request is signed by the named service. This eliminates virtually any possibility for phishing since the service controls the entire authentication flow. Even if the user does not pay attention to the text in the confirmation window, it would not be possible to trick user confirm action on that service without hijacking their session. +## How to display contents of signature + +In the `plaintext` scheme, the wallet simply shows the UTF-8 text as-is. + +In the `app_data` scheme, the wallet displays binary contents of the `data` and `ext` cells (e.g. in hex). +Future extensions to this protocol may add layout description into the `ext` field to describe the contents of the `data` in a human-readable form. + # Prior art From 2882578fa28fde91915d25da9ae6ed2e69947f9a Mon Sep 17 00:00:00 2001 From: Oleg Andreev Date: Thu, 15 Dec 2022 09:52:28 +0100 Subject: [PATCH 14/14] wording --- text/0000-data-signatures.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0000-data-signatures.md b/text/0000-data-signatures.md index 91a3b16c..4576b90e 100644 --- a/text/0000-data-signatures.md +++ b/text/0000-data-signatures.md @@ -210,7 +210,7 @@ Wallets may display a name and an icon for the well-known contracts and even int Binding the singature to the TON.DNS name allows wallets perform a real-time verification that the request is signed by the named service. This eliminates virtually any possibility for phishing since the service controls the entire authentication flow. Even if the user does not pay attention to the text in the confirmation window, it would not be possible to trick user confirm action on that service without hijacking their session. -## How to display contents of signature +## How to display data before signing In the `plaintext` scheme, the wallet simply shows the UTF-8 text as-is.