Contents

Architecture Design of Ethereum-Based Private Katinrun Foundation Token


Last updated: January 28, 2019


Synopsis on Katinrun Platform


Katinrun is the first open source blockchain community in Thailand. We are developing an Ethereum-based donation platform where a donee who needs some support and a donor who wants to give support can meet together. We are aiming at creating a donation platform that provides transparency and accountability to every donation campaign. The platform we are creating, moreover, must be fully driven by an open community.

There are four types of participants in Katinrun platform: donor, donee, runner and contributor. A donee raises a supporting campaign by submitting a donation proposal to our platform. The submitted campaign has to collect enough votes from a community of voters who we call runners in order for the campaign to be opened for support. A donor is freely to give support to any open campaign. Once a donation campaign finishes, a donee has to submit a summary report to our platform.

In order to fairly distribute voting rights, we are currently building KTR (Katinrun) token and this token will be distributed to runners. Specifically, a runner just downloads and installs Katinrun mobile application on a smartphone and use our application to get KTR tokens. That is, a runner can get KTR tokens by doing Proof of Running and get tokens according to a distance he/she can gain (e.g., 1 KM of running for 1 KTR token). A runner can then vote to any favour campaign depending on KTR tokens he/she possesses.

Another important type of participant is contributors who are working behind the scene including platform developers, platform supporters, community participants, etc. Besides creating KTR token for runners, we are simultaneously creating another token called KTF (Katinrun Foundation) for contributors. This kind of token will be distributed to contributors and will be used to transparently vote when any platform configuration change is required.

In Katinrun platform, all proposal and report documents will be stored on a distributed database like IPFS whereas Ethereum blockchain will be used to manage and store platform configurations and changes, voting results as well as hashes of the IPFS-stored documents. This enables transparency and accountability features to the platform and its donation campaigns.

Meanwhile, Katinrun platform including KTR and KTF tokens are under development, we decided to distribute KTF token in advance so that when the platform is ready to be launched we will have plenty of contributors to govern and run the platform instantly.

To make this possible, we have developed another token named PKTF (Private Katinrun Foundation) token. PKTF token will be distributed to platform contributors beforehand and it will eventually be transferred to the real KTF token once KTF is ready to use. In this article, I would like to explain the architecture design of Ethereum-based PKTF token as well as analyzing security and privacy issues on it. You can find out more about PKTF token in this repo.


.    .    .

Architecture Design of PKTF Token


We decided to distribute PKTF token by way of handing over a paper-based voucher card to platform contributors when they attend our community event. A contributor can redeem tokens via our web portal then.

PKTF token consists of two stages: Voucher Creation and Voucher Redemption.


PKTF Voucher Creation

PKTF Voucher Creation


To generate a voucher card, a platform admin must execute Voucher Creation stage as illustrated in the figure above.


Voucher Creation Step-by-Step


  1. Web App makes a request to Redemption Server to get VoucherID which is randomly generated uniquely.

  2. Web App randomly generates ParityCode. Then, an admin specifies Amount and Expired parameters for a voucher being created through a web user interface. Web App then generates a transaction payload message and prompt an admin to sign the generated message with his/her private key. Notice that, the admin’s private key is protected by a hardware wallet all the time even during the message signing process.

  3. Web App sends Redemption Server VoucherPayload including the following parameters: Signature(r, s, v), VoucherID, Amount and Expired. Note that, Signature(r, s, v) is a resulting output from the message signing process invoked by an admin at Step 2. The signature will be used in Voucher Redemption stage to prove that a voucher was legitimately issued by an authorized admin.

  4. Redemption Server stores VoucherPayload into Voucher DB.

  5. Web App commands Printer to print out a voucher card.

  6. Paper-based voucher card is printed out.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
signMessage = async () => {
    const web3 = this.state.web3;
    const { voucherId, parity, amount, dateUnix } = this.state;

    const intVoucherId = web3.utils.toDecimal('0x' + this.String2Hex(voucherId));
    const intParity = web3.utils.toDecimal('0x' + this.String2Hex(parity));

    console.log('signerAddress', this.state.signerAddress);

    console.log(intVoucherId);
    console.log(intParity);
    console.log(amount);
    console.log(dateUnix);

    const msg = '0x' + this.padZeros(this.String2Hex(voucherId), 64) 
        + this.padZeros(this.String2Hex(parity), 64) 
        + this.padZeros(amount.toString(16), 256) 
        + this.padZeros(dateUnix.toString(16), 256);

    console.log(msg);

    web3.eth.personal.sign(msg, this.state.signerAddress).then(signature => {
        const r = signature.slice(0, 66);
        const s = '0x' + signature.slice(66, 130);
        const v = web3.utils.toDecimal('0x' + signature.slice(130, 132));

        this.setState({
            signature: {
                signature: signature,
                r: r,
                s: s,
                v: v,
            }
        })

      console.log('v: ' + v)
      console.log('r: ' + r)
      console.log('s: ' + s)
    })
}


The JavaScript code snippet above shows how to generate a signed transaction payload message at Step 2 in Voucher Creation stage.


.    .    .


PKTF Voucher Redemption

PKTF Voucher Redemption


A voucher holder (i.e., platform contributor) can redeem PKTF token through our web portal. Then, he/she can check the status of PKTF token through an Ethereum wallet that he/she is using after the redemption process succeeds. The figure above describes Voucher Redemption stage in more detail.


Voucher Redemption Step-by-Step


  1. Voucher Holder accesses to Web App and authenticates himself/herself with any social media platform of choice. He/she then fills in his/her Ethereum ReceiverAddress along with filling in the 10-character RedeemCode (or using QR code scanning) as shown on a voucher card. He/she finally presses Redeem button. Please notice that RedeemCode consists of 10 characters. Actually, RedeemCode was made up from string concatenation of 5-character VoucherID and 5-character ParityCode parameters in Voucher Creation stage. After that, Web App extracts VoucherID and ParityCode from RedeemCode and then sends all the inputted parameters to Redemption Server.

  2. Redemption Server sends a query to Voucher DB along with using VoucherID as a primary key for searching.

  3. Voucher DB searches for the key: VoucherID, and responds the corresponding VoucherPayload including Signature(r, s, v), VoucherID, Amount and Expired parameters to Redemption Server.

  4. Redemption Server forwards the received VoucherPayload together with ParityCode, ReceiverAddress and SocialHash (Hash of SocialType concatenated with SocialID) to Transaction Server.

  5. Transaction Server makes a transaction proposal from the received payload, signs the transaction proposal with its private key and then sends the signed transaction proposal to PKTF Smart Contract on Ethereum Network.

  6. PKTF Smart Contract verifies that the specified voucher parameters (i.e., Signature(r, s, v), VoucherID, ParityCode, Amount and Expired) had been legitimately issued by an authorized admin and VoucherID was neither expired (i.e., checking against Expired parameter) nor redeemed before. If all parameters pass the verification check, PKTF Smart Contract mints some new PKTF tokens according to Amount parameter, then transfers the minted tokens to the given ReceiverAddress, and then marks VoucherID as redeemed. Once the transaction proposal gets mined into the blockchain, Ethereum Network responds TransactionID back to Transaction Server.

  7. Transaction Server responds TransactionID back to Redemption Server.

  8. Redemption Server updates Redemption DB by marking VoucherID as redeemed and recording TransactionID and voucher holder’s social info (including SocialType and SocialID) into its database.

  9. Redemption Server removes the record of VoucherID from Voucher DB.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
function redeemVoucher( 
    uint8 _v, 
    bytes32 _r, 
    bytes32 _s,
    uint64 _voucherID,
    uint64 _parityCode,
    uint256 _amount,
    uint256 _expired,
    address _receiver,
    bytes32 _socialHash)  
public 
isNotFreezed
{
    require(
        !isVoucherUsed(_voucherID), 
        "Voucher has already been used."
    );

    require(
        !isVoucherExpired(_expired), 
        "Voucher is expired."
    );

    bytes memory prefix = "\x19Ethereum Signed Message:\n80";
    bytes memory encoded = abi.encodePacked(
        prefix, 
        _voucherID, 
        _parityCode, 
        _amount, 
        _expired
    );

    require(
        ecrecover(keccak256(encoded), _v, _r, _s) == owner()
    );

    // Mint
    _mint(_receiver, _amount);

    // Record new holder
    _recordNewTokenHolder(_receiver);

    markVoucherAsUsed(_voucherID);
    holderRedemptionCount[_socialHash]++;

    emit VoucherUsed(
        _voucherID, 
        _parityCode, 
        _amount, 
        _expired, 
        _receiver, 
        _socialHash
    );
}


The Solidity code snippet above shows how redeemVoucher() function on PKTF Smart Contract was implemented.


.    .    .

Security and Privacy Analysis


In PKTF, Voucher Creation stage can only be executed by an authorized admin. That is, a transaction payload message of a created voucher would be digitally signed with an admin’s private key which is kept secret on a hardware wallet. The private key, therefore, would never be exposed to anywhere else even during a message signing process.

Parameters which were assembled to be a transaction payload message include VoucherID, ParityCode, Amount, Expired and Signature(r, s, v). VoucherID is a 5-character randomly unique string, used as a primary key for database queries. ParityCode is a 5-character random (but not unique) string, used as a secret code for voucher redeeming.

Both VoucherID and ParityCode are 5-character strings randomly chosen from a set of characters {a..zA..Z0..9}. Hence, they both have (26 + 26 + 10)⁵ = 916,132,832 possibilities which is considered to be huge enough for using as a primary key or a secret code. VoucherID and ParityCode would be concatenated together in order to form a 10-character RedeemCode which would finally be printed out on a paper-based voucher card.

Amount is a parameter indicating that how much PKTF tokens a voucher has. Expired designates an expiry date of a voucher in Unix Timestamp. For Signature(r, s, v), these parameters are an output from a message signing process and would be used by PKTF Smart Contract for proving legitimacy of a voucher on-chain.

There are three servers in PKTF: Web App, Redemption Server and Transaction Server. Of course, Web App is for hosting a web front-end portal. Redemption Server is used for generating VoucherID in Voucher Creation stage, looking up for a relevant VoucherPayload stored on Voucher DB and updating Redemption DB during Voucher Redemption stage. Transaction Server is connected with Ethereum Mainnet and is used for making and signing a transaction proposal in order to invoke a function of PKTF Smart Contract. All the three servers would be hosted separately on cloud. In case one of the three servers gets compromised, therefore, that would not be affected to the others.

Even though Transaction Server would store its private key on itself, that private key is different to an admin’s private key kept on a hardware wallet and PKTF Smart Contract would accept only a voucher signed by an admin’s private key. Hence, an attacker cannot adopt Transaction Server’s private key to create any forged voucher anyway.

In order to mitigate risk in case our servers and/or databases are being compromised, moreover, the voucher’s RedeemCode would be split off into two parts VoucherID and ParityCode. They will be kept separately. Specifically, VoucherID parameter would be stored into Voucher DB as one of VoucherPayload. Further, VoucherID is also printed onto a voucher card as a part of RedeemCode. Whereas, ParityCode parameter would be printed out onto a voucher card only. In other words, even if Voucher DB is compromised, an attacker still need to know ParityCode part in order to form up RedeemCode. In this way, the only voucher holder is able to redeem his/her voucher.

To prevent a replay attack, any voucher that is successfully redeemed would be marked as used on both PKTF Smart Contract on-chain and Redemption DB off-chain. Moreover, each voucher will be limited its time-to-live period with Expired parameter. An attacker, therefore, would have only a short period of time to do a brute-force attack on VoucherID and/or ParityCode.

In addition to a brute-force attack, an attacker has to do an attack on both VoucherID and ParityCode in case Voucher DB is not compromised, which has (26 + 26 + 10)¹⁰ = 8.392993659 * 10¹⁷ possibilities/voucher. Even in case Voucher DB is being compromised, an attacker still need to perform an attack on ParityCode, which has (26 + 26 + 10)⁵ = 916,132,832 possibilities/voucher. Hence, PKTF is considered to be brute-force attack proof.

To redeem a voucher, a voucher holder would be asked to authenticate himself/herself with any social media platform of choice such as Facebook, Google, Line, GitHub, etc. Such social info including SocialType and SocialID parameters would be recorded for later auditing purposes into Redemption DB. To preserve our user privacy, all social info would not be stored publicly however. On PKTF Smart Contract, we will store only the hash of SocialType concatenated with SocialID which is named SocialHash for guaranteeing integrity of the info stored privately in our database. Although SocialHash would be revealed publicly, no one can reverse it to the original contents.


.    .    .

List of Contributors (in order of seniority HaHa!)



.    .    .

Summary


Katinrun is an open source blockchain community which aims at creating a transparent and community-driven platform for donations. We are open for everyone to join and contribute. If you need to be one of the contributors, do not hesitate to contact us at our facebook group or you can follow us at our facebook page.