@@ -8,8 +8,9 @@ use crate::{
8
8
File , OptionalPostalAddress , PostalAddress ,
9
9
company:: { Company , CompanyKeys } ,
10
10
} ;
11
- use borsh:: to_vec;
11
+ use borsh:: { from_slice , to_vec} ;
12
12
use borsh_derive:: { BorshDeserialize , BorshSerialize } ;
13
+ use log:: error;
13
14
use secp256k1:: PublicKey ;
14
15
use serde:: { Deserialize , Serialize } ;
15
16
@@ -26,6 +27,7 @@ pub enum CompanyOpCode {
26
27
pub struct CompanyBlockDataToHash {
27
28
company_id : NodeId ,
28
29
id : u64 ,
30
+ plaintext_hash : String ,
29
31
previous_hash : String ,
30
32
data : String ,
31
33
timestamp : u64 ,
@@ -54,6 +56,7 @@ pub struct CompanyBlockData {
54
56
pub struct CompanyBlock {
55
57
pub company_id : NodeId ,
56
58
pub id : u64 ,
59
+ pub plaintext_hash : String ,
57
60
pub hash : String ,
58
61
pub timestamp : u64 ,
59
62
pub data : String ,
@@ -145,6 +148,10 @@ impl Block for CompanyBlock {
145
148
& self . op_code
146
149
}
147
150
151
+ fn plaintext_hash ( & self ) -> & str {
152
+ & self . plaintext_hash
153
+ }
154
+
148
155
fn hash ( & self ) -> & str {
149
156
& self . hash
150
157
}
@@ -169,10 +176,52 @@ impl Block for CompanyBlock {
169
176
true
170
177
}
171
178
179
+ /// We validate the plaintext hash against the plaintext data from the CompanyBlockData wrapper
180
+ fn validate_plaintext_hash ( & self , private_key : & secp256k1:: SecretKey ) -> bool {
181
+ match util:: base58_decode ( & self . data ) {
182
+ Ok ( decoded_wrapper) => match from_slice :: < CompanyBlockData > ( & decoded_wrapper) {
183
+ Ok ( data_wrapper) => match util:: base58_decode ( & data_wrapper. data ) {
184
+ Ok ( decoded) => match util:: crypto:: decrypt_ecies ( & decoded, private_key) {
185
+ Ok ( decrypted) => self . plaintext_hash ( ) == util:: sha256_hash ( & decrypted) ,
186
+ Err ( e) => {
187
+ error ! (
188
+ "Decrypt Error while validating plaintext hash for id {}: {e}" ,
189
+ self . id( )
190
+ ) ;
191
+ false
192
+ }
193
+ } ,
194
+ Err ( e) => {
195
+ error ! (
196
+ "Decode Error while validating plaintext hash for id {}: {e}" ,
197
+ self . id( )
198
+ ) ;
199
+ false
200
+ }
201
+ } ,
202
+ Err ( e) => {
203
+ error ! (
204
+ "Wrapper Deserialize Error while validating plaintext hash for id {}: {e}" ,
205
+ self . id( )
206
+ ) ;
207
+ false
208
+ }
209
+ } ,
210
+ Err ( e) => {
211
+ error ! (
212
+ "Wrapper Decode Error while validating plaintext hash for id {}: {e}" ,
213
+ self . id( )
214
+ ) ;
215
+ false
216
+ }
217
+ }
218
+ }
219
+
172
220
fn get_block_data_to_hash ( & self ) -> Self :: BlockDataToHash {
173
221
CompanyBlockDataToHash {
174
222
company_id : self . company_id . clone ( ) ,
175
223
id : self . id ( ) ,
224
+ plaintext_hash : self . plaintext_hash ( ) . to_owned ( ) ,
176
225
previous_hash : self . previous_hash ( ) . to_owned ( ) ,
177
226
data : self . data ( ) . to_owned ( ) ,
178
227
timestamp : self . timestamp ( ) ,
@@ -195,6 +244,7 @@ impl CompanyBlock {
195
244
identity_keys : & BcrKeys ,
196
245
company_keys : & CompanyKeys ,
197
246
timestamp : u64 ,
247
+ plaintext_hash : String ,
198
248
) -> Result < Self > {
199
249
// The order here is important: identity -> company
200
250
let keys: Vec < secp256k1:: SecretKey > = vec ! [
@@ -206,6 +256,7 @@ impl CompanyBlock {
206
256
let hash = Self :: calculate_hash ( CompanyBlockDataToHash {
207
257
company_id : company_id. clone ( ) ,
208
258
id,
259
+ plaintext_hash : plaintext_hash. clone ( ) ,
209
260
previous_hash : previous_hash. clone ( ) ,
210
261
data : data. clone ( ) ,
211
262
timestamp,
@@ -218,6 +269,7 @@ impl CompanyBlock {
218
269
Ok ( Self {
219
270
company_id,
220
271
id,
272
+ plaintext_hash,
221
273
hash,
222
274
timestamp,
223
275
previous_hash,
@@ -238,6 +290,7 @@ impl CompanyBlock {
238
290
timestamp : u64 ,
239
291
) -> Result < Self > {
240
292
let company_bytes = to_vec ( company) ?;
293
+ let plaintext_hash = Self :: calculate_plaintext_hash ( company) ?;
241
294
// encrypt data using company pub key
242
295
let encrypted_data = util:: base58_encode ( & util:: crypto:: encrypt_ecies (
243
296
& company_bytes,
@@ -266,6 +319,7 @@ impl CompanyBlock {
266
319
identity_keys,
267
320
company_keys,
268
321
timestamp,
322
+ plaintext_hash,
269
323
)
270
324
}
271
325
@@ -365,6 +419,7 @@ impl CompanyBlock {
365
419
op_code : CompanyOpCode ,
366
420
) -> Result < Self > {
367
421
let bytes = to_vec ( & data) ?;
422
+ let plaintext_hash = Self :: calculate_plaintext_hash ( data) ?;
368
423
// encrypt data using the company pub key
369
424
let encrypted_data = util:: base58_encode ( & util:: crypto:: encrypt_ecies (
370
425
& bytes,
@@ -400,6 +455,7 @@ impl CompanyBlock {
400
455
identity_keys,
401
456
company_keys,
402
457
timestamp,
458
+ plaintext_hash,
403
459
) ?;
404
460
405
461
if !new_block. validate_with_previous ( previous_block) {
@@ -504,6 +560,24 @@ mod tests {
504
560
) ,
505
561
)
506
562
}
563
+
564
+ #[ test]
565
+ fn test_plaintext_hash ( ) {
566
+ let ( _id, ( company, company_keys) ) = get_baseline_company_data ( ) ;
567
+
568
+ let chain = CompanyBlockchain :: new (
569
+ & CompanyCreateBlockData :: from ( company) ,
570
+ & BcrKeys :: new ( ) ,
571
+ & company_keys,
572
+ 1731593928 ,
573
+ ) ;
574
+ assert ! ( chain. is_ok( ) ) ;
575
+ assert ! ( chain. as_ref( ) . unwrap( ) . is_chain_valid( ) ) ;
576
+ assert ! (
577
+ chain. as_ref( ) . unwrap( ) . blocks( ) [ 0 ] . validate_plaintext_hash( & company_keys. private_key)
578
+ ) ;
579
+ }
580
+
507
581
#[ test]
508
582
fn create_and_check_validity ( ) {
509
583
let ( _id, ( company, company_keys) ) = get_baseline_company_data ( ) ;
@@ -605,6 +679,11 @@ mod tests {
605
679
assert ! ( new_chain_from_empty_blocks. is_err( ) ) ;
606
680
607
681
let blocks = chain. blocks ( ) ;
682
+
683
+ for block in blocks {
684
+ assert ! ( block. validate_plaintext_hash( & company_keys. private_key) ) ;
685
+ }
686
+
608
687
let new_chain_from_blocks = CompanyBlockchain :: new_from_blocks ( blocks. to_owned ( ) ) ;
609
688
assert ! ( new_chain_from_blocks. is_ok( ) ) ;
610
689
assert ! ( new_chain_from_blocks. as_ref( ) . unwrap( ) . is_chain_valid( ) ) ;
0 commit comments