ledger-core
AbstractExtendedPublicKey.h
1 /*
2  *
3  * AbstractExtendedPublicKey
4  *
5  * Created by El Khalil Bellakrid on 06/01/2019.
6  *
7  * The MIT License (MIT)
8  *
9  * Copyright (c) 2019 Ledger
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a copy
12  * of this software and associated documentation files (the "Software"), to deal
13  * in the Software without restriction, including without limitation the rights
14  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15  * copies of the Software, and to permit persons to whom the Software is
16  * furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included in all
19  * copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27  * SOFTWARE.
28  *
29  */
30 
31 
32 #ifndef LEDGER_CORE_ABSTRACTEXTENDEDPUBLICKEY_H
33 #define LEDGER_CORE_ABSTRACTEXTENDEDPUBLICKEY_H
34 
35 #include <memory>
36 
37 #include <math/Base58.hpp>
38 
39 #include <crypto/SECP256k1Point.hpp>
40 #include <crypto/HashAlgorithm.h>
41 #include <crypto/DeterministicPublicKey.hpp>
42 #include <crypto/RIPEMD160.hpp>
43 
44 #include <utils/Option.hpp>
45 #include <utils/DerivationPath.hpp>
46 
47 #include <bytes/BytesReader.h>
48 
49 #include <api/Currency.hpp>
50 #include <collections/DynamicObject.hpp>
51 namespace ledger {
52  namespace core {
53  template <class NetworkParameters>
55 
56  public:
57  static inline DeterministicPublicKey _derive(int index, const std::vector<uint32_t>& childNums, const DeterministicPublicKey& key) {
58  if (index >= childNums.size()) {
59  return key;
60  }
61  return _derive(index + 1, childNums, key.derive(childNums[index]));
62  }
63 
64  std::string toBase58() {
65  auto config = std::make_shared<DynamicObject>();
66  config->putString("networkIdentifier", params().Identifier);
67  return Base58::encodeWithChecksum(getKey().toByteArray(params().XPUBVersion), config);
68  }
69 
71  fromRaw(const api::Currency &currency,
72  const NetworkParameters &params,
73  const optional<std::vector<uint8_t>> &parentPublicKey,
74  const std::vector<uint8_t> &publicKey,
75  const std::vector<uint8_t> &chainCode,
76  const std::string &path) {
77  uint32_t parentFingerprint = 0;
78  SECP256k1Point pk(publicKey);
79  if (parentPublicKey) {
80  SECP256k1Point ppp(parentPublicKey.value());
81  HashAlgorithm hashAlgorithm(params.Identifier);
82  auto hash = hashAlgorithm.bytesToBytesHash(ppp.toByteArray(true));
83  hash = RIPEMD160::hash(hash);
84  parentFingerprint = ((hash[0] & 0xFFU) << 24) |
85  ((hash[1] & 0xFFU) << 16) |
86  ((hash[2] & 0xFFU) << 8) |
87  (hash[3] & 0xFFU);
88  }
89  DerivationPath p(path);
90  return DeterministicPublicKey(pk.toByteArray(true), chainCode, p.getLastChildNum(), p.getDepth(), parentFingerprint, params.Identifier);
91  }
92 
94  fromBase58(const api::Currency &currency,
95  const NetworkParameters &params,
96  const std::string &xpubBase58,
97  const Option<std::string> &path,
98  const std::string &networkBase58Dictionary = "") {
99  //xpubBase58 should be composed of version(4) || depth(1) || fingerprint(4) || index(4) || chain(32) || key(33)
100  auto config = std::make_shared<DynamicObject>();
101  config->putString("networkIdentifier", params.Identifier);
102  if (!networkBase58Dictionary.empty()) {
103  config->putString("base58Dictionary", networkBase58Dictionary);
104  }
105  auto decodeResult = Base58::checkAndDecode(xpubBase58, config);
106  if (decodeResult.isFailure())
107  throw decodeResult.getFailure();
108  BytesReader reader(decodeResult.getValue());
109 
110  //4 bytes of version
111  auto version = reader.read(params.XPUBVersion.size());
112  if (version != params.XPUBVersion) {
113  throw Exception(api::ErrorCode::INVALID_NETWORK_ADDRESS_VERSION, "Provided network parameters and address version do not match.");
114  }
115  //1 byte of depth
116  auto depth = reader.readNextByte();
117  //4 bytes of fingerprint
118  auto fingerprint = reader.readNextBeUint();
119  //4 bytes of child's index
120  auto childNum = reader.readNextBeUint();
121  //32 bytes of chaincode
122  auto chainCode = reader.read(32);
123  //33 bytes of publicKey
124  auto publicKey = reader.readUntilEnd();
125  return DeterministicPublicKey(publicKey, chainCode, childNum, depth, fingerprint, params.Identifier);
126  }
127 
128  std::vector<uint8_t> derivePublicKey(const std::string &path) {
129  DerivationPath p(path);
130  auto key = _derive(0, p.toVector(), getKey());
131  return key.getPublicKey();
132  }
133 
134  std::vector<uint8_t> deriveHash160(const std::string &path) {
135  DerivationPath p(path);
136  auto key = _derive(0, p.toVector(), getKey());
137  return key.getPublicKeyHash160();
138  }
139 
140  protected:
141  virtual const NetworkParameters &params() const = 0;
142  virtual const DeterministicPublicKey &getKey() const = 0;
143  virtual const DerivationPath &getPath() const = 0;
144  virtual const api::Currency &getCurrency() const = 0;
145  };
146  }
147 }
148 
149 
150 #endif //LEDGER_CORE_ABSTRACTEXTENDEDPUBLICKEY_H
Definition: DeterministicPublicKey.hpp:38
std::vector< uint8_t > read(unsigned long length)
Definition: BytesReader.cpp:71
Definition: SECP256k1Point.hpp:40
Definition: AbstractExtendedPublicKey.h:54
Definition: DerivationPath.hpp:40
Definition: BytesReader.h:47
Definition: Currency.hpp:23
Definition: Account.cpp:8
Definition: HashAlgorithm.h:39
Definition: optional.hpp:177
Definition: Exception.hpp:45