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
use ethereum_types::{H160, H256, U256};
use rlp::RlpStream;
use tiny_keccak::keccak256;
use secp256k1::key::SecretKey;
use secp256k1::Message;
use secp256k1::Secp256k1;
use secp256k1::ContextFlag;
#[derive(Debug, Default, Clone, PartialEq, Deserialize, Serialize)]
pub struct RawTransaction {
pub nonce: U256,
pub to: Option<H160>,
pub value: U256,
#[serde(rename = "gasPrice")]
pub gas_price: U256,
pub gas: U256,
pub data: Vec<u8>
}
impl RawTransaction {
pub fn sign(&self, private_key: &H256,CHAIN_ID : &u8) -> Vec<u8> {
let hash = self.hash(*CHAIN_ID);
let sig = ecdsa_sign(&hash, &private_key.0, &CHAIN_ID);
let mut tx = RlpStream::new();
tx.begin_unbounded_list();
self.encode(&mut tx);
tx.append(&sig.v);
tx.append(&sig.r);
tx.append(&sig.s);
tx.complete_unbounded_list();
tx.out()
}
fn hash(&self, CHAIN_ID: u8) -> Vec<u8> {
let mut hash = RlpStream::new();
hash.begin_unbounded_list();
self.encode(&mut hash);
hash.append(&mut vec![CHAIN_ID]);
hash.append(&mut U256::zero());
hash.append(&mut U256::zero());
hash.complete_unbounded_list();
keccak256_hash(&hash.out())
}
fn encode(&self, s: &mut RlpStream) {
s.append(&self.nonce);
s.append(&self.gas_price);
s.append(&self.gas);
if let Some(ref t) = self.to {
s.append(t);
} else {
s.append(&vec![]);
}
s.append(&self.value);
s.append(&self.data);
}
}
fn keccak256_hash(bytes: &[u8]) -> Vec<u8> {
keccak256(bytes).into_iter().cloned().collect()
}
fn ecdsa_sign(hash: &[u8], private_key: &[u8], CHAIN_ID: &u8) -> EcdsaSig {
let s = Secp256k1::with_caps(ContextFlag::SignOnly);
let msg = Message::from_slice(hash).unwrap();
let key = SecretKey::from_slice(&s, private_key).unwrap();
let (v,sig_bytes) = s.sign_recoverable(&msg, &key).unwrap().serialize_compact(&s);
println!("V m8 {:?}", v);
EcdsaSig {
v: vec![v.to_i32() as u8 + CHAIN_ID * 2 + 35],
r: sig_bytes[0..32].to_vec(),
s: sig_bytes[32..64].to_vec(),
}
}
pub struct EcdsaSig {
v: Vec<u8>,
r: Vec<u8>,
s: Vec<u8>
}
mod test {
#[test]
fn test_signs_transaction() {
use std::io::Read;
use std::fs::File;
use ethereum_types::*;
use raw_transaction::RawTransaction;
use serde_json;
#[derive(Deserialize)]
struct Signing {
signed: Vec<u8>,
private_key: H256
}
let mut file = File::open("./test/test_txs.json").unwrap();
let mut f_string = String::new();
file.read_to_string(&mut f_string).unwrap();
let txs: Vec<(RawTransaction, Signing)> = serde_json::from_str(&f_string).unwrap();
for (tx, signed) in txs.into_iter() {
assert_eq!(signed.signed, tx.sign(&signed.private_key));
}
}
}