forked from zcash/zcash
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtest_noteencryption.cpp
204 lines (170 loc) · 5.9 KB
/
test_noteencryption.cpp
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
#include <gtest/gtest.h>
#include "sodium.h"
#include <stdexcept>
#include "zcash/NoteEncryption.hpp"
#include "zcash/prf.h"
#include "crypto/sha256.h"
class TestNoteDecryption : public ZCNoteDecryption {
public:
TestNoteDecryption(uint256 sk_enc) : ZCNoteDecryption(sk_enc) {}
void change_pk_enc(uint256 to) {
pk_enc = to;
}
};
TEST(noteencryption, api)
{
uint256 sk_enc = ZCNoteEncryption::generate_privkey(uint252(uint256S("21035d60bc1983e37950ce4803418a8fb33ea68d5b937ca382ecbae7564d6a07")));
uint256 pk_enc = ZCNoteEncryption::generate_pubkey(sk_enc);
ZCNoteEncryption b = ZCNoteEncryption(uint256());
for (size_t i = 0; i < 100; i++)
{
ZCNoteEncryption c = ZCNoteEncryption(uint256());
ASSERT_TRUE(b.get_epk() != c.get_epk());
}
boost::array<unsigned char, ZC_NOTEPLAINTEXT_SIZE> message;
for (size_t i = 0; i < ZC_NOTEPLAINTEXT_SIZE; i++) {
// Fill the message with dummy data
message[i] = (unsigned char) i;
}
for (int i = 0; i < 255; i++) {
auto ciphertext = b.encrypt(pk_enc, message);
{
ZCNoteDecryption decrypter(sk_enc);
// Test decryption
auto plaintext = decrypter.decrypt(ciphertext, b.get_epk(), uint256(), i);
ASSERT_TRUE(plaintext == message);
// Test wrong nonce
ASSERT_THROW(decrypter.decrypt(ciphertext, b.get_epk(), uint256(), (i == 0) ? 1 : (i - 1)),
libzcash::note_decryption_failed);
// Test wrong ephemeral key
{
ZCNoteEncryption c = ZCNoteEncryption(uint256());
ASSERT_THROW(decrypter.decrypt(ciphertext, c.get_epk(), uint256(), i),
libzcash::note_decryption_failed);
}
// Test wrong seed
ASSERT_THROW(decrypter.decrypt(ciphertext, b.get_epk(), uint256S("11035d60bc1983e37950ce4803418a8fb33ea68d5b937ca382ecbae7564d6a77"), i),
libzcash::note_decryption_failed);
// Test corrupted ciphertext
ciphertext[10] ^= 0xff;
ASSERT_THROW(decrypter.decrypt(ciphertext, b.get_epk(), uint256(), i),
libzcash::note_decryption_failed);
ciphertext[10] ^= 0xff;
}
{
// Test wrong private key
uint256 sk_enc_2 = ZCNoteEncryption::generate_privkey(uint252());
ZCNoteDecryption decrypter(sk_enc_2);
ASSERT_THROW(decrypter.decrypt(ciphertext, b.get_epk(), uint256(), i),
libzcash::note_decryption_failed);
}
{
TestNoteDecryption decrypter(sk_enc);
// Test decryption
auto plaintext = decrypter.decrypt(ciphertext, b.get_epk(), uint256(), i);
ASSERT_TRUE(plaintext == message);
// Test wrong public key (test of KDF)
decrypter.change_pk_enc(uint256());
ASSERT_THROW(decrypter.decrypt(ciphertext, b.get_epk(), uint256(), i),
libzcash::note_decryption_failed);
}
}
// Nonce space should run out here
try {
b.encrypt(pk_enc, message);
FAIL() << "Expected std::logic_error";
}
catch(std::logic_error const & err) {
EXPECT_EQ(err.what(), std::string("no additional nonce space for KDF"));
}
catch(...) {
FAIL() << "Expected std::logic_error";
}
}
uint256 test_prf(
unsigned char distinguisher,
uint252 seed_x,
uint256 y
) {
uint256 x = seed_x.inner();
*x.begin() &= 0x0f;
*x.begin() |= distinguisher;
CSHA256 hasher;
hasher.Write(x.begin(), 32);
hasher.Write(y.begin(), 32);
uint256 ret;
hasher.FinalizeNoPadding(ret.begin());
return ret;
}
TEST(noteencryption, prf_addr)
{
for (size_t i = 0; i < 100; i++) {
uint252 a_sk = libzcash::random_uint252();
uint256 rest;
ASSERT_TRUE(
test_prf(0xc0, a_sk, rest) == PRF_addr_a_pk(a_sk)
);
}
for (size_t i = 0; i < 100; i++) {
uint252 a_sk = libzcash::random_uint252();
uint256 rest;
*rest.begin() = 0x01;
ASSERT_TRUE(
test_prf(0xc0, a_sk, rest) == PRF_addr_sk_enc(a_sk)
);
}
}
TEST(noteencryption, prf_nf)
{
for (size_t i = 0; i < 100; i++) {
uint252 a_sk = libzcash::random_uint252();
uint256 rho = libzcash::random_uint256();
ASSERT_TRUE(
test_prf(0xe0, a_sk, rho) == PRF_nf(a_sk, rho)
);
}
}
TEST(noteencryption, prf_pk)
{
for (size_t i = 0; i < 100; i++) {
uint252 a_sk = libzcash::random_uint252();
uint256 h_sig = libzcash::random_uint256();
ASSERT_TRUE(
test_prf(0x00, a_sk, h_sig) == PRF_pk(a_sk, 0, h_sig)
);
}
for (size_t i = 0; i < 100; i++) {
uint252 a_sk = libzcash::random_uint252();
uint256 h_sig = libzcash::random_uint256();
ASSERT_TRUE(
test_prf(0x40, a_sk, h_sig) == PRF_pk(a_sk, 1, h_sig)
);
}
uint252 dummy_a;
uint256 dummy_b;
ASSERT_THROW(PRF_pk(dummy_a, 2, dummy_b), std::domain_error);
}
TEST(noteencryption, prf_rho)
{
for (size_t i = 0; i < 100; i++) {
uint252 phi = libzcash::random_uint252();
uint256 h_sig = libzcash::random_uint256();
ASSERT_TRUE(
test_prf(0x20, phi, h_sig) == PRF_rho(phi, 0, h_sig)
);
}
for (size_t i = 0; i < 100; i++) {
uint252 phi = libzcash::random_uint252();
uint256 h_sig = libzcash::random_uint256();
ASSERT_TRUE(
test_prf(0x60, phi, h_sig) == PRF_rho(phi, 1, h_sig)
);
}
uint252 dummy_a;
uint256 dummy_b;
ASSERT_THROW(PRF_rho(dummy_a, 2, dummy_b), std::domain_error);
}
TEST(noteencryption, uint252)
{
ASSERT_THROW(uint252(uint256S("f6da8716682d600f74fc16bd0187faad6a26b4aa4c24d5c055b216d94516847e")), std::domain_error);
}