Fabcoin Core  0.16.2
P2P Digital Currency
Message.cpp
Go to the documentation of this file.
1 /*
2  This file is part of cpp-ethereum.
3 
4  cpp-ethereum is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  cpp-ethereum is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
16 */
22 #include "Message.h"
23 #include "BloomFilter.h"
24 
25 using namespace std;
26 using namespace dev;
27 using namespace dev::p2p;
28 using namespace dev::shh;
29 
30 Message::Message(Envelope const& _e, Topics const& _t, Secret const& _s)
31 {
32  try
33  {
34  bytes b;
35  if (_s)
36  if (!decrypt(_s, &(_e.data()), b))
37  return;
38  else{}
39  else if (!openBroadcastEnvelope(_e, _t, b))
40  return;
41 
42  if (populate(b))
43  if (_s)
44  m_to = KeyPair(_s).pub();
45  }
46  catch (...) // Invalid secret? TODO: replace ... with InvalidSecret
47  {
48  }
49 }
50 
51 bool Message::openBroadcastEnvelope(Envelope const& _e, Topics const& _fk, bytes& o_b)
52 {
53  // retrieve the key using the known topic and topicIndex.
54  unsigned topicIndex = 0;
55  Secret topicSecret;
56 
57  // determine topicSecret/topicIndex from knowledge of the collapsed topics (which give the order) and our full-size filter topic.
58  AbridgedTopics knownTopic = abridge(_fk);
59  for (unsigned ti = 0; ti < _fk.size() && !topicSecret; ++ti)
60  for (unsigned i = 0; i < _e.topic().size(); ++i)
61  if (_e.topic()[i] == knownTopic[ti])
62  {
63  topicSecret = Secret(_fk[ti]);
64  topicIndex = i;
65  break;
66  }
67 
68  if (_e.data().size() < _e.topic().size() * h256::size)
69  return false;
70 
71  unsigned index = topicIndex * 2;
72  Secret encryptedKey(bytesConstRef(&(_e.data())).cropped(h256::size * index, h256::size));
73  h256 salt = h256(bytesConstRef(&(_e.data())).cropped(h256::size * ++index, h256::size));
74  Secret key = Secret(generateGamma(topicSecret, salt).makeInsecure() ^ encryptedKey.makeInsecure());
75  bytesConstRef cipherText = bytesConstRef(&(_e.data())).cropped(h256::size * 2 * _e.topic().size());
76  return decryptSym(key, cipherText, o_b);
77 }
78 
79 bool Message::populate(bytes const& _data)
80 {
81  if (!_data.size())
82  return false;
83 
84  byte flags = _data[0];
85  if (!!(flags & ContainsSignature) && _data.size() >= sizeof(Signature) + 1) // has a signature
86  {
87  bytesConstRef payload = bytesConstRef(&_data).cropped(1, _data.size() - sizeof(Signature) - 1);
88  h256 h = sha3(payload);
89  Signature const& sig = *(Signature const*)&(_data[1 + payload.size()]);
90  m_from = recover(sig, h);
91  if (!m_from)
92  return false;
93  m_payload = payload.toBytes();
94  }
95  else
96  m_payload = bytesConstRef(&_data).cropped(1).toBytes();
97  return true;
98 }
99 
100 Envelope Message::seal(Secret const& _from, Topics const& _fullTopics, unsigned _ttl, unsigned _workToProve) const
101 {
102  AbridgedTopics topics = abridge(_fullTopics);
103  Envelope ret(utcTime() + _ttl, _ttl, topics);
104 
105  bytes input(1 + m_payload.size());
106  input[0] = 0;
107  memcpy(input.data() + 1, m_payload.data(), m_payload.size());
108 
109  if (_from) // needs a signature
110  {
111  input.resize(1 + m_payload.size() + sizeof(Signature));
112  input[0] |= ContainsSignature;
113  *(Signature*)&(input[1 + m_payload.size()]) = sign(_from, sha3(m_payload));
114  // If this fails, the something is wrong with the sign-recover round-trip.
115  assert(recover(*(Signature*)&(input[1 + m_payload.size()]), sha3(m_payload)) == KeyPair(_from).pub());
116  }
117 
118  if (m_to)
119  encrypt(m_to, &input, ret.m_data);
120  else
121  {
122  // this message is for broadcast (could be read by anyone who knows at least one of the topics)
123  // create the shared secret for encrypting the payload, then encrypt the shared secret with each topic
124  Secret s = Secret::random();
125  for (h256 const& t: _fullTopics)
126  {
127  h256 salt = h256::random();
128  ret.m_data += (generateGamma(Secret(t), salt).makeInsecure() ^ s.makeInsecure()).ref().toBytes();
129  ret.m_data += salt.asBytes();
130  }
131 
132  bytes d;
133  encryptSym(s, &input, d);
134  ret.m_data += d;
135  }
136 
137  ret.proveWork(_workToProve);
138  return ret;
139 }
140 
141 Envelope::Envelope(RLP const& _m)
142 {
143  m_expiry = _m[0].toInt<unsigned>();
144  m_ttl = _m[1].toInt<unsigned>();
145  m_topic = _m[2].toVector<FixedHash<4>>();
146  m_data = _m[3].toBytes();
147  m_nonce = _m[4].toInt<u256>();
148 }
149 
150 Message Envelope::open(Topics const& _t, Secret const& _s) const
151 {
152  return Message(*this, _t, _s);
153 }
154 
155 unsigned Envelope::workProved() const
156 {
157  h256 d[2];
158  d[0] = sha3(WithoutNonce);
159  d[1] = m_nonce;
160  return dev::sha3(bytesConstRef(d[0].data(), 64)).firstBitSet();
161 }
162 
163 void Envelope::proveWork(unsigned _ms)
164 {
165  h256 d[2];
166  d[0] = sha3(WithoutNonce);
167  unsigned bestBitSet = 0;
168  bytesConstRef chuck(d[0].data(), 64);
169 
170  chrono::high_resolution_clock::time_point then = chrono::high_resolution_clock::now() + chrono::milliseconds(_ms);
171  while (chrono::high_resolution_clock::now() < then)
172  // do it rounds of 1024 for efficiency
173  for (unsigned i = 0; i < 1024; ++i, ++d[1])
174  {
175  auto fbs = dev::sha3(chuck).firstBitSet();
176  if (fbs > bestBitSet)
177  {
178  bestBitSet = fbs;
179  m_nonce = (h256::Arith)d[1];
180  }
181  }
182 }
183 
184 bool Envelope::matchesBloomFilter(TopicBloomFilterHash const& f) const
185 {
186  for (AbridgedTopic t: m_topic)
188  return true;
189 
190  return false;
191 }
Adapted from code found on http://stackoverflow.com/questions/180947/base64-decode-snippet-in-c Origi...
Definition: Arith256.cpp:15
uint8_t byte
Definition: Common.h:57
void encryptSym(Secret const &_k, bytesConstRef _plain, bytes &o_cipher)
Symmetric encryption.
Definition: Common.cpp:145
bytes const & data() const
Definition: Message.h:77
vector_ref< _T const > ref(_T const &_t)
Definition: vector_ref.h:115
bool contains(FixedHash const &_c) const
Definition: FixedHash.h:116
uint64_t utcTime()
Get the current time in seconds since the epoch in UTC.
Definition: Common.cpp:64
std::vector< T > toVector(int _flags=LaissezFaire) const
Definition: RLP.h:204
std::vector< AbridgedTopic > AbridgedTopics
Definition: Common.h:68
#define h(i)
Definition: sha.cpp:736
Simple class that represents a "key pair".
Definition: Common.h:150
h256s Topics
Definition: Common.h:69
SecureFixedHash< 32 > Secret
Definition: Common.h:35
std::hash for asio::adress
Definition: Common.h:323
assert(len-trim+(2 *lenIndices)<=WIDTH)
Definition: Eth.h:45
vector_ref< _T > cropped(size_t _begin, size_t _count) const
Definition: vector_ref.h:62
AbridgedTopics const & topic() const
Definition: Message.h:76
boost::multiprecision::number< boost::multiprecision::cpp_int_backend< N *8, N *8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void >> Arith
The corresponding arithmetic type.
Definition: FixedHash.h:51
bool decryptSym(Secret const &_k, bytesConstRef _cipher, bytes &o_plaintext)
Symmetric decryption.
Definition: Common.cpp:151
Public const & pub() const
Retrieve the public key.
Definition: Common.h:170
FixedHash< T > const & makeInsecure() const
Definition: FixedHash.h:253
Public recover(Signature const &_sig, h256 const &_hash)
Recovers Public key from signed message hash.
Definition: Common.cpp:203
std::vector< byte > bytes
Definition: Common.h:75
std::vector< unsigned char > toBytes() const
Definition: vector_ref.h:45
vector_ref< byte const > bytesConstRef
Definition: Common.h:77
FixedHash< 32 > h256
Definition: FixedHash.h:340
boost::multiprecision::number< boost::multiprecision::cpp_int_backend< 256, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void >> u256
Definition: Common.h:125
h520 Signature
A signature: 65 bytes: r: [0, 32), s: [32, 64), v: 64.
Definition: Common.h:43
#define b(i, j)
size_t size() const
Definition: vector_ref.h:55
AbridgedTopic abridge(Topic const &_topic)
Definition: Common.cpp:32
bytes asBytes() const
Definition: FixedHash.h:145
Signature sign(Secret const &_k, h256 const &_hash)
Returns siganture of message hash.
Definition: Common.cpp:233
#define f(x)
Definition: gost.cpp:57
void encrypt(Public const &_k, bytesConstRef _plain, bytes &o_cipher)
Encrypts plain text using Public key.
Definition: Common.cpp:102
uint8_t const size_t const size
Definition: sha3.h:20
void * memcpy(void *a, const void *b, size_t c)
bool decrypt(Secret const &_k, bytesConstRef _cipher, bytes &o_plaintext)
Decrypts cipher using Secret key.
Definition: Common.cpp:109
An (unencrypted) message, constructed from the combination of an Envelope, and, potentially, a Secret key to decrypt the Message.
Definition: Message.h:100
clock::time_point time_point
Definition: bench.h:49
bool sha3(bytesConstRef _input, bytesRef o_output)
Calculate SHA3-256 hash of the given input and load it into the given output.
Definition: SHA3.cpp:214
void proveWork(unsigned _ms)
Definition: Message.cpp:163
#define d(i)
Definition: sha.cpp:732
_T toInt(int _flags=Strict) const
Converts to int of type given; if isString(), decodes as big-endian bytestream.
Definition: RLP.h:275
uint8_t const * data
Definition: sha3.h:19
Class for interpreting Recursive Linear-Prefix Data.
Definition: RLP.h:64
bytes toBytes(int _flags=LaissezFaire) const
Converts to bytearray.
Definition: RLP.h:195
LogBloom bloom(LogEntries const &_logs)
Definition: ExtVMFace.h:158