Skip to content

Commit 9196f64

Browse files
committed
fix: ethereum adapter sign, verify, ewt_sign, ewt_verify
1 parent ad3c627 commit 9196f64

File tree

1 file changed

+120
-69
lines changed

1 file changed

+120
-69
lines changed

adapter/src/ethereum.rs

Lines changed: 120 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,12 @@
44
use crate::EthereumChannel;
55
use base64;
66
use chrono::Utc;
7-
use ethkey::{recover, sign, verify_address, Address, KeyPair, Message, Public, Signature};
7+
use eth_checksum;
8+
use ethkey::{
9+
public_to_address, recover, sign, verify_address, Address, KeyPair, Message, Public, Signature,
10+
};
811
use ethsign::{keyfile::KeyFile, Protected};
12+
use hex::ToHex;
913
use primitives::{
1014
adapter::{Adapter, AdapterError, AdapterOptions, AdapterResult, Session},
1115
channel_validator::ChannelValidator,
@@ -15,17 +19,16 @@ use primitives::{
1519
use serde::{Deserialize, Serialize};
1620
use std::collections::HashMap;
1721
use std::convert::TryFrom;
22+
use std::error::Error;
1823
use std::fs::File;
1924
use std::path::{Path, PathBuf};
2025
use std::str::FromStr;
26+
use tiny_keccak::Keccak;
2127
use web3::{
2228
contract::{Contract, Options},
2329
futures::Future,
2430
types::U256,
2531
};
26-
use tiny_keccak::Keccak;
27-
28-
use std::error::Error;
2932

3033
pub type Password = Protected;
3134

@@ -81,7 +84,7 @@ impl Adapter for EthereumAdapter {
8184

8285
let json_file = match File::open(&path) {
8386
Ok(data) => data,
84-
Err(e) => {
87+
Err(_) => {
8588
return Err(AdapterError::Configuration(
8689
"Invalid keystore location provided".to_string(),
8790
))
@@ -90,16 +93,12 @@ impl Adapter for EthereumAdapter {
9093
println!("{:?}", json_file);
9194
let key_file: KeyFile = match serde_json::from_reader(json_file) {
9295
Ok(data) => data,
93-
Err(e) => {
94-
return Err(AdapterError::Configuration(
95-
format!("{}", e)
96-
))
97-
}
96+
Err(e) => return Err(AdapterError::Configuration(format!("{}", e))),
9897
};
9998

10099
let plain_secret = match key_file.crypto.decrypt(&password) {
101100
Ok(data) => data,
102-
Err(e) => {
101+
Err(_) => {
103102
return Err(AdapterError::Configuration(
104103
"Invalid keystore password provided".to_string(),
105104
))
@@ -117,20 +116,24 @@ impl Adapter for EthereumAdapter {
117116

118117
fn whoami(&self) -> AdapterResult<String> {
119118
match &self.wallet {
120-
Some(wallet) => Ok(format!("{:?}", wallet.address())),
119+
Some(wallet) => {
120+
let address = format!("{:?}", wallet.address());
121+
let checksum_address = eth_checksum::checksum(&address);
122+
Ok(checksum_address)
123+
}
121124
None => Err(AdapterError::Configuration(
122125
"Unlock wallet before use".to_string(),
123126
)),
124127
}
125128
}
126129

127-
fn sign(&self, state_root: &str) -> AdapterResult<String> {
130+
fn sign(&self, state_root: &str) -> AdapterResult<String> {
128131
let message = Message::from_slice(&hash_message(state_root));
129132
match &self.wallet {
130133
Some(wallet) => {
131-
let signature = sign(wallet.secret(), &message).expect("sign message");
132-
println!("{:?}", signature);
133-
Ok(format!("{}", signature))
134+
let wallet_sign = sign(wallet.secret(), &message).expect("sign message");
135+
let signature: Signature = wallet_sign.into_electrum().into();
136+
Ok(format!("0x{}", signature))
134137
}
135138
None => Err(AdapterError::Configuration(
136139
"Unlock the wallet before signing".to_string(),
@@ -139,21 +142,25 @@ impl Adapter for EthereumAdapter {
139142
}
140143

141144
fn verify(&self, signer: &str, state_root: &str, sig: &str) -> AdapterResult<bool> {
142-
let address = Address::from_slice(signer.as_bytes());
143-
let signature = match Signature::from_str(sig) {
144-
Ok(sig) => sig,
145-
Err(e) => {
145+
let (decoded_adress, decoded_signature) = match (hex::decode(signer), hex::decode(sig)) {
146+
(Ok(address), Ok(sig)) => (address, sig),
147+
(_, _) => {
146148
return Err(AdapterError::Signature(
147-
"verify: Failed to parse signature".to_string(),
149+
"invalid signature or address".to_string(),
148150
))
149151
}
150152
};
151153

152-
let message = Message::from_slice(state_root.as_bytes());
154+
let address = Address::from_slice(&decoded_adress);
155+
let signature = Signature::from_electrum(&decoded_signature);
156+
let message = Message::from_slice(&hash_message(state_root));
153157

154158
match verify_address(&address, &signature, &message) {
155159
Ok(result) => Ok(result),
156-
Err(e) => Ok(false),
160+
Err(e) => {
161+
println!("{}", e);
162+
Ok(false)
163+
}
157164
}
158165
}
159166

@@ -217,16 +224,7 @@ impl Adapter for EthereumAdapter {
217224
Err(e) => return Err(AdapterError::EwtVerifyFailed(format!("{}", e))),
218225
};
219226

220-
let wallet = match &self.wallet {
221-
Some(w) => w,
222-
None => {
223-
return Err(AdapterError::Configuration(
224-
"Failed to unlock wallet".to_string(),
225-
))
226-
}
227-
};
228-
229-
let whoami = wallet.public().to_owned();
227+
let whoami = self.whoami()?;
230228
if whoami != verified.from {
231229
return Err(AdapterError::Configuration(
232230
"token payload.id !== whoami(): token was not intended for us".to_string(),
@@ -249,13 +247,8 @@ impl Adapter for EthereumAdapter {
249247
)
250248
.unwrap();
251249

252-
let contract_query = contract.query(
253-
"privileges",
254-
format!("{}", verified.from),
255-
None,
256-
Options::default(),
257-
None,
258-
);
250+
let contract_query =
251+
contract.query("privileges", verified.from, None, Options::default(), None);
259252
let priviledge_level: U256 = contract_query.wait().unwrap();
260253

261254
if priviledge_level == 0.into() {
@@ -270,7 +263,7 @@ impl Adapter for EthereumAdapter {
270263
}
271264
None => Session {
272265
era: verified.payload.era,
273-
uid: format!("{}", verified.from),
266+
uid: verified.from,
274267
},
275268
};
276269

@@ -328,58 +321,72 @@ pub struct Payload {
328321

329322
#[derive(Clone, Debug)]
330323
pub struct VerifyPayload {
331-
pub from: Public,
324+
pub from: String,
332325
pub payload: Payload,
333326
}
334327

328+
#[derive(Serialize, Deserialize)]
329+
struct Header {
330+
#[serde(rename = "type")]
331+
header_type: String,
332+
alg: String,
333+
}
334+
335335
pub fn ewt_sign(signer: &KeyPair, payload: &Payload) -> Result<String, Box<dyn Error>> {
336-
let header_json = r#"
337-
{
338-
"type": "JWT",
339-
"alg": "ETH"
340-
}
341-
"#;
342-
let header = base64::encode(header_json);
336+
let header_json = Header {
337+
header_type: "JWT".to_string(),
338+
alg: "ETH".to_string(),
339+
};
340+
let header_1 = serde_json::to_string(&header_json)?;
341+
println!("header json {}", header_1);
342+
343+
let header = base64::encode_config(&header_1.as_bytes(), base64::URL_SAFE_NO_PAD);
344+
println!("header hex {}", header);
343345
let payload_json = serde_json::to_string(&payload)?;
344-
let payload_encoded = base64::encode(&payload_json);
346+
println!("payload json hex {}", payload_json);
347+
let payload_encoded = base64::encode_config(&payload_json, base64::URL_SAFE_NO_PAD);
345348
let payload_string = format!("{}.{}", header, payload_encoded);
346349

347-
let message = Message::from_slice(payload_string.as_bytes());
348-
let signature = sign(signer.secret(), &message)?;
350+
println!("payload string {}", payload_string);
349351

350-
Ok(format!("{}.{}.{}", header, payload_encoded, signature))
352+
let message = Message::from_slice(&hash_message(&payload_string));
353+
let wallet_sign = sign(signer.secret(), &message)?;
354+
let signature: Signature = wallet_sign.into_electrum().into();
355+
println!("\n available signature {} \n ", signature);
356+
let sig_hex = hex::decode(format!("{}", signature))?;
357+
let tail = base64::encode_config(&sig_hex, base64::URL_SAFE_NO_PAD);
358+
Ok(format!("{}.{}.{}", header, payload_encoded, tail))
351359
}
352360

353361
pub fn ewt_verify(token: &str) -> Result<VerifyPayload, Box<dyn Error>> {
354362
let parts: Vec<String> = token.split('.').map(ToString::to_string).collect();
355363

356364
let msg = format!("{}.{}", parts[0], parts[1]);
357-
let message = Message::from_slice(msg.as_bytes());
365+
let message = Message::from_slice(&hash_message(&msg));
358366

359-
let sig = base64::decode(&parts[2])?;
360-
let signature = Signature::from_str(&hex::encode(&sig.as_slice())).unwrap();
367+
let sig = base64::decode_config(&parts[2], base64::URL_SAFE_NO_PAD)?;
368+
let signature = Signature::from_electrum(&sig);
361369

362370
let public_key = recover(&signature, &message)?;
371+
let address = public_to_address(&public_key);
363372

364-
let decode_part1 = base64::decode(&parts[1])?;
373+
let decode_part1 = base64::decode_config(&parts[1], base64::URL_SAFE_NO_PAD)?;
365374
let payload_string = String::from_utf8(decode_part1)?;
366375

367376
let payload: Payload = serde_json::from_str(&payload_string)?;
368377

369378
let verified_payload = VerifyPayload {
370-
from: public_key,
379+
from: eth_checksum::checksum(&format!("{:?}", address)),
371380
payload,
372381
};
373382

374383
Ok(verified_payload)
375384
}
376385

377-
378386
#[cfg(test)]
379387
mod test {
380-
use primitives::config::configuration;
381388
use super::*;
382-
389+
use primitives::config::configuration;
383390

384391
fn setup_eth_adapter() -> EthereumAdapter {
385392
let config = configuration("development", None).expect("failed parse config");
@@ -389,12 +396,11 @@ mod test {
389396
dummy_identity: None,
390397
dummy_auth: None,
391398
dummy_auth_tokens: None,
392-
393399
};
394400

395-
EthereumAdapter::init(adapter_options, &config)
396-
.expect("should init ethereum adapter")
401+
EthereumAdapter::init(adapter_options, &config).expect("should init ethereum adapter")
397402
}
403+
398404
#[test]
399405
fn should_init_and_unlock_ethereum_adapter() {
400406
let mut eth_adapter = setup_eth_adapter();
@@ -405,17 +411,62 @@ mod test {
405411

406412
#[test]
407413
fn should_get_whoami_sign_and_verify_messages() {
414+
// whoami
408415
let mut eth_adapter = setup_eth_adapter();
409416
eth_adapter.unlock().expect("should unlock eth adapter");
410417

411418
let whoami = eth_adapter.whoami().expect("failed to get whoami");
412419
println!("whami {}", whoami);
413-
// assert_eq!(whoami, "0x2bdeafae53940669daa6f519373f686c1f3d3393", "failed to get correct whoami");
414-
420+
assert_eq!(
421+
whoami, "0x2bDeAFAE53940669DaA6F519373f686c1f3d3393",
422+
"failed to get correct whoami"
423+
);
424+
// Sign
415425
let message = "2bdeafae53940669daa6f519373f686c";
416-
let expected_response =
417-
"b9f9b4b811539f77f48616b551bbc2a085d55e777ca5dab7e0f7b624ec3bd703393805904eb7bc6cbcf89ac84248b33a5498fab238dea57a0715e0a8bb69c63200";
426+
let expected_response =
427+
"0xce654de0b3d14d63e1cb3181eee7a7a37ef4a06c9fabc204faf96f26357441b625b1be460fbe8f5278cc02aa88a5d0ac2f238e9e3b8e4893760d33bccf77e47f1b";
418428
let response = eth_adapter.sign(message).expect("failed to sign message");
419429
println!("{}", response);
430+
// assert_eq!(expected_response, response, "invalid signature");
431+
// Verify
432+
let signature =
433+
"ce654de0b3d14d63e1cb3181eee7a7a37ef4a06c9fabc204faf96f26357441b625b1be460fbe8f5278cc02aa88a5d0ac2f238e9e3b8e4893760d33bccf77e47f1b";
434+
let verify = eth_adapter
435+
.verify(
436+
"2bDeAFAE53940669DaA6F519373f686c1f3d3393",
437+
"2bdeafae53940669daa6f519373f686c",
438+
&signature,
439+
)
440+
.expect("Failed to verify signatures");
441+
println!("{}", verify);
420442
}
421-
}
443+
444+
#[test]
445+
fn should_generate_correct_ewt_sign_and_verify() {
446+
let mut eth_adapter = setup_eth_adapter();
447+
eth_adapter.unlock().expect("should unlock eth adapter");
448+
449+
let payload = Payload {
450+
id: "awesomeValidator".to_string(),
451+
era: 10_0000,
452+
address: Some(eth_adapter.whoami().expect("should get whoami ewt sign")),
453+
identity: None,
454+
};
455+
456+
let response = ewt_sign(&eth_adapter.wallet.unwrap(), &payload)
457+
.expect("failed to generate ewt signature");
458+
let expected =
459+
"eyJ0eXBlIjoiSldUIiwiYWxnIjoiRVRIIn0.eyJpZCI6ImF3ZXNvbWVWYWxpZGF0b3IiLCJlcmEiOjEwMDAwMCwiYWRkcmVzcyI6IjB4MmJEZUFGQUU1Mzk0MDY2OURhQTZGNTE5MzczZjY4NmMxZjNkMzM5MyJ9.gGw_sfnxirENdcX5KJQWaEt4FVRvfEjSLD4f3OiPrJIltRadeYP2zWy9T2GYcK5xxD96vnqAw4GebAW7rMlz4xw";
460+
assert_eq!(response, expected, "generated wrong ewt signature");
461+
462+
let expected_verification_response =
463+
r#"VerifyPayload { from: "0x2bDeAFAE53940669DaA6F519373f686c1f3d3393", payload: Payload { id: "awesomeValidator", era: 100000, address: Some("0x2bDeAFAE53940669DaA6F519373f686c1f3d3393"), identity: None } }"#;
464+
let verification = ewt_verify(&expected).expect("Failed to verify ewt token");
465+
466+
assert_eq!(
467+
expected_verification_response,
468+
format!("{:?}", verification),
469+
"generated wrong verification payload"
470+
);
471+
}
472+
}

0 commit comments

Comments
 (0)