Permalink
Browse files

Update details about External ID ordering, and signing

  • Loading branch information...
AdamSLevy committed Nov 25, 2018
1 parent 3a54cf9 commit 535c272bfee539a51d70a8a7a2d46f99d34d37fb
Showing with 61 additions and 34 deletions.
  1. +61 −34 fatips/0.md
@@ -208,36 +208,46 @@ entry.


#### External IDs
Transaction Entries must include two External IDs for every input address listed in the transaction: the RCD
that hashes to the corresponding input address, and a signature.
Transaction Entries must include exactly two External IDs for every input
address listed in the transaction: the RCD that hashes to the corresponding
input address, and a signature.

Implementations should ignore any External IDs after the first `2n`, where `n`
is the number of input addresses with respect to Factoid address signing & verification process. This allows a user to optionally append any additional External IDs.
In the case of normal transaction, all inputs must have a corresponding RCD in
an even External ID.

In the case of coinbase transactions, the last External ID is used to hold a signature of the issuing identity as per [FATIP-101](101.md). The `idNonce` being signed shall be the transaction `chain ID` concatenated with the entry content. The `IDKey` shall be the issuing identity's IDKey at the time of entry into Factom.
In the case of coinbase transactions, the RCD in the 0th External ID must hash
to the ID Key of the issuing Identity as per [FATIP-101](101.md).

Since the Transaction Entry Hash MUST be unique, implementations must ignore
any entries that do not contain EXACTLY twice as many External IDs as inputs.
This prevents replay of transactions through manipulating the Transaction Entry
Hash by appending additional External IDs to a previously posted valid
transaction.

In the following table `X` is any even number less than `2n`.

| External ID Index | External ID Value (RAW DATA) |
| -------------------------- | ------------------------------------------------------------ |
| 0 | RCD corresponding to `input[0].address` |
| 0 | RCD corresponding to one of the inputs or Issuer ID Key |
| 1 | ed25519 signature by key of RCD in preceding External ID |
| 2 | RCD corresponding to one of the inputs |
| 3 | ed25519 signature by key of RCD in preceding External ID |
| ... | |
| `X` | RCD corresponding to `input[X/2].address` |
| `X` | RCD corresponding to one of the inputs |
| `X + 1` | ed25519 signature by key of RCD in preceding External ID |
| `ExtIds[ExtID.length - 1]` | Raw binary ed25519 signature output of signing transaction `chainID` + entry content. ed25519 signature validation (`chainID`+ entry content, `idKey`, `ExtID[0]`) |



##### Encoding

All of the RCD and Signature External IDs in a Transaction Entry shall be raw
data and not use any encoding. The [Factom Explorer](https://explorer.factom.com/) now properly displays External IDs
that contain raw data as hex encoded data. So there is little reason to encode
the data we put in the External IDs.
data and not use any encoding. The [Factom
Explorer](https://explorer.factom.com/) now properly displays External IDs that
contain raw data as hex encoded data. So there is little reason to encode the
data we put in the External IDs.


##### RCD

The RCD is a data structure that hashes to the payload of a Factoid Address.
The RCD data structure is 33 bytes long. The first byte is the RCD type
(`0x01`), the remaining 32 bytes are a ed25519 public key.
@@ -255,7 +265,8 @@ To validate that an RCD "corresponds" to a Factoid Address,


##### Signature
The signature is the same as that used in a [Factoid

The cryptographic signature algorithm is the same as that used in a [Factoid
Transaction](https://github.com/FactomProject/FactomDocs/blob/master/factomDataStructureDetails.md#factoid-transaction).

From the Factom Documentation:
@@ -266,31 +277,47 @@ From the Factom Documentation:
> [canonical](https://github.com/FactomProject/ed25519/blob/master/ed25519.go#L143).
> This will limit malleability by attackers without the private key.
The signed data shall be the concatenation of the raw bytes of the chain ID and
the content of the entry.
A signed transaction should only be valid once, so signed data must be
protected against replay within a given FAT chain and across various FAT
chains. For this reason both the index of the External ID and the chain id is
used to salt the signature. This prevents reordering the External IDs and
replaying a transaction on a different chain.

```
signature = ed25519_sign(priv_key, chain_id + entry_content)
```
Let `i` be the integer index of the External ID that the signature will be
place in the Factom Entry.

The chain ID is included to prevent replay attacks across FAT token chains.
The signed data shall be the concatenation of the following:
1. The shortest (no leading zeros) string decimal representation of `int(i/2)`
2. The raw bytes of the chain ID
3. The content of the entry

For example, if there were two inputs, and `+` is concatenation of bytes, then
the valid External IDs would be,
```
ExtID[0] = 0x01 + pub_key0
ExtID[1] = ed25519_sign(priv_key0, "0" + chain_id + entry_content)
ExtID[2] = 0x01 + pub_key1
ExtID[3] = ed25519_sign(priv_key1, "1" + chain_id + entry_content)
```

### Transaction Validation and State

There are two types of transactions which have slightly different validation
requirements: Normal transactions between Factoid Addresses, and Coinbase
transactions that mint tokens. Coinbase transactions require an additional signature of the entry content by the issuer, stored in the transaction's ExtIds.
transactions that mint tokens. Coinbase transactions require an additional
signature of the entry content by the issuer, stored in the transaction's
ExtIds.

A Coinbase transaction is identified by whether it has an input from the
Coinbase address: `FA1zT4aFpEvcnPqPCigB3fvGu4Q4mTXY22iiuV69DqE1pNhdF2MC`

#### Computing the current state

Implementations must maintain the state of the balances of all addresses in
order to evaluate the validity of a transaction. The current state can be built
by iterating through all entries in the token chain and sequentially,
updating the state for any transaction that meets all of the necessary
Transaction Validation Requirements.
by iterating through all entries in the token chain and sequentially, updating
the state for any transaction that meets all of the necessary Transaction
Validation Requirements.

The following pseudo code describes how to compute the current state of all
balances. A transaction must be applied entirely or not at all. Entries that
@@ -312,9 +339,9 @@ for entry in transaction_chain.entries:

All Transactions must meet all of the T.x requirements.

Normal Transactions must also meet all of the N.x requirements.
Normal Transactions must additionally meet all of the N.x requirements.

Coinbase Transactions must also meet all of the C.x requirements.
Coinbase Transactions must additionally meet all of the C.x requirements.

In general, requirements are ordered by the computational and programmatic ease
of checking.
@@ -331,15 +358,15 @@ The x.3.x requirements are generally related to cryptographic validations.
- T.1.2: The JSON must contain all required transaction fields listed in the
above table. The fields must comply with all stated validation criteria. No
unspecified fields may be present.
- T.1.3: The sum of all values(amounts) in the `inputs` object must be equal to
the sum of all values(amounts) in the `outputs` object.
- T.1.3: The entry MUST contain exactly `2n` External IDs, where `n` is the
number of keys in the `inputs` object. This is required to prevent replay
attacks.
- T.1.4: A Factoid Address may only appear ONCE in the `inputs` and `outputs`
objects combined. This means that the "inputs" and "outputs" may not share
any common keys (Factoid Addresses), nor each have any duplicates.
- N.1.1: The entry MUST contain exactly `2n` External IDs, where `n` is the
number of keys in the `inputs` object. This is required to prevent replay
attacks.
- T.2.1: The entry hash of the transaction entry must be unique among all
- T.2.1: The sum of all values(amounts) in the `inputs` object must be equal to
the sum of all values(amounts) in the `outputs` object.
- T.2.2: The entry hash of the transaction entry must be unique among all
transactions belonging to this token.
- T.3.1: If `i` is odd then the `i`th External ID must be the raw data of a
valid signature verified against the public key stored in the last 32 bytes
@@ -363,9 +390,9 @@ All references to External ID indexes use `0`-based indexing.
key in `inputs`.
- N.2.2: The Factoid Addresses (keys) in `inputs` must all have balances
greater than or equal to their respective input amounts.
- N.3.1: If `i` is even then the `i`th External ID must be the raw data of an
RCD which hashes to the raw data payload of the human readable Factoid
Address in `inputs[i/2].address`.
- N.3.1: For each input address, there exists an External ID with even index
which is the raw data of an RCD which hashes to the raw data payload of the
human readable Factoid Address input.

##### C.x Requirements for Coinbase distribution transactions

0 comments on commit 535c272

Please sign in to comment.