---
# System prepended metadata

title: Meta Transaction and Signing
tags: [Standard, Engineering]

---

# Meta Transaction and Signing

###### tags: `Engineering` `Standard`

## Signing

Here we defines the SPEC of the signing mechanism for validating a meta transaction.

### Tezos Signing

To normalzie the signing data from tezos, we need to pack each signing variables and turn it into bytes. For example, if we want to sign the contract address, we will do 

```ocaml
let contract_address_bytes = Bytes.pack Tezos.get_self_address in
```

After we have all the variables ready, we then concatenate them into a signing message with a message prefix `Tezos Signed Message:` and split all variables by the message separator `|` .


For example, if we are going to sign these three variables: `contract`, `tokenID`, `counter`. The signing message will be 

```ocaml
Tezos Signed Message:Bytes.pack($contract)|Bytes.pack($tokenID)|Bytes.pack($counter)
```

Which would be the following code specifically in ligo.

```ocaml
// message prefix: Tezos Signed Message:
let msg_prefix = 0x54657a6f73205369676e6564204d6573736167653a

// message separator: |
let msg_separator = 0x7c

let signing_message = Bytes.concat([
    msg_prefix; contract_address_bytes; 
    msg_separator; token_id_bytes; 
    msg_separator; counter_bytes;
])
```

Now we have the signing message ready. Now, we can sign the message by a Tezos account.

```ocaml
signature = sign(signing_hash)
```

:::info
Note: It is an convention for tezos sign function implicitly includes a step of hashing the signing message with `blake2b` before goes to crypto curve signing. Please make sure we do not make extra hash of the signing message.
:::

Thus, the whole process will be

```ocaml!
signature = 
    sign(
        Bytes.concat(
            "Tezos Signed Message:", 
            Bytes.pack($contract), "|", 
            Bytes.pack($tokenID), "|", 
            Bytes.pack($counter)
    ))
```

### Ethereum Signing

To do an Ethereum signing, we start from giving a list of signing variables. For those variables, we concatenate them into a bytes by `abi.encode`. For example, if there is a function with two parameters `tokenID` and `counter`, we will sign chainID, contract address, tokenID, and counter:

```solidity
bytes signing_message = abi.encode(block.chainid, address(this), tokenID, counter)
```
`chainID` and contract address are used for preventing replay attack between different chains.

Now we have the signing message. What we will do next is to hash the signing message into signing hash. In Ethereum, we use `keccak256` hash function. 

```solidity
bytes32 signing_hash = keccak256(signing_message)
```

In Ethereum [eth_sign](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign), it implicitly appends the message `\x19Ethereum Signed Message:\n32` in front of any signing data. Thus, the `ethSigedMessage` will end to be 

```solidity!
bytes32 ethSigedMessage = keccak256(
    abi.encodePacked("\x19Ethereum Signed Message:\n32", signing_hash));
```

The `ethSigedMessage` will be signed by an Ethereum account.

```go
signature = sign(ethSigedMessage)
```