WinRarConfig.hpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  1. #pragma once
  2. #include "GaloisField.hpp"
  3. #include "EllipticCurveGF2m.hpp"
  4. #include "BigInteger.hpp"
  5. struct WinRarConfig {
  6. public:
  7. // Irreducible polynomial of ground field = x^15 + x + 1
  8. // Irreducible polynomial of extension field = y^17 + y^3 + 1;
  9. struct GF2p15p17Traits {
  10. struct ElementType {
  11. uint16_t Items[17];
  12. };
  13. static constexpr size_t BitSizeValue = 15 * 17;
  14. static constexpr size_t DumpSizeValue = (BitSizeValue + 7) / 8;
  15. using GF2p15LogExpTableType = uint16_t[0x8000];
  16. static const GF2p15LogExpTableType& InitializeGF2p15Table(bool ReturnLogTable) noexcept {
  17. static GF2p15LogExpTableType LogTable;
  18. static GF2p15LogExpTableType ExpTable;
  19. constexpr size_t Order = 0x7fff;
  20. if (ExpTable[Order] == 0) {
  21. ExpTable[0] = 1;
  22. for (size_t i = 1; i < Order; ++i) {
  23. uint32_t temp = ExpTable[i - 1] * 2;
  24. if (temp & 0x8000) {
  25. temp ^= 0x8003;
  26. }
  27. ExpTable[i] = temp;
  28. }
  29. // mark as initialized
  30. ExpTable[Order] = ~ExpTable[Order];
  31. for (size_t i = 0; i < Order; ++i) {
  32. // #if defined(_MSC_VER)
  33. // __assume(ExpTable[i] <= Order);
  34. // #endif
  35. LogTable[ExpTable[i]] = static_cast<uint16_t>(i);
  36. }
  37. }
  38. if (ReturnLogTable) {
  39. return LogTable;
  40. } else {
  41. return ExpTable;
  42. }
  43. }
  44. static inline const GF2p15LogExpTableType& GF2p15LogTable = InitializeGF2p15Table(true);
  45. static inline const GF2p15LogExpTableType& GF2p15ExpTable = InitializeGF2p15Table(false);
  46. static inline const ElementType ZeroValue = {};
  47. static inline const ElementType OneValue = { 1 };
  48. static void Verify(const ElementType& Val) {
  49. for (size_t i = 0; i < 17; ++i) {
  50. if (Val.Items[i] >= 0x8000) {
  51. throw std::invalid_argument("Val is not in GF((2 ^ 15) ^ 17).");
  52. }
  53. }
  54. }
  55. static size_t Dump(const ElementType& Val, void* lpBuffer, size_t cbBuffer) {
  56. if (cbBuffer < DumpSizeValue) {
  57. throw std::length_error("Insufficient buffer.");
  58. } else {
  59. uint8_t* pbWritePtr = reinterpret_cast<uint8_t*>(lpBuffer);
  60. unsigned left_bits = 8;
  61. for (size_t i = 0; i < 17; ++i) {
  62. uint8_t low8 = static_cast<uint8_t>(Val.Items[i]);
  63. uint8_t high7 = static_cast<uint8_t>(Val.Items[i] >> 8);
  64. if (left_bits == 8) {
  65. *pbWritePtr = low8;
  66. ++pbWritePtr;
  67. } else {
  68. *pbWritePtr |= low8 << (8 - left_bits);
  69. ++pbWritePtr;
  70. *pbWritePtr = low8 >> left_bits;
  71. }
  72. if (left_bits == 8) {
  73. *pbWritePtr = high7;
  74. left_bits = 1;
  75. } else if (left_bits == 7) {
  76. *pbWritePtr |= high7 << 1;
  77. ++pbWritePtr;
  78. left_bits = 8;
  79. } else {
  80. *pbWritePtr |= high7 << (8 - left_bits);
  81. ++pbWritePtr;
  82. *pbWritePtr = high7 >> left_bits;
  83. left_bits = 8 - (7 - left_bits);
  84. }
  85. }
  86. return DumpSizeValue;
  87. }
  88. }
  89. static std::vector<uint8_t> Dump(const ElementType& Val) noexcept {
  90. std::vector<uint8_t> bytes(DumpSizeValue);
  91. Dump(Val, bytes.data(), bytes.size());
  92. return bytes;
  93. }
  94. static void Load(ElementType& Val, const void* lpBuffer, size_t cbBuffer) {
  95. if (cbBuffer != DumpSizeValue) {
  96. throw std::length_error("The length of buffer is not correct.");
  97. } else {
  98. const uint8_t* pbBuffer = reinterpret_cast<const uint8_t*>(lpBuffer);
  99. if (pbBuffer[DumpSizeValue - 1] & 0x80) {
  100. throw std::invalid_argument("Not in GF((2 ^ 15) ^ 17).");
  101. }
  102. uint16_t* pbWritePtr = Val.Items;
  103. unsigned left_bits = 15;
  104. for (size_t i = 0; i < DumpSizeValue; ++i) {
  105. uint16_t v;
  106. if (left_bits == 15) {
  107. v = pbBuffer[i];
  108. left_bits = 15 - 8;
  109. } else if (left_bits > 8) {
  110. v |= pbBuffer[i] << (15 - left_bits);
  111. left_bits -= 8;
  112. } else {
  113. v |= (pbBuffer[i] << (15 - left_bits)) & 0x7fff;
  114. *pbWritePtr = v;
  115. ++pbWritePtr;
  116. v = pbBuffer[i] >> left_bits;
  117. left_bits = 15 - (8 - left_bits);
  118. }
  119. }
  120. }
  121. }
  122. static void Load(ElementType& Val, const std::vector<uint8_t>& Buffer) {
  123. Load(Val, Buffer.data(), Buffer.size());
  124. }
  125. static inline void Swap(ElementType& A, ElementType& B) noexcept {
  126. for (size_t i = 0; i < 17; ++i) {
  127. std::swap(A.Items[i], B.Items[i]);
  128. }
  129. }
  130. static inline void SetZero(ElementType& Val) noexcept {
  131. memset(Val.Items, 0, sizeof(Val.Items));
  132. }
  133. static inline void SetOne(ElementType& Val) noexcept {
  134. Val.Items[0] = 1;
  135. memset(Val.Items + 1, 0, sizeof(Val.Items) - sizeof(Val.Items[0]));
  136. }
  137. static inline bool IsEqual(const ElementType& A, const ElementType& B) noexcept {
  138. return memcmp(A.Items, B.Items, sizeof(ElementType::Items)) == 0;
  139. }
  140. static inline bool IsZero(const ElementType& Val) noexcept {
  141. return memcmp(Val.Items, ZeroValue.Items, sizeof(ElementType::Items)) == 0;
  142. }
  143. static inline bool IsOne(const ElementType& Val) noexcept {
  144. return memcmp(Val.Items, OneValue.Items, sizeof(ElementType::Items)) == 0;
  145. }
  146. // Result = A + B
  147. static inline void Add(ElementType& Result, const ElementType& A, const ElementType& B) noexcept {
  148. for (size_t i = 0; i < 17; ++i) {
  149. Result.Items[i] = A.Items[i] ^ B.Items[i];
  150. }
  151. }
  152. // A += B
  153. static inline void AddAssign(ElementType& A, const ElementType& B) noexcept {
  154. for (size_t i = 0; i < 17; ++i) {
  155. A.Items[i] ^= B.Items[i];
  156. }
  157. }
  158. // Result = A + 1
  159. static inline void AddOne(ElementType& Result, const ElementType& A) noexcept {
  160. Result.Items[0] = A.Items[0] ^ 0x0001;
  161. memcpy(Result.Items + 1, A.Items + 1, sizeof(ElementType::Items) - sizeof(uint16_t));
  162. }
  163. // A += 1
  164. static inline void AddOneAssign(ElementType& A) noexcept {
  165. A.Items[0] ^= 0x0001;
  166. }
  167. // Result = A - B
  168. static inline void Substract(ElementType& Result, const ElementType& A, const ElementType& B) noexcept {
  169. for (size_t i = 0; i < 17; ++i) {
  170. Result.Items[i] = A.Items[i] ^ B.Items[i];
  171. }
  172. }
  173. // A -= B
  174. static inline void SubstractAssign(ElementType& A, const ElementType& B) noexcept {
  175. for (size_t i = 0; i < 17; ++i) {
  176. A.Items[i] ^= B.Items[i];
  177. }
  178. }
  179. // Result = A - 1
  180. static inline void SubstractOne(ElementType& Result, const ElementType& A) noexcept {
  181. Result.Items[0] = A.Items[0] ^ 0x0001;
  182. memcpy(Result.Items + 1, A.Items + 1, sizeof(ElementType::Items) - sizeof(uint16_t));
  183. }
  184. // A -= 1
  185. static inline void SubstractOneAssign(ElementType& A) noexcept {
  186. A.Items[0] ^= 0x0001;
  187. }
  188. // Result = A * B
  189. // Require: len(Result) == M + N - 1
  190. static inline void FullMultiplySchoolBook(size_t M, size_t N, uint16_t Result[], const uint16_t A[], const uint16_t B[]) noexcept {
  191. memset(Result, 0, (M + N - 1) * sizeof(uint16_t));
  192. for (size_t i = 0; i < M; ++i) {
  193. if (A[i]) {
  194. for (size_t j = 0; j < N; ++j) {
  195. if (B[j]) {
  196. auto g = GF2p15LogTable[A[i]] + GF2p15LogTable[B[j]];
  197. if (g >= 0x7fff) {
  198. g -= 0x7fff;
  199. }
  200. Result[i + j] ^= GF2p15ExpTable[g];
  201. }
  202. }
  203. }
  204. }
  205. }
  206. static inline void ModularReduction(size_t N, uint16_t A[]) noexcept {
  207. // Irreducible polynomial of extension field = y^17 + y^3 + 1;
  208. for (size_t i = N - 1; i > 16; --i) {
  209. if (A[i] != 0) {
  210. A[i - 17 + 0] ^= A[i];
  211. A[i - 17 + 3] ^= A[i];
  212. A[i] = 0;
  213. }
  214. }
  215. }
  216. // Result = A * B mod (x^15 + x + 1, y^17 + y^3 + 1)
  217. static inline void Multiply(ElementType& Result, const ElementType& A, const ElementType& B) noexcept {
  218. uint16_t temp[16 + 16 + 1];
  219. FullMultiplySchoolBook(17, 17, temp, A.Items, B.Items);
  220. ModularReduction(16 + 16 + 1, temp);
  221. memcpy(Result.Items, temp, sizeof(ElementType::Items));
  222. }
  223. static inline void MultiplyAssign(ElementType& A, const ElementType& B) noexcept {
  224. Multiply(A, A, B);
  225. }
  226. static inline void Divide(ElementType& Result, const ElementType& A, const ElementType& B) {
  227. ElementType InverseOfB;
  228. Inverse(InverseOfB, B);
  229. Multiply(Result, A, InverseOfB);
  230. }
  231. static inline void DivideAssign(ElementType& A, const ElementType& B) {
  232. ElementType InverseOfB;
  233. Inverse(InverseOfB, B);
  234. MultiplyAssign(A, InverseOfB);
  235. }
  236. static inline void Inverse(ElementType& Result, const ElementType& A) {
  237. // lpA += (Alpha * x ^ j) * B
  238. auto AddScale = [](uint16_t A[], size_t& degA, uint16_t Alpha, size_t j, const uint16_t B[], size_t degB) {
  239. auto logAlpha = GF2p15LogTable[Alpha];
  240. auto Aj = A + j;
  241. for (size_t i = 0; i <= degB; ++i) {
  242. if (B[i]) {
  243. auto g = logAlpha + GF2p15LogTable[B[i]];
  244. if (g >= 0x7fff) {
  245. g -= 0x7fff;
  246. }
  247. Aj[i] ^= GF2p15ExpTable[g];
  248. if (Aj[i] && i + j > degA) {
  249. degA = i + j;
  250. }
  251. }
  252. }
  253. while (A[degA] == 0) {
  254. --degA;
  255. }
  256. };
  257. size_t degB;
  258. size_t degC;
  259. size_t degF;
  260. size_t degG;
  261. uint16_t B[2 * 17];
  262. uint16_t C[2 * 17];
  263. uint16_t F[2 * 17];
  264. uint16_t G[2 * 17];
  265. // Initialize B
  266. degB = 0;
  267. B[0] = 1;
  268. memset(B + 1, 0, sizeof(B) - sizeof(uint16_t));
  269. // Initialize C
  270. degC = 0;
  271. memset(C, 0, sizeof(C));
  272. // Initialize F
  273. bool isZero = true;
  274. for (unsigned i = 0; i < 17; ++i) {
  275. if (A.Items[i] != 0) {
  276. isZero = false;
  277. }
  278. F[i] = A.Items[i];
  279. if (F[i]) {
  280. degF = i;
  281. }
  282. }
  283. memset(F + 17, 0, 17 * sizeof(uint16_t));
  284. if (isZero) {
  285. throw std::domain_error("Zero doesn't have inverse.");
  286. }
  287. // initialize G = x^17 + x^3 + 1;
  288. degG = 17;
  289. memset(G, 0, sizeof(G));
  290. G[0] = 1;
  291. G[3] = 1;
  292. G[17] = 1;
  293. for (uint16_t *lpF = F, *lpG = G, *lpB = B, *lpC = C;;) {
  294. if (degF == 0) {
  295. for (size_t i = 0; i <= degB; ++i) {
  296. if (lpB[i]) {
  297. auto g = GF2p15LogTable[lpB[i]] - GF2p15LogTable[lpF[0]];
  298. if (g < 0) {
  299. g += 0x7fff;
  300. }
  301. Result.Items[i] = GF2p15ExpTable[g];
  302. } else {
  303. Result.Items[i] = 0;
  304. }
  305. }
  306. for (size_t i = degB + 1; i < 17; ++i) {
  307. Result.Items[i] = 0;
  308. }
  309. break;
  310. }
  311. if (degF < degG) {
  312. std::swap(lpF, lpG);
  313. std::swap(degF, degG);
  314. std::swap(lpB, lpC);
  315. std::swap(degB, degC);
  316. }
  317. auto j = degF - degG;
  318. auto g = GF2p15LogTable[lpF[degF]] - GF2p15LogTable[lpG[degG]];
  319. if (g < 0) {
  320. g += 0x7fff;
  321. }
  322. auto Alpha = GF2p15ExpTable[g];
  323. AddScale(lpF, degF, Alpha, j, lpG, degG);
  324. AddScale(lpB, degB, Alpha, j, lpC, degC);
  325. }
  326. }
  327. static inline void InverseAssign(ElementType& Result) {
  328. Inverse(Result, Result);
  329. }
  330. static inline void Square(ElementType& Result, const ElementType& A) noexcept {
  331. uint16_t temp[16 + 16 + 1];
  332. for (size_t i = 0; i < 17; ++i) {
  333. if (A.Items[i]) {
  334. auto g = GF2p15LogTable[A.Items[i]] * 2;
  335. if (g >= 0x7fff) {
  336. g -= 0x7fff;
  337. }
  338. temp[2 * i] = GF2p15ExpTable[g];
  339. } else {
  340. temp[2 * i] = 0;
  341. }
  342. }
  343. for (size_t i = 1; i < 16 + 16 + 1; i += 2) {
  344. temp[i] = 0;
  345. }
  346. ModularReduction(16 + 16 + 1, temp);
  347. memcpy(Result.Items, temp, sizeof(ElementType::Items));
  348. }
  349. static inline void SquareAssign(ElementType& A) noexcept {
  350. Square(A, A);
  351. }
  352. };
  353. static inline const EllipticCurveGF2m<GaloisField<GF2p15p17Traits>> Curve{
  354. { GaloisFieldInitByZero{} }, // A
  355. { GaloisFieldInitByElement{}, { 161 } } // B
  356. };
  357. static inline const EllipticCurveGF2m<GaloisField<GF2p15p17Traits>>::Point G = Curve.GetPoint(
  358. {
  359. GaloisFieldInitByElement{},
  360. {
  361. 0x38CC, 0x052F, 0x2510, 0x45AA,
  362. 0x1B89, 0x4468, 0x4882, 0x0D67,
  363. 0x4FEB, 0x55CE, 0x0025, 0x4CB7,
  364. 0x0CC2, 0x59DC, 0x289E, 0x65E3,
  365. 0x56FD
  366. }
  367. },
  368. {
  369. GaloisFieldInitByElement{},
  370. {
  371. 0x31A7, 0x65F2, 0x18C4, 0x3412,
  372. 0x7388, 0x54C1, 0x539B, 0x4A02,
  373. 0x4D07, 0x12D6, 0x7911, 0x3B5E,
  374. 0x4F0E, 0x216F, 0x2BF2, 0x1974,
  375. 0x20DA
  376. }
  377. }
  378. );
  379. static inline const BigInteger Order = "0x1026dd85081b82314691ced9bbec30547840e4bf72d8b5e0d258442bbcd31";
  380. // Generated by `WinRarKeygen<WinRarConfig>::GeneratePrivateKey(nullptr, 0);`
  381. static inline const BigInteger PrivateKey = "0x59fe6abcca90bdb95f0105271fa85fb9f11f467450c1ae9044b7fd61d65e";
  382. static inline const EllipticCurveGF2m<GaloisField<GF2p15p17Traits>>::Point PublicKey = Curve.GetPoint(
  383. {
  384. GaloisFieldInitByElement{},
  385. {
  386. 0x3A1A, 0x1109, 0x268A, 0x12F7,
  387. 0x3734, 0x75F0, 0x576C, 0x2EA4,
  388. 0x4813, 0x3F62, 0x0567, 0x784D,
  389. 0x753D, 0x6D92, 0x366C, 0x1107,
  390. 0x3861
  391. }
  392. },
  393. {
  394. GaloisFieldInitByElement{},
  395. {
  396. 0x6C20, 0x6027, 0x1B22, 0x7A87,
  397. 0x43C4, 0x1908, 0x2449, 0x4675,
  398. 0x7933, 0x2E66, 0x32F5, 0x2A58,
  399. 0x1145, 0x74AC, 0x36D0, 0x2731,
  400. 0x12B6
  401. }
  402. }
  403. );
  404. };