NIP: 4
Layer: Library
Title: Apostille Improvement Protocol
Author: Jonathan Tey <[email protected]>
Discussions-To: #wg-apostille
Comments-URI: https://github.com/nemtech/NIP/issues/11
Status: Draft
Type: Standards Track
Created: 2019-04-02
License: Apache-2.0
License-Code: ASL v2
- Introduction
- Specification
- Motivation
- Design Decisions
- Implementation
- Backwards compatibility
- Drawbacks
- Alternatives
- References
- History
This proposal intends to improve the apostille creation standard to utilize the newer features of Catapult as well as to consolidate private and public apostille into a single standard. Any wallet or explorer that is compatible with this NIP will be able to parse and display accounts that are created according to this standard.
Future work should be done to define standards for handling transfer of ownership, scaling, verifying, and the use case for metadata.
The steps below describe using private apostille standard to generate an asset account (Section 3.3 in the Apostille whitepaper). The point of deviation from the whitepaper will be indicated as below and is part of the improvement proposal.
X0 - Private key of owner
X1 - Private key of document to apostille
PA - Public address of apostille sink account
To generate X1, hash the filename and sign with X0. The resulting signature is truncated and will be X0
The file hash, Fh is generated as follows:
0xFE 'N' 'T' 'Y' 0x81 + sign(md5(data)
0xFE 'N' 'T' 'Y' 0x82 + sign(sha-1(data)
0xFE 'N' 'T' 'Y' 0x83 + sign(sha-256(data)
0xFE 'N' 'T' 'Y' 0x88 + sign(keccak-256(data)
0xFE 'N' 'T' 'Y' 0x89 + sign(keccak-512(data))
0xFE 'N' 'T' 'Y' 0x90 + sign(sha3-256(data)
0xFE 'N' 'T' 'Y' 0x91 + sign(sha3-512(data))
As @daoka pointed out, the SHA3 used in NIS1 differs from Catapult. Hence we will distinguish the two to ensure compatibility.
with the magic header 0xFE4E5459
and sign()
is the signing function using the owner's private key, for X0.
Important!
Note that the non-signed version of apostille is not included here.
The section that follows will now deviate from the previous apostille standard
The announcing of apostille will now use aggregate transactions that will contain at least one inner transaction.
aggregateTx = AggregateCompleteTransaction[
innerTransaction1, // Required
innerTransaction2, // Optional
innerTransaction3, // Optional
innerTransaction4 // Optional
]
The first inner transaction will contain the file hash and is the core of the apostille system.
apostilleTx = TransferTransaction.create(
Deadline.create(),
<address of apostille account>,
[],
PlainMessage.create(<File hash>),
NetworkType.MIJIN_TEST);
innerTransaction1 = apostilleTx.toAggregate(<owner public account>);
The second inner transaction will announce the creation of the apostille to a public sink address.
sinkTx = TransferTransaction.create(
Deadline.create(),
<address of public sink account>,
[],
PlainMessage.create(<File hash>),
NetworkType.MIJIN_TEST);
innerTransaction2 = sinkTx.toAggregate(<apostille public account>);
The third inner transaction will assign ownership of the apostille. Solving the private key leakage issue (https://github.com/daoka/asset-apostille).
multisigTx = ModifyMultisigAccountTransaction.create(
Deadline.create(),
1,
1,
[
new MultisigCosignatoryModification(
MultisigCosignatoryModificationType.Add,
cosignatory,
)
],
NetworkType.MIJIN_TEST);
innerTransaction3 = multisigTx.toAggregate(<apostille public account>);
cosignatory will be the PublicAccount of X0 or any other public account to assign first ownership to.
A fourth optional inner transaction can be added to contain certain apostille metadata.
metadataTx = TransferTransaction.create(
Deadline.create(),
<address of apostille account>
[],
PlainMessage.create(<metadata>),
NetworkType.MIJIN_TEST
);
innerTransaction4 = metadataTx.toAggregate(<apostille public accout>);
where metadata is a JSON string.
{
"filename": "sample.pdf",
"tags": ["sample", "apostille"],
"description": "apostille sample file",
"originFileURL": "http://example.com/sample_file.pdf"
}
Note
- The size of the JSON payload is limited to the transaction message size.
- When Metadata Key/Value Association (#8) specification is decided and implemented, this section might use that feature. Future implementations should always check for a transfer transaction with a JSON payload to ensure backwards compatibility.
signedTx = aggregateTx
.signTransactionWithCosignatories(
<owner account>,
[apostille account]
)
transactionHttp
.announce(signedTransaction)
.subscribe(x => console.log(x), err => console.error(err));
This concludes the first section on how to create an apostille account.
After the creation of the apostille account, we can tokenize it by issuing mosaics from the apostille account.
To do this, we will designate certain nonces to represent different categories of tokens, eg. initial offering, STO compatibility list, etc.
const nonce = <as defined below>;
const mosaicDefinitionTransaction = MosaicDefinitionTransaction.create(
Deadline.create(),
nonce,
MosaicId.createFromNonce(nonce, account.publicAccount),
MosaicProperties.create({
supplyMutable: true,
transferable: true,
levyMutable: false,
divisibility: 0,
duration: UInt64.fromUint(1000)
}),
NetworkType.MIJIN_TEST);
with account.publicAccount
being the apostille public account.
Below is a set of recommendations, subject to change.
Nonce | Description |
---|---|
0x544F4B00 |
Generic token |
0x53544F01 |
Global STO token |
0x53544F02 |
Region locked STO token |
0x53544F03 |
Vesting token |
Nonces in Catapult are 32 bit long binary string. The above is the nonce encoded in HEX.
Hex values 54
, 4F
, 4B
represents T
, O
, K
respectively while53
, 54
, 4F
represents S
, T
, O
, in UTF-8.
There have been discussions in https://github.com/daoka/asset-apostille regarding the possibility of using mosaics to represent private apostille .
While representing assets as mosaics can give certain benefits, eg. tokenization, it does not give enough flexibility as being represented as an account. For example, with multisig it is easy to enforce a 2 of 3 contract where no transfer of ownership happens without a minimum of a combination of 2 signatures of the three owners. Using mosaics to enforce such a contract is difficult and control of ownership of mosaics is more complicated (not impossible).
Private apostille is already proven to be very useful in representing non-fungible assets on the NEM blockchain, but lacks the tokenization property as the number of multisig owners of an account is limited and much smaller than the possible divisibility of mosaics.
There has been confusion regarding private vs public apostille, and the ability to switch between the two. In actual fact, the implementation for private apostille is almost not compatible with public apostille.
Naming both methods as apostille does not provide a good developer experience. For example, someone implements a public apostille application because it is simple in concept and works well as a first Proof of Concept (PoC). Later on, they would add a new feature on their road map to have a transferable apostille as they read it is possible with apostille, not knowing that it would entail rewriting their PoC from scratch to support the more "complicated" private apostille.
Hence in this proposal, we would like to consolidate both private and public apostille into a single standard; combining the feature sets of private and public apostille into one apostille standard.
Right now, in order for private apostille to be functional, eg. transfer of ownership, the apostille account needs to be funded with XEMs. This raises an issue where by a small amount of XEMs need to be kept in these accounts which can be spent by anyone who currently controls the multisig contract.
Using aggregate transactions, it is possible to have a third party pay the transaction fee of the transfer, etc. without needing to preload the apostille account with XEMs. How this is done will be detailed in the #Specification section.
Another trend that is happening in the blockchain world is the move towards tokenization, eg. STOs. This NIP will also set forth a recommendation on how to support different tokens that are compatible with certain regulations, etc.
https://github.com/luxtagofficial/Apostille-library/tree/NIP0004
This standard will deprecate the public apostille standard. As for how we can transition current public apostille to the new standard is not determined and is outside the scope of this NIP.
This standard is NOT backwards compatible with NIS1, as it relies on certain Catapult only features.
A separate verifier class needs to be maintained to support verification of older .nty
files (NanoWallet generated apostille certificate). This is subject to the details of the migration plans.
On the blockchain, the maximum number multisig accounts that a single account can cosign for is limited to 5 (for NIS1) and 25 (for Catapult, but configurable for each chain). The point being that NEM accounts are not designed to "own" (cosign for) a large number of asset/apostille accounts, as opposed to mosaics, which theoretically an account can hold significantly more of.
The scalability issues of this NIP will be addressed in a separate issue as it is outside the scope of this NIP.
-
https://nem.io/wp-content/themes/nem/files/ApostilleWhitePaper.pdf
De facto standard. No changes necessary
-
https://github.com/daoka/asset-apostille
Uses namespaces and mosaics to represent apostille
- https://github.com/nemtech/NIP/issues/2
- https://nem.io/wp-content/themes/nem/files/ApostilleWhitePaper.pdf
- https://nemtech.github.io/concepts/aggregate-transaction.html
- https://nemtech.github.io/concepts/mosaic.html
- https://github.com/daoka/asset-apostille
Date | Version |
---|---|
2019-04-02 | Initial draft |
2019-04-08 | Add apostille metadata transaction |
2019-04-15 | Split SHA 3 from KECCAK |
2019-04-16 | Add implementation source |