Skip to content

Commit

Permalink
Update details about External ID ordering, and signing
Browse files Browse the repository at this point in the history
  • Loading branch information
AdamSLevy committed Nov 25, 2018
1 parent 3a54cf9 commit 535c272
Showing 1 changed file with 61 additions and 34 deletions.
95 changes: 61 additions & 34 deletions fatips/0.md
Expand Up @@ -208,36 +208,46 @@ entry.




#### External IDs #### External IDs
Transaction Entries must include two External IDs for every input address listed in the transaction: the RCD Transaction Entries must include exactly two External IDs for every input
that hashes to the corresponding input address, and a signature. 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` In the case of normal transaction, all inputs must have a corresponding RCD in
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. 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`. In the following table `X` is any even number less than `2n`.


| External ID Index | External ID Value (RAW DATA) | | 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 | | 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 | | `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 ##### Encoding


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




##### RCD ##### RCD

The RCD is a data structure that hashes to the payload of a Factoid Address. 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 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. (`0x01`), the remaining 32 bytes are a ed25519 public key.
Expand All @@ -255,7 +265,8 @@ To validate that an RCD "corresponds" to a Factoid Address,




##### Signature ##### 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). Transaction](https://github.com/FactomProject/FactomDocs/blob/master/factomDataStructureDetails.md#factoid-transaction).


From the Factom Documentation: From the Factom Documentation:
Expand All @@ -266,31 +277,47 @@ From the Factom Documentation:
> [canonical](https://github.com/FactomProject/ed25519/blob/master/ed25519.go#L143). > [canonical](https://github.com/FactomProject/ed25519/blob/master/ed25519.go#L143).
> This will limit malleability by attackers without the private key. > 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 A signed transaction should only be valid once, so signed data must be
the content of the entry. 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.


``` Let `i` be the integer index of the External ID that the signature will be
signature = ed25519_sign(priv_key, chain_id + entry_content) 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 ### Transaction Validation and State


There are two types of transactions which have slightly different validation There are two types of transactions which have slightly different validation
requirements: Normal transactions between Factoid Addresses, and Coinbase 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 A Coinbase transaction is identified by whether it has an input from the
Coinbase address: `FA1zT4aFpEvcnPqPCigB3fvGu4Q4mTXY22iiuV69DqE1pNhdF2MC` Coinbase address: `FA1zT4aFpEvcnPqPCigB3fvGu4Q4mTXY22iiuV69DqE1pNhdF2MC`


#### Computing the current state #### Computing the current state

Implementations must maintain the state of the balances of all addresses in 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 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, by iterating through all entries in the token chain and sequentially, updating
updating the state for any transaction that meets all of the necessary the state for any transaction that meets all of the necessary Transaction
Transaction Validation Requirements. Validation Requirements.


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


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


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


Expand Down

0 comments on commit 535c272

Please sign in to comment.