summaryrefslogtreecommitdiff
path: root/src/androidTest/kotlin/net/taler/wallet/kotlin/crypto/PlanchetTest.kt
blob: d7f1dae380288bf752b3d9da6971e8bfec35934f (plain)
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/*
 * This file is part of GNU Taler
 * (C) 2020 Taler Systems S.A.
 *
 * GNU Taler is free software; you can redistribute it and/or modify it under the
 * terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 3, or (at your option) any later version.
 *
 * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
 */

package net.taler.wallet.kotlin.crypto

import net.taler.wallet.kotlin.Amount
import net.taler.wallet.kotlin.Base32Crockford
import net.taler.wallet.kotlin.crypto.Planchet.CreationRequest
import net.taler.wallet.kotlin.crypto.Planchet.CreationResult
import kotlin.random.Random
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotEquals

// TODO move to commonTest once RsaBlinding is implemented everywhere
class PlanchetTest {

    private val crypto = CryptoFactory.getCrypto()
    private val planchet = Planchet(crypto)

    private class PlanchetVector(val request: CreationRequest, val eddsaKeyPair: EddsaKeyPair, val blindingFactor: String, val result: CreationResult)

    @Test
    fun testCreate() {
        val vectors = listOf(
            PlanchetVector(
                CreationRequest(
                    denomPub = "040000XVGVWCHVQVTQ06Q5V0XRAVQKPPZQZ68GYVXSC5RAG37VDCG0CEQHS4876BX6DDABB2WFY7TRJ7MFKTMMDF7A7ZW9PKQ8S3RQ15TVTKWBFGGKBKYSP6CVHNG9AY738NCPC8AFWYGP8J2VJE9HRR7M1GQK19E2M7Q2Y54KCSZ583BTNX275DW6EYYE1KBV4FK009Z621EHF5R87S6VQDSBCKSK15JCH1JYC2VPRHHAEGRA2WYX1HD9KFET0C9G1CZJB1MHZ5Z7Y803YZJH441P3PJJTRB9WCTA03H6M43CJ9MB33BEJ3KR22R8CS0D6QC2E7ZQS5MGBWCF51FK97SHCJW93SAT7VHB3YX5VVDNTW9N3SDW56HNWT11D306H9VN7BTP84T404VF482Y09K4SHEF5704002",
                    feeWithdraw = Amount.fromJSONString("KOADwTb3:9329564218.42023"),
                    reservePriv = "9TM70AKDTS57AWY9JK2J4TMBTMW6K62WHHGZWYDG0VM5ABPZKD40",
                    reservePub = "8GSJZ649T2PXMKZC01Y4ANNBE7MF14QVK9SQEC4E46ZHKCVG8AS0",
                    value = Amount.fromJSONString("KOADwTb3:3932974019564218.48282023")
                ),
                EddsaKeyPair(
                    Base32Crockford.decode("GX5DGW3RJ4HMXS53W29TK2667NWA3Z4WB41X7GPAX3WX4036VQGG"),
                    Base32Crockford.decode("Z6DXSXGEQ8C4G50FF6TG6ZKBH11APJ2HSNS21BAR72VY3KV7CC90")
                ),
                "H58V73J73HXTA9CPT8ZZ5G7VVKCWZFAE1TMCCV176QBQTPBB2H40",
                CreationResult(
                    blindingKey = "H58V73J73HXTA9CPT8ZZ5G7VVKCWZFAE1TMCCV176QBQTPBB2H40",
                    coinEv = "AK23AD09K8462T621RPER66WQRNE845JAMBT4Y1AA39M22M5K0DZFPH2P5V9E8RD0VC1Z915WB432D2C1BHKHZGP62X9A424JZRPVTFJGYCFYHH52BG0VTJ58ZK70S52KYC2DW4Z0XHKBW0BW3F8NAGGTTGE6NF6EJ3SXYBVYTN0TDJE7HED3ZEGM34N73656TADK0VNZN04BQQNZYW7WWDGT5A06CZTCS4HTSD74CVNJ70CQQQ1C9D14AA75NJ902K6FC7ANBHFGENZXAYNAC0WQQQ6J7XW0TCC3N39TYSCC7TJVH7FZQEXKE8RDGT873QX4C7XDVV6TNWEBBCPM9AABW9PXBEQSM55DT79GVZ7156MZWJKGZAGNVX1FASAY0J3CW507672300R603MW1RRRC",
                    coinPriv = "GX5DGW3RJ4HMXS53W29TK2667NWA3Z4WB41X7GPAX3WX4036VQGG",
                    coinPub = "Z6DXSXGEQ8C4G50FF6TG6ZKBH11APJ2HSNS21BAR72VY3KV7CC90",
                    coinValue = Amount.fromJSONString("KOADwTb3:3932974019564218.48282023"),
                    denomPub = "040000XVGVWCHVQVTQ06Q5V0XRAVQKPPZQZ68GYVXSC5RAG37VDCG0CEQHS4876BX6DDABB2WFY7TRJ7MFKTMMDF7A7ZW9PKQ8S3RQ15TVTKWBFGGKBKYSP6CVHNG9AY738NCPC8AFWYGP8J2VJE9HRR7M1GQK19E2M7Q2Y54KCSZ583BTNX275DW6EYYE1KBV4FK009Z621EHF5R87S6VQDSBCKSK15JCH1JYC2VPRHHAEGRA2WYX1HD9KFET0C9G1CZJB1MHZ5Z7Y803YZJH441P3PJJTRB9WCTA03H6M43CJ9MB33BEJ3KR22R8CS0D6QC2E7ZQS5MGBWCF51FK97SHCJW93SAT7VHB3YX5VVDNTW9N3SDW56HNWT11D306H9VN7BTP84T404VF482Y09K4SHEF5704002",
                    denomPubHash = "XB6T8NRGSRPWBM2YGS3R0AQYGEMK7PAM3CQRX6XM04B4N48PWRVZ5DG5JTT0NNQAGHN5HTGSCPR06R6B5NJBZ2DT5VZSQRD8FTNFPEG",
                    reservePub = "8GSJZ649T2PXMKZC01Y4ANNBE7MF14QVK9SQEC4E46ZHKCVG8AS0",
                    withdrawSig = "SNTZ4DWRVJBK89YGAZ60EDV0T7BM80MD6J6P88BRKDQFP331CXPSGM45CMCVBB7GR6X2FWQC5EJGR0J8KBR459PSGT18DA5PMQZKG08",
                    coinEvHash = "FW36XSCBJCBQMSTT798CYG363481MASXGH5W73G24D2F9C7J76YZ2644PGQ6346XBYDXW7Z61JJZN2C2Y8152NNKW3NB0DHTMKHZ5BR"

                )
            ),
            PlanchetVector(
                CreationRequest(
                    denomPub = "040000YE5QYTJTCYF7YDWN2ECYAMBNENHQT7YT740XNC88V5F1K4YC2QD94WABBVHZY597B2BTGBD2NJJV028JKJTD1KBPKXF4D87B7ZJYZVQSA4ZB5H1FVPE7X7YQVG668YZ2YY229X29NM4B6QR0G3TH821QBT1J5EDPKS0RP8E6X4654DTAAYBEN14H96E8D1JFVE40773FVVPXXMX7ZXT7TCVC2EZFMZR1HQ2DDXD8KJZ9AEGS1YH4D629Y08T9X2533MS6R4X58VVKHN1YQVKJT2044A0S8B4AKCW2GJHMQM10XC3K7C3D1C841A6R96GRXPC02QVBQSA1D5VY5VG2T4HVC6NKVK5WAXDEYZNKYVPD9AV4MNCYGK23AZWGHX5E16BQTNG47C9DEETP2D87XFC9D04002",
                    feeWithdraw = Amount.fromJSONString("cRai6j:32749022734.44771"),
                    reservePriv = "H58V73J73HXTA9CPT8ZZ5G7VVKCWZFAE1TMCCV176QBQTPBB2H40",
                    reservePub = "G3R433316Z9PW1H8XRSATJWZJNMKPZ3EE20Z386X7CYM29JDFE0G",
                    value = Amount.fromJSONString("cRai6j:166032749022734.69444771")
                ),
                EddsaKeyPair(
                    Base32Crockford.decode("5QNA3FX8NA7SETDNEEFJK5W3MNP8AJ8WSBY8FYDVZEYQ1BD21EW0"),
                    Base32Crockford.decode("54NDT04NA3TRA38T0D8TMR52PH1EWQP2S4J279GMQWQHKN4W9850")
                ),
                "7EKNT64GV5MX0KHZZNB1NREPWCZ7KF9K815M8CQN3B8AKJYF1JV0",
                CreationResult(
                    blindingKey = "7EKNT64GV5MX0KHZZNB1NREPWCZ7KF9K815M8CQN3B8AKJYF1JV0",
                    coinEv = "AATPF1TXN84PV5P7HE7274B7KT525MFRSPT62MDNYXJXJ2TDGKTMNGPJRH6CMWBD3QQENAEFNS7CZ7P27CBFN6W3EFCFNAS12EWGM6GTTV643RH3A5YJA2R93G0PZPXW9HZP3KZZYFG6MGCRHMHEXTA7T5WKVH6KWE9SM64X9SVKV856VY7TPPWZ0MKZV24KF6TDJ9QC74D2X2FEBDSK7CEA870JENBXC7PZZWJDN8CVN1ZDY4Q0SV8Y4B0YX6CZZ6KVX10PXW56FQ4SSP34EBZCPXCHRZPCQCQRAJ78H4GBP8Y8394QQV1TRH35JQ20R98JSH0WFNAMPQZ246QY8MRFTAT816EY7FEX74ENNKX8494K476BN9VM6CJ5CD0FZYRFSR7DRC5RG9V84SK71EXEDR",
                    coinPriv = "5QNA3FX8NA7SETDNEEFJK5W3MNP8AJ8WSBY8FYDVZEYQ1BD21EW0",
                    coinPub = "54NDT04NA3TRA38T0D8TMR52PH1EWQP2S4J279GMQWQHKN4W9850",
                    coinValue = Amount.fromJSONString("cRai6j:166032749022734.69444771"),
                    denomPub = "040000YE5QYTJTCYF7YDWN2ECYAMBNENHQT7YT740XNC88V5F1K4YC2QD94WABBVHZY597B2BTGBD2NJJV028JKJTD1KBPKXF4D87B7ZJYZVQSA4ZB5H1FVPE7X7YQVG668YZ2YY229X29NM4B6QR0G3TH821QBT1J5EDPKS0RP8E6X4654DTAAYBEN14H96E8D1JFVE40773FVVPXXMX7ZXT7TCVC2EZFMZR1HQ2DDXD8KJZ9AEGS1YH4D629Y08T9X2533MS6R4X58VVKHN1YQVKJT2044A0S8B4AKCW2GJHMQM10XC3K7C3D1C841A6R96GRXPC02QVBQSA1D5VY5VG2T4HVC6NKVK5WAXDEYZNKYVPD9AV4MNCYGK23AZWGHX5E16BQTNG47C9DEETP2D87XFC9D04002",
                    denomPubHash = "RJKMJ93AJ0NYC7X514FPVJ82ST4GW6WZKGK64R69880XBMMGE7H7R8QW71FGWCTKD3KZPW4D3QM854M4YHMYSZ5K3YEA2S7B2GJ9XTR",
                    reservePub = "G3R433316Z9PW1H8XRSATJWZJNMKPZ3EE20Z386X7CYM29JDFE0G",
                    withdrawSig = "X2015X2KE7Z0Q407QEKQ01TKBVV62QT07V9GJGP8GYH04K09TATB9KJG5K4VZG72Y79M1SM1EETVPARSETMN0J7Q057RB6V2F2B2P1G",
                    coinEvHash = "DZ0TEHNTRCXQB3YDZNQYGA0S4RRNKD96Y0PKMG9QQX1KD534RPNRW526CQ5FWESKDT8AJ8R79A9TD20V3JJG3ZQ5JJCMPK9DTF3A8B0"
                )
            )
        )
        for (v in vectors) testPlanchetVector(v)
    }

    private fun testPlanchetVector(v: PlanchetVector) {
        // test vector should match expected result
        val blindingFactor = Base32Crockford.decode(v.blindingFactor)
        assertEquals(v.result, planchet.create(v.request, v.eddsaKeyPair, blindingFactor))

        // different value should produce different signature
        val diffValue = v.request.value - Amount.min(v.request.value.currency)
        val requestDiffValue = v.request.copy(value = diffValue)
        val requestDiffResult = v.result.copy(coinValue = diffValue)
        val result = planchet.create(requestDiffValue, v.eddsaKeyPair, blindingFactor)
        assertNotEquals(v.result.withdrawSig, result.withdrawSig)
        assertNotEquals(requestDiffResult, result)

        // different fee should produce different signature
        val diffFee = v.request.feeWithdraw - Amount.min(v.request.feeWithdraw.currency)
        val requestDiffFee = v.request.copy(feeWithdraw = diffFee)
        val resultDiffFee = planchet.create(requestDiffFee, v.eddsaKeyPair, blindingFactor)
        assertNotEquals(v.result.withdrawSig, resultDiffFee.withdrawSig)
        assertNotEquals(v.result, resultDiffFee)

        // different blinding factor should change result
        val diffBlindingFactor = Random.nextBytes(32)
        assertNotEquals(v.result, planchet.create(v.request, v.eddsaKeyPair, diffBlindingFactor))

        // different coin keys should change result
        val diffEddsaKeyPair = crypto.createEddsaKeyPair()
        assertNotEquals(v.result, planchet.create(v.request, diffEddsaKeyPair, blindingFactor))
    }

}